VirtualBox

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

Last change on this file since 59248 was 59248, checked in by vboxsync, 9 years ago

Storage: Get rid of the block driver and merge the the little extra functionality it had into the VD driver. Enables us to get rid of PDMIBLOCK which is basically a subset of PDMIMEDIA and makes changes to the latter interface tedious because it had to be replicated in the former. (bugref:4114)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 328.4 KB
Line 
1/* $Id: DevAHCI.cpp 59248 2016-01-04 14:13:22Z vboxsync $ */
2/** @file
3 * DevAHCI - AHCI controller device (disk and cdrom).
4 *
5 * Implements the AHCI standard 1.1
6 */
7
8/*
9 * Copyright (C) 2006-2015 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20/** @page pg_dev_ahci AHCI - Advanced Host Controller Interface Emulation.
21 *
22 * This component implements an AHCI serial ATA controller. The device is split
23 * into two parts. The first part implements the register interface for the
24 * guest and the second one does the data transfer.
25 *
26 * The guest can access the controller in two ways. The first one is the native
27 * way implementing the registers described in the AHCI specification and is
28 * the preferred one. The second implements the I/O ports used for booting from
29 * the hard disk and for guests which don't have an AHCI SATA driver.
30 *
31 * The data is transferred in an asynchronous way using one thread per implemented
32 * port or using the new async completion interface which is still under
33 * development. [not quite up to date]
34 */
35
36
37/*********************************************************************************************************************************
38* Header Files *
39*********************************************************************************************************************************/
40#define LOG_GROUP LOG_GROUP_DEV_AHCI
41#include <VBox/vmm/pdmdev.h>
42#include <VBox/vmm/pdmqueue.h>
43#include <VBox/vmm/pdmthread.h>
44#include <VBox/vmm/pdmcritsect.h>
45#include <VBox/sup.h>
46#include <VBox/scsi.h>
47#include <iprt/assert.h>
48#include <iprt/asm.h>
49#include <iprt/string.h>
50#include <iprt/list.h>
51#ifdef IN_RING3
52# include <iprt/param.h>
53# include <iprt/thread.h>
54# include <iprt/semaphore.h>
55# include <iprt/alloc.h>
56# include <iprt/uuid.h>
57# include <iprt/time.h>
58#endif
59#include "PIIX3ATABmDma.h"
60#include "ide.h"
61#include "ATAPIPassthrough.h"
62#include "VBoxDD.h"
63
64#if defined(VBOX_WITH_DTRACE) \
65 && defined(IN_RING3) \
66 && !defined(VBOX_DEVICE_STRUCT_TESTCASE)
67# include "dtrace/VBoxDD.h"
68#else
69# define VBOXDD_AHCI_REQ_SUBMIT(a,b,c,d) do { } while (0)
70# define VBOXDD_AHCI_REQ_SUBMIT_TIMESTAMP(a,b) do { } while (0)
71# define VBOXDD_AHCI_REQ_COMPLETED(a,b,c,d,e) do { } while (0)
72# define VBOXDD_AHCI_REQ_COMPLETED_TIMESTAMP(a,b) do { } while (0)
73#endif
74
75/** Maximum number of ports available.
76 * Spec defines 32 but we have one allocated for command completion coalescing
77 * and another for a reserved future feature.
78 */
79#define AHCI_MAX_NR_PORTS_IMPL 30
80/** Maximum number of command slots available. */
81#define AHCI_NR_COMMAND_SLOTS 32
82
83#define AHCI_MAX_ALLOC_TOO_MUCH 20
84
85/** The current saved state version. */
86#define AHCI_SAVED_STATE_VERSION 8
87/** The saved state version before changing the port reset logic in an incompatible way. */
88#define AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES 7
89/** Saved state version before the per port hotplug port was added. */
90#define AHCI_SAVED_STATE_VERSION_PRE_HOTPLUG_FLAG 6
91/** Saved state version before legacy ATA emulation was dropped. */
92#define AHCI_SAVED_STATE_VERSION_IDE_EMULATION 5
93/** Saved state version before ATAPI support was added. */
94#define AHCI_SAVED_STATE_VERSION_PRE_ATAPI 3
95/** The saved state version use in VirtualBox 3.0 and earlier.
96 * This was before the config was added and ahciIOTasks was dropped. */
97#define AHCI_SAVED_STATE_VERSION_VBOX_30 2
98/* for Older ATA state Read handling */
99#define ATA_CTL_SAVED_STATE_VERSION 3
100#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE 1
101#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS 2
102
103/** The maximum number of release log entries per device. */
104#define MAX_LOG_REL_ERRORS 1024
105
106/**
107 * Maximum number of sectors to transfer in a READ/WRITE MULTIPLE request.
108 * Set to 1 to disable multi-sector read support. According to the ATA
109 * specification this must be a power of 2 and it must fit in an 8 bit
110 * value. Thus the only valid values are 1, 2, 4, 8, 16, 32, 64 and 128.
111 */
112#define ATA_MAX_MULT_SECTORS 128
113
114/**
115 * Fastest PIO mode supported by the drive.
116 */
117#define ATA_PIO_MODE_MAX 4
118/**
119 * Fastest MDMA mode supported by the drive.
120 */
121#define ATA_MDMA_MODE_MAX 2
122/**
123 * Fastest UDMA mode supported by the drive.
124 */
125#define ATA_UDMA_MODE_MAX 6
126
127/**
128 * Length of the configurable VPD data (without termination)
129 */
130#define AHCI_SERIAL_NUMBER_LENGTH 20
131#define AHCI_FIRMWARE_REVISION_LENGTH 8
132#define AHCI_MODEL_NUMBER_LENGTH 40
133#define AHCI_ATAPI_INQUIRY_VENDOR_ID_LENGTH 8
134#define AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH 16
135#define AHCI_ATAPI_INQUIRY_REVISION_LENGTH 4
136
137/* MediaEventStatus */
138#define ATA_EVENT_STATUS_UNCHANGED 0 /**< medium event status not changed */
139#define ATA_EVENT_STATUS_MEDIA_NEW 1 /**< new medium inserted */
140#define ATA_EVENT_STATUS_MEDIA_REMOVED 2 /**< medium removed */
141#define ATA_EVENT_STATUS_MEDIA_CHANGED 3 /**< medium was removed + new medium was inserted */
142#define ATA_EVENT_STATUS_MEDIA_EJECT_REQUESTED 4 /**< medium eject requested (eject button pressed) */
143
144/* Media track type */
145#define ATA_MEDIA_TYPE_UNKNOWN 0 /**< unknown CD type */
146
147/** ATAPI sense info size. */
148#define ATAPI_SENSE_SIZE 64
149
150/**
151 * Command Header.
152 */
153#pragma pack(1)
154typedef struct
155{
156 /** Description Information. */
157 uint32_t u32DescInf;
158 /** Command status. */
159 uint32_t u32PRDBC;
160 /** Command Table Base Address. */
161 uint32_t u32CmdTblAddr;
162 /** Command Table Base Address - upper 32-bits. */
163 uint32_t u32CmdTblAddrUp;
164 /** Reserved */
165 uint32_t u32Reserved[4];
166} CmdHdr;
167#pragma pack()
168AssertCompileSize(CmdHdr, 32);
169
170/* Defines for the command header. */
171#define AHCI_CMDHDR_PRDTL_MASK 0xffff0000
172#define AHCI_CMDHDR_PRDTL_ENTRIES(x) ((x & AHCI_CMDHDR_PRDTL_MASK) >> 16)
173#define AHCI_CMDHDR_C RT_BIT(10)
174#define AHCI_CMDHDR_B RT_BIT(9)
175#define AHCI_CMDHDR_R RT_BIT(8)
176#define AHCI_CMDHDR_P RT_BIT(7)
177#define AHCI_CMDHDR_W RT_BIT(6)
178#define AHCI_CMDHDR_A RT_BIT(5)
179#define AHCI_CMDHDR_CFL_MASK 0x1f
180
181#define AHCI_CMDHDR_PRDT_OFFSET 0x80
182#define AHCI_CMDHDR_ACMD_OFFSET 0x40
183
184/* Defines for the command FIS. */
185/* Defines that are used in the first double word. */
186#define AHCI_CMDFIS_TYPE 0 /* The first byte. */
187# define AHCI_CMDFIS_TYPE_H2D 0x27 /* Register - Host to Device FIS. */
188# define AHCI_CMDFIS_TYPE_H2D_SIZE 20 /* Five double words. */
189# define AHCI_CMDFIS_TYPE_D2H 0x34 /* Register - Device to Host FIS. */
190# define AHCI_CMDFIS_TYPE_D2H_SIZE 20 /* Five double words. */
191# define AHCI_CMDFIS_TYPE_SETDEVBITS 0xa1 /* Set Device Bits - Device to Host FIS. */
192# define AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE 8 /* Two double words. */
193# define AHCI_CMDFIS_TYPE_DMAACTD2H 0x39 /* DMA Activate - Device to Host FIS. */
194# define AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE 4 /* One double word. */
195# define AHCI_CMDFIS_TYPE_DMASETUP 0x41 /* DMA Setup - Bidirectional FIS. */
196# define AHCI_CMDFIS_TYPE_DMASETUP_SIZE 28 /* Seven double words. */
197# define AHCI_CMDFIS_TYPE_PIOSETUP 0x5f /* PIO Setup - Device to Host FIS. */
198# define AHCI_CMDFIS_TYPE_PIOSETUP_SIZE 20 /* Five double words. */
199# define AHCI_CMDFIS_TYPE_DATA 0x46 /* Data - Bidirectional FIS. */
200
201#define AHCI_CMDFIS_BITS 1 /* Interrupt and Update bit. */
202#define AHCI_CMDFIS_C RT_BIT(7) /* Host to device. */
203#define AHCI_CMDFIS_I RT_BIT(6) /* Device to Host. */
204#define AHCI_CMDFIS_D RT_BIT(5)
205
206#define AHCI_CMDFIS_CMD 2
207#define AHCI_CMDFIS_FET 3
208
209#define AHCI_CMDFIS_SECTN 4
210#define AHCI_CMDFIS_CYLL 5
211#define AHCI_CMDFIS_CYLH 6
212#define AHCI_CMDFIS_HEAD 7
213
214#define AHCI_CMDFIS_SECTNEXP 8
215#define AHCI_CMDFIS_CYLLEXP 9
216#define AHCI_CMDFIS_CYLHEXP 10
217#define AHCI_CMDFIS_FETEXP 11
218
219#define AHCI_CMDFIS_SECTC 12
220#define AHCI_CMDFIS_SECTCEXP 13
221#define AHCI_CMDFIS_CTL 15
222# define AHCI_CMDFIS_CTL_SRST RT_BIT(2) /* Reset device. */
223# define AHCI_CMDFIS_CTL_NIEN RT_BIT(1) /* Assert or clear interrupt. */
224
225/* For D2H FIS */
226#define AHCI_CMDFIS_STS 2
227#define AHCI_CMDFIS_ERR 3
228
229/** Pointer to a task state. */
230typedef struct AHCIREQ *PAHCIREQ;
231
232/**
233 * Data processing callback
234 *
235 * @returns VBox status code.
236 * @param pAhciReq The task state.
237 * @param ppvProc Where to store the pointer to the buffer holding the processed data on success.
238 * Must be freed with RTMemFree().
239 * @param pcbProc Where to store the size of the buffer on success.
240 */
241typedef DECLCALLBACK(int) FNAHCIPOSTPROCESS(PAHCIREQ pAhciReq, void **ppvProc, size_t *pcbProc);
242/** Pointer to a FNAHCIPOSTPROCESS() function. */
243typedef FNAHCIPOSTPROCESS *PFNAHCIPOSTPROCESS;
244
245/**
246 * Transfer type.
247 */
248typedef enum AHCITXDIR
249{
250 /** Invalid */
251 AHCITXDIR_INVALID = 0,
252 /** None */
253 AHCITXDIR_NONE,
254 /** Read */
255 AHCITXDIR_READ,
256 /** Write */
257 AHCITXDIR_WRITE,
258 /** Flush */
259 AHCITXDIR_FLUSH,
260 /** Trim */
261 AHCITXDIR_TRIM
262} AHCITXDIR;
263
264/**
265 * Task state.
266 */
267typedef enum AHCITXSTATE
268{
269 /** Invalid. */
270 AHCITXSTATE_INVALID = 0,
271 /** Task is not active. */
272 AHCITXSTATE_FREE,
273 /** Task is active */
274 AHCITXSTATE_ACTIVE,
275 /** Task was canceled but the request didn't completed yet. */
276 AHCITXSTATE_CANCELED,
277 /** 32bit hack. */
278 AHCITXSTATE_32BIT_HACK = 0x7fffffff
279} AHCITXSTATE, *PAHCITXSTATE;
280AssertCompileSize(AHCITXSTATE, sizeof(uint32_t));
281
282/** Task encountered a buffer overflow. */
283#define AHCI_REQ_OVERFLOW RT_BIT_32(0)
284/** Request is a PIO data command, if this flag is not set it either is
285 * a command which does not transfer data or a DMA command based on the transfer size. */
286#define AHCI_REQ_PIO_DATA RT_BIT_32(1)
287/** The request has the SACT register set. */
288#define AHCI_REQ_CLEAR_SACT RT_BIT_32(2)
289/** Flag whether the request is queued. */
290#define AHCI_REQ_IS_QUEUED RT_BIT_32(3)
291/** Flag whether the request is stored on the stack. */
292#define AHCI_REQ_IS_ON_STACK RT_BIT_32(4)
293
294/**
295 * A task state.
296 */
297typedef struct AHCIREQ
298{
299 /** List node for the free list if the request is not in use. */
300 RTLISTNODE NodeList;
301 /** Task state. */
302 volatile AHCITXSTATE enmTxState;
303 /** Start timestamp of the request. */
304 uint64_t tsStart;
305 /** Tag of the task. */
306 uint32_t uTag;
307 /** The command header for this task. */
308 CmdHdr cmdHdr;
309 /** The command Fis for this task. */
310 uint8_t cmdFis[AHCI_CMDFIS_TYPE_H2D_SIZE];
311 /** The ATAPI command data. */
312 uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
313 /** Size of one sector for the ATAPI transfer. */
314 size_t cbATAPISector;
315 /** Physical address of the command header. - GC */
316 RTGCPHYS GCPhysCmdHdrAddr;
317 /** Physical address if the PRDT */
318 RTGCPHYS GCPhysPrdtl;
319 /** Number of entries in the PRDTL. */
320 unsigned cPrdtlEntries;
321 /** Data direction. */
322 AHCITXDIR enmTxDir;
323 /** Start offset. */
324 uint64_t uOffset;
325 /** Number of bytes to transfer. */
326 uint32_t cbTransfer;
327 /** ATA error register */
328 uint8_t uATARegError;
329 /** ATA status register */
330 uint8_t uATARegStatus;
331 /** Flags for this task. */
332 uint32_t fFlags;
333 /** Additional memory allocation for this task. */
334 void *pvAlloc;
335 /** Siize of the allocation. */
336 size_t cbAlloc;
337 /** Number of times we had too much memory allocated for the request. */
338 unsigned cAllocTooMuch;
339 /** Data dependent on the transfer direction. */
340 union
341 {
342 /** Data for an I/O request. */
343 struct
344 {
345 /** Data segment. */
346 RTSGSEG DataSeg;
347 /** Post processing callback.
348 * If this is set we will use a buffer for the data
349 * and the callback returns a buffer with the final data. */
350 PFNAHCIPOSTPROCESS pfnPostProcess;
351 } Io;
352 /** Data for a trim request. */
353 struct
354 {
355 /** Pointer to the array of ranges to trim. */
356 PRTRANGE paRanges;
357 /** Number of entries in the array. */
358 unsigned cRanges;
359 } Trim;
360 } u;
361} AHCIREQ;
362
363/**
364 * Notifier queue item.
365 */
366typedef struct DEVPORTNOTIFIERQUEUEITEM
367{
368 /** The core part owned by the queue manager. */
369 PDMQUEUEITEMCORE Core;
370 /** The port to process. */
371 uint8_t iPort;
372} DEVPORTNOTIFIERQUEUEITEM, *PDEVPORTNOTIFIERQUEUEITEM;
373
374
375/**
376 * @implements PDMIBASE
377 * @implements PDMIMEDIAPORT
378 * @implements PDMIMEDIAASYNCPORT
379 * @implements PDMIMOUNTNOTIFY
380 */
381typedef struct AHCIPort
382{
383 /** Pointer to the device instance - HC ptr */
384 PPDMDEVINSR3 pDevInsR3;
385 /** Pointer to the device instance - R0 ptr */
386 PPDMDEVINSR0 pDevInsR0;
387 /** Pointer to the device instance - RC ptr. */
388 PPDMDEVINSRC pDevInsRC;
389
390#if HC_ARCH_BITS == 64
391 uint32_t Alignment0;
392#endif
393
394 /** Pointer to the parent AHCI structure - R3 ptr. */
395 R3PTRTYPE(struct AHCI *) pAhciR3;
396 /** Pointer to the parent AHCI structure - R0 ptr. */
397 R0PTRTYPE(struct AHCI *) pAhciR0;
398 /** Pointer to the parent AHCI structure - RC ptr. */
399 RCPTRTYPE(struct AHCI *) pAhciRC;
400
401 /** Command List Base Address. */
402 uint32_t regCLB;
403 /** Command List Base Address upper bits. */
404 uint32_t regCLBU;
405 /** FIS Base Address. */
406 uint32_t regFB;
407 /** FIS Base Address upper bits. */
408 uint32_t regFBU;
409 /** Interrupt Status. */
410 volatile uint32_t regIS;
411 /** Interrupt Enable. */
412 uint32_t regIE;
413 /** Command. */
414 uint32_t regCMD;
415 /** Task File Data. */
416 uint32_t regTFD;
417 /** Signature */
418 uint32_t regSIG;
419 /** Serial ATA Status. */
420 uint32_t regSSTS;
421 /** Serial ATA Control. */
422 uint32_t regSCTL;
423 /** Serial ATA Error. */
424 uint32_t regSERR;
425 /** Serial ATA Active. */
426 volatile uint32_t regSACT;
427 /** Command Issue. */
428 uint32_t regCI;
429
430 /** Current number of active tasks. */
431 volatile uint32_t cTasksActive;
432 /** Command List Base Address */
433 volatile RTGCPHYS GCPhysAddrClb;
434 /** FIS Base Address */
435 volatile RTGCPHYS GCPhysAddrFb;
436
437 /** Device is powered on. */
438 bool fPoweredOn;
439 /** Device has spun up. */
440 bool fSpunUp;
441 /** First D2H FIS was send. */
442 bool fFirstD2HFisSend;
443 /** Mark the drive as having a non-rotational medium (i.e. as a SSD). */
444 bool fNonRotational;
445 /** Attached device is a CD/DVD drive. */
446 bool fATAPI;
447 /** Passthrough SCSI commands. */
448 bool fATAPIPassthrough;
449 /** Flag whether this port is in a reset state. */
450 volatile bool fPortReset;
451 /** If we use the new async interface. */
452 bool fAsyncInterface;
453 /** Flag if we are in a device reset. */
454 bool fResetDevice;
455 /** Flag whether this port is hot plug capable. */
456 bool fHotpluggable;
457 /** Flag whether the port is in redo task mode. */
458 volatile bool fRedo;
459 /** Flag whether the worker thread is sleeping. */
460 volatile bool fWrkThreadSleeping;
461
462 bool afAlignment[3];
463
464 /** Number of total sectors. */
465 uint64_t cTotalSectors;
466 /** Size of one sector. */
467 uint32_t cbSector;
468 /** Currently configured number of sectors in a multi-sector transfer. */
469 uint32_t cMultSectors;
470 /** Currently active transfer mode (MDMA/UDMA) and speed. */
471 uint8_t uATATransferMode;
472 /** ATAPI sense data. */
473 uint8_t abATAPISense[ATAPI_SENSE_SIZE];
474 /** HACK: Countdown till we report a newly unmounted drive as mounted. */
475 uint8_t cNotifiedMediaChange;
476 /** Exponent of logical sectors in a physical sector, number of logical sectors is 2^exp. */
477 uint8_t cLogSectorsPerPhysicalExp;
478 /** The same for GET_EVENT_STATUS for mechanism */
479 volatile uint32_t MediaEventStatus;
480 /** Media type if known. */
481 volatile uint32_t MediaTrackType;
482 /** The LUN. */
483 RTUINT iLUN;
484
485 /** Bitmap for finished tasks (R3 -> Guest). */
486 volatile uint32_t u32TasksFinished;
487 /** Bitmap for finished queued tasks (R3 -> Guest). */
488 volatile uint32_t u32QueuedTasksFinished;
489 /** Bitmap for new queued tasks (Guest -> R3). */
490 volatile uint32_t u32TasksNew;
491 /** Bitmap of tasks which must be redone because of a non fatal error. */
492 volatile uint32_t u32TasksRedo;
493
494 /** Current command slot processed.
495 * Accessed by the guest by reading the CMD register.
496 * Holds the command slot of the command processed at the moment. */
497 volatile uint32_t u32CurrentCommandSlot;
498
499#if HC_ARCH_BITS == 64
500 uint32_t u32Alignment2;
501#endif
502
503 /** Device specific settings (R3 only stuff). */
504 /** Pointer to the attached driver's base interface. */
505 R3PTRTYPE(PPDMIBASE) pDrvBase;
506 /** Pointer to the attached driver's block interface. */
507 R3PTRTYPE(PPDMIMEDIA) pDrvMedia;
508 /** Pointer to the attached driver's async block interface. */
509 R3PTRTYPE(PPDMIMEDIAASYNC) pDrvMediaAsync;
510 /** Pointer to the attached driver's mount interface. */
511 R3PTRTYPE(PPDMIMOUNT) pDrvMount;
512 /** The base interface. */
513 PDMIBASE IBase;
514 /** The block port interface. */
515 PDMIMEDIAPORT IPort;
516 /** The optional block async port interface. */
517 PDMIMEDIAASYNCPORT IPortAsync;
518 /** The mount notify interface. */
519 PDMIMOUNTNOTIFY IMountNotify;
520 /** Physical geometry of this image. */
521 PDMMEDIAGEOMETRY PCHSGeometry;
522 /** The status LED state for this drive. */
523 PDMLED Led;
524
525 uint32_t u32Alignment3;
526
527 /** Async IO Thread. */
528 R3PTRTYPE(PPDMTHREAD) pAsyncIOThread;
529 /** Array of active tasks indexed by the tag. */
530 R3PTRTYPE(volatile PAHCIREQ) aActiveTasks[AHCI_NR_COMMAND_SLOTS];
531 /** First task throwing an error. */
532 R3PTRTYPE(volatile PAHCIREQ) pTaskErr;
533 /** The current tracklist of the loaded medium if passthrough is used. */
534 R3PTRTYPE(PTRACKLIST) pTrackList;
535
536 /** The event semaphore the processing thread waits on. */
537 SUPSEMEVENT hEvtProcess;
538
539 /** Release statistics: number of DMA commands. */
540 STAMCOUNTER StatDMA;
541 /** Release statistics: number of bytes written. */
542 STAMCOUNTER StatBytesWritten;
543 /** Release statistics: number of bytes read. */
544 STAMCOUNTER StatBytesRead;
545 /** Release statistics: Number of I/O requests processed per second. */
546 STAMCOUNTER StatIORequestsPerSecond;
547#ifdef VBOX_WITH_STATISTICS
548 /** Statistics: Time to complete one request. */
549 STAMPROFILE StatProfileProcessTime;
550 /** Statistics: Amount of time to read/write data. */
551 STAMPROFILE StatProfileReadWrite;
552#endif /* VBOX_WITH_STATISTICS */
553
554 /** The serial numnber to use for IDENTIFY DEVICE commands. */
555 char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
556 /** The firmware revision to use for IDENTIFY DEVICE commands. */
557 char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1]; /** < one extra byte for termination */
558 /** The model number to use for IDENTIFY DEVICE commands. */
559 char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
560 /** The vendor identification string for SCSI INQUIRY commands. */
561 char szInquiryVendorId[AHCI_ATAPI_INQUIRY_VENDOR_ID_LENGTH+1];
562 /** The product identification string for SCSI INQUIRY commands. */
563 char szInquiryProductId[AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH+1];
564 /** The revision string for SCSI INQUIRY commands. */
565 char szInquiryRevision[AHCI_ATAPI_INQUIRY_REVISION_LENGTH+1];
566 /** Error counter */
567 uint32_t cErrors;
568
569 uint32_t u32Alignment5;
570
571 /** Critical section protecting the global free list. */
572 RTCRITSECT CritSectReqsFree;
573 /** Head of the global free request list. */
574 R3PTRTYPE(PRTLISTANCHOR) pListReqsFree;
575
576 /** Align to a multiple of 8. */
577#if HC_ARCH_BITS == 32
578 uint32_t u32Alignment6;
579#endif
580
581} AHCIPort;
582/** Pointer to the state of an AHCI port. */
583typedef AHCIPort *PAHCIPort;
584
585AssertCompileMemberAlignment(AHCIPort, StatDMA, 8);
586AssertCompileSizeAlignment(AHCIPort, 8);
587
588/**
589 * Main AHCI device state.
590 *
591 * @implements PDMILEDPORTS
592 */
593typedef struct AHCI
594{
595 /** The PCI device structure. */
596 PCIDEVICE dev;
597 /** Pointer to the device instance - R3 ptr */
598 PPDMDEVINSR3 pDevInsR3;
599 /** Pointer to the device instance - R0 ptr */
600 PPDMDEVINSR0 pDevInsR0;
601 /** Pointer to the device instance - RC ptr. */
602 PPDMDEVINSRC pDevInsRC;
603
604#if HC_ARCH_BITS == 64
605 uint32_t Alignment0;
606#endif
607
608 /** Status LUN: The base interface. */
609 PDMIBASE IBase;
610 /** Status LUN: Leds interface. */
611 PDMILEDPORTS ILeds;
612 /** Status LUN: Partner of ILeds. */
613 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
614 /** Status LUN: Media Notifys. */
615 R3PTRTYPE(PPDMIMEDIANOTIFY) pMediaNotify;
616
617#if HC_ARCH_BITS == 32
618 uint32_t Alignment1;
619#endif
620
621 /** Base address of the MMIO region. */
622 RTGCPHYS MMIOBase;
623 /** Base address of the I/O port region for Idx/Data. */
624 RTIOPORT IOPortBase;
625
626 /** Global Host Control register of the HBA */
627
628 /** HBA Capabilities - Readonly */
629 uint32_t regHbaCap;
630 /** HBA Control */
631 uint32_t regHbaCtrl;
632 /** Interrupt Status */
633 uint32_t regHbaIs;
634 /** Ports Implemented - Readonly */
635 uint32_t regHbaPi;
636 /** AHCI Version - Readonly */
637 uint32_t regHbaVs;
638 /** Command completion coalescing control */
639 uint32_t regHbaCccCtl;
640 /** Command completion coalescing ports */
641 uint32_t regHbaCccPorts;
642
643 /** Index register for BIOS access. */
644 uint32_t regIdx;
645
646#if HC_ARCH_BITS == 64
647 uint32_t Alignment3;
648#endif
649
650 /** Countdown timer for command completion coalescing - R3 ptr */
651 PTMTIMERR3 pHbaCccTimerR3;
652 /** Countdown timer for command completion coalescing - R0 ptr */
653 PTMTIMERR0 pHbaCccTimerR0;
654 /** Countdown timer for command completion coalescing - RC ptr */
655 PTMTIMERRC pHbaCccTimerRC;
656
657#if HC_ARCH_BITS == 64
658 uint32_t Alignment4;
659#endif
660
661 /** Queue to send tasks to R3. - HC ptr */
662 R3PTRTYPE(PPDMQUEUE) pNotifierQueueR3;
663 /** Queue to send tasks to R3. - HC ptr */
664 R0PTRTYPE(PPDMQUEUE) pNotifierQueueR0;
665 /** Queue to send tasks to R3. - RC ptr */
666 RCPTRTYPE(PPDMQUEUE) pNotifierQueueRC;
667
668#if HC_ARCH_BITS == 64
669 uint32_t Alignment5;
670#endif
671
672
673 /** Which port number is used to mark an CCC interrupt */
674 uint8_t uCccPortNr;
675
676#if HC_ARCH_BITS == 64
677 uint32_t Alignment6;
678#endif
679
680 /** Timeout value */
681 uint64_t uCccTimeout;
682 /** Number of completions used to assert an interrupt */
683 uint32_t uCccNr;
684 /** Current number of completed commands */
685 uint32_t uCccCurrentNr;
686
687 /** Register structure per port */
688 AHCIPort ahciPort[AHCI_MAX_NR_PORTS_IMPL];
689
690 /** The critical section. */
691 PDMCRITSECT lock;
692
693 /** Bitmask of ports which asserted an interrupt. */
694 volatile uint32_t u32PortsInterrupted;
695 /** Number of I/O threads currently active - used for async controller reset handling. */
696 volatile uint32_t cThreadsActive;
697 /** Device is in a reset state. */
698 bool fReset;
699 /** Supports 64bit addressing */
700 bool f64BitAddr;
701 /** GC enabled. */
702 bool fGCEnabled;
703 /** R0 enabled. */
704 bool fR0Enabled;
705 /** If the new async interface is used if available. */
706 bool fUseAsyncInterfaceIfAvailable;
707 /** Indicates that PDMDevHlpAsyncNotificationCompleted should be called when
708 * a port is entering the idle state. */
709 bool volatile fSignalIdle;
710 /** Flag whether the controller has BIOS access enabled. */
711 bool fBootable;
712 /** Flag whether the legacy port reset method should be used to make it work with saved states. */
713 bool fLegacyPortResetMethod;
714
715 /** Number of usable ports on this controller. */
716 uint32_t cPortsImpl;
717 /** Number of usable command slots for each port. */
718 uint32_t cCmdSlotsAvail;
719
720 /** Flag whether we have written the first 4bytes in an 8byte MMIO write successfully. */
721 volatile bool f8ByteMMIO4BytesWrittenSuccessfully;
722
723#if HC_ARCH_BITS == 64
724 uint32_t Alignment7;
725#endif
726
727 /** The support driver session handle. */
728 R3R0PTRTYPE(PSUPDRVSESSION) pSupDrvSession;
729} AHCI;
730/** Pointer to the state of an AHCI device. */
731typedef AHCI *PAHCI;
732
733AssertCompileMemberAlignment(AHCI, ahciPort, 8);
734
735/**
736 * Scatter gather list entry.
737 */
738typedef struct
739{
740 /** Data Base Address. */
741 uint32_t u32DBA;
742 /** Data Base Address - Upper 32-bits. */
743 uint32_t u32DBAUp;
744 /** Reserved */
745 uint32_t u32Reserved;
746 /** Description information. */
747 uint32_t u32DescInf;
748} SGLEntry;
749AssertCompileSize(SGLEntry, 16);
750
751/** Defines for a scatter gather list entry. */
752#define SGLENTRY_DBA_READONLY ~(RT_BIT(0))
753#define SGLENTRY_DESCINF_I RT_BIT(31)
754#define SGLENTRY_DESCINF_DBC 0x3fffff
755#define SGLENTRY_DESCINF_READONLY 0x803fffff
756
757/* Defines for the global host control registers for the HBA. */
758
759#define AHCI_HBA_GLOBAL_SIZE 0x100
760
761/* Defines for the HBA Capabilities - Readonly */
762#define AHCI_HBA_CAP_S64A RT_BIT(31)
763#define AHCI_HBA_CAP_SNCQ RT_BIT(30)
764#define AHCI_HBA_CAP_SIS RT_BIT(28)
765#define AHCI_HBA_CAP_SSS RT_BIT(27)
766#define AHCI_HBA_CAP_SALP RT_BIT(26)
767#define AHCI_HBA_CAP_SAL RT_BIT(25)
768#define AHCI_HBA_CAP_SCLO RT_BIT(24)
769#define AHCI_HBA_CAP_ISS (RT_BIT(23) | RT_BIT(22) | RT_BIT(21) | RT_BIT(20))
770# define AHCI_HBA_CAP_ISS_SHIFT(x) (((x) << 20) & AHCI_HBA_CAP_ISS)
771# define AHCI_HBA_CAP_ISS_GEN1 RT_BIT(0)
772# define AHCI_HBA_CAP_ISS_GEN2 RT_BIT(1)
773#define AHCI_HBA_CAP_SNZO RT_BIT(19)
774#define AHCI_HBA_CAP_SAM RT_BIT(18)
775#define AHCI_HBA_CAP_SPM RT_BIT(17)
776#define AHCI_HBA_CAP_PMD RT_BIT(15)
777#define AHCI_HBA_CAP_SSC RT_BIT(14)
778#define AHCI_HBA_CAP_PSC RT_BIT(13)
779#define AHCI_HBA_CAP_NCS (RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
780#define AHCI_HBA_CAP_NCS_SET(x) (((x-1) << 8) & AHCI_HBA_CAP_NCS) /* 0's based */
781#define AHCI_HBA_CAP_CCCS RT_BIT(7)
782#define AHCI_HBA_CAP_NP (RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
783#define AHCI_HBA_CAP_NP_SET(x) ((x-1) & AHCI_HBA_CAP_NP) /* 0's based */
784
785/* Defines for the HBA Control register - Read/Write */
786#define AHCI_HBA_CTRL_AE RT_BIT(31)
787#define AHCI_HBA_CTRL_IE RT_BIT(1)
788#define AHCI_HBA_CTRL_HR RT_BIT(0)
789#define AHCI_HBA_CTRL_RW_MASK (RT_BIT(0) | RT_BIT(1)) /* Mask for the used bits */
790
791/* Defines for the HBA Version register - Readonly (We support AHCI 1.0) */
792#define AHCI_HBA_VS_MJR (1 << 16)
793#define AHCI_HBA_VS_MNR 0x100
794
795/* Defines for the command completion coalescing control register */
796#define AHCI_HBA_CCC_CTL_TV 0xffff0000
797#define AHCI_HBA_CCC_CTL_TV_SET(x) (x << 16)
798#define AHCI_HBA_CCC_CTL_TV_GET(x) ((x & AHCI_HBA_CCC_CTL_TV) >> 16)
799
800#define AHCI_HBA_CCC_CTL_CC 0xff00
801#define AHCI_HBA_CCC_CTL_CC_SET(x) (x << 8)
802#define AHCI_HBA_CCC_CTL_CC_GET(x) ((x & AHCI_HBA_CCC_CTL_CC) >> 8)
803
804#define AHCI_HBA_CCC_CTL_INT 0xf8
805#define AHCI_HBA_CCC_CTL_INT_SET(x) (x << 3)
806#define AHCI_HBA_CCC_CTL_INT_GET(x) ((x & AHCI_HBA_CCC_CTL_INT) >> 3)
807
808#define AHCI_HBA_CCC_CTL_EN RT_BIT(0)
809
810/* Defines for the port registers. */
811
812#define AHCI_PORT_REGISTER_SIZE 0x80
813
814#define AHCI_PORT_CLB_RESERVED 0xfffffc00 /* For masking out the reserved bits. */
815
816#define AHCI_PORT_FB_RESERVED 0xffffff00 /* For masking out the reserved bits. */
817
818#define AHCI_PORT_IS_CPDS RT_BIT(31)
819#define AHCI_PORT_IS_TFES RT_BIT(30)
820#define AHCI_PORT_IS_HBFS RT_BIT(29)
821#define AHCI_PORT_IS_HBDS RT_BIT(28)
822#define AHCI_PORT_IS_IFS RT_BIT(27)
823#define AHCI_PORT_IS_INFS RT_BIT(26)
824#define AHCI_PORT_IS_OFS RT_BIT(24)
825#define AHCI_PORT_IS_IPMS RT_BIT(23)
826#define AHCI_PORT_IS_PRCS RT_BIT(22)
827#define AHCI_PORT_IS_DIS RT_BIT(7)
828#define AHCI_PORT_IS_PCS RT_BIT(6)
829#define AHCI_PORT_IS_DPS RT_BIT(5)
830#define AHCI_PORT_IS_UFS RT_BIT(4)
831#define AHCI_PORT_IS_SDBS RT_BIT(3)
832#define AHCI_PORT_IS_DSS RT_BIT(2)
833#define AHCI_PORT_IS_PSS RT_BIT(1)
834#define AHCI_PORT_IS_DHRS RT_BIT(0)
835#define AHCI_PORT_IS_READONLY 0xfd8000af /* Readonly mask including reserved bits. */
836
837#define AHCI_PORT_IE_CPDE RT_BIT(31)
838#define AHCI_PORT_IE_TFEE RT_BIT(30)
839#define AHCI_PORT_IE_HBFE RT_BIT(29)
840#define AHCI_PORT_IE_HBDE RT_BIT(28)
841#define AHCI_PORT_IE_IFE RT_BIT(27)
842#define AHCI_PORT_IE_INFE RT_BIT(26)
843#define AHCI_PORT_IE_OFE RT_BIT(24)
844#define AHCI_PORT_IE_IPME RT_BIT(23)
845#define AHCI_PORT_IE_PRCE RT_BIT(22)
846#define AHCI_PORT_IE_DIE RT_BIT(7) /* Not supported for now, readonly. */
847#define AHCI_PORT_IE_PCE RT_BIT(6)
848#define AHCI_PORT_IE_DPE RT_BIT(5)
849#define AHCI_PORT_IE_UFE RT_BIT(4)
850#define AHCI_PORT_IE_SDBE RT_BIT(3)
851#define AHCI_PORT_IE_DSE RT_BIT(2)
852#define AHCI_PORT_IE_PSE RT_BIT(1)
853#define AHCI_PORT_IE_DHRE RT_BIT(0)
854#define AHCI_PORT_IE_READONLY (0xfdc000ff) /* Readonly mask including reserved bits. */
855
856#define AHCI_PORT_CMD_ICC (RT_BIT(28) | RT_BIT(29) | RT_BIT(30) | RT_BIT(31))
857#define AHCI_PORT_CMD_ICC_SHIFT(x) ((x) << 28)
858# define AHCI_PORT_CMD_ICC_IDLE 0x0
859# define AHCI_PORT_CMD_ICC_ACTIVE 0x1
860# define AHCI_PORT_CMD_ICC_PARTIAL 0x2
861# define AHCI_PORT_CMD_ICC_SLUMBER 0x6
862#define AHCI_PORT_CMD_ASP RT_BIT(27) /* Not supported - Readonly */
863#define AHCI_PORT_CMD_ALPE RT_BIT(26) /* Not supported - Readonly */
864#define AHCI_PORT_CMD_DLAE RT_BIT(25)
865#define AHCI_PORT_CMD_ATAPI RT_BIT(24)
866#define AHCI_PORT_CMD_CPD RT_BIT(20)
867#define AHCI_PORT_CMD_ISP RT_BIT(19) /* Readonly */
868#define AHCI_PORT_CMD_HPCP RT_BIT(18)
869#define AHCI_PORT_CMD_PMA RT_BIT(17) /* Not supported - Readonly */
870#define AHCI_PORT_CMD_CPS RT_BIT(16)
871#define AHCI_PORT_CMD_CR RT_BIT(15) /* Readonly */
872#define AHCI_PORT_CMD_FR RT_BIT(14) /* Readonly */
873#define AHCI_PORT_CMD_ISS RT_BIT(13) /* Readonly */
874#define AHCI_PORT_CMD_CCS (RT_BIT(8) | RT_BIT(9) | RT_BIT(10) | RT_BIT(11) | RT_BIT(12))
875#define AHCI_PORT_CMD_CCS_SHIFT(x) (x << 8) /* Readonly */
876#define AHCI_PORT_CMD_FRE RT_BIT(4)
877#define AHCI_PORT_CMD_CLO RT_BIT(3)
878#define AHCI_PORT_CMD_POD RT_BIT(2)
879#define AHCI_PORT_CMD_SUD RT_BIT(1)
880#define AHCI_PORT_CMD_ST RT_BIT(0)
881#define AHCI_PORT_CMD_READONLY (0xff02001f & ~(AHCI_PORT_CMD_ASP | AHCI_PORT_CMD_ALPE | AHCI_PORT_CMD_PMA))
882
883#define AHCI_PORT_SCTL_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
884#define AHCI_PORT_SCTL_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
885#define AHCI_PORT_SCTL_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
886#define AHCI_PORT_SCTL_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
887#define AHCI_PORT_SCTL_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
888#define AHCI_PORT_SCTL_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
889#define AHCI_PORT_SCTL_DET_NINIT 0
890#define AHCI_PORT_SCTL_DET_INIT 1
891#define AHCI_PORT_SCTL_DET_OFFLINE 4
892#define AHCI_PORT_SCTL_READONLY 0xfff
893
894#define AHCI_PORT_SSTS_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
895#define AHCI_PORT_SSTS_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
896#define AHCI_PORT_SSTS_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
897#define AHCI_PORT_SSTS_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
898#define AHCI_PORT_SSTS_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
899#define AHCI_PORT_SSTS_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
900
901#define AHCI_PORT_TFD_BSY RT_BIT(7)
902#define AHCI_PORT_TFD_DRQ RT_BIT(3)
903#define AHCI_PORT_TFD_ERR RT_BIT(0)
904
905#define AHCI_PORT_SERR_X RT_BIT(26)
906#define AHCI_PORT_SERR_W RT_BIT(18)
907#define AHCI_PORT_SERR_N RT_BIT(16)
908
909/* Signatures for attached storage devices. */
910#define AHCI_PORT_SIG_DISK 0x00000101
911#define AHCI_PORT_SIG_ATAPI 0xeb140101
912
913/*
914 * The AHCI spec defines an area of memory where the HBA posts received FIS's from the device.
915 * regFB points to the base of this area.
916 * Every FIS type has an offset where it is posted in this area.
917 */
918#define AHCI_RECFIS_DSFIS_OFFSET 0x00 /* DMA Setup FIS */
919#define AHCI_RECFIS_PSFIS_OFFSET 0x20 /* PIO Setup FIS */
920#define AHCI_RECFIS_RFIS_OFFSET 0x40 /* D2H Register FIS */
921#define AHCI_RECFIS_SDBFIS_OFFSET 0x58 /* Set Device Bits FIS */
922#define AHCI_RECFIS_UFIS_OFFSET 0x60 /* Unknown FIS type */
923
924/** Mask to get the LBA value from a LBA range. */
925#define AHCI_RANGE_LBA_MASK UINT64_C(0xffffffffffff)
926/** Mas to get the length value from a LBA range. */
927#define AHCI_RANGE_LENGTH_MASK UINT64_C(0xffff000000000000)
928/** Returns the length of the range in sectors. */
929#define AHCI_RANGE_LENGTH_GET(val) (((val) & AHCI_RANGE_LENGTH_MASK) >> 48)
930
931/**
932 * AHCI register operator.
933 */
934typedef struct ahci_opreg
935{
936 const char *pszName;
937 int (*pfnRead )(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value);
938 int (*pfnWrite)(PAHCI ahci, uint32_t iReg, uint32_t u32Value);
939} AHCIOPREG;
940
941/**
942 * AHCI port register operator.
943 */
944typedef struct pAhciPort_opreg
945{
946 const char *pszName;
947 int (*pfnRead )(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value);
948 int (*pfnWrite)(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value);
949} AHCIPORTOPREG;
950
951#ifndef VBOX_DEVICE_STRUCT_TESTCASE
952RT_C_DECLS_BEGIN
953static void ahciHBAReset(PAHCI pThis);
954#ifdef IN_RING3
955static int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *cmdFis);
956static void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort);
957static size_t ahciCopyToPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
958 void *pvBuf, size_t cbBuf);
959static size_t ahciCopyFromPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
960 void *pvBuf, size_t cbBuf);
961static bool ahciCancelActiveTasks(PAHCIPort pAhciPort, PAHCIREQ pAhciReqExcept);
962static void ahciReqMemFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, bool fForceFree);
963static void ahciR3PortCachedReqsFree(PAHCIPort pAhciPort);
964#endif
965RT_C_DECLS_END
966
967#define PCIDEV_2_PAHCI(pPciDev) ( (PAHCI)(pPciDev) )
968#define PDMIMOUNT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMount)) )
969#define PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMountNotify)) )
970#define PDMIBASE_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IBase)) )
971#define PDMIMEDIAPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IPort)) )
972#define PDMIBASE_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, IBase)) )
973#define PDMILEDPORTS_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, ILeds)) )
974
975#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) )
976
977#ifdef IN_RING3
978
979# ifdef LOG_USE_C99
980# define ahciLog(a) \
981 Log(("R3 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
982# else
983# define ahciLog(a) \
984 do { Log(("R3 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
985# endif
986
987#elif IN_RING0
988
989# ifdef LOG_USE_C99
990# define ahciLog(a) \
991 Log(("R0 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
992# else
993# define ahciLog(a) \
994 do { Log(("R0 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
995# endif
996
997#elif IN_RC
998
999# ifdef LOG_USE_C99
1000# define ahciLog(a) \
1001 Log(("GC P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
1002# else
1003# define ahciLog(a) \
1004 do { Log(("GC P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
1005# endif
1006
1007#endif
1008
1009/**
1010 * Update PCI IRQ levels
1011 */
1012static void ahciHbaClearInterrupt(PAHCI pAhci)
1013{
1014 Log(("%s: Clearing interrupt\n", __FUNCTION__));
1015 PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 0);
1016}
1017
1018/**
1019 * Updates the IRQ level and sets port bit in the global interrupt status register of the HBA.
1020 */
1021static int ahciHbaSetInterrupt(PAHCI pAhci, uint8_t iPort, int rcBusy)
1022{
1023 Log(("P%u: %s: Setting interrupt\n", iPort, __FUNCTION__));
1024
1025 int rc = PDMCritSectEnter(&pAhci->lock, rcBusy);
1026 if (rc != VINF_SUCCESS)
1027 return rc;
1028
1029 if (pAhci->regHbaCtrl & AHCI_HBA_CTRL_IE)
1030 {
1031 if ((pAhci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN) && (pAhci->regHbaCccPorts & (1 << iPort)))
1032 {
1033 pAhci->uCccCurrentNr++;
1034 if (pAhci->uCccCurrentNr >= pAhci->uCccNr)
1035 {
1036 /* Reset command completion coalescing state. */
1037 TMTimerSetMillies(pAhci->CTX_SUFF(pHbaCccTimer), pAhci->uCccTimeout);
1038 pAhci->uCccCurrentNr = 0;
1039
1040 pAhci->u32PortsInterrupted |= (1 << pAhci->uCccPortNr);
1041 if (!(pAhci->u32PortsInterrupted & ~(1 << pAhci->uCccPortNr)))
1042 {
1043 Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
1044 PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 1);
1045 }
1046 }
1047 }
1048 else
1049 {
1050 /* If only the bit of the actual port is set assert an interrupt
1051 * because the interrupt status register was already read by the guest
1052 * and we need to send a new notification.
1053 * Otherwise an interrupt is still pending.
1054 */
1055 ASMAtomicOrU32((volatile uint32_t *)&pAhci->u32PortsInterrupted, (1 << iPort));
1056 if (!(pAhci->u32PortsInterrupted & ~(1 << iPort)))
1057 {
1058 Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
1059 PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 1);
1060 }
1061 }
1062 }
1063
1064 PDMCritSectLeave(&pAhci->lock);
1065 return VINF_SUCCESS;
1066}
1067
1068#ifdef IN_RING3
1069/*
1070 * Assert irq when an CCC timeout occurs
1071 */
1072static DECLCALLBACK(void) ahciCccTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1073{
1074 PAHCI pAhci = (PAHCI)pvUser;
1075
1076 int rc = ahciHbaSetInterrupt(pAhci, pAhci->uCccPortNr, VERR_IGNORED);
1077 AssertRC(rc);
1078}
1079
1080/**
1081 * Finishes the port reset of the given port.
1082 *
1083 * @returns nothing.
1084 * @param pAhciPort The port to finish the reset on.
1085 */
1086static void ahciPortResetFinish(PAHCIPort pAhciPort)
1087{
1088 /* Cancel all tasks first. */
1089 bool fAllTasksCanceled = ahciCancelActiveTasks(pAhciPort, NULL);
1090 Assert(fAllTasksCanceled);
1091
1092 /* Signature for SATA device. */
1093 if (pAhciPort->fATAPI)
1094 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
1095 else
1096 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
1097
1098 /* We received a COMINIT from the device. Tell the guest. */
1099 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
1100 pAhciPort->regSERR |= AHCI_PORT_SERR_X;
1101 pAhciPort->regTFD |= ATA_STAT_BUSY;
1102
1103 if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSend))
1104 {
1105 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1106 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
1107
1108 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
1109 {
1110 int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
1111 AssertRC(rc);
1112 }
1113 }
1114
1115 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1116 (0x03 << 0); /* Device detected and communication established. */
1117
1118 /*
1119 * Use the maximum allowed speed.
1120 * (Not that it changes anything really)
1121 */
1122 switch (AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL))
1123 {
1124 case 0x01:
1125 pAhciPort->regSSTS |= (0x01 << 4); /* Generation 1 (1.5GBps) speed. */
1126 break;
1127 case 0x02:
1128 case 0x00:
1129 default:
1130 pAhciPort->regSSTS |= (0x02 << 4); /* Generation 2 (3.0GBps) speed. */
1131 break;
1132 }
1133
1134 ASMAtomicXchgBool(&pAhciPort->fPortReset, false);
1135}
1136#endif
1137
1138/**
1139 * Kicks the I/O thread from RC or R0.
1140 *
1141 * @returns nothing.
1142 * @param pAhci The AHCI controller instance.
1143 * @param pAhciPort The port to kick.
1144 */
1145static void ahciIoThreadKick(PAHCI pAhci, PAHCIPort pAhciPort)
1146{
1147#ifdef IN_RC
1148 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
1149 AssertMsg(VALID_PTR(pItem), ("Allocating item for queue failed\n"));
1150
1151 if (pItem)
1152 {
1153 pItem->iPort = pAhciPort->iLUN;
1154 PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
1155 }
1156#else
1157 LogFlowFunc(("Signal event semaphore\n"));
1158 int rc = SUPSemEventSignal(pAhci->pSupDrvSession, pAhciPort->hEvtProcess);
1159 AssertRC(rc);
1160#endif
1161}
1162
1163static int PortCmdIssue_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1164{
1165 uint32_t uCIValue;
1166
1167 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1168
1169 /* Update the CI register first. */
1170 uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
1171 pAhciPort->regCI &= ~uCIValue;
1172
1173 if ( (pAhciPort->regCMD & AHCI_PORT_CMD_CR)
1174 && u32Value > 0)
1175 {
1176 /*
1177 * Clear all tasks which are already marked as busy. The guest
1178 * shouldn't write already busy tasks actually.
1179 */
1180 u32Value &= ~pAhciPort->regCI;
1181
1182 ASMAtomicOrU32(&pAhciPort->u32TasksNew, u32Value);
1183
1184 /* Send a notification to R3 if u32TasksNew was 0 before our write. */
1185 if (ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping))
1186 ahciIoThreadKick(ahci, pAhciPort);
1187 }
1188
1189 pAhciPort->regCI |= u32Value;
1190
1191 return VINF_SUCCESS;
1192}
1193
1194static int PortCmdIssue_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1195{
1196 uint32_t uCIValue = 0;
1197
1198 uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
1199
1200 ahciLog(("%s: read regCI=%#010x uCIValue=%#010x\n", __FUNCTION__, pAhciPort->regCI, uCIValue));
1201
1202 pAhciPort->regCI &= ~uCIValue;
1203
1204 *pu32Value = pAhciPort->regCI;
1205
1206 return VINF_SUCCESS;
1207}
1208
1209static int PortSActive_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1210{
1211 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1212
1213 pAhciPort->regSACT |= u32Value;
1214
1215 return VINF_SUCCESS;
1216}
1217
1218static int PortSActive_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1219{
1220 uint32_t u32TasksFinished = ASMAtomicXchgU32(&pAhciPort->u32QueuedTasksFinished, 0);
1221
1222 pAhciPort->regSACT &= ~u32TasksFinished;
1223
1224 ahciLog(("%s: read regSACT=%#010x regCI=%#010x u32TasksFinished=%#010x\n",
1225 __FUNCTION__, pAhciPort->regSACT, pAhciPort->regCI, u32TasksFinished));
1226
1227 *pu32Value = pAhciPort->regSACT;
1228
1229 return VINF_SUCCESS;
1230}
1231
1232static int PortSError_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1233{
1234 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1235
1236 if ( (u32Value & AHCI_PORT_SERR_X)
1237 && (pAhciPort->regSERR & AHCI_PORT_SERR_X))
1238 {
1239 ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PCS);
1240 pAhciPort->regTFD |= ATA_STAT_ERR;
1241 pAhciPort->regTFD &= ~(ATA_STAT_DRQ | ATA_STAT_BUSY);
1242 }
1243
1244 if ( (u32Value & AHCI_PORT_SERR_N)
1245 && (pAhciPort->regSERR & AHCI_PORT_SERR_N))
1246 ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PRCS);
1247
1248 pAhciPort->regSERR &= ~u32Value;
1249
1250 return VINF_SUCCESS;
1251}
1252
1253static int PortSError_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1254{
1255 ahciLog(("%s: read regSERR=%#010x\n", __FUNCTION__, pAhciPort->regSERR));
1256 *pu32Value = pAhciPort->regSERR;
1257 return VINF_SUCCESS;
1258}
1259
1260static int PortSControl_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1261{
1262 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1263 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1264 AHCI_PORT_SCTL_IPM_GET(u32Value), AHCI_PORT_SCTL_SPD_GET(u32Value), AHCI_PORT_SCTL_DET_GET(u32Value)));
1265
1266#ifndef IN_RING3
1267 return VINF_IOM_R3_MMIO_WRITE;
1268#else
1269 if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
1270 {
1271 if (!ASMAtomicXchgBool(&pAhciPort->fPortReset, true))
1272 LogRel(("AHCI#%u: Port %d reset\n", ahci->CTX_SUFF(pDevIns)->iInstance,
1273 pAhciPort->iLUN));
1274
1275 pAhciPort->regSSTS = 0;
1276 pAhciPort->regSIG = ~0;
1277 pAhciPort->regTFD = 0x7f;
1278 pAhciPort->fFirstD2HFisSend = false;
1279 pAhciPort->regSCTL = u32Value;
1280 }
1281 else if ( (u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT
1282 && (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT
1283 && pAhciPort->pDrvBase)
1284 {
1285 /* Do the port reset here, so the guest sees the new status immediately. */
1286 if (ahci->fLegacyPortResetMethod)
1287 {
1288 ahciPortResetFinish(pAhciPort);
1289 pAhciPort->regSCTL = u32Value; /* Update after finishing the reset, so the I/O thread doesn't get a chance to do the reset. */
1290 }
1291 else
1292 {
1293 pAhciPort->regSSTS = 0x1; /* Indicate device presence detected but communication not established. */
1294 pAhciPort->regSCTL = u32Value; /* Update before kicking the I/O thread. */
1295
1296 /* Kick the thread to finish the reset. */
1297 ahciIoThreadKick(ahci, pAhciPort);
1298 }
1299 }
1300 else /* Just update the value if there is no device attached. */
1301 pAhciPort->regSCTL = u32Value;
1302
1303 return VINF_SUCCESS;
1304#endif
1305}
1306
1307static int PortSControl_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1308{
1309 ahciLog(("%s: read regSCTL=%#010x\n", __FUNCTION__, pAhciPort->regSCTL));
1310 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1311 AHCI_PORT_SCTL_IPM_GET(pAhciPort->regSCTL), AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL),
1312 AHCI_PORT_SCTL_DET_GET(pAhciPort->regSCTL)));
1313
1314 *pu32Value = pAhciPort->regSCTL;
1315 return VINF_SUCCESS;
1316}
1317
1318static int PortSStatus_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1319{
1320 ahciLog(("%s: read regSSTS=%#010x\n", __FUNCTION__, pAhciPort->regSSTS));
1321 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1322 AHCI_PORT_SSTS_IPM_GET(pAhciPort->regSSTS), AHCI_PORT_SSTS_SPD_GET(pAhciPort->regSSTS),
1323 AHCI_PORT_SSTS_DET_GET(pAhciPort->regSSTS)));
1324
1325 *pu32Value = pAhciPort->regSSTS;
1326 return VINF_SUCCESS;
1327}
1328
1329static int PortSignature_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1330{
1331 ahciLog(("%s: read regSIG=%#010x\n", __FUNCTION__, pAhciPort->regSIG));
1332 *pu32Value = pAhciPort->regSIG;
1333 return VINF_SUCCESS;
1334}
1335
1336static int PortTaskFileData_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1337{
1338 ahciLog(("%s: read regTFD=%#010x\n", __FUNCTION__, pAhciPort->regTFD));
1339 ahciLog(("%s: ERR=%x BSY=%d DRQ=%d ERR=%d\n", __FUNCTION__,
1340 (pAhciPort->regTFD >> 8), (pAhciPort->regTFD & AHCI_PORT_TFD_BSY) >> 7,
1341 (pAhciPort->regTFD & AHCI_PORT_TFD_DRQ) >> 3, (pAhciPort->regTFD & AHCI_PORT_TFD_ERR)));
1342 *pu32Value = pAhciPort->regTFD;
1343 return VINF_SUCCESS;
1344}
1345
1346/**
1347 * Read from the port command register.
1348 */
1349static int PortCmd_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1350{
1351 ahciLog(("%s: read regCMD=%#010x\n", __FUNCTION__, pAhciPort->regCMD | AHCI_PORT_CMD_CCS_SHIFT(pAhciPort->u32CurrentCommandSlot)));
1352 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",
1353 __FUNCTION__, (pAhciPort->regCMD & AHCI_PORT_CMD_ICC) >> 28, (pAhciPort->regCMD & AHCI_PORT_CMD_ASP) >> 27,
1354 (pAhciPort->regCMD & AHCI_PORT_CMD_ALPE) >> 26, (pAhciPort->regCMD & AHCI_PORT_CMD_DLAE) >> 25,
1355 (pAhciPort->regCMD & AHCI_PORT_CMD_ATAPI) >> 24, (pAhciPort->regCMD & AHCI_PORT_CMD_CPD) >> 20,
1356 (pAhciPort->regCMD & AHCI_PORT_CMD_ISP) >> 19, (pAhciPort->regCMD & AHCI_PORT_CMD_HPCP) >> 18,
1357 (pAhciPort->regCMD & AHCI_PORT_CMD_PMA) >> 17, (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) >> 16,
1358 (pAhciPort->regCMD & AHCI_PORT_CMD_CR) >> 15, (pAhciPort->regCMD & AHCI_PORT_CMD_FR) >> 14,
1359 (pAhciPort->regCMD & AHCI_PORT_CMD_ISS) >> 13, pAhciPort->u32CurrentCommandSlot,
1360 (pAhciPort->regCMD & AHCI_PORT_CMD_FRE) >> 4, (pAhciPort->regCMD & AHCI_PORT_CMD_CLO) >> 3,
1361 (pAhciPort->regCMD & AHCI_PORT_CMD_POD) >> 2, (pAhciPort->regCMD & AHCI_PORT_CMD_SUD) >> 1,
1362 (pAhciPort->regCMD & AHCI_PORT_CMD_ST)));
1363 *pu32Value = pAhciPort->regCMD | AHCI_PORT_CMD_CCS_SHIFT(pAhciPort->u32CurrentCommandSlot);
1364 return VINF_SUCCESS;
1365}
1366
1367/**
1368 * Write to the port command register.
1369 * This is the register where all the data transfer is started
1370 */
1371static int PortCmd_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1372{
1373 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1374 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",
1375 __FUNCTION__, (u32Value & AHCI_PORT_CMD_ICC) >> 28, (u32Value & AHCI_PORT_CMD_ASP) >> 27,
1376 (u32Value & AHCI_PORT_CMD_ALPE) >> 26, (u32Value & AHCI_PORT_CMD_DLAE) >> 25,
1377 (u32Value & AHCI_PORT_CMD_ATAPI) >> 24, (u32Value & AHCI_PORT_CMD_CPD) >> 20,
1378 (u32Value & AHCI_PORT_CMD_ISP) >> 19, (u32Value & AHCI_PORT_CMD_HPCP) >> 18,
1379 (u32Value & AHCI_PORT_CMD_PMA) >> 17, (u32Value & AHCI_PORT_CMD_CPS) >> 16,
1380 (u32Value & AHCI_PORT_CMD_CR) >> 15, (u32Value & AHCI_PORT_CMD_FR) >> 14,
1381 (u32Value & AHCI_PORT_CMD_ISS) >> 13, (u32Value & AHCI_PORT_CMD_CCS) >> 8,
1382 (u32Value & AHCI_PORT_CMD_FRE) >> 4, (u32Value & AHCI_PORT_CMD_CLO) >> 3,
1383 (u32Value & AHCI_PORT_CMD_POD) >> 2, (u32Value & AHCI_PORT_CMD_SUD) >> 1,
1384 (u32Value & AHCI_PORT_CMD_ST)));
1385
1386 /* The PxCMD.CCS bits are R/O and maintained separately. */
1387 u32Value &= ~AHCI_PORT_CMD_CCS;
1388
1389 if (pAhciPort->fPoweredOn && pAhciPort->fSpunUp)
1390 {
1391 if (u32Value & AHCI_PORT_CMD_CLO)
1392 {
1393 ahciLog(("%s: Command list override requested\n", __FUNCTION__));
1394 u32Value &= ~(AHCI_PORT_TFD_BSY | AHCI_PORT_TFD_DRQ);
1395 /* Clear the CLO bit. */
1396 u32Value &= ~(AHCI_PORT_CMD_CLO);
1397 }
1398
1399 if (u32Value & AHCI_PORT_CMD_ST)
1400 {
1401 /*
1402 * Set engine state to running if there is a device attached and
1403 * IS.PCS is clear.
1404 */
1405 if ( pAhciPort->pDrvBase
1406 && !(pAhciPort->regIS & AHCI_PORT_IS_PCS))
1407 {
1408 ahciLog(("%s: Engine starts\n", __FUNCTION__));
1409 u32Value |= AHCI_PORT_CMD_CR;
1410
1411 /* If there is something in CI, kick the I/O thread. */
1412 if ( pAhciPort->regCI > 0
1413 && ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping))
1414 {
1415 ASMAtomicOrU32(&pAhciPort->u32TasksNew, pAhciPort->regCI);
1416#ifdef IN_RC
1417 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
1418 AssertMsg(VALID_PTR(pItem), ("Allocating item for queue failed\n"));
1419
1420 pItem->iPort = pAhciPort->iLUN;
1421 PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
1422#else
1423 LogFlowFunc(("Signal event semaphore\n"));
1424 int rc = SUPSemEventSignal(ahci->pSupDrvSession, pAhciPort->hEvtProcess);
1425 AssertRC(rc);
1426#endif
1427 }
1428 }
1429 else
1430 u32Value &= ~AHCI_PORT_CMD_CR;
1431 }
1432 else
1433 {
1434 ahciLog(("%s: Engine stops\n", __FUNCTION__));
1435 /* Clear command issue register. */
1436 pAhciPort->regCI = 0;
1437 pAhciPort->regSACT = 0;
1438 /* Clear current command slot. */
1439 pAhciPort->u32CurrentCommandSlot = 0;
1440 u32Value &= ~AHCI_PORT_CMD_CR;
1441 }
1442 }
1443 else if (pAhciPort->pDrvBase)
1444 {
1445 if ((u32Value & AHCI_PORT_CMD_POD) && (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) && !pAhciPort->fPoweredOn)
1446 {
1447 ahciLog(("%s: Power on the device\n", __FUNCTION__));
1448 pAhciPort->fPoweredOn = true;
1449
1450 /*
1451 * Set states in the Port Signature and SStatus registers.
1452 */
1453 if (pAhciPort->fATAPI)
1454 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
1455 else
1456 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
1457 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1458 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
1459 (0x03 << 0); /* Device detected and communication established. */
1460
1461 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
1462 {
1463#ifndef IN_RING3
1464 return VINF_IOM_R3_MMIO_WRITE;
1465#else
1466 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1467 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
1468
1469 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
1470 {
1471 int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
1472 AssertRC(rc);
1473 }
1474#endif
1475 }
1476 }
1477
1478 if ((u32Value & AHCI_PORT_CMD_SUD) && pAhciPort->fPoweredOn && !pAhciPort->fSpunUp)
1479 {
1480 ahciLog(("%s: Spin up the device\n", __FUNCTION__));
1481 pAhciPort->fSpunUp = true;
1482 }
1483 }
1484
1485 if (u32Value & AHCI_PORT_CMD_FRE)
1486 {
1487 ahciLog(("%s: FIS receive enabled\n", __FUNCTION__));
1488
1489 u32Value |= AHCI_PORT_CMD_FR;
1490
1491 /* Send the first D2H FIS only if it wasn't already send. */
1492 if ( !pAhciPort->fFirstD2HFisSend
1493 && pAhciPort->pDrvBase)
1494 {
1495#ifndef IN_RING3
1496 return VINF_IOM_R3_MMIO_WRITE;
1497#else
1498 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1499 pAhciPort->fFirstD2HFisSend = true;
1500#endif
1501 }
1502 }
1503 else if (!(u32Value & AHCI_PORT_CMD_FRE))
1504 {
1505 ahciLog(("%s: FIS receive disabled\n", __FUNCTION__));
1506 u32Value &= ~AHCI_PORT_CMD_FR;
1507 }
1508
1509 pAhciPort->regCMD = u32Value;
1510
1511 return VINF_SUCCESS;
1512}
1513
1514/**
1515 * Read from the port interrupt enable register.
1516 */
1517static int PortIntrEnable_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1518{
1519 ahciLog(("%s: read regIE=%#010x\n", __FUNCTION__, pAhciPort->regIE));
1520 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",
1521 __FUNCTION__, (pAhciPort->regIE & AHCI_PORT_IE_CPDE) >> 31, (pAhciPort->regIE & AHCI_PORT_IE_TFEE) >> 30,
1522 (pAhciPort->regIE & AHCI_PORT_IE_HBFE) >> 29, (pAhciPort->regIE & AHCI_PORT_IE_HBDE) >> 28,
1523 (pAhciPort->regIE & AHCI_PORT_IE_IFE) >> 27, (pAhciPort->regIE & AHCI_PORT_IE_INFE) >> 26,
1524 (pAhciPort->regIE & AHCI_PORT_IE_OFE) >> 24, (pAhciPort->regIE & AHCI_PORT_IE_IPME) >> 23,
1525 (pAhciPort->regIE & AHCI_PORT_IE_PRCE) >> 22, (pAhciPort->regIE & AHCI_PORT_IE_DIE) >> 7,
1526 (pAhciPort->regIE & AHCI_PORT_IE_PCE) >> 6, (pAhciPort->regIE & AHCI_PORT_IE_DPE) >> 5,
1527 (pAhciPort->regIE & AHCI_PORT_IE_UFE) >> 4, (pAhciPort->regIE & AHCI_PORT_IE_SDBE) >> 3,
1528 (pAhciPort->regIE & AHCI_PORT_IE_DSE) >> 2, (pAhciPort->regIE & AHCI_PORT_IE_PSE) >> 1,
1529 (pAhciPort->regIE & AHCI_PORT_IE_DHRE)));
1530 *pu32Value = pAhciPort->regIE;
1531 return VINF_SUCCESS;
1532}
1533
1534/**
1535 * Write to the port interrupt enable register.
1536 */
1537static int PortIntrEnable_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1538{
1539 int rc = VINF_SUCCESS;
1540 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1541 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",
1542 __FUNCTION__, (u32Value & AHCI_PORT_IE_CPDE) >> 31, (u32Value & AHCI_PORT_IE_TFEE) >> 30,
1543 (u32Value & AHCI_PORT_IE_HBFE) >> 29, (u32Value & AHCI_PORT_IE_HBDE) >> 28,
1544 (u32Value & AHCI_PORT_IE_IFE) >> 27, (u32Value & AHCI_PORT_IE_INFE) >> 26,
1545 (u32Value & AHCI_PORT_IE_OFE) >> 24, (u32Value & AHCI_PORT_IE_IPME) >> 23,
1546 (u32Value & AHCI_PORT_IE_PRCE) >> 22, (u32Value & AHCI_PORT_IE_DIE) >> 7,
1547 (u32Value & AHCI_PORT_IE_PCE) >> 6, (u32Value & AHCI_PORT_IE_DPE) >> 5,
1548 (u32Value & AHCI_PORT_IE_UFE) >> 4, (u32Value & AHCI_PORT_IE_SDBE) >> 3,
1549 (u32Value & AHCI_PORT_IE_DSE) >> 2, (u32Value & AHCI_PORT_IE_PSE) >> 1,
1550 (u32Value & AHCI_PORT_IE_DHRE)));
1551
1552 u32Value &= AHCI_PORT_IE_READONLY;
1553
1554 /* Check if some a interrupt status bit changed*/
1555 uint32_t u32IntrStatus = ASMAtomicReadU32(&pAhciPort->regIS);
1556
1557 if (u32Value & u32IntrStatus)
1558 rc = ahciHbaSetInterrupt(ahci, pAhciPort->iLUN, VINF_IOM_R3_MMIO_WRITE);
1559
1560 if (rc == VINF_SUCCESS)
1561 pAhciPort->regIE = u32Value;
1562
1563 return rc;
1564}
1565
1566/**
1567 * Read from the port interrupt status register.
1568 */
1569static int PortIntrSts_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1570{
1571 ahciLog(("%s: read regIS=%#010x\n", __FUNCTION__, pAhciPort->regIS));
1572 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",
1573 __FUNCTION__, (pAhciPort->regIS & AHCI_PORT_IS_CPDS) >> 31, (pAhciPort->regIS & AHCI_PORT_IS_TFES) >> 30,
1574 (pAhciPort->regIS & AHCI_PORT_IS_HBFS) >> 29, (pAhciPort->regIS & AHCI_PORT_IS_HBDS) >> 28,
1575 (pAhciPort->regIS & AHCI_PORT_IS_IFS) >> 27, (pAhciPort->regIS & AHCI_PORT_IS_INFS) >> 26,
1576 (pAhciPort->regIS & AHCI_PORT_IS_OFS) >> 24, (pAhciPort->regIS & AHCI_PORT_IS_IPMS) >> 23,
1577 (pAhciPort->regIS & AHCI_PORT_IS_PRCS) >> 22, (pAhciPort->regIS & AHCI_PORT_IS_DIS) >> 7,
1578 (pAhciPort->regIS & AHCI_PORT_IS_PCS) >> 6, (pAhciPort->regIS & AHCI_PORT_IS_DPS) >> 5,
1579 (pAhciPort->regIS & AHCI_PORT_IS_UFS) >> 4, (pAhciPort->regIS & AHCI_PORT_IS_SDBS) >> 3,
1580 (pAhciPort->regIS & AHCI_PORT_IS_DSS) >> 2, (pAhciPort->regIS & AHCI_PORT_IS_PSS) >> 1,
1581 (pAhciPort->regIS & AHCI_PORT_IS_DHRS)));
1582 *pu32Value = pAhciPort->regIS;
1583 return VINF_SUCCESS;
1584}
1585
1586/**
1587 * Write to the port interrupt status register.
1588 */
1589static int PortIntrSts_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1590{
1591 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1592 ASMAtomicAndU32(&pAhciPort->regIS, ~(u32Value & AHCI_PORT_IS_READONLY));
1593
1594 return VINF_SUCCESS;
1595}
1596
1597/**
1598 * Read from the port FIS base address upper 32bit register.
1599 */
1600static int PortFisAddrUp_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1601{
1602 ahciLog(("%s: read regFBU=%#010x\n", __FUNCTION__, pAhciPort->regFBU));
1603 *pu32Value = pAhciPort->regFBU;
1604 return VINF_SUCCESS;
1605}
1606
1607/**
1608 * Write to the port FIS base address upper 32bit register.
1609 */
1610static int PortFisAddrUp_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1611{
1612 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1613
1614 pAhciPort->regFBU = u32Value;
1615 pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
1616
1617 return VINF_SUCCESS;
1618}
1619
1620/**
1621 * Read from the port FIS base address register.
1622 */
1623static int PortFisAddr_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1624{
1625 ahciLog(("%s: read regFB=%#010x\n", __FUNCTION__, pAhciPort->regFB));
1626 *pu32Value = pAhciPort->regFB;
1627 return VINF_SUCCESS;
1628}
1629
1630/**
1631 * Write to the port FIS base address register.
1632 */
1633static int PortFisAddr_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1634{
1635 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1636
1637 Assert(!(u32Value & ~AHCI_PORT_FB_RESERVED));
1638
1639 pAhciPort->regFB = (u32Value & AHCI_PORT_FB_RESERVED);
1640 pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
1641
1642 return VINF_SUCCESS;
1643}
1644
1645/**
1646 * Write to the port command list base address upper 32bit register.
1647 */
1648static int PortCmdLstAddrUp_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1649{
1650 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1651
1652 pAhciPort->regCLBU = u32Value;
1653 pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
1654
1655 return VINF_SUCCESS;
1656}
1657
1658/**
1659 * Read from the port command list base address upper 32bit register.
1660 */
1661static int PortCmdLstAddrUp_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1662{
1663 ahciLog(("%s: read regCLBU=%#010x\n", __FUNCTION__, pAhciPort->regCLBU));
1664 *pu32Value = pAhciPort->regCLBU;
1665 return VINF_SUCCESS;
1666}
1667
1668/**
1669 * Read from the port command list base address register.
1670 */
1671static int PortCmdLstAddr_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1672{
1673 ahciLog(("%s: read regCLB=%#010x\n", __FUNCTION__, pAhciPort->regCLB));
1674 *pu32Value = pAhciPort->regCLB;
1675 return VINF_SUCCESS;
1676}
1677
1678/**
1679 * Write to the port command list base address register.
1680 */
1681static int PortCmdLstAddr_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1682{
1683 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1684
1685 Assert(!(u32Value & ~AHCI_PORT_CLB_RESERVED));
1686
1687 pAhciPort->regCLB = (u32Value & AHCI_PORT_CLB_RESERVED);
1688 pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
1689
1690 return VINF_SUCCESS;
1691}
1692
1693/**
1694 * Read from the global Version register.
1695 */
1696static int HbaVersion_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1697{
1698 Log(("%s: read regHbaVs=%#010x\n", __FUNCTION__, ahci->regHbaVs));
1699 *pu32Value = ahci->regHbaVs;
1700 return VINF_SUCCESS;
1701}
1702
1703/**
1704 * Read from the global Ports implemented register.
1705 */
1706static int HbaPortsImplemented_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1707{
1708 Log(("%s: read regHbaPi=%#010x\n", __FUNCTION__, ahci->regHbaPi));
1709 *pu32Value = ahci->regHbaPi;
1710 return VINF_SUCCESS;
1711}
1712
1713/**
1714 * Write to the global interrupt status register.
1715 */
1716static int HbaInterruptStatus_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1717{
1718 int rc;
1719 Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1720
1721 rc = PDMCritSectEnter(&ahci->lock, VINF_IOM_R3_MMIO_WRITE);
1722 if (rc != VINF_SUCCESS)
1723 return rc;
1724
1725 ahci->regHbaIs &= ~(u32Value);
1726
1727 /*
1728 * Update interrupt status register and check for ports who
1729 * set the interrupt inbetween.
1730 */
1731 bool fClear = true;
1732 ahci->regHbaIs |= ASMAtomicXchgU32(&ahci->u32PortsInterrupted, 0);
1733 if (!ahci->regHbaIs)
1734 {
1735 unsigned i = 0;
1736
1737 /* Check if the cleared ports have a interrupt status bit set. */
1738 while ((u32Value > 0) && (i < AHCI_MAX_NR_PORTS_IMPL))
1739 {
1740 if (u32Value & 0x01)
1741 {
1742 PAHCIPort pAhciPort = &ahci->ahciPort[i];
1743
1744 if (pAhciPort->regIE & pAhciPort->regIS)
1745 {
1746 Log(("%s: Interrupt status of port %u set -> Set interrupt again\n", __FUNCTION__, i));
1747 ASMAtomicOrU32(&ahci->u32PortsInterrupted, 1 << i);
1748 fClear = false;
1749 break;
1750 }
1751 }
1752 u32Value >>= 1;
1753 i++;
1754 }
1755 }
1756 else
1757 fClear = false;
1758
1759 if (fClear)
1760 ahciHbaClearInterrupt(ahci);
1761 else
1762 {
1763 Log(("%s: Not clearing interrupt: u32PortsInterrupted=%#010x\n", __FUNCTION__, ahci->u32PortsInterrupted));
1764 /*
1765 * We need to set the interrupt again because the I/O APIC does not set it again even if the
1766 * line is still high.
1767 * We need to clear it first because the PCI bus only calls the interrupt controller if the state changes.
1768 */
1769 PDMDevHlpPCISetIrq(ahci->CTX_SUFF(pDevIns), 0, 0);
1770 PDMDevHlpPCISetIrq(ahci->CTX_SUFF(pDevIns), 0, 1);
1771 }
1772
1773 PDMCritSectLeave(&ahci->lock);
1774 return VINF_SUCCESS;
1775}
1776
1777/**
1778 * Read from the global interrupt status register.
1779 */
1780static int HbaInterruptStatus_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1781{
1782 uint32_t u32PortsInterrupted;
1783 int rc;
1784
1785 rc = PDMCritSectEnter(&ahci->lock, VINF_IOM_R3_MMIO_READ);
1786 if (rc != VINF_SUCCESS)
1787 return rc;
1788
1789 u32PortsInterrupted = ASMAtomicXchgU32(&ahci->u32PortsInterrupted, 0);
1790
1791 PDMCritSectLeave(&ahci->lock);
1792 Log(("%s: read regHbaIs=%#010x u32PortsInterrupted=%#010x\n", __FUNCTION__, ahci->regHbaIs, u32PortsInterrupted));
1793
1794 ahci->regHbaIs |= u32PortsInterrupted;
1795
1796#ifdef LOG_ENABLED
1797 Log(("%s:", __FUNCTION__));
1798 unsigned i;
1799 for (i = 0; i < ahci->cPortsImpl; i++)
1800 {
1801 if ((ahci->regHbaIs >> i) & 0x01)
1802 Log((" P%d", i));
1803 }
1804 Log(("\n"));
1805#endif
1806
1807 *pu32Value = ahci->regHbaIs;
1808
1809 return VINF_SUCCESS;
1810}
1811
1812/**
1813 * Write to the global control register.
1814 */
1815static int HbaControl_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1816{
1817 Log(("%s: write u32Value=%#010x\n"
1818 "%s: AE=%d IE=%d HR=%d\n",
1819 __FUNCTION__, u32Value,
1820 __FUNCTION__, (u32Value & AHCI_HBA_CTRL_AE) >> 31, (u32Value & AHCI_HBA_CTRL_IE) >> 1,
1821 (u32Value & AHCI_HBA_CTRL_HR)));
1822
1823#ifndef IN_RING3
1824 return VINF_IOM_R3_MMIO_WRITE;
1825#else
1826 /*
1827 * Increase the active thread counter because we might set the host controller
1828 * reset bit.
1829 */
1830 ASMAtomicIncU32(&ahci->cThreadsActive);
1831 ASMAtomicWriteU32(&ahci->regHbaCtrl, (u32Value & AHCI_HBA_CTRL_RW_MASK) | AHCI_HBA_CTRL_AE);
1832
1833 /*
1834 * Do the HBA reset if requested and there is no other active thread at the moment,
1835 * the work is deferred to the last active thread otherwise.
1836 */
1837 uint32_t cThreadsActive = ASMAtomicDecU32(&ahci->cThreadsActive);
1838 if ( (u32Value & AHCI_HBA_CTRL_HR)
1839 && !cThreadsActive)
1840 ahciHBAReset(ahci);
1841
1842 return VINF_SUCCESS;
1843#endif
1844}
1845
1846/**
1847 * Read the global control register.
1848 */
1849static int HbaControl_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1850{
1851 Log(("%s: read regHbaCtrl=%#010x\n"
1852 "%s: AE=%d IE=%d HR=%d\n",
1853 __FUNCTION__, ahci->regHbaCtrl,
1854 __FUNCTION__, (ahci->regHbaCtrl & AHCI_HBA_CTRL_AE) >> 31, (ahci->regHbaCtrl & AHCI_HBA_CTRL_IE) >> 1,
1855 (ahci->regHbaCtrl & AHCI_HBA_CTRL_HR)));
1856 *pu32Value = ahci->regHbaCtrl;
1857 return VINF_SUCCESS;
1858}
1859
1860/**
1861 * Read the global capabilities register.
1862 */
1863static int HbaCapabilities_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1864{
1865 Log(("%s: read regHbaCap=%#010x\n"
1866 "%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",
1867 __FUNCTION__, ahci->regHbaCap,
1868 __FUNCTION__, (ahci->regHbaCap & AHCI_HBA_CAP_S64A) >> 31, (ahci->regHbaCap & AHCI_HBA_CAP_SNCQ) >> 30,
1869 (ahci->regHbaCap & AHCI_HBA_CAP_SIS) >> 28, (ahci->regHbaCap & AHCI_HBA_CAP_SSS) >> 27,
1870 (ahci->regHbaCap & AHCI_HBA_CAP_SALP) >> 26, (ahci->regHbaCap & AHCI_HBA_CAP_SAL) >> 25,
1871 (ahci->regHbaCap & AHCI_HBA_CAP_SCLO) >> 24, (ahci->regHbaCap & AHCI_HBA_CAP_ISS) >> 20,
1872 (ahci->regHbaCap & AHCI_HBA_CAP_SNZO) >> 19, (ahci->regHbaCap & AHCI_HBA_CAP_SAM) >> 18,
1873 (ahci->regHbaCap & AHCI_HBA_CAP_SPM) >> 17, (ahci->regHbaCap & AHCI_HBA_CAP_PMD) >> 15,
1874 (ahci->regHbaCap & AHCI_HBA_CAP_SSC) >> 14, (ahci->regHbaCap & AHCI_HBA_CAP_PSC) >> 13,
1875 (ahci->regHbaCap & AHCI_HBA_CAP_NCS) >> 8, (ahci->regHbaCap & AHCI_HBA_CAP_NP)));
1876 *pu32Value = ahci->regHbaCap;
1877 return VINF_SUCCESS;
1878}
1879
1880/**
1881 * Write to the global command completion coalescing control register.
1882 */
1883static int HbaCccCtl_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1884{
1885 Log(("%s: write u32Value=%#010x\n"
1886 "%s: TV=%d CC=%d INT=%d EN=%d\n",
1887 __FUNCTION__, u32Value,
1888 __FUNCTION__, AHCI_HBA_CCC_CTL_TV_GET(u32Value), AHCI_HBA_CCC_CTL_CC_GET(u32Value),
1889 AHCI_HBA_CCC_CTL_INT_GET(u32Value), (u32Value & AHCI_HBA_CCC_CTL_EN)));
1890
1891 ahci->regHbaCccCtl = u32Value;
1892 ahci->uCccTimeout = AHCI_HBA_CCC_CTL_TV_GET(u32Value);
1893 ahci->uCccPortNr = AHCI_HBA_CCC_CTL_INT_GET(u32Value);
1894 ahci->uCccNr = AHCI_HBA_CCC_CTL_CC_GET(u32Value);
1895
1896 if (u32Value & AHCI_HBA_CCC_CTL_EN)
1897 {
1898 /* Arm the timer */
1899 TMTimerSetMillies(ahci->CTX_SUFF(pHbaCccTimer), ahci->uCccTimeout);
1900 }
1901 else
1902 {
1903 TMTimerStop(ahci->CTX_SUFF(pHbaCccTimer));
1904 }
1905
1906 return VINF_SUCCESS;
1907}
1908
1909/**
1910 * Read the global command completion coalescing control register.
1911 */
1912static int HbaCccCtl_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1913{
1914 Log(("%s: read regHbaCccCtl=%#010x\n"
1915 "%s: TV=%d CC=%d INT=%d EN=%d\n",
1916 __FUNCTION__, ahci->regHbaCccCtl,
1917 __FUNCTION__, AHCI_HBA_CCC_CTL_TV_GET(ahci->regHbaCccCtl), AHCI_HBA_CCC_CTL_CC_GET(ahci->regHbaCccCtl),
1918 AHCI_HBA_CCC_CTL_INT_GET(ahci->regHbaCccCtl), (ahci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN)));
1919 *pu32Value = ahci->regHbaCccCtl;
1920 return VINF_SUCCESS;
1921}
1922
1923/**
1924 * Write to the global command completion coalescing ports register.
1925 */
1926static int HbaCccPorts_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1927{
1928 Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1929
1930 ahci->regHbaCccPorts = u32Value;
1931
1932 return VINF_SUCCESS;
1933}
1934
1935/**
1936 * Read the global command completion coalescing ports register.
1937 */
1938static int HbaCccPorts_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1939{
1940 Log(("%s: read regHbaCccPorts=%#010x\n", __FUNCTION__, ahci->regHbaCccPorts));
1941
1942#ifdef LOG_ENABLED
1943 Log(("%s:", __FUNCTION__));
1944 unsigned i;
1945 for (i = 0; i < ahci->cPortsImpl; i++)
1946 {
1947 if ((ahci->regHbaCccPorts >> i) & 0x01)
1948 Log((" P%d", i));
1949 }
1950 Log(("\n"));
1951#endif
1952
1953 *pu32Value = ahci->regHbaCccPorts;
1954 return VINF_SUCCESS;
1955}
1956
1957/**
1958 * Invalid write to global register
1959 */
1960static int HbaInvalid_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1961{
1962 Log(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
1963 return VINF_SUCCESS;
1964}
1965
1966/**
1967 * Invalid Port write.
1968 */
1969static int PortInvalid_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1970{
1971 ahciLog(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
1972 return VINF_SUCCESS;
1973}
1974
1975/**
1976 * Invalid Port read.
1977 */
1978static int PortInvalid_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1979{
1980 ahciLog(("%s: Read denied!!! iReg=%u\n", __FUNCTION__, iReg));
1981 return VINF_SUCCESS;
1982}
1983
1984/**
1985 * Register descriptor table for global HBA registers
1986 */
1987static const AHCIOPREG g_aOpRegs[] =
1988{
1989 {"HbaCapabilites", HbaCapabilities_r, HbaInvalid_w}, /* Readonly */
1990 {"HbaControl" , HbaControl_r, HbaControl_w},
1991 {"HbaInterruptStatus", HbaInterruptStatus_r, HbaInterruptStatus_w},
1992 {"HbaPortsImplemented", HbaPortsImplemented_r, HbaInvalid_w}, /* Readonly */
1993 {"HbaVersion", HbaVersion_r, HbaInvalid_w}, /* ReadOnly */
1994 {"HbaCccCtl", HbaCccCtl_r, HbaCccCtl_w},
1995 {"HbaCccPorts", HbaCccPorts_r, HbaCccPorts_w},
1996};
1997
1998/**
1999 * Register descriptor table for port registers
2000 */
2001static const AHCIPORTOPREG g_aPortOpRegs[] =
2002{
2003 {"PortCmdLstAddr", PortCmdLstAddr_r, PortCmdLstAddr_w},
2004 {"PortCmdLstAddrUp", PortCmdLstAddrUp_r, PortCmdLstAddrUp_w},
2005 {"PortFisAddr", PortFisAddr_r, PortFisAddr_w},
2006 {"PortFisAddrUp", PortFisAddrUp_r, PortFisAddrUp_w},
2007 {"PortIntrSts", PortIntrSts_r, PortIntrSts_w},
2008 {"PortIntrEnable", PortIntrEnable_r, PortIntrEnable_w},
2009 {"PortCmd", PortCmd_r, PortCmd_w},
2010 {"PortReserved1", PortInvalid_r, PortInvalid_w}, /* Not used. */
2011 {"PortTaskFileData", PortTaskFileData_r, PortInvalid_w}, /* Readonly */
2012 {"PortSignature", PortSignature_r, PortInvalid_w}, /* Readonly */
2013 {"PortSStatus", PortSStatus_r, PortInvalid_w}, /* Readonly */
2014 {"PortSControl", PortSControl_r, PortSControl_w},
2015 {"PortSError", PortSError_r, PortSError_w},
2016 {"PortSActive", PortSActive_r, PortSActive_w},
2017 {"PortCmdIssue", PortCmdIssue_r, PortCmdIssue_w},
2018 {"PortReserved2", PortInvalid_r, PortInvalid_w}, /* Not used. */
2019};
2020
2021#ifdef IN_RING3
2022/**
2023 * Reset initiated by system software for one port.
2024 *
2025 * @param pAhciPort The port to reset.
2026 */
2027static void ahciPortSwReset(PAHCIPort pAhciPort)
2028{
2029 bool fAllTasksCanceled;
2030
2031 /* Cancel all tasks first. */
2032 fAllTasksCanceled = ahciCancelActiveTasks(pAhciPort, NULL);
2033 Assert(fAllTasksCanceled);
2034
2035 Assert(pAhciPort->cTasksActive == 0);
2036
2037 pAhciPort->regIS = 0;
2038 pAhciPort->regIE = 0;
2039 pAhciPort->regCMD = AHCI_PORT_CMD_CPD | /* Cold presence detection */
2040 AHCI_PORT_CMD_SUD | /* Device has spun up. */
2041 AHCI_PORT_CMD_POD; /* Port is powered on. */
2042
2043 /* Hotplugging supported?. */
2044 if (pAhciPort->fHotpluggable)
2045 pAhciPort->regCMD |= AHCI_PORT_CMD_HPCP;
2046
2047 pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
2048 pAhciPort->regSIG = ~0;
2049 pAhciPort->regSSTS = 0;
2050 pAhciPort->regSCTL = 0;
2051 pAhciPort->regSERR = 0;
2052 pAhciPort->regSACT = 0;
2053 pAhciPort->regCI = 0;
2054
2055 pAhciPort->fResetDevice = false;
2056 pAhciPort->fPoweredOn = true;
2057 pAhciPort->fSpunUp = true;
2058 pAhciPort->cMultSectors = ATA_MAX_MULT_SECTORS;
2059 pAhciPort->uATATransferMode = ATA_MODE_UDMA | 6;
2060
2061 pAhciPort->u32TasksNew = 0;
2062 pAhciPort->u32TasksRedo = 0;
2063 pAhciPort->u32TasksFinished = 0;
2064 pAhciPort->u32QueuedTasksFinished = 0;
2065 pAhciPort->u32CurrentCommandSlot = 0;
2066
2067 ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_UNCHANGED);
2068 ASMAtomicWriteU32(&pAhciPort->MediaTrackType, ATA_MEDIA_TYPE_UNKNOWN);
2069
2070 if (pAhciPort->pDrvBase)
2071 {
2072 pAhciPort->regCMD |= AHCI_PORT_CMD_CPS; /* Indicate that there is a device on that port */
2073
2074 if (pAhciPort->fPoweredOn)
2075 {
2076 /*
2077 * Set states in the Port Signature and SStatus registers.
2078 */
2079 if (pAhciPort->fATAPI)
2080 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
2081 else
2082 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
2083 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
2084 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
2085 (0x03 << 0); /* Device detected and communication established. */
2086 }
2087 }
2088}
2089
2090/**
2091 * Hardware reset used for machine power on and reset.
2092 *
2093 * @param pAhciport The port to reset.
2094 */
2095static void ahciPortHwReset(PAHCIPort pAhciPort)
2096{
2097 /* Reset the address registers. */
2098 pAhciPort->regCLB = 0;
2099 pAhciPort->regCLBU = 0;
2100 pAhciPort->regFB = 0;
2101 pAhciPort->regFBU = 0;
2102
2103 /* Reset calculated addresses. */
2104 pAhciPort->GCPhysAddrClb = 0;
2105 pAhciPort->GCPhysAddrFb = 0;
2106}
2107
2108/**
2109 * Create implemented ports bitmap.
2110 *
2111 * @returns 32bit bitmask with a bit set for every implemented port.
2112 * @param cPorts Number of ports.
2113 */
2114static uint32_t ahciGetPortsImplemented(unsigned cPorts)
2115{
2116 uint32_t uPortsImplemented = 0;
2117
2118 for (unsigned i = 0; i < cPorts; i++)
2119 uPortsImplemented |= (1 << i);
2120
2121 return uPortsImplemented;
2122}
2123
2124/**
2125 * Reset the entire HBA.
2126 *
2127 * @param pThis The HBA state.
2128 */
2129static void ahciHBAReset(PAHCI pThis)
2130{
2131 unsigned i;
2132 int rc = VINF_SUCCESS;
2133
2134 LogRel(("AHCI#%u: Reset the HBA\n", pThis->CTX_SUFF(pDevIns)->iInstance));
2135
2136 /* Stop the CCC timer. */
2137 if (pThis->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN)
2138 {
2139 rc = TMTimerStop(pThis->CTX_SUFF(pHbaCccTimer));
2140 if (RT_FAILURE(rc))
2141 AssertMsgFailed(("%s: Failed to stop timer!\n", __FUNCTION__));
2142 }
2143
2144 /* Reset every port */
2145 for (i = 0; i < pThis->cPortsImpl; i++)
2146 {
2147 PAHCIPort pAhciPort = &pThis->ahciPort[i];
2148
2149 pAhciPort->iLUN = i;
2150 ahciPortSwReset(pAhciPort);
2151 }
2152
2153 /* Init Global registers */
2154 pThis->regHbaCap = AHCI_HBA_CAP_ISS_SHIFT(AHCI_HBA_CAP_ISS_GEN2) |
2155 AHCI_HBA_CAP_S64A | /* 64bit addressing supported */
2156 AHCI_HBA_CAP_SAM | /* AHCI mode only */
2157 AHCI_HBA_CAP_SNCQ | /* Support native command queuing */
2158 AHCI_HBA_CAP_SSS | /* Staggered spin up */
2159 AHCI_HBA_CAP_CCCS | /* Support command completion coalescing */
2160 AHCI_HBA_CAP_NCS_SET(pThis->cCmdSlotsAvail) | /* Number of command slots we support */
2161 AHCI_HBA_CAP_NP_SET(pThis->cPortsImpl); /* Number of supported ports */
2162 pThis->regHbaCtrl = AHCI_HBA_CTRL_AE;
2163 pThis->regHbaPi = ahciGetPortsImplemented(pThis->cPortsImpl);
2164 pThis->regHbaVs = AHCI_HBA_VS_MJR | AHCI_HBA_VS_MNR;
2165 pThis->regHbaCccCtl = 0;
2166 pThis->regHbaCccPorts = 0;
2167 pThis->uCccTimeout = 0;
2168 pThis->uCccPortNr = 0;
2169 pThis->uCccNr = 0;
2170
2171 /* Clear pending interrupts. */
2172 pThis->regHbaIs = 0;
2173 pThis->u32PortsInterrupted = 0;
2174 ahciHbaClearInterrupt(pThis);
2175
2176 pThis->f64BitAddr = false;
2177 pThis->u32PortsInterrupted = 0;
2178 pThis->f8ByteMMIO4BytesWrittenSuccessfully = false;
2179 /* Clear the HBA Reset bit */
2180 pThis->regHbaCtrl &= ~AHCI_HBA_CTRL_HR;
2181}
2182#endif
2183
2184/**
2185 * Reads from a AHCI controller register.
2186 *
2187 * @returns VBox status code.
2188 *
2189 * @param pAhci The AHCI instance.
2190 * @param uReg The register to write.
2191 * @param pv Where to store the result.
2192 * @param cb Number of bytes read.
2193 */
2194static int ahciRegisterRead(PAHCI pAhci, uint32_t uReg, void *pv, unsigned cb)
2195{
2196 int rc = VINF_SUCCESS;
2197 uint32_t iReg;
2198
2199 /*
2200 * If the access offset is smaller than AHCI_HBA_GLOBAL_SIZE the guest accesses the global registers.
2201 * Otherwise it accesses the registers of a port.
2202 */
2203 if (uReg < AHCI_HBA_GLOBAL_SIZE)
2204 {
2205 iReg = uReg >> 2;
2206 Log3(("%s: Trying to read from global register %u\n", __FUNCTION__, iReg));
2207 if (iReg < RT_ELEMENTS(g_aOpRegs))
2208 {
2209 const AHCIOPREG *pReg = &g_aOpRegs[iReg];
2210 rc = pReg->pfnRead(pAhci, iReg, (uint32_t *)pv);
2211 }
2212 else
2213 {
2214 Log3(("%s: Trying to read global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
2215 *(uint32_t *)pv = 0;
2216 }
2217 }
2218 else
2219 {
2220 uint32_t iRegOffset;
2221 uint32_t iPort;
2222
2223 /* Calculate accessed port. */
2224 uReg -= AHCI_HBA_GLOBAL_SIZE;
2225 iPort = uReg / AHCI_PORT_REGISTER_SIZE;
2226 iRegOffset = (uReg % AHCI_PORT_REGISTER_SIZE);
2227 iReg = iRegOffset >> 2;
2228
2229 Log3(("%s: Trying to read from port %u and register %u\n", __FUNCTION__, iPort, iReg));
2230
2231 if (RT_LIKELY( iPort < pAhci->cPortsImpl
2232 && iReg < RT_ELEMENTS(g_aPortOpRegs)))
2233 {
2234 const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
2235 rc = pPortReg->pfnRead(pAhci, &pAhci->ahciPort[iPort], iReg, (uint32_t *)pv);
2236 }
2237 else
2238 {
2239 Log3(("%s: Trying to read port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
2240 rc = VINF_IOM_MMIO_UNUSED_00;
2241 }
2242
2243 /*
2244 * Windows Vista tries to read one byte from some registers instead of four.
2245 * Correct the value according to the read size.
2246 */
2247 if (RT_SUCCESS(rc) && cb != sizeof(uint32_t))
2248 {
2249 switch (cb)
2250 {
2251 case 1:
2252 {
2253 uint8_t uNewValue;
2254 uint8_t *p = (uint8_t *)pv;
2255
2256 iRegOffset &= 3;
2257 Log3(("%s: iRegOffset=%u\n", __FUNCTION__, iRegOffset));
2258 uNewValue = p[iRegOffset];
2259 /* Clear old value */
2260 *(uint32_t *)pv = 0;
2261 *(uint8_t *)pv = uNewValue;
2262 break;
2263 }
2264 default:
2265 AssertMsgFailed(("%s: unsupported access width cb=%d iPort=%x iRegOffset=%x iReg=%x!!!\n",
2266 __FUNCTION__, cb, iPort, iRegOffset, iReg));
2267 }
2268 }
2269 }
2270
2271 return rc;
2272}
2273
2274/**
2275 * Writes a value to one of the AHCI controller registers.
2276 *
2277 * @returns VBox status code.
2278 *
2279 * @param pAhci The AHCI instance.
2280 * @param offReg The offset of the register to write to.
2281 * @param u32Value The value to write.
2282 */
2283static int ahciRegisterWrite(PAHCI pAhci, uint32_t offReg, uint32_t u32Value)
2284{
2285 int rc;
2286 uint32_t iReg;
2287
2288 /*
2289 * If the access offset is smaller than 100h the guest accesses the global registers.
2290 * Otherwise it accesses the registers of a port.
2291 */
2292 if (offReg < AHCI_HBA_GLOBAL_SIZE)
2293 {
2294 Log3(("Write global HBA register\n"));
2295 iReg = offReg >> 2;
2296 if (iReg < RT_ELEMENTS(g_aOpRegs))
2297 {
2298 const AHCIOPREG *pReg = &g_aOpRegs[iReg];
2299 rc = pReg->pfnWrite(pAhci, iReg, u32Value);
2300 }
2301 else
2302 {
2303 Log3(("%s: Trying to write global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
2304 rc = VINF_SUCCESS;
2305 }
2306 }
2307 else
2308 {
2309 uint32_t iPort;
2310 Log3(("Write Port register\n"));
2311 /* Calculate accessed port. */
2312 offReg -= AHCI_HBA_GLOBAL_SIZE;
2313 iPort = offReg / AHCI_PORT_REGISTER_SIZE;
2314 iReg = (offReg % AHCI_PORT_REGISTER_SIZE) >> 2;
2315 Log3(("%s: Trying to write to port %u and register %u\n", __FUNCTION__, iPort, iReg));
2316 if (RT_LIKELY( iPort < pAhci->cPortsImpl
2317 && iReg < RT_ELEMENTS(g_aPortOpRegs)))
2318 {
2319 const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
2320 rc = pPortReg->pfnWrite(pAhci, &pAhci->ahciPort[iPort], iReg, u32Value);
2321 }
2322 else
2323 {
2324 Log3(("%s: Trying to write port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
2325 rc = VINF_SUCCESS;
2326 }
2327 }
2328
2329 return rc;
2330}
2331
2332/**
2333 * Memory mapped I/O Handler for read operations.
2334 *
2335 * @returns VBox status code.
2336 *
2337 * @param pDevIns The device instance.
2338 * @param pvUser User argument.
2339 * @param GCPhysAddr Physical address (in GC) where the read starts.
2340 * @param pv Where to store the result.
2341 * @param cb Number of bytes read.
2342 */
2343PDMBOTHCBDECL(int) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
2344{
2345 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2346 Log2(("#%d ahciMMIORead: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp\n",
2347 pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr));
2348
2349 int rc = ahciRegisterRead(pAhci, GCPhysAddr - pAhci->MMIOBase, pv, cb);
2350
2351 Log2(("#%d ahciMMIORead: return pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
2352 pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
2353 return rc;
2354}
2355
2356
2357/**
2358 * Memory mapped I/O Handler for write operations.
2359 *
2360 * @returns VBox status code.
2361 *
2362 * @param pDevIns The device instance.
2363 * @param pvUser User argument.
2364 * @param GCPhysAddr Physical address (in GC) where the read starts.
2365 * @param pv Where to fetch the result.
2366 * @param cb Number of bytes to write.
2367 */
2368PDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
2369{
2370 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2371 Assert(cb == 4 || cb == 8);
2372 Assert(!(GCPhysAddr & (cb - 1)));
2373
2374 /* Break up 64 bits writes into two dword writes. */
2375 /** @todo Eliminate this code once the IOM/EM starts taking care of these
2376 * situations. */
2377 if (cb == 8)
2378 {
2379 /*
2380 * Only write the first 4 bytes if they weren't already.
2381 * It is possible that the last write to the register caused a world
2382 * switch and we entered this function again.
2383 * Writing the first 4 bytes again could cause indeterminate behavior
2384 * which can cause errors in the guest.
2385 */
2386 int rc = VINF_SUCCESS;
2387 if (!pAhci->f8ByteMMIO4BytesWrittenSuccessfully)
2388 {
2389 rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr, pv, 4);
2390 if (rc != VINF_SUCCESS)
2391 return rc;
2392
2393 pAhci->f8ByteMMIO4BytesWrittenSuccessfully = true;
2394 }
2395
2396 rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr + 4, (uint8_t *)pv + 4, 4);
2397 /*
2398 * Reset flag again so that the first 4 bytes are written again on the next
2399 * 8byte MMIO access.
2400 */
2401 if (rc == VINF_SUCCESS)
2402 pAhci->f8ByteMMIO4BytesWrittenSuccessfully = false;
2403
2404 return rc;
2405 }
2406
2407 /* Do the access. */
2408 Log2(("#%d ahciMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp\n", pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr));
2409 return ahciRegisterWrite(pAhci, GCPhysAddr - pAhci->MMIOBase, *(uint32_t const *)pv);
2410}
2411
2412PDMBOTHCBDECL(int) ahciLegacyFakeWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2413{
2414 AssertMsgFailed(("Should not happen\n"));
2415 return VINF_SUCCESS;
2416}
2417
2418PDMBOTHCBDECL(int) ahciLegacyFakeRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2419{
2420 AssertMsgFailed(("Should not happen\n"));
2421 return VINF_SUCCESS;
2422}
2423
2424/**
2425 * I/O port handler for writes to the index/data register pair.
2426 *
2427 * @returns VBox status code.
2428 *
2429 * @param pDevIns The device instance.
2430 * @param pvUser User argument.
2431 * @param Port Port address where the write starts.
2432 * @param pv Where to fetch the result.
2433 * @param cb Number of bytes to write.
2434 */
2435PDMBOTHCBDECL(int) ahciIdxDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2436{
2437 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2438 int rc = VINF_SUCCESS;
2439
2440 if (Port - pAhci->IOPortBase >= 8)
2441 {
2442 unsigned iReg = (Port - pAhci->IOPortBase - 8) / 4;
2443
2444 Assert(cb == 4);
2445
2446 if (iReg == 0)
2447 {
2448 /* Write the index register. */
2449 pAhci->regIdx = u32;
2450 }
2451 else
2452 {
2453 /** @todo range check? */
2454 Assert(iReg == 1);
2455 rc = ahciRegisterWrite(pAhci, pAhci->regIdx, u32);
2456 if (rc == VINF_IOM_R3_MMIO_WRITE)
2457 rc = VINF_IOM_R3_IOPORT_WRITE;
2458 }
2459 }
2460 /* else: ignore */
2461
2462 Log2(("#%d ahciIdxDataWrite: pu32=%p:{%.*Rhxs} cb=%d Port=%#x rc=%Rrc\n",
2463 pDevIns->iInstance, &u32, cb, &u32, cb, Port, rc));
2464 return rc;
2465}
2466
2467/**
2468 * I/O port handler for reads from the index/data register pair.
2469 *
2470 * @returns VBox status code.
2471 *
2472 * @param pDevIns The device instance.
2473 * @param pvUser User argument.
2474 * @param Port Port address where the read starts.
2475 * @param pv Where to fetch the result.
2476 * @param cb Number of bytes to write.
2477 */
2478PDMBOTHCBDECL(int) ahciIdxDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2479{
2480 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2481 int rc = VINF_SUCCESS;
2482
2483 if (Port - pAhci->IOPortBase >= 8)
2484 {
2485 unsigned iReg = (Port - pAhci->IOPortBase - 8) / 4;
2486
2487 Assert(cb == 4);
2488
2489 if (iReg == 0)
2490 {
2491 /* Read the index register. */
2492 *pu32 = pAhci->regIdx;
2493 }
2494 else
2495 {
2496 Assert(iReg == 1);
2497 /** @todo range check? */
2498 rc = ahciRegisterRead(pAhci, pAhci->regIdx, pu32, cb);
2499 if (rc == VINF_IOM_R3_MMIO_READ)
2500 rc = VINF_IOM_R3_IOPORT_READ;
2501 else if (rc == VINF_IOM_MMIO_UNUSED_00)
2502 rc = VERR_IOM_IOPORT_UNUSED;
2503 }
2504 }
2505 else
2506 *pu32 = UINT32_C(0xffffffff);
2507
2508 Log2(("#%d ahciIdxDataRead: pu32=%p:{%.*Rhxs} cb=%d Port=%#x rc=%Rrc\n",
2509 pDevIns->iInstance, pu32, cb, pu32, cb, Port, rc));
2510 return rc;
2511}
2512
2513#ifdef IN_RING3
2514
2515static DECLCALLBACK(int) ahciR3MMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2516{
2517 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2518 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2519 int rc = VINF_SUCCESS;
2520
2521 Log2(("%s: registering MMIO area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
2522
2523 Assert(enmType == PCI_ADDRESS_SPACE_MEM);
2524 Assert(cb >= 4352);
2525
2526 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2527 /** @todo change this to IOMMMIO_FLAGS_WRITE_ONLY_DWORD once EM/IOM starts
2528 * handling 2nd DWORD failures on split accesses correctly. */
2529 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
2530 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD,
2531 ahciMMIOWrite, ahciMMIORead, "AHCI");
2532 if (RT_FAILURE(rc))
2533 return rc;
2534
2535 if (pThis->fR0Enabled)
2536 {
2537 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/, "ahciMMIOWrite", "ahciMMIORead");
2538 if (RT_FAILURE(rc))
2539 return rc;
2540 }
2541
2542 if (pThis->fGCEnabled)
2543 {
2544 rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/, "ahciMMIOWrite", "ahciMMIORead");
2545 if (RT_FAILURE(rc))
2546 return rc;
2547 }
2548
2549 pThis->MMIOBase = GCPhysAddress;
2550 return rc;
2551}
2552
2553/**
2554 * Map the legacy I/O port ranges to make Solaris work with the controller.
2555 */
2556static DECLCALLBACK(int) ahciR3LegacyFakeIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2557{
2558 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2559 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2560 int rc = VINF_SUCCESS;
2561
2562 Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
2563
2564 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2565
2566 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2567 rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, cb, NULL,
2568 ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL, NULL, "AHCI Fake");
2569 if (RT_FAILURE(rc))
2570 return rc;
2571
2572 if (pThis->fR0Enabled)
2573 {
2574 rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2575 "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
2576 if (RT_FAILURE(rc))
2577 return rc;
2578 }
2579
2580 if (pThis->fGCEnabled)
2581 {
2582 rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2583 "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
2584 if (RT_FAILURE(rc))
2585 return rc;
2586 }
2587
2588 return rc;
2589}
2590
2591/**
2592 * Map the BMDMA I/O port range (used for the Index/Data pair register access)
2593 */
2594static DECLCALLBACK(int) ahciR3IdxDataIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2595{
2596 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2597 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2598 int rc = VINF_SUCCESS;
2599
2600 Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
2601
2602 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2603
2604 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2605 rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, cb, NULL,
2606 ahciIdxDataWrite, ahciIdxDataRead, NULL, NULL, "AHCI IDX/DATA");
2607 if (RT_FAILURE(rc))
2608 return rc;
2609
2610 if (pThis->fR0Enabled)
2611 {
2612 rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2613 "ahciIdxDataWrite", "ahciIdxDataRead", NULL, NULL, "AHCI IDX/DATA");
2614 if (RT_FAILURE(rc))
2615 return rc;
2616 }
2617
2618 if (pThis->fGCEnabled)
2619 {
2620 rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2621 "ahciIdxDataWrite", "ahciIdxDataRead", NULL, NULL, "AHCI IDX/DATA");
2622 if (RT_FAILURE(rc))
2623 return rc;
2624 }
2625
2626 pThis->IOPortBase = (RTIOPORT)GCPhysAddress;
2627 return rc;
2628}
2629
2630/* -=-=-=-=-=- PAHCI::ILeds -=-=-=-=-=- */
2631
2632/**
2633 * Gets the pointer to the status LED of a unit.
2634 *
2635 * @returns VBox status code.
2636 * @param pInterface Pointer to the interface structure containing the called function pointer.
2637 * @param iLUN The unit which status LED we desire.
2638 * @param ppLed Where to store the LED pointer.
2639 */
2640static DECLCALLBACK(int) ahciR3Status_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
2641{
2642 PAHCI pAhci = PDMILEDPORTS_2_PAHCI(pInterface);
2643 if (iLUN < AHCI_MAX_NR_PORTS_IMPL)
2644 {
2645 *ppLed = &pAhci->ahciPort[iLUN].Led;
2646 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
2647 return VINF_SUCCESS;
2648 }
2649 return VERR_PDM_LUN_NOT_FOUND;
2650}
2651
2652/**
2653 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2654 */
2655static DECLCALLBACK(void *) ahciR3Status_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
2656{
2657 PAHCI pThis = PDMIBASE_2_PAHCI(pInterface);
2658 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2659 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
2660 return NULL;
2661}
2662
2663/**
2664 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2665 */
2666static DECLCALLBACK(void *) ahciR3PortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2667{
2668 PAHCIPort pAhciPort = PDMIBASE_2_PAHCIPORT(pInterface);
2669 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pAhciPort->IBase);
2670 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pAhciPort->IPort);
2671 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNCPORT, &pAhciPort->IPortAsync);
2672 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNTNOTIFY, &pAhciPort->IMountNotify);
2673 return NULL;
2674}
2675
2676/**
2677 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
2678 */
2679static DECLCALLBACK(int) ahciR3PortQueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
2680 uint32_t *piInstance, uint32_t *piLUN)
2681{
2682 PAHCIPort pAhciPort = PDMIMEDIAPORT_2_PAHCIPORT(pInterface);
2683 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
2684
2685 AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
2686 AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
2687 AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
2688
2689 *ppcszController = pDevIns->pReg->szName;
2690 *piInstance = pDevIns->iInstance;
2691 *piLUN = pAhciPort->iLUN;
2692
2693 return VINF_SUCCESS;
2694}
2695
2696#ifdef LOG_ENABLED
2697
2698/**
2699 * Dump info about the FIS
2700 *
2701 * @returns nothing
2702 * @param pAhciPort The port the command FIS was read from.
2703 * @param cmdFis The FIS to print info from.
2704 */
2705static void ahciDumpFisInfo(PAHCIPort pAhciPort, uint8_t *cmdFis)
2706{
2707 ahciLog(("%s: *** Begin FIS info dump. ***\n", __FUNCTION__));
2708 /* Print FIS type. */
2709 switch (cmdFis[AHCI_CMDFIS_TYPE])
2710 {
2711 case AHCI_CMDFIS_TYPE_H2D:
2712 {
2713 ahciLog(("%s: Command Fis type: H2D\n", __FUNCTION__));
2714 ahciLog(("%s: Command Fis size: %d bytes\n", __FUNCTION__, AHCI_CMDFIS_TYPE_H2D_SIZE));
2715 if (cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
2716 ahciLog(("%s: Command register update\n", __FUNCTION__));
2717 else
2718 ahciLog(("%s: Control register update\n", __FUNCTION__));
2719 ahciLog(("%s: CMD=%#04x \"%s\"\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CMD], ATACmdText(cmdFis[AHCI_CMDFIS_CMD])));
2720 ahciLog(("%s: FEAT=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FET]));
2721 ahciLog(("%s: SECTN=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTN]));
2722 ahciLog(("%s: CYLL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLL]));
2723 ahciLog(("%s: CYLH=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLH]));
2724 ahciLog(("%s: HEAD=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_HEAD]));
2725
2726 ahciLog(("%s: SECTNEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTNEXP]));
2727 ahciLog(("%s: CYLLEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLLEXP]));
2728 ahciLog(("%s: CYLHEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLHEXP]));
2729 ahciLog(("%s: FETEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FETEXP]));
2730
2731 ahciLog(("%s: SECTC=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTC]));
2732 ahciLog(("%s: SECTCEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTCEXP]));
2733 ahciLog(("%s: CTL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CTL]));
2734 if (cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
2735 ahciLog(("%s: Reset bit is set\n", __FUNCTION__));
2736 break;
2737 }
2738 case AHCI_CMDFIS_TYPE_D2H:
2739 {
2740 ahciLog(("%s: Command Fis type D2H\n", __FUNCTION__));
2741 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_D2H_SIZE));
2742 break;
2743 }
2744 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2745 {
2746 ahciLog(("%s: Command Fis type Set Device Bits\n", __FUNCTION__));
2747 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE));
2748 break;
2749 }
2750 case AHCI_CMDFIS_TYPE_DMAACTD2H:
2751 {
2752 ahciLog(("%s: Command Fis type DMA Activate H2D\n", __FUNCTION__));
2753 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE));
2754 break;
2755 }
2756 case AHCI_CMDFIS_TYPE_DMASETUP:
2757 {
2758 ahciLog(("%s: Command Fis type DMA Setup\n", __FUNCTION__));
2759 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMASETUP_SIZE));
2760 break;
2761 }
2762 case AHCI_CMDFIS_TYPE_PIOSETUP:
2763 {
2764 ahciLog(("%s: Command Fis type PIO Setup\n", __FUNCTION__));
2765 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_PIOSETUP_SIZE));
2766 break;
2767 }
2768 case AHCI_CMDFIS_TYPE_DATA:
2769 {
2770 ahciLog(("%s: Command Fis type Data\n", __FUNCTION__));
2771 break;
2772 }
2773 default:
2774 ahciLog(("%s: ERROR Unknown command FIS type\n", __FUNCTION__));
2775 break;
2776 }
2777 ahciLog(("%s: *** End FIS info dump. ***\n", __FUNCTION__));
2778}
2779
2780/**
2781 * Dump info about the command header
2782 *
2783 * @returns nothing
2784 * @param pAhciPort Pointer to the port the command header was read from.
2785 * @param pCmdHdr The command header to print info from.
2786 */
2787static void ahciDumpCmdHdrInfo(PAHCIPort pAhciPort, CmdHdr *pCmdHdr)
2788{
2789 ahciLog(("%s: *** Begin command header info dump. ***\n", __FUNCTION__));
2790 ahciLog(("%s: Number of Scatter/Gatther List entries: %u\n", __FUNCTION__, AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf)));
2791 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_C)
2792 ahciLog(("%s: Clear busy upon R_OK\n", __FUNCTION__));
2793 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_B)
2794 ahciLog(("%s: BIST Fis\n", __FUNCTION__));
2795 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_R)
2796 ahciLog(("%s: Device Reset Fis\n", __FUNCTION__));
2797 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_P)
2798 ahciLog(("%s: Command prefetchable\n", __FUNCTION__));
2799 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_W)
2800 ahciLog(("%s: Device write\n", __FUNCTION__));
2801 else
2802 ahciLog(("%s: Device read\n", __FUNCTION__));
2803 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_A)
2804 ahciLog(("%s: ATAPI command\n", __FUNCTION__));
2805 else
2806 ahciLog(("%s: ATA command\n", __FUNCTION__));
2807
2808 ahciLog(("%s: Command FIS length %u DW\n", __FUNCTION__, (pCmdHdr->u32DescInf & AHCI_CMDHDR_CFL_MASK)));
2809 ahciLog(("%s: *** End command header info dump. ***\n", __FUNCTION__));
2810}
2811
2812#endif /* LOG_ENABLED */
2813
2814/**
2815 * Post the first D2H FIS from the device into guest memory.
2816 *
2817 * @returns nothing
2818 * @param pAhciPort Pointer to the port which "receives" the FIS.
2819 */
2820static void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort)
2821{
2822 uint8_t d2hFis[AHCI_CMDFIS_TYPE_D2H_SIZE];
2823
2824 pAhciPort->fFirstD2HFisSend = true;
2825
2826 ahciLog(("%s: Sending First D2H FIS from FIFO\n", __FUNCTION__));
2827 memset(&d2hFis[0], 0, sizeof(d2hFis));
2828 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
2829 d2hFis[AHCI_CMDFIS_ERR] = 0x01;
2830
2831 d2hFis[AHCI_CMDFIS_STS] = 0x00;
2832
2833 /* Set the signature based on the device type. */
2834 if (pAhciPort->fATAPI)
2835 {
2836 d2hFis[AHCI_CMDFIS_CYLL] = 0x14;
2837 d2hFis[AHCI_CMDFIS_CYLH] = 0xeb;
2838 }
2839 else
2840 {
2841 d2hFis[AHCI_CMDFIS_CYLL] = 0x00;
2842 d2hFis[AHCI_CMDFIS_CYLH] = 0x00;
2843 }
2844
2845 d2hFis[AHCI_CMDFIS_HEAD] = 0x00;
2846 d2hFis[AHCI_CMDFIS_SECTN] = 0x01;
2847 d2hFis[AHCI_CMDFIS_SECTC] = 0x01;
2848
2849 pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
2850 if (!pAhciPort->fATAPI)
2851 pAhciPort->regTFD |= ATA_STAT_READY;
2852
2853 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
2854}
2855
2856/**
2857 * Post the FIS in the memory area allocated by the guest and set interrupt if necessary.
2858 *
2859 * @returns VBox status code
2860 * @param pAhciPort The port which "receives" the FIS.
2861 * @param uFisType The type of the FIS.
2862 * @param pCmdFis Pointer to the FIS which is to be posted into memory.
2863 */
2864static int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *pCmdFis)
2865{
2866 int rc = VINF_SUCCESS;
2867 RTGCPHYS GCPhysAddrRecFis = pAhciPort->GCPhysAddrFb;
2868 unsigned cbFis = 0;
2869
2870 ahciLog(("%s: pAhciPort=%p uFisType=%u pCmdFis=%p\n", __FUNCTION__, pAhciPort, uFisType, pCmdFis));
2871
2872 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
2873 {
2874 AssertMsg(GCPhysAddrRecFis, ("%s: GCPhysAddrRecFis is 0\n", __FUNCTION__));
2875
2876 /* Determine the offset and size of the FIS based on uFisType. */
2877 switch (uFisType)
2878 {
2879 case AHCI_CMDFIS_TYPE_D2H:
2880 {
2881 GCPhysAddrRecFis += AHCI_RECFIS_RFIS_OFFSET;
2882 cbFis = AHCI_CMDFIS_TYPE_D2H_SIZE;
2883 break;
2884 }
2885 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2886 {
2887 GCPhysAddrRecFis += AHCI_RECFIS_SDBFIS_OFFSET;
2888 cbFis = AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE;
2889 break;
2890 }
2891 case AHCI_CMDFIS_TYPE_DMASETUP:
2892 {
2893 GCPhysAddrRecFis += AHCI_RECFIS_DSFIS_OFFSET;
2894 cbFis = AHCI_CMDFIS_TYPE_DMASETUP_SIZE;
2895 break;
2896 }
2897 case AHCI_CMDFIS_TYPE_PIOSETUP:
2898 {
2899 GCPhysAddrRecFis += AHCI_RECFIS_PSFIS_OFFSET;
2900 cbFis = AHCI_CMDFIS_TYPE_PIOSETUP_SIZE;
2901 break;
2902 }
2903 default:
2904 /*
2905 * We should post the unknown FIS into memory too but this never happens because
2906 * we know which FIS types we generate. ;)
2907 */
2908 AssertMsgFailed(("%s: Unknown FIS type!\n", __FUNCTION__));
2909 }
2910
2911 /* Post the FIS into memory. */
2912 ahciLog(("%s: PDMDevHlpPCIPhysWrite GCPhysAddrRecFis=%RGp cbFis=%u\n", __FUNCTION__, GCPhysAddrRecFis, cbFis));
2913 PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrRecFis, pCmdFis, cbFis);
2914 }
2915
2916 return rc;
2917}
2918
2919DECLINLINE(void) ataH2BE_U16(uint8_t *pbBuf, uint16_t val)
2920{
2921 pbBuf[0] = val >> 8;
2922 pbBuf[1] = val;
2923}
2924
2925
2926DECLINLINE(void) ataH2BE_U24(uint8_t *pbBuf, uint32_t val)
2927{
2928 pbBuf[0] = val >> 16;
2929 pbBuf[1] = val >> 8;
2930 pbBuf[2] = val;
2931}
2932
2933
2934DECLINLINE(void) ataH2BE_U32(uint8_t *pbBuf, uint32_t val)
2935{
2936 pbBuf[0] = val >> 24;
2937 pbBuf[1] = val >> 16;
2938 pbBuf[2] = val >> 8;
2939 pbBuf[3] = val;
2940}
2941
2942
2943DECLINLINE(uint16_t) ataBE2H_U16(const uint8_t *pbBuf)
2944{
2945 return (pbBuf[0] << 8) | pbBuf[1];
2946}
2947
2948
2949DECLINLINE(uint32_t) ataBE2H_U24(const uint8_t *pbBuf)
2950{
2951 return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
2952}
2953
2954
2955DECLINLINE(uint32_t) ataBE2H_U32(const uint8_t *pbBuf)
2956{
2957 return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
2958}
2959
2960
2961DECLINLINE(void) ataLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA)
2962{
2963 iATAPILBA += 150;
2964 pbBuf[0] = (iATAPILBA / 75) / 60;
2965 pbBuf[1] = (iATAPILBA / 75) % 60;
2966 pbBuf[2] = iATAPILBA % 75;
2967}
2968
2969
2970DECLINLINE(uint32_t) ataMSF2LBA(const uint8_t *pbBuf)
2971{
2972 return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2];
2973}
2974
2975static void atapiCmdOK(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
2976{
2977 pAhciReq->uATARegError = 0;
2978 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
2979 pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] & ~7)
2980 | ((pAhciReq->enmTxDir != AHCITXDIR_WRITE) ? ATAPI_INT_REASON_IO : 0)
2981 | (!pAhciReq->cbTransfer ? ATAPI_INT_REASON_CD : 0);
2982 memset(pAhciPort->abATAPISense, '\0', sizeof(pAhciPort->abATAPISense));
2983 pAhciPort->abATAPISense[0] = 0x70;
2984 pAhciPort->abATAPISense[7] = 10;
2985}
2986
2987static void atapiCmdError(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, const uint8_t *pabATAPISense, size_t cbATAPISense)
2988{
2989 Log(("%s: sense=%#x (%s) asc=%#x ascq=%#x (%s)\n", __FUNCTION__, pabATAPISense[2] & 0x0f, SCSISenseText(pabATAPISense[2] & 0x0f),
2990 pabATAPISense[12], pabATAPISense[13], SCSISenseExtText(pabATAPISense[12], pabATAPISense[13])));
2991 pAhciReq->uATARegError = pabATAPISense[2] << 4;
2992 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
2993 pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] & ~7) |
2994 ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
2995 memset(pAhciPort->abATAPISense, '\0', sizeof(pAhciPort->abATAPISense));
2996 memcpy(pAhciPort->abATAPISense, pabATAPISense, RT_MIN(cbATAPISense, sizeof(pAhciPort->abATAPISense)));
2997}
2998
2999/** @todo deprecated function - doesn't provide enough info. Replace by direct
3000 * calls to atapiCmdError() with full data. */
3001static void atapiCmdErrorSimple(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
3002{
3003 uint8_t abATAPISense[ATAPI_SENSE_SIZE];
3004 memset(abATAPISense, '\0', sizeof(abATAPISense));
3005 abATAPISense[0] = 0x70 | (1 << 7);
3006 abATAPISense[2] = uATAPISenseKey & 0x0f;
3007 abATAPISense[7] = 10;
3008 abATAPISense[12] = uATAPIASC;
3009 atapiCmdError(pAhciPort, pAhciReq, abATAPISense, sizeof(abATAPISense));
3010}
3011
3012static void ataSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
3013{
3014 for (uint32_t i = 0; i < cbSize; i++)
3015 {
3016 if (*pbSrc)
3017 pbDst[i] = *pbSrc++;
3018 else
3019 pbDst[i] = ' ';
3020 }
3021}
3022
3023static void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
3024{
3025 for (uint32_t i = 0; i < cbSize; i++)
3026 {
3027 if (*pbSrc)
3028 pbDst[i ^ 1] = *pbSrc++;
3029 else
3030 pbDst[i ^ 1] = ' ';
3031 }
3032}
3033
3034static uint32_t ataChecksum(void* ptr, size_t count)
3035{
3036 uint8_t u8Sum = 0xa5, *p = (uint8_t*)ptr;
3037 size_t i;
3038
3039 for (i = 0; i < count; i++)
3040 {
3041 u8Sum += *p++;
3042 }
3043
3044 return (uint8_t)-(int32_t)u8Sum;
3045}
3046
3047static int ahciIdentifySS(PAHCIPort pAhciPort, void *pvBuf)
3048{
3049 uint16_t *p;
3050 int rc = VINF_SUCCESS;
3051
3052 p = (uint16_t *)pvBuf;
3053 memset(p, 0, 512);
3054 p[0] = RT_H2LE_U16(0x0040);
3055 p[1] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
3056 p[3] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
3057 /* Block size; obsolete, but required for the BIOS. */
3058 p[5] = RT_H2LE_U16(512);
3059 p[6] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
3060 ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
3061 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
3062 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
3063 p[22] = RT_H2LE_U16(0); /* ECC bytes per sector */
3064 ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
3065 ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
3066#if ATA_MAX_MULT_SECTORS > 1
3067 p[47] = RT_H2LE_U16(0x8000 | ATA_MAX_MULT_SECTORS);
3068#endif
3069 p[48] = RT_H2LE_U16(1); /* dword I/O, used by the BIOS */
3070 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
3071 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
3072 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
3073 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
3074 p[53] = RT_H2LE_U16(1 | 1 << 1 | 1 << 2); /* words 54-58,64-70,88 valid */
3075 p[54] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
3076 p[55] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
3077 p[56] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
3078 p[57] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors);
3079 p[58] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors >> 16);
3080 if (pAhciPort->cMultSectors)
3081 p[59] = RT_H2LE_U16(0x100 | pAhciPort->cMultSectors);
3082 if (pAhciPort->cTotalSectors <= (1 << 28) - 1)
3083 {
3084 p[60] = RT_H2LE_U16(pAhciPort->cTotalSectors);
3085 p[61] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
3086 }
3087 else
3088 {
3089 /* Report maximum number of sectors possible with LBA28 */
3090 p[60] = RT_H2LE_U16(((1 << 28) - 1) & 0xffff);
3091 p[61] = RT_H2LE_U16(((1 << 28) - 1) >> 16);
3092 }
3093 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
3094 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
3095 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
3096 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
3097 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
3098 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
3099 if ( pAhciPort->pDrvMedia->pfnDiscard
3100 || ( pAhciPort->fAsyncInterface
3101 && pAhciPort->pDrvMediaAsync->pfnStartDiscard)
3102 || pAhciPort->cbSector != 512
3103 || pAhciPort->fNonRotational)
3104 {
3105 p[80] = RT_H2LE_U16(0x1f0); /* support everything up to ATA/ATAPI-8 ACS */
3106 p[81] = RT_H2LE_U16(0x28); /* conforms to ATA/ATAPI-8 ACS */
3107 }
3108 else
3109 {
3110 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
3111 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
3112 }
3113 p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
3114 p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
3115 p[84] = RT_H2LE_U16(1 << 14);
3116 p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
3117 p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
3118 p[87] = RT_H2LE_U16(1 << 14);
3119 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
3120 p[93] = RT_H2LE_U16(0x00);
3121 p[100] = RT_H2LE_U16(pAhciPort->cTotalSectors);
3122 p[101] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
3123 p[102] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 32);
3124 p[103] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 48);
3125
3126 /* valid information, more than one logical sector per physical sector, 2^cLogSectorsPerPhysicalExp logical sectors per physical sector */
3127 if (pAhciPort->cLogSectorsPerPhysicalExp)
3128 p[106] = RT_H2LE_U16(RT_BIT(14) | RT_BIT(13) | pAhciPort->cLogSectorsPerPhysicalExp);
3129
3130 if (pAhciPort->cbSector != 512)
3131 {
3132 uint32_t cSectorSizeInWords = pAhciPort->cbSector / sizeof(uint16_t);
3133 /* Enable reporting of logical sector size. */
3134 p[106] |= RT_H2LE_U16(RT_BIT(12) | RT_BIT(14));
3135 p[117] = RT_H2LE_U16(cSectorSizeInWords);
3136 p[118] = RT_H2LE_U16(cSectorSizeInWords >> 16);
3137 }
3138
3139 if (pAhciPort->fNonRotational)
3140 p[217] = RT_H2LE_U16(1); /* Non-rotational medium */
3141
3142 if ( pAhciPort->pDrvMedia->pfnDiscard
3143 || ( pAhciPort->fAsyncInterface
3144 && pAhciPort->pDrvMediaAsync->pfnStartDiscard)) /** @todo: Set bit 14 in word 69 too? (Deterministic read after TRIM). */
3145 p[169] = RT_H2LE_U16(1); /* DATA SET MANAGEMENT command supported. */
3146
3147 /* The following are SATA specific */
3148 p[75] = RT_H2LE_U16(pAhciPort->CTX_SUFF(pAhci)->cCmdSlotsAvail-1); /* Number of commands we support, 0's based */
3149 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
3150
3151 uint32_t uCsum = ataChecksum(p, 510);
3152 p[255] = RT_H2LE_U16(0xa5 | (uCsum << 8)); /* Integrity word */
3153
3154 return VINF_SUCCESS;
3155}
3156
3157typedef int (*PAtapiFunc)(PAHCIREQ, PAHCIPort, size_t, size_t *);
3158
3159static int atapiGetConfigurationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3160static int atapiGetEventStatusNotificationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3161static int atapiIdentifySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3162static int atapiInquirySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3163static int atapiMechanismStatusSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3164static int atapiModeSenseErrorRecoverySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3165static int atapiModeSenseCDStatusSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3166static int atapiReadCapacitySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3167static int atapiReadDiscInformationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3168static int atapiReadTOCNormalSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3169static int atapiReadTOCMultiSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3170static int atapiReadTOCRawSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3171static int atapiReadTrackInformationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3172static int atapiRequestSenseSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3173static int atapiPassthroughSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3174static int atapiReadDVDStructureSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3175
3176/**
3177 * Source/sink function indexes for g_apfnAtapiFuncs.
3178 */
3179typedef enum ATAPIFN
3180{
3181 ATAFN_SS_NULL = 0,
3182 ATAFN_SS_ATAPI_GET_CONFIGURATION,
3183 ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION,
3184 ATAFN_SS_ATAPI_IDENTIFY,
3185 ATAFN_SS_ATAPI_INQUIRY,
3186 ATAFN_SS_ATAPI_MECHANISM_STATUS,
3187 ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY,
3188 ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS,
3189 ATAFN_SS_ATAPI_READ_CAPACITY,
3190 ATAFN_SS_ATAPI_READ_DISC_INFORMATION,
3191 ATAFN_SS_ATAPI_READ_TOC_NORMAL,
3192 ATAFN_SS_ATAPI_READ_TOC_MULTI,
3193 ATAFN_SS_ATAPI_READ_TOC_RAW,
3194 ATAFN_SS_ATAPI_READ_TRACK_INFORMATION,
3195 ATAFN_SS_ATAPI_REQUEST_SENSE,
3196 ATAFN_SS_ATAPI_PASSTHROUGH,
3197 ATAFN_SS_ATAPI_READ_DVD_STRUCTURE,
3198 ATAFN_SS_MAX
3199} ATAPIFN;
3200
3201/**
3202 * Array of source/sink functions, the index is ATAFNSS.
3203 * Make sure ATAFNSS and this array match!
3204 */
3205static const PAtapiFunc g_apfnAtapiFuncs[ATAFN_SS_MAX] =
3206{
3207 NULL,
3208 atapiGetConfigurationSS,
3209 atapiGetEventStatusNotificationSS,
3210 atapiIdentifySS,
3211 atapiInquirySS,
3212 atapiMechanismStatusSS,
3213 atapiModeSenseErrorRecoverySS,
3214 atapiModeSenseCDStatusSS,
3215 atapiReadCapacitySS,
3216 atapiReadDiscInformationSS,
3217 atapiReadTOCNormalSS,
3218 atapiReadTOCMultiSS,
3219 atapiReadTOCRawSS,
3220 atapiReadTrackInformationSS,
3221 atapiRequestSenseSS,
3222 atapiPassthroughSS,
3223 atapiReadDVDStructureSS
3224};
3225
3226static int atapiIdentifySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3227{
3228 uint16_t p[256];
3229
3230 memset(p, 0, 512);
3231 /* Removable CDROM, 50us response, 12 byte packets */
3232 p[0] = RT_H2LE_U16(2 << 14 | 5 << 8 | 1 << 7 | 2 << 5 | 0 << 0);
3233 ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
3234 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
3235 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
3236 ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
3237 ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
3238 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
3239 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
3240 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
3241 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
3242 p[53] = RT_H2LE_U16(1 << 1 | 1 << 2); /* words 64-70,88 are valid */
3243 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
3244 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
3245 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
3246 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
3247 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
3248 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
3249 p[73] = RT_H2LE_U16(0x003e); /* ATAPI CDROM major */
3250 p[74] = RT_H2LE_U16(9); /* ATAPI CDROM minor */
3251 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
3252 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
3253 p[82] = RT_H2LE_U16(1 << 4 | 1 << 9); /* supports packet command set and DEVICE RESET */
3254 p[83] = RT_H2LE_U16(1 << 14);
3255 p[84] = RT_H2LE_U16(1 << 14);
3256 p[85] = RT_H2LE_U16(1 << 4 | 1 << 9); /* enabled packet command set and DEVICE RESET */
3257 p[86] = RT_H2LE_U16(0);
3258 p[87] = RT_H2LE_U16(1 << 14);
3259 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
3260 p[93] = RT_H2LE_U16((1 | 1 << 1) << ((pAhciPort->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
3261
3262 /* The following are SATA specific */
3263 p[75] = RT_H2LE_U16(31); /* We support 32 commands */
3264 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
3265
3266 /* Copy the buffer in to the scatter gather list. */
3267 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&p[0],
3268 RT_MIN(cbData, sizeof(p)));
3269
3270 atapiCmdOK(pAhciPort, pAhciReq);
3271 return VINF_SUCCESS;
3272}
3273
3274static int atapiReadCapacitySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3275{
3276 uint8_t aBuf[8];
3277
3278 ataH2BE_U32(aBuf, pAhciPort->cTotalSectors - 1);
3279 ataH2BE_U32(aBuf + 4, 2048);
3280
3281 /* Copy the buffer in to the scatter gather list. */
3282 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
3283 RT_MIN(cbData, sizeof(aBuf)));
3284
3285 atapiCmdOK(pAhciPort, pAhciReq);
3286 return VINF_SUCCESS;
3287}
3288
3289
3290static int atapiReadDiscInformationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3291{
3292 uint8_t aBuf[34];
3293
3294 memset(aBuf, '\0', 34);
3295 ataH2BE_U16(aBuf, 32);
3296 aBuf[2] = (0 << 4) | (3 << 2) | (2 << 0); /* not erasable, complete session, complete disc */
3297 aBuf[3] = 1; /* number of first track */
3298 aBuf[4] = 1; /* number of sessions (LSB) */
3299 aBuf[5] = 1; /* first track number in last session (LSB) */
3300 aBuf[6] = 1; /* last track number in last session (LSB) */
3301 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 */
3302 aBuf[8] = 0; /* disc type = CD-ROM */
3303 aBuf[9] = 0; /* number of sessions (MSB) */
3304 aBuf[10] = 0; /* number of sessions (MSB) */
3305 aBuf[11] = 0; /* number of sessions (MSB) */
3306 ataH2BE_U32(aBuf + 16, 0x00ffffff); /* last session lead-in start time is not available */
3307 ataH2BE_U32(aBuf + 20, 0x00ffffff); /* last possible start time for lead-out is not available */
3308
3309 /* Copy the buffer in to the scatter gather list. */
3310 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
3311 RT_MIN(cbData, sizeof(aBuf)));
3312
3313 atapiCmdOK(pAhciPort, pAhciReq);
3314 return VINF_SUCCESS;
3315}
3316
3317
3318static int atapiReadTrackInformationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3319{
3320 uint8_t aBuf[36];
3321
3322 /* Accept address/number type of 1 only, and only track 1 exists. */
3323 if ((pAhciReq->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&pAhciReq->aATAPICmd[2]) != 1)
3324 {
3325 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3326 return VINF_SUCCESS;
3327 }
3328 memset(aBuf, '\0', 36);
3329 ataH2BE_U16(aBuf, 34);
3330 aBuf[2] = 1; /* track number (LSB) */
3331 aBuf[3] = 1; /* session number (LSB) */
3332 aBuf[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
3333 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 */
3334 aBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
3335 ataH2BE_U32(aBuf + 8, 0); /* track start address is 0 */
3336 ataH2BE_U32(aBuf + 24, pAhciPort->cTotalSectors); /* track size */
3337 aBuf[32] = 0; /* track number (MSB) */
3338 aBuf[33] = 0; /* session number (MSB) */
3339
3340 /* Copy the buffer in to the scatter gather list. */
3341 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
3342 RT_MIN(cbData, sizeof(aBuf)));
3343
3344 atapiCmdOK(pAhciPort, pAhciReq);
3345 return VINF_SUCCESS;
3346}
3347
3348static size_t atapiGetConfigurationFillFeatureListProfiles(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
3349{
3350 if (cbBuf < 3*4)
3351 return 0;
3352
3353 ataH2BE_U16(pbBuf, 0x0); /* feature 0: list of profiles supported */
3354 pbBuf[2] = (0 << 2) | (1 << 1) | (1 << 0); /* version 0, persistent, current */
3355 pbBuf[3] = 8; /* additional bytes for profiles */
3356 /* The MMC-3 spec says that DVD-ROM read capability should be reported
3357 * before CD-ROM read capability. */
3358 ataH2BE_U16(pbBuf + 4, 0x10); /* profile: read-only DVD */
3359 pbBuf[6] = (0 << 0); /* NOT current profile */
3360 ataH2BE_U16(pbBuf + 8, 0x08); /* profile: read only CD */
3361 pbBuf[10] = (1 << 0); /* current profile */
3362
3363 return 3*4; /* Header + 2 profiles entries */
3364}
3365
3366static size_t atapiGetConfigurationFillFeatureCore(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
3367{
3368 if (cbBuf < 12)
3369 return 0;
3370
3371 ataH2BE_U16(pbBuf, 0x1); /* feature 0001h: Core Feature */
3372 pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3373 pbBuf[3] = 8; /* Additional length */
3374 ataH2BE_U16(pbBuf + 4, 0x00000002); /* Physical interface ATAPI. */
3375 pbBuf[8] = RT_BIT(0); /* DBE */
3376 /* Rest is reserved. */
3377
3378 return 12;
3379}
3380
3381static size_t atapiGetConfigurationFillFeatureMorphing(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
3382{
3383 if (cbBuf < 8)
3384 return 0;
3385
3386 ataH2BE_U16(pbBuf, 0x2); /* feature 0002h: Morphing Feature */
3387 pbBuf[2] = (0x1 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3388 pbBuf[3] = 4; /* Additional length */
3389 pbBuf[4] = RT_BIT(1) | 0x0; /* OCEvent | !ASYNC */
3390 /* Rest is reserved. */
3391
3392 return 8;
3393}
3394
3395static size_t atapiGetConfigurationFillFeatureRemovableMedium(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
3396{
3397 if (cbBuf < 8)
3398 return 0;
3399
3400 ataH2BE_U16(pbBuf, 0x3); /* feature 0003h: Removable Medium Feature */
3401 pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3402 pbBuf[3] = 4; /* Additional length */
3403 /* Tray type loading | Load | Eject | !Pvnt Jmpr | !DBML | Lock */
3404 pbBuf[4] = (0x2 << 5) | RT_BIT(4) | RT_BIT(3) | (0x0 << 2) | (0x0 << 1) | RT_BIT(0);
3405 /* Rest is reserved. */
3406
3407 return 8;
3408}
3409
3410static size_t atapiGetConfigurationFillFeatureRandomReadable(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
3411{
3412 if (cbBuf < 12)
3413 return 0;
3414
3415 ataH2BE_U16(pbBuf, 0x10); /* feature 0010h: Random Readable Feature */
3416 pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3417 pbBuf[3] = 8; /* Additional length */
3418 ataH2BE_U32(pbBuf + 4, 2048); /* Logical block size. */
3419 ataH2BE_U16(pbBuf + 8, 0x10); /* Blocking (0x10 for DVD, CD is not defined). */
3420 pbBuf[10] = 0; /* PP not present */
3421 /* Rest is reserved. */
3422
3423 return 12;
3424}
3425
3426static size_t atapiGetConfigurationFillFeatureCDRead(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
3427{
3428 if (cbBuf < 8)
3429 return 0;
3430
3431 ataH2BE_U16(pbBuf, 0x1e); /* feature 001Eh: CD Read Feature */
3432 pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3433 pbBuf[3] = 0; /* Additional length */
3434 pbBuf[4] = (0x0 << 7) | (0x0 << 1) | 0x0; /* !DAP | !C2-Flags | !CD-Text. */
3435 /* Rest is reserved. */
3436
3437 return 8;
3438}
3439
3440static size_t atapiGetConfigurationFillFeaturePowerManagement(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
3441{
3442 if (cbBuf < 4)
3443 return 0;
3444
3445 ataH2BE_U16(pbBuf, 0x100); /* feature 0100h: Power Management Feature */
3446 pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3447 pbBuf[3] = 0; /* Additional length */
3448
3449 return 4;
3450}
3451
3452static size_t atapiGetConfigurationFillFeatureTimeout(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
3453{
3454 if (cbBuf < 8)
3455 return 0;
3456
3457 ataH2BE_U16(pbBuf, 0x105); /* feature 0105h: Timeout Feature */
3458 pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3459 pbBuf[3] = 4; /* Additional length */
3460 pbBuf[4] = 0x0; /* !Group3 */
3461
3462 return 8;
3463}
3464
3465static int atapiGetConfigurationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3466{
3467 uint8_t aBuf[80];
3468 uint8_t *pbBuf = &aBuf[0];
3469 size_t cbBuf = sizeof(aBuf);
3470 size_t cbCopied = 0;
3471
3472 /* Accept valid request types only, and only starting feature 0. */
3473 if ((pAhciReq->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&pAhciReq->aATAPICmd[2]) != 0)
3474 {
3475 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3476 return VINF_SUCCESS;
3477 }
3478 /** @todo implement switching between CD-ROM and DVD-ROM profile (the only
3479 * way to differentiate them right now is based on the image size). */
3480 if (pAhciPort->cTotalSectors)
3481 ataH2BE_U16(pbBuf + 6, 0x08); /* current profile: read-only CD */
3482 else
3483 ataH2BE_U16(pbBuf + 6, 0x00); /* current profile: none -> no media */
3484 cbBuf -= 8;
3485 pbBuf += 8;
3486
3487 cbCopied = atapiGetConfigurationFillFeatureListProfiles(pAhciPort, pbBuf, cbBuf);
3488 cbBuf -= cbCopied;
3489 pbBuf += cbCopied;
3490
3491 cbCopied = atapiGetConfigurationFillFeatureCore(pAhciPort, pbBuf, cbBuf);
3492 cbBuf -= cbCopied;
3493 pbBuf += cbCopied;
3494
3495 cbCopied = atapiGetConfigurationFillFeatureMorphing(pAhciPort, pbBuf, cbBuf);
3496 cbBuf -= cbCopied;
3497 pbBuf += cbCopied;
3498
3499 cbCopied = atapiGetConfigurationFillFeatureRemovableMedium(pAhciPort, pbBuf, cbBuf);
3500 cbBuf -= cbCopied;
3501 pbBuf += cbCopied;
3502
3503 cbCopied = atapiGetConfigurationFillFeatureRandomReadable(pAhciPort, pbBuf, cbBuf);
3504 cbBuf -= cbCopied;
3505 pbBuf += cbCopied;
3506
3507 cbCopied = atapiGetConfigurationFillFeatureCDRead(pAhciPort, pbBuf, cbBuf);
3508 cbBuf -= cbCopied;
3509 pbBuf += cbCopied;
3510
3511 cbCopied = atapiGetConfigurationFillFeaturePowerManagement(pAhciPort, pbBuf, cbBuf);
3512 cbBuf -= cbCopied;
3513 pbBuf += cbCopied;
3514
3515 cbCopied = atapiGetConfigurationFillFeatureTimeout(pAhciPort, pbBuf, cbBuf);
3516 cbBuf -= cbCopied;
3517 pbBuf += cbCopied;
3518
3519 /* Set data length now. */
3520 ataH2BE_U32(&aBuf[0], sizeof(aBuf) - cbBuf);
3521
3522 /* Copy the buffer in to the scatter gather list. */
3523 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
3524 RT_MIN(cbData, sizeof(aBuf)));
3525
3526 atapiCmdOK(pAhciPort, pAhciReq);
3527 return VINF_SUCCESS;
3528}
3529
3530
3531static int atapiGetEventStatusNotificationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3532{
3533 uint8_t abBuf[8];
3534
3535 Assert(pAhciReq->enmTxDir == AHCITXDIR_READ);
3536 Assert(pAhciReq->cbTransfer <= 8);
3537
3538 if (!(pAhciReq->aATAPICmd[1] & 1))
3539 {
3540 /* no asynchronous operation supported */
3541 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3542 return VINF_SUCCESS;
3543 }
3544
3545 uint32_t OldStatus, NewStatus;
3546 do
3547 {
3548 OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
3549 NewStatus = ATA_EVENT_STATUS_UNCHANGED;
3550 switch (OldStatus)
3551 {
3552 case ATA_EVENT_STATUS_MEDIA_NEW:
3553 /* mount */
3554 ataH2BE_U16(abBuf + 0, 6);
3555 abBuf[2] = 0x04; /* media */
3556 abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
3557 abBuf[4] = 0x02; /* new medium */
3558 abBuf[5] = 0x02; /* medium present / door closed */
3559 abBuf[6] = 0x00;
3560 abBuf[7] = 0x00;
3561 break;
3562
3563 case ATA_EVENT_STATUS_MEDIA_CHANGED:
3564 case ATA_EVENT_STATUS_MEDIA_REMOVED:
3565 /* umount */
3566 ataH2BE_U16(abBuf + 0, 6);
3567 abBuf[2] = 0x04; /* media */
3568 abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
3569 abBuf[4] = 0x03; /* media removal */
3570 abBuf[5] = 0x00; /* medium absent / door closed */
3571 abBuf[6] = 0x00;
3572 abBuf[7] = 0x00;
3573 if (OldStatus == ATA_EVENT_STATUS_MEDIA_CHANGED)
3574 NewStatus = ATA_EVENT_STATUS_MEDIA_NEW;
3575 break;
3576
3577 case ATA_EVENT_STATUS_MEDIA_EJECT_REQUESTED: /* currently unused */
3578 ataH2BE_U16(abBuf + 0, 6);
3579 abBuf[2] = 0x04; /* media */
3580 abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
3581 abBuf[4] = 0x01; /* eject requested (eject button pressed) */
3582 abBuf[5] = 0x02; /* medium present / door closed */
3583 abBuf[6] = 0x00;
3584 abBuf[7] = 0x00;
3585 break;
3586
3587 case ATA_EVENT_STATUS_UNCHANGED:
3588 default:
3589 ataH2BE_U16(abBuf + 0, 6);
3590 abBuf[2] = 0x01; /* operational change request / notification */
3591 abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
3592 abBuf[4] = 0x00;
3593 abBuf[5] = 0x00;
3594 abBuf[6] = 0x00;
3595 abBuf[7] = 0x00;
3596 break;
3597 }
3598 } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
3599
3600 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&abBuf[0],
3601 RT_MIN(cbData, sizeof(abBuf)));
3602
3603 atapiCmdOK(pAhciPort, pAhciReq);
3604 return VINF_SUCCESS;
3605}
3606
3607
3608static int atapiInquirySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3609{
3610 uint8_t aBuf[36];
3611
3612 aBuf[0] = 0x05; /* CD-ROM */
3613 aBuf[1] = 0x80; /* removable */
3614 aBuf[2] = 0x00; /* ISO */
3615 aBuf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
3616 aBuf[4] = 31; /* additional length */
3617 aBuf[5] = 0; /* reserved */
3618 aBuf[6] = 0; /* reserved */
3619 aBuf[7] = 0; /* reserved */
3620 ataSCSIPadStr(aBuf + 8, pAhciPort->szInquiryVendorId, 8);
3621 ataSCSIPadStr(aBuf + 16, pAhciPort->szInquiryProductId, 16);
3622 ataSCSIPadStr(aBuf + 32, pAhciPort->szInquiryRevision, 4);
3623
3624 /* Copy the buffer in to the scatter gather list. */
3625 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
3626 RT_MIN(cbData, sizeof(aBuf)));
3627
3628 atapiCmdOK(pAhciPort, pAhciReq);
3629 return VINF_SUCCESS;
3630}
3631
3632
3633static int atapiModeSenseErrorRecoverySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3634{
3635 uint8_t aBuf[16];
3636
3637 ataH2BE_U16(&aBuf[0], 16 + 6);
3638 aBuf[2] = 0x70;
3639 aBuf[3] = 0;
3640 aBuf[4] = 0;
3641 aBuf[5] = 0;
3642 aBuf[6] = 0;
3643 aBuf[7] = 0;
3644
3645 aBuf[8] = 0x01;
3646 aBuf[9] = 0x06;
3647 aBuf[10] = 0x00;
3648 aBuf[11] = 0x05;
3649 aBuf[12] = 0x00;
3650 aBuf[13] = 0x00;
3651 aBuf[14] = 0x00;
3652 aBuf[15] = 0x00;
3653
3654 /* Copy the buffer in to the scatter gather list. */
3655 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
3656 RT_MIN(cbData, sizeof(aBuf)));
3657
3658 atapiCmdOK(pAhciPort, pAhciReq);
3659 return VINF_SUCCESS;
3660}
3661
3662
3663static int atapiModeSenseCDStatusSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3664{
3665 uint8_t aBuf[40];
3666
3667 ataH2BE_U16(&aBuf[0], 38);
3668 aBuf[2] = 0x70;
3669 aBuf[3] = 0;
3670 aBuf[4] = 0;
3671 aBuf[5] = 0;
3672 aBuf[6] = 0;
3673 aBuf[7] = 0;
3674
3675 aBuf[8] = 0x2a;
3676 aBuf[9] = 30; /* page length */
3677 aBuf[10] = 0x08; /* DVD-ROM read support */
3678 aBuf[11] = 0x00; /* no write support */
3679 /* The following claims we support audio play. This is obviously false,
3680 * but the Linux generic CDROM support makes many features depend on this
3681 * capability. If it's not set, this causes many things to be disabled. */
3682 aBuf[12] = 0x71; /* multisession support, mode 2 form 1/2 support, audio play */
3683 aBuf[13] = 0x00; /* no subchannel reads supported */
3684 aBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
3685 if (pAhciPort->pDrvMount->pfnIsLocked(pAhciPort->pDrvMount))
3686 aBuf[14] |= 1 << 1; /* report lock state */
3687 aBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
3688 ataH2BE_U16(&aBuf[16], 5632); /* (obsolete) claim 32x speed support */
3689 ataH2BE_U16(&aBuf[18], 2); /* number of audio volume levels */
3690 ataH2BE_U16(&aBuf[20], 128); /* buffer size supported in Kbyte - We don't have a buffer because we write directly into guest memory.
3691 Just write the value DevATA is using. */
3692 ataH2BE_U16(&aBuf[22], 5632); /* (obsolete) current read speed 32x */
3693 aBuf[24] = 0; /* reserved */
3694 aBuf[25] = 0; /* reserved for digital audio (see idx 15) */
3695 ataH2BE_U16(&aBuf[26], 0); /* (obsolete) maximum write speed */
3696 ataH2BE_U16(&aBuf[28], 0); /* (obsolete) current write speed */
3697 ataH2BE_U16(&aBuf[30], 0); /* copy management revision supported 0=no CSS */
3698 aBuf[32] = 0; /* reserved */
3699 aBuf[33] = 0; /* reserved */
3700 aBuf[34] = 0; /* reserved */
3701 aBuf[35] = 1; /* rotation control CAV */
3702 ataH2BE_U16(&aBuf[36], 0); /* current write speed */
3703 ataH2BE_U16(&aBuf[38], 0); /* number of write speed performance descriptors */
3704
3705 /* Copy the buffer in to the scatter gather list. */
3706 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
3707 RT_MIN(cbData, sizeof(aBuf)));
3708
3709 atapiCmdOK(pAhciPort, pAhciReq);
3710 return VINF_SUCCESS;
3711}
3712
3713
3714static int atapiRequestSenseSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3715{
3716 /* Copy the buffer in to the scatter gather list. */
3717 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
3718 pAhciPort->abATAPISense, RT_MIN(cbData, sizeof(pAhciPort->abATAPISense)));
3719
3720 atapiCmdOK(pAhciPort, pAhciReq);
3721 return VINF_SUCCESS;
3722}
3723
3724
3725static int atapiMechanismStatusSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3726{
3727 uint8_t aBuf[8];
3728
3729 ataH2BE_U16(&aBuf[0], 0);
3730 /* no current LBA */
3731 aBuf[2] = 0;
3732 aBuf[3] = 0;
3733 aBuf[4] = 0;
3734 aBuf[5] = 1;
3735 ataH2BE_U16(aBuf + 6, 0);
3736
3737 /* Copy the buffer in to the scatter gather list. */
3738 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
3739 RT_MIN(cbData, sizeof(aBuf)));
3740
3741 atapiCmdOK(pAhciPort, pAhciReq);
3742 return VINF_SUCCESS;
3743}
3744
3745
3746static int atapiReadTOCNormalSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3747{
3748 uint8_t aBuf[20], *q, iStartTrack;
3749 bool fMSF;
3750 uint32_t cbSize;
3751
3752 fMSF = (pAhciReq->aATAPICmd[1] >> 1) & 1;
3753 iStartTrack = pAhciReq->aATAPICmd[6];
3754 if (iStartTrack > 1 && iStartTrack != 0xaa)
3755 {
3756 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3757 return VINF_SUCCESS;
3758 }
3759 q = aBuf + 2;
3760 *q++ = 1; /* first session */
3761 *q++ = 1; /* last session */
3762 if (iStartTrack <= 1)
3763 {
3764 *q++ = 0; /* reserved */
3765 *q++ = 0x14; /* ADR, control */
3766 *q++ = 1; /* track number */
3767 *q++ = 0; /* reserved */
3768 if (fMSF)
3769 {
3770 *q++ = 0; /* reserved */
3771 ataLBA2MSF(q, 0);
3772 q += 3;
3773 }
3774 else
3775 {
3776 /* sector 0 */
3777 ataH2BE_U32(q, 0);
3778 q += 4;
3779 }
3780 }
3781 /* lead out track */
3782 *q++ = 0; /* reserved */
3783 *q++ = 0x14; /* ADR, control */
3784 *q++ = 0xaa; /* track number */
3785 *q++ = 0; /* reserved */
3786 if (fMSF)
3787 {
3788 *q++ = 0; /* reserved */
3789 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3790 q += 3;
3791 }
3792 else
3793 {
3794 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3795 q += 4;
3796 }
3797 cbSize = q - aBuf;
3798 ataH2BE_U16(aBuf, cbSize - 2);
3799
3800 /* Copy the buffer in to the scatter gather list. */
3801 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
3802 RT_MIN(cbData, cbSize));
3803
3804 atapiCmdOK(pAhciPort, pAhciReq);
3805 return VINF_SUCCESS;
3806}
3807
3808
3809static int atapiReadTOCMultiSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3810{
3811 uint8_t aBuf[12];
3812 bool fMSF;
3813
3814 fMSF = (pAhciReq->aATAPICmd[1] >> 1) & 1;
3815 /* multi session: only a single session defined */
3816/** @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. */
3817 memset(aBuf, 0, 12);
3818 aBuf[1] = 0x0a;
3819 aBuf[2] = 0x01;
3820 aBuf[3] = 0x01;
3821 aBuf[5] = 0x14; /* ADR, control */
3822 aBuf[6] = 1; /* first track in last complete session */
3823 if (fMSF)
3824 {
3825 aBuf[8] = 0; /* reserved */
3826 ataLBA2MSF(&aBuf[9], 0);
3827 }
3828 else
3829 {
3830 /* sector 0 */
3831 ataH2BE_U32(aBuf + 8, 0);
3832 }
3833
3834 /* Copy the buffer in to the scatter gather list. */
3835 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
3836 RT_MIN(cbData, sizeof(aBuf)));
3837
3838 atapiCmdOK(pAhciPort, pAhciReq);
3839 return VINF_SUCCESS;
3840}
3841
3842
3843static int atapiReadTOCRawSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3844{
3845 uint8_t aBuf[50]; /* Counted a maximum of 45 bytes but better be on the safe side. */
3846 uint8_t *q, iStartTrack;
3847 bool fMSF;
3848 uint32_t cbSize;
3849
3850 fMSF = (pAhciReq->aATAPICmd[1] >> 1) & 1;
3851 iStartTrack = pAhciReq->aATAPICmd[6];
3852
3853 q = aBuf + 2;
3854 *q++ = 1; /* first session */
3855 *q++ = 1; /* last session */
3856
3857 *q++ = 1; /* session number */
3858 *q++ = 0x14; /* data track */
3859 *q++ = 0; /* track number */
3860 *q++ = 0xa0; /* first track in program area */
3861 *q++ = 0; /* min */
3862 *q++ = 0; /* sec */
3863 *q++ = 0; /* frame */
3864 *q++ = 0;
3865 *q++ = 1; /* first track */
3866 *q++ = 0x00; /* disk type CD-DA or CD data */
3867 *q++ = 0;
3868
3869 *q++ = 1; /* session number */
3870 *q++ = 0x14; /* data track */
3871 *q++ = 0; /* track number */
3872 *q++ = 0xa1; /* last track in program area */
3873 *q++ = 0; /* min */
3874 *q++ = 0; /* sec */
3875 *q++ = 0; /* frame */
3876 *q++ = 0;
3877 *q++ = 1; /* last track */
3878 *q++ = 0;
3879 *q++ = 0;
3880
3881 *q++ = 1; /* session number */
3882 *q++ = 0x14; /* data track */
3883 *q++ = 0; /* track number */
3884 *q++ = 0xa2; /* lead-out */
3885 *q++ = 0; /* min */
3886 *q++ = 0; /* sec */
3887 *q++ = 0; /* frame */
3888 if (fMSF)
3889 {
3890 *q++ = 0; /* reserved */
3891 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3892 q += 3;
3893 }
3894 else
3895 {
3896 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3897 q += 4;
3898 }
3899
3900 *q++ = 1; /* session number */
3901 *q++ = 0x14; /* ADR, control */
3902 *q++ = 0; /* track number */
3903 *q++ = 1; /* point */
3904 *q++ = 0; /* min */
3905 *q++ = 0; /* sec */
3906 *q++ = 0; /* frame */
3907 if (fMSF)
3908 {
3909 *q++ = 0; /* reserved */
3910 ataLBA2MSF(q, 0);
3911 q += 3;
3912 }
3913 else
3914 {
3915 /* sector 0 */
3916 ataH2BE_U32(q, 0);
3917 q += 4;
3918 }
3919
3920 cbSize = q - aBuf;
3921 ataH2BE_U16(aBuf, cbSize - 2);
3922
3923 /* Copy the buffer in to the scatter gather list. */
3924 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
3925 RT_MIN(cbData, cbSize));
3926
3927 atapiCmdOK(pAhciPort, pAhciReq);
3928 return VINF_SUCCESS;
3929}
3930
3931/**
3932 * Sets the given media track type.
3933 */
3934static uint32_t ahciMediumTypeSet(PAHCIPort pAhciPort, uint32_t MediaTrackType)
3935{
3936 return ASMAtomicXchgU32(&pAhciPort->MediaTrackType, MediaTrackType);
3937}
3938
3939static int atapiPassthroughSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3940{
3941 int rc = VINF_SUCCESS;
3942 uint8_t abATAPISense[ATAPI_SENSE_SIZE];
3943 uint32_t cbTransfer;
3944 void *pvBuf = NULL;
3945
3946 cbTransfer = pAhciReq->cbTransfer;
3947
3948 if (cbTransfer)
3949 {
3950 pvBuf = (uint8_t *)RTMemAlloc(cbTransfer);
3951 if (!pvBuf)
3952 return VERR_NO_MEMORY;
3953
3954 if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
3955 {
3956 ahciCopyFromPrdtl(pAhciPort->pDevInsR3, pAhciReq, pvBuf, cbTransfer);
3957 if (pAhciReq->fFlags & AHCI_REQ_OVERFLOW)
3958 return VINF_SUCCESS;
3959 }
3960 }
3961
3962 /* Simple heuristics: if there is at least one sector of data
3963 * to transfer, it's worth updating the LEDs. */
3964 if (cbTransfer >= 2048)
3965 {
3966 if (pAhciReq->enmTxDir != AHCITXDIR_WRITE)
3967 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
3968 else
3969 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
3970 }
3971
3972 if (cbTransfer > SCSI_MAX_BUFFER_SIZE)
3973 {
3974 /* Linux accepts commands with up to 100KB of data, but expects
3975 * us to handle commands with up to 128KB of data. The usual
3976 * imbalance of powers. */
3977 uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
3978 uint32_t iATAPILBA, cSectors, cReqSectors, cbCurrTX;
3979 uint8_t *pbBuf = (uint8_t *)pvBuf;
3980
3981 switch (pAhciReq->aATAPICmd[0])
3982 {
3983 case SCSI_READ_10:
3984 case SCSI_WRITE_10:
3985 case SCSI_WRITE_AND_VERIFY_10:
3986 iATAPILBA = ataBE2H_U32(pAhciReq->aATAPICmd + 2);
3987 cSectors = ataBE2H_U16(pAhciReq->aATAPICmd + 7);
3988 break;
3989 case SCSI_READ_12:
3990 case SCSI_WRITE_12:
3991 iATAPILBA = ataBE2H_U32(pAhciReq->aATAPICmd + 2);
3992 cSectors = ataBE2H_U32(pAhciReq->aATAPICmd + 6);
3993 break;
3994 case SCSI_READ_CD:
3995 iATAPILBA = ataBE2H_U32(pAhciReq->aATAPICmd + 2);
3996 cSectors = ataBE2H_U24(pAhciReq->aATAPICmd + 6);
3997 break;
3998 case SCSI_READ_CD_MSF:
3999 iATAPILBA = ataMSF2LBA(pAhciReq->aATAPICmd + 3);
4000 cSectors = ataMSF2LBA(pAhciReq->aATAPICmd + 6) - iATAPILBA;
4001 break;
4002 default:
4003 AssertMsgFailed(("Don't know how to split command %#04x\n", pAhciReq->aATAPICmd[0]));
4004 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
4005 LogRel(("AHCI: LUN#%d: CD-ROM passthrough split error\n", pAhciPort->iLUN));
4006 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
4007 RTMemFree(pvBuf);
4008 return VINF_SUCCESS;
4009 }
4010 memcpy(aATAPICmd, pAhciReq->aATAPICmd, ATAPI_PACKET_SIZE);
4011 cReqSectors = 0;
4012 for (uint32_t i = cSectors; i > 0; i -= cReqSectors)
4013 {
4014 if (i * pAhciReq->cbATAPISector > SCSI_MAX_BUFFER_SIZE)
4015 cReqSectors = SCSI_MAX_BUFFER_SIZE / pAhciReq->cbATAPISector;
4016 else
4017 cReqSectors = i;
4018 cbCurrTX = pAhciReq->cbATAPISector * cReqSectors;
4019 switch (pAhciReq->aATAPICmd[0])
4020 {
4021 case SCSI_READ_10:
4022 case SCSI_WRITE_10:
4023 case SCSI_WRITE_AND_VERIFY_10:
4024 ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
4025 ataH2BE_U16(aATAPICmd + 7, cReqSectors);
4026 break;
4027 case SCSI_READ_12:
4028 case SCSI_WRITE_12:
4029 ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
4030 ataH2BE_U32(aATAPICmd + 6, cReqSectors);
4031 break;
4032 case SCSI_READ_CD:
4033 ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
4034 ataH2BE_U24(aATAPICmd + 6, cReqSectors);
4035 break;
4036 case SCSI_READ_CD_MSF:
4037 ataLBA2MSF(aATAPICmd + 3, iATAPILBA);
4038 ataLBA2MSF(aATAPICmd + 6, iATAPILBA + cReqSectors);
4039 break;
4040 }
4041 rc = pAhciPort->pDrvMedia->pfnSendCmd(pAhciPort->pDrvMedia,
4042 aATAPICmd,
4043 pAhciReq->enmTxDir == AHCITXDIR_READ
4044 ? PDMMEDIATXDIR_FROM_DEVICE
4045 : PDMMEDIATXDIR_TO_DEVICE,
4046 pbBuf,
4047 &cbCurrTX,
4048 abATAPISense,
4049 sizeof(abATAPISense),
4050 30000 /**< @todo timeout */);
4051 if (rc != VINF_SUCCESS)
4052 break;
4053 iATAPILBA += cReqSectors;
4054 pbBuf += pAhciReq->cbATAPISector * cReqSectors;
4055 }
4056 }
4057 else
4058 {
4059 PDMMEDIATXDIR enmBlockTxDir = PDMMEDIATXDIR_NONE;
4060
4061 if (pAhciReq->enmTxDir == AHCITXDIR_READ)
4062 enmBlockTxDir = PDMMEDIATXDIR_FROM_DEVICE;
4063 else if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
4064 enmBlockTxDir = PDMMEDIATXDIR_TO_DEVICE;
4065 else if (pAhciReq->enmTxDir == AHCITXDIR_NONE)
4066 enmBlockTxDir = PDMMEDIATXDIR_NONE;
4067 else
4068 AssertMsgFailed(("Invalid transfer direction %d\n", pAhciReq->enmTxDir));
4069
4070 rc = pAhciPort->pDrvMedia->pfnSendCmd(pAhciPort->pDrvMedia,
4071 pAhciReq->aATAPICmd,
4072 enmBlockTxDir,
4073 pvBuf,
4074 &cbTransfer,
4075 abATAPISense,
4076 sizeof(abATAPISense),
4077 30000 /**< @todo timeout */);
4078 }
4079
4080 /* Update the LEDs and the read/write statistics. */
4081 if (cbTransfer >= 2048)
4082 {
4083 if (pAhciReq->enmTxDir != AHCITXDIR_WRITE)
4084 {
4085 pAhciPort->Led.Actual.s.fReading = 0;
4086 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbTransfer);
4087 }
4088 else
4089 {
4090 pAhciPort->Led.Actual.s.fWriting = 0;
4091 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, cbTransfer);
4092 }
4093 }
4094
4095 if (RT_SUCCESS(rc))
4096 {
4097 /* Do post processing for certain commands. */
4098 switch (pAhciReq->aATAPICmd[0])
4099 {
4100 case SCSI_SEND_CUE_SHEET:
4101 case SCSI_READ_TOC_PMA_ATIP:
4102 {
4103 if (!pAhciPort->pTrackList)
4104 rc = ATAPIPassthroughTrackListCreateEmpty(&pAhciPort->pTrackList);
4105
4106 if (RT_SUCCESS(rc))
4107 rc = ATAPIPassthroughTrackListUpdate(pAhciPort->pTrackList, pAhciReq->aATAPICmd, pvBuf);
4108
4109 if ( RT_FAILURE(rc)
4110 && pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
4111 LogRel(("AHCI: Error (%Rrc) while updating the tracklist during %s, burning the disc might fail\n",
4112 rc, pAhciReq->aATAPICmd[0] == SCSI_SEND_CUE_SHEET ? "SEND CUE SHEET" : "READ TOC/PMA/ATIP"));
4113 break;
4114 }
4115 case SCSI_SYNCHRONIZE_CACHE:
4116 {
4117 if (pAhciPort->pTrackList)
4118 ATAPIPassthroughTrackListClear(pAhciPort->pTrackList);
4119 break;
4120 }
4121 }
4122
4123 if (pAhciReq->enmTxDir == AHCITXDIR_READ)
4124 {
4125 Assert(cbTransfer <= pAhciReq->cbTransfer);
4126
4127 if (pAhciReq->aATAPICmd[0] == SCSI_INQUIRY)
4128 {
4129 /* Make sure that the real drive cannot be identified.
4130 * Motivation: changing the VM configuration should be as
4131 * invisible as possible to the guest. */
4132 if (cbTransfer >= 8 + 8)
4133 ataSCSIPadStr((uint8_t *)pvBuf + 8, "VBOX", 8);
4134 if (cbTransfer >= 16 + 16)
4135 ataSCSIPadStr((uint8_t *)pvBuf + 16, "CD-ROM", 16);
4136 if (cbTransfer >= 32 + 4)
4137 ataSCSIPadStr((uint8_t *)pvBuf + 32, "1.0", 4);
4138 }
4139
4140 if (cbTransfer)
4141 {
4142 Log3(("ATAPI PT data read (%d): %.*Rhxs\n", cbTransfer, cbTransfer, (uint8_t *)pvBuf));
4143
4144 /* Reply with the same amount of data as the real drive. */
4145 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, pvBuf,
4146 cbTransfer);
4147 }
4148 else
4149 *pcbData = 0;
4150 }
4151 else
4152 *pcbData = cbTransfer;
4153 atapiCmdOK(pAhciPort, pAhciReq);
4154 }
4155 else
4156 {
4157 if (pAhciPort->cErrors < MAX_LOG_REL_ERRORS)
4158 {
4159 uint8_t u8Cmd = pAhciReq->aATAPICmd[0];
4160 do
4161 {
4162 /* don't log superfluous errors */
4163 if ( rc == VERR_DEV_IO_ERROR
4164 && ( u8Cmd == SCSI_TEST_UNIT_READY
4165 || u8Cmd == SCSI_READ_CAPACITY
4166 || u8Cmd == SCSI_READ_DVD_STRUCTURE
4167 || u8Cmd == SCSI_READ_TOC_PMA_ATIP))
4168 break;
4169 pAhciPort->cErrors++;
4170 LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough cmd=%#04x sense=%d ASC=%#02x ASCQ=%#02x %Rrc\n",
4171 pAhciPort->iLUN, u8Cmd, abATAPISense[2] & 0x0f, abATAPISense[12], abATAPISense[13], rc));
4172 } while (0);
4173 }
4174 atapiCmdError(pAhciPort, pAhciReq, abATAPISense, sizeof(abATAPISense));
4175 }
4176
4177 if (pvBuf)
4178 RTMemFree(pvBuf);
4179
4180 return VINF_SUCCESS;
4181}
4182
4183/** @todo: Revise ASAP. */
4184/* Keep in sync with DevATA.cpp! */
4185static int atapiReadDVDStructureSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
4186{
4187 uint8_t aBuf[25]; /* Counted a maximum of 20 bytes but better be on the safe side. */
4188 uint8_t *buf = aBuf;
4189 int media = pAhciReq->aATAPICmd[1];
4190 int format = pAhciReq->aATAPICmd[7];
4191
4192 uint16_t max_len = RT_MIN(ataBE2H_U16(&pAhciReq->aATAPICmd[8]), sizeof(aBuf));
4193
4194 memset(buf, 0, max_len);
4195
4196 switch (format) {
4197 case 0x00:
4198 case 0x01:
4199 case 0x02:
4200 case 0x03:
4201 case 0x04:
4202 case 0x05:
4203 case 0x06:
4204 case 0x07:
4205 case 0x08:
4206 case 0x09:
4207 case 0x0a:
4208 case 0x0b:
4209 case 0x0c:
4210 case 0x0d:
4211 case 0x0e:
4212 case 0x0f:
4213 case 0x10:
4214 case 0x11:
4215 case 0x30:
4216 case 0x31:
4217 case 0xff:
4218 if (media == 0)
4219 {
4220 int uASC = SCSI_ASC_NONE;
4221
4222 switch (format)
4223 {
4224 case 0x0: /* Physical format information */
4225 {
4226 int layer = pAhciReq->aATAPICmd[6];
4227 uint64_t total_sectors;
4228
4229 if (layer != 0)
4230 {
4231 uASC = -SCSI_ASC_INV_FIELD_IN_CMD_PACKET;
4232 break;
4233 }
4234
4235 total_sectors = pAhciPort->cTotalSectors;
4236 total_sectors >>= 2;
4237 if (total_sectors == 0)
4238 {
4239 uASC = -SCSI_ASC_MEDIUM_NOT_PRESENT;
4240 break;
4241 }
4242
4243 buf[4] = 1; /* DVD-ROM, part version 1 */
4244 buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
4245 buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */
4246 buf[7] = 0; /* default densities */
4247
4248 /* FIXME: 0x30000 per spec? */
4249 ataH2BE_U32(buf + 8, 0); /* start sector */
4250 ataH2BE_U32(buf + 12, total_sectors - 1); /* end sector */
4251 ataH2BE_U32(buf + 16, total_sectors - 1); /* l0 end sector */
4252
4253 /* Size of buffer, not including 2 byte size field */
4254 ataH2BE_U32(&buf[0], 2048 + 2);
4255
4256 /* 2k data + 4 byte header */
4257 uASC = (2048 + 4);
4258 break;
4259 }
4260 case 0x01: /* DVD copyright information */
4261 buf[4] = 0; /* no copyright data */
4262 buf[5] = 0; /* no region restrictions */
4263
4264 /* Size of buffer, not including 2 byte size field */
4265 ataH2BE_U16(buf, 4 + 2);
4266
4267 /* 4 byte header + 4 byte data */
4268 uASC = (4 + 4);
4269 break;
4270
4271 case 0x03: /* BCA information - invalid field for no BCA info */
4272 uASC = -SCSI_ASC_INV_FIELD_IN_CMD_PACKET;
4273 break;
4274
4275 case 0x04: /* DVD disc manufacturing information */
4276 /* Size of buffer, not including 2 byte size field */
4277 ataH2BE_U16(buf, 2048 + 2);
4278
4279 /* 2k data + 4 byte header */
4280 uASC = (2048 + 4);
4281 break;
4282 case 0xff:
4283 /*
4284 * This lists all the command capabilities above. Add new ones
4285 * in order and update the length and buffer return values.
4286 */
4287
4288 buf[4] = 0x00; /* Physical format */
4289 buf[5] = 0x40; /* Not writable, is readable */
4290 ataH2BE_U16((buf + 6), 2048 + 4);
4291
4292 buf[8] = 0x01; /* Copyright info */
4293 buf[9] = 0x40; /* Not writable, is readable */
4294 ataH2BE_U16((buf + 10), 4 + 4);
4295
4296 buf[12] = 0x03; /* BCA info */
4297 buf[13] = 0x40; /* Not writable, is readable */
4298 ataH2BE_U16((buf + 14), 188 + 4);
4299
4300 buf[16] = 0x04; /* Manufacturing info */
4301 buf[17] = 0x40; /* Not writable, is readable */
4302 ataH2BE_U16((buf + 18), 2048 + 4);
4303
4304 /* Size of buffer, not including 2 byte size field */
4305 ataH2BE_U16(buf, 16 + 2);
4306
4307 /* data written + 4 byte header */
4308 uASC = (16 + 4);
4309 break;
4310 default: /* TODO: formats beyond DVD-ROM requires */
4311 uASC = -SCSI_ASC_INV_FIELD_IN_CMD_PACKET;
4312 }
4313
4314 if (uASC < 0)
4315 {
4316 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, -uASC);
4317 return false;
4318 }
4319 break;
4320 }
4321 /* TODO: BD support, fall through for now */
4322
4323 /* Generic disk structures */
4324 case 0x80: /* TODO: AACS volume identifier */
4325 case 0x81: /* TODO: AACS media serial number */
4326 case 0x82: /* TODO: AACS media identifier */
4327 case 0x83: /* TODO: AACS media key block */
4328 case 0x90: /* TODO: List of recognized format layers */
4329 case 0xc0: /* TODO: Write protection status */
4330 default:
4331 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST,
4332 SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4333 return false;
4334 }
4335
4336 /* Copy the buffer into the scatter gather list. */
4337 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
4338 RT_MIN(cbData, max_len));
4339
4340 atapiCmdOK(pAhciPort, pAhciReq);
4341 return false;
4342}
4343
4344static int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cbMax, ATAPIFN iSourceSink)
4345{
4346 size_t cbTransfered = 0;
4347 int rcSourceSink;
4348
4349 rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciReq, pAhciPort, cbMax,
4350 &cbTransfered);
4351
4352 pAhciReq->cmdHdr.u32PRDBC = cbTransfered;
4353 pAhciReq->cbTransfer = cbTransfered;
4354
4355 LogFlow(("cbTransfered=%d\n", cbTransfered));
4356
4357 /* Write updated command header into memory of the guest. */
4358 PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
4359
4360 return rcSourceSink;
4361}
4362
4363static DECLCALLBACK(int) atapiReadSectors2352PostProcess(PAHCIREQ pAhciReq, void **ppvProc, size_t *pcbProc)
4364{
4365 uint8_t *pbBuf = NULL;
4366 uint32_t cSectors = pAhciReq->cbTransfer / 2048;
4367 uint32_t iATAPILBA = pAhciReq->uOffset / 2048;
4368 uint8_t *pbBufDst;
4369 uint8_t *pbBufSrc = (uint8_t *)pAhciReq->u.Io.DataSeg.pvSeg;
4370 size_t cbAlloc = pAhciReq->cbTransfer + cSectors * (1 + 11 + 3 + 1 + 288); /* Per sector data like ECC. */
4371
4372 pbBuf = (uint8_t *)RTMemAlloc(cbAlloc);
4373 if (RT_UNLIKELY(!pbBuf))
4374 return VERR_NO_MEMORY;
4375
4376 pbBufDst = pbBuf;
4377
4378 for (uint32_t i = iATAPILBA; i < iATAPILBA + cSectors; i++)
4379 {
4380 /* sync bytes */
4381 *pbBufDst++ = 0x00;
4382 memset(pbBufDst, 0xff, 11);
4383 pbBufDst += 11;
4384 /* MSF */
4385 ataLBA2MSF(pbBufDst, i);
4386 pbBufDst += 3;
4387 *pbBufDst++ = 0x01; /* mode 1 data */
4388 /* data */
4389 memcpy(pbBufDst, pbBufSrc, 2048);
4390 pbBufDst += 2048;
4391 pbBufSrc += 2048;
4392 /* ECC */
4393 memset(pbBufDst, 0, 288);
4394 pbBufDst += 288;
4395 }
4396
4397 *ppvProc = pbBuf;
4398 *pcbProc = cbAlloc;
4399
4400 return VINF_SUCCESS;
4401}
4402
4403static int atapiReadSectors(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
4404{
4405 Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iATAPILBA));
4406
4407 switch (cbSector)
4408 {
4409 case 2048:
4410 pAhciReq->uOffset = (uint64_t)iATAPILBA * cbSector;
4411 pAhciReq->cbTransfer = cSectors * cbSector;
4412 break;
4413 case 2352:
4414 {
4415 pAhciReq->u.Io.pfnPostProcess = atapiReadSectors2352PostProcess;
4416 pAhciReq->uOffset = (uint64_t)iATAPILBA * 2048;
4417 pAhciReq->cbTransfer = cSectors * 2048;
4418 break;
4419 }
4420 default:
4421 AssertMsgFailed(("Unsupported sectors size\n"));
4422 break;
4423 }
4424
4425 return VINF_SUCCESS;
4426}
4427
4428static AHCITXDIR atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
4429{
4430 AHCITXDIR enmTxDir = AHCITXDIR_NONE;
4431 const uint8_t *pbPacket;
4432 uint32_t cbMax;
4433
4434 pbPacket = pAhciReq->aATAPICmd;
4435
4436 ahciLog(("%s: ATAPI CMD=%#04x \"%s\"\n", __FUNCTION__, pbPacket[0], SCSICmdText(pbPacket[0])));
4437
4438 switch (pbPacket[0])
4439 {
4440 case SCSI_TEST_UNIT_READY:
4441 if (pAhciPort->cNotifiedMediaChange > 0)
4442 {
4443 if (pAhciPort->cNotifiedMediaChange-- > 2)
4444 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4445 else
4446 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4447 }
4448 else if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4449 atapiCmdOK(pAhciPort, pAhciReq);
4450 else
4451 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4452 break;
4453 case SCSI_GET_EVENT_STATUS_NOTIFICATION:
4454 cbMax = ataBE2H_U16(pbPacket + 7);
4455 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
4456 break;
4457 case SCSI_MODE_SENSE_10:
4458 {
4459 uint8_t uPageControl, uPageCode;
4460 cbMax = ataBE2H_U16(pbPacket + 7);
4461 uPageControl = pbPacket[2] >> 6;
4462 uPageCode = pbPacket[2] & 0x3f;
4463 switch (uPageControl)
4464 {
4465 case SCSI_PAGECONTROL_CURRENT:
4466 switch (uPageCode)
4467 {
4468 case SCSI_MODEPAGE_ERROR_RECOVERY:
4469 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY);
4470 break;
4471 case SCSI_MODEPAGE_CD_STATUS:
4472 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS);
4473 break;
4474 default:
4475 goto error_cmd;
4476 }
4477 break;
4478 case SCSI_PAGECONTROL_CHANGEABLE:
4479 goto error_cmd;
4480 case SCSI_PAGECONTROL_DEFAULT:
4481 goto error_cmd;
4482 default:
4483 case SCSI_PAGECONTROL_SAVED:
4484 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
4485 break;
4486 }
4487 break;
4488 }
4489 case SCSI_REQUEST_SENSE:
4490 cbMax = pbPacket[4];
4491 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_REQUEST_SENSE);
4492 break;
4493 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
4494 if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4495 {
4496 if (pbPacket[4] & 1)
4497 pAhciPort->pDrvMount->pfnLock(pAhciPort->pDrvMount);
4498 else
4499 pAhciPort->pDrvMount->pfnUnlock(pAhciPort->pDrvMount);
4500 atapiCmdOK(pAhciPort, pAhciReq);
4501 }
4502 else
4503 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4504 break;
4505 case SCSI_READ_10:
4506 case SCSI_READ_12:
4507 {
4508 uint32_t cSectors, iATAPILBA;
4509
4510 if (pAhciPort->cNotifiedMediaChange > 0)
4511 {
4512 pAhciPort->cNotifiedMediaChange-- ;
4513 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4514 break;
4515 }
4516 if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4517 {
4518 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4519 break;
4520 }
4521 if (pbPacket[0] == SCSI_READ_10)
4522 cSectors = ataBE2H_U16(pbPacket + 7);
4523 else
4524 cSectors = ataBE2H_U32(pbPacket + 6);
4525 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4526 if (cSectors == 0)
4527 {
4528 atapiCmdOK(pAhciPort, pAhciReq);
4529 break;
4530 }
4531 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
4532 {
4533 /* Rate limited logging, one log line per second. For
4534 * guests that insist on reading from places outside the
4535 * valid area this often generates too many release log
4536 * entries otherwise. */
4537 static uint64_t s_uLastLogTS = 0;
4538 if (RTTimeMilliTS() >= s_uLastLogTS + 1000)
4539 {
4540 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
4541 s_uLastLogTS = RTTimeMilliTS();
4542 }
4543 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
4544 break;
4545 }
4546 atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2048);
4547 enmTxDir = AHCITXDIR_READ;
4548 break;
4549 }
4550 case SCSI_READ_CD:
4551 {
4552 uint32_t cSectors, iATAPILBA;
4553
4554 if (pAhciPort->cNotifiedMediaChange > 0)
4555 {
4556 pAhciPort->cNotifiedMediaChange-- ;
4557 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4558 break;
4559 }
4560 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4561 {
4562 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4563 break;
4564 }
4565 cSectors = (pbPacket[6] << 16) | (pbPacket[7] << 8) | pbPacket[8];
4566 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4567 if (cSectors == 0)
4568 {
4569 atapiCmdOK(pAhciPort, pAhciReq);
4570 break;
4571 }
4572 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
4573 {
4574 /* Rate limited logging, one log line per second. For
4575 * guests that insist on reading from places outside the
4576 * valid area this often generates too many release log
4577 * entries otherwise. */
4578 static uint64_t s_uLastLogTS = 0;
4579 if (RTTimeMilliTS() >= s_uLastLogTS + 1000)
4580 {
4581 LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
4582 s_uLastLogTS = RTTimeMilliTS();
4583 }
4584 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
4585 break;
4586 }
4587 switch (pbPacket[9] & 0xf8)
4588 {
4589 case 0x00:
4590 /* nothing */
4591 atapiCmdOK(pAhciPort, pAhciReq);
4592 break;
4593 case 0x10:
4594 /* normal read */
4595 atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2048);
4596 enmTxDir = AHCITXDIR_READ;
4597 break;
4598 case 0xf8:
4599 /* read all data */
4600 atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2352);
4601 enmTxDir = AHCITXDIR_READ;
4602 break;
4603 default:
4604 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM sector format not supported\n", pAhciPort->iLUN));
4605 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4606 break;
4607 }
4608 break;
4609 }
4610 case SCSI_SEEK_10:
4611 {
4612 uint32_t iATAPILBA;
4613 if (pAhciPort->cNotifiedMediaChange > 0)
4614 {
4615 pAhciPort->cNotifiedMediaChange-- ;
4616 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4617 break;
4618 }
4619 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4620 {
4621 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4622 break;
4623 }
4624 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4625 if (iATAPILBA > pAhciPort->cTotalSectors)
4626 {
4627 /* Rate limited logging, one log line per second. For
4628 * guests that insist on seeking to places outside the
4629 * valid area this often generates too many release log
4630 * entries otherwise. */
4631 static uint64_t s_uLastLogTS = 0;
4632 if (RTTimeMilliTS() >= s_uLastLogTS + 1000)
4633 {
4634 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA));
4635 s_uLastLogTS = RTTimeMilliTS();
4636 }
4637 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
4638 break;
4639 }
4640 atapiCmdOK(pAhciPort, pAhciReq);
4641 pAhciReq->uATARegStatus |= ATA_STAT_SEEK; /* Linux expects this. */
4642 break;
4643 }
4644 case SCSI_START_STOP_UNIT:
4645 {
4646 int rc = VINF_SUCCESS;
4647 switch (pbPacket[4] & 3)
4648 {
4649 case 0: /* 00 - Stop motor */
4650 case 1: /* 01 - Start motor */
4651 break;
4652 case 2: /* 10 - Eject media */
4653 {
4654 /* This must be done from EMT. */
4655 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
4656 PPDMDEVINS pDevIns = pAhci->CTX_SUFF(pDevIns);
4657
4658 /*
4659 * Free the I/O memory of all cached tasks of this port
4660 * because the driver providing I/O memory allocation interface
4661 * is about to be destroyed.
4662 */
4663 ahciR3PortCachedReqsFree(pAhciPort);
4664
4665 /*
4666 * Also make sure that the current request has no memory allocated
4667 * from the driver below us. We don't require it here anyway.
4668 */
4669 ahciReqMemFree(pAhciPort, pAhciReq, true /* fForceFree */);
4670
4671 rc = VMR3ReqPriorityCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
4672 (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 3,
4673 pAhciPort->pDrvMount, false/*=fForce*/, true/*=fEject*/);
4674 Assert(RT_SUCCESS(rc) || rc == VERR_PDM_MEDIA_LOCKED || rc == VERR_PDM_MEDIA_NOT_MOUNTED);
4675 if (RT_SUCCESS(rc) && pAhci->pMediaNotify)
4676 {
4677 rc = VMR3ReqCallNoWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
4678 (PFNRT)pAhci->pMediaNotify->pfnEjected, 2,
4679 pAhci->pMediaNotify, pAhciPort->iLUN);
4680 AssertRC(rc);
4681 }
4682 break;
4683 }
4684 case 3: /* 11 - Load media */
4685 /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
4686 break;
4687 }
4688 if (RT_SUCCESS(rc))
4689 atapiCmdOK(pAhciPort, pAhciReq);
4690 else
4691 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
4692 break;
4693 }
4694 case SCSI_MECHANISM_STATUS:
4695 {
4696 cbMax = ataBE2H_U16(pbPacket + 8);
4697 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MECHANISM_STATUS);
4698 break;
4699 }
4700 case SCSI_READ_TOC_PMA_ATIP:
4701 {
4702 uint8_t format;
4703
4704 if (pAhciPort->cNotifiedMediaChange > 0)
4705 {
4706 pAhciPort->cNotifiedMediaChange-- ;
4707 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4708 break;
4709 }
4710 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4711 {
4712 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4713 break;
4714 }
4715 cbMax = ataBE2H_U16(pbPacket + 7);
4716 /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
4717 * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
4718 * the other field is clear... */
4719 format = (pbPacket[2] & 0xf) | (pbPacket[9] >> 6);
4720 switch (format)
4721 {
4722 case 0:
4723 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_NORMAL);
4724 break;
4725 case 1:
4726 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_MULTI);
4727 break;
4728 case 2:
4729 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_RAW);
4730 break;
4731 default:
4732 error_cmd:
4733 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4734 break;
4735 }
4736 break;
4737 }
4738 case SCSI_READ_CAPACITY:
4739 if (pAhciPort->cNotifiedMediaChange > 0)
4740 {
4741 pAhciPort->cNotifiedMediaChange-- ;
4742 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4743 break;
4744 }
4745 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4746 {
4747 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4748 break;
4749 }
4750 atapiDoTransfer(pAhciPort, pAhciReq, 8 /* cbMax */, ATAFN_SS_ATAPI_READ_CAPACITY);
4751 break;
4752 case SCSI_READ_DISC_INFORMATION:
4753 if (pAhciPort->cNotifiedMediaChange > 0)
4754 {
4755 pAhciPort->cNotifiedMediaChange-- ;
4756 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4757 break;
4758 }
4759 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4760 {
4761 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4762 break;
4763 }
4764 cbMax = ataBE2H_U16(pbPacket + 7);
4765 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_DISC_INFORMATION);
4766 break;
4767 case SCSI_READ_TRACK_INFORMATION:
4768 if (pAhciPort->cNotifiedMediaChange > 0)
4769 {
4770 pAhciPort->cNotifiedMediaChange-- ;
4771 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4772 break;
4773 }
4774 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4775 {
4776 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4777 break;
4778 }
4779 cbMax = ataBE2H_U16(pbPacket + 7);
4780 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION);
4781 break;
4782 case SCSI_GET_CONFIGURATION:
4783 /* No media change stuff here, it can confuse Linux guests. */
4784 cbMax = ataBE2H_U16(pbPacket + 7);
4785 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_GET_CONFIGURATION);
4786 break;
4787 case SCSI_INQUIRY:
4788 cbMax = pbPacket[4];
4789 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_INQUIRY);
4790 break;
4791 case SCSI_READ_DVD_STRUCTURE:
4792 cbMax = ataBE2H_U16(pbPacket + 8);
4793 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_DVD_STRUCTURE);
4794 break;
4795 default:
4796 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
4797 break;
4798 }
4799
4800 return enmTxDir;
4801}
4802
4803/*
4804 * Parse ATAPI commands, passing them directly to the CD/DVD drive.
4805 */
4806static AHCITXDIR atapiParseCmdPassthrough(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
4807{
4808 const uint8_t *pbPacket;
4809 uint32_t cSectors, iATAPILBA;
4810 uint32_t cbTransfer = 0;
4811 AHCITXDIR enmTxDir = AHCITXDIR_NONE;
4812
4813 pbPacket = pAhciReq->aATAPICmd;
4814 switch (pbPacket[0])
4815 {
4816 case SCSI_BLANK:
4817 goto sendcmd;
4818 case SCSI_CLOSE_TRACK_SESSION:
4819 goto sendcmd;
4820 case SCSI_ERASE_10:
4821 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4822 cbTransfer = ataBE2H_U16(pbPacket + 7);
4823 Log2(("ATAPI PT: lba %d\n", iATAPILBA));
4824 enmTxDir = AHCITXDIR_WRITE;
4825 goto sendcmd;
4826 case SCSI_FORMAT_UNIT:
4827 cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
4828 enmTxDir = AHCITXDIR_WRITE;
4829 goto sendcmd;
4830 case SCSI_GET_CONFIGURATION:
4831 cbTransfer = ataBE2H_U16(pbPacket + 7);
4832 enmTxDir = AHCITXDIR_READ;
4833 goto sendcmd;
4834 case SCSI_GET_EVENT_STATUS_NOTIFICATION:
4835 cbTransfer = ataBE2H_U16(pbPacket + 7);
4836 if (ASMAtomicReadU32(&pAhciPort->MediaEventStatus) != ATA_EVENT_STATUS_UNCHANGED)
4837 {
4838 pAhciReq->cbTransfer = RT_MIN(cbTransfer, 8);
4839 atapiDoTransfer(pAhciPort, pAhciReq, pAhciReq->cbTransfer, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
4840 break;
4841 }
4842 enmTxDir = AHCITXDIR_READ;
4843 goto sendcmd;
4844 case SCSI_GET_PERFORMANCE:
4845 cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
4846 enmTxDir = AHCITXDIR_READ;
4847 goto sendcmd;
4848 case SCSI_INQUIRY:
4849 cbTransfer = ataBE2H_U16(pbPacket + 3);
4850 enmTxDir = AHCITXDIR_READ;
4851 goto sendcmd;
4852 case SCSI_LOAD_UNLOAD_MEDIUM:
4853 goto sendcmd;
4854 case SCSI_MECHANISM_STATUS:
4855 cbTransfer = ataBE2H_U16(pbPacket + 8);
4856 enmTxDir = AHCITXDIR_READ;
4857 goto sendcmd;
4858 case SCSI_MODE_SELECT_10:
4859 cbTransfer = ataBE2H_U16(pbPacket + 7);
4860 enmTxDir = AHCITXDIR_WRITE;
4861 goto sendcmd;
4862 case SCSI_MODE_SENSE_10:
4863 cbTransfer = ataBE2H_U16(pbPacket + 7);
4864 enmTxDir = AHCITXDIR_READ;
4865 goto sendcmd;
4866 case SCSI_PAUSE_RESUME:
4867 goto sendcmd;
4868 case SCSI_PLAY_AUDIO_10:
4869 goto sendcmd;
4870 case SCSI_PLAY_AUDIO_12:
4871 goto sendcmd;
4872 case SCSI_PLAY_AUDIO_MSF:
4873 goto sendcmd;
4874 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
4875 /** @todo do not forget to unlock when a VM is shut down */
4876 goto sendcmd;
4877 case SCSI_READ_10:
4878 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4879 cSectors = ataBE2H_U16(pbPacket + 7);
4880 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
4881 pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
4882 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4883 enmTxDir = AHCITXDIR_READ;
4884 goto sendcmd;
4885 case SCSI_READ_12:
4886 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4887 cSectors = ataBE2H_U32(pbPacket + 6);
4888 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
4889 pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
4890 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4891 enmTxDir = AHCITXDIR_READ;
4892 goto sendcmd;
4893 case SCSI_READ_BUFFER:
4894 cbTransfer = ataBE2H_U24(pbPacket + 6);
4895 enmTxDir = AHCITXDIR_READ;
4896 goto sendcmd;
4897 case SCSI_READ_BUFFER_CAPACITY:
4898 cbTransfer = ataBE2H_U16(pbPacket + 7);
4899 enmTxDir = AHCITXDIR_READ;
4900 goto sendcmd;
4901 case SCSI_READ_CAPACITY:
4902 cbTransfer = 8;
4903 enmTxDir = AHCITXDIR_READ;
4904 goto sendcmd;
4905 case SCSI_READ_CD:
4906 case SCSI_READ_CD_MSF:
4907 {
4908 /* Get sector size based on the expected sector type field. */
4909 switch ((pbPacket[1] >> 2) & 0x7)
4910 {
4911 case 0x0: /* All types. */
4912 {
4913 uint32_t iLbaStart;
4914
4915 if (pbPacket[0] == SCSI_READ_CD)
4916 iLbaStart = ataBE2H_U32(&pbPacket[2]);
4917 else
4918 iLbaStart = ataMSF2LBA(&pbPacket[3]);
4919
4920 if (pAhciPort->pTrackList)
4921 pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iLbaStart);
4922 else
4923 pAhciReq->cbATAPISector = 2048; /* Might be incorrect if we couldn't determine the type. */
4924 break;
4925 }
4926 case 0x1: /* CD-DA */
4927 pAhciReq->cbATAPISector = 2352;
4928 break;
4929 case 0x2: /* Mode 1 */
4930 pAhciReq->cbATAPISector = 2048;
4931 break;
4932 case 0x3: /* Mode 2 formless */
4933 pAhciReq->cbATAPISector = 2336;
4934 break;
4935 case 0x4: /* Mode 2 form 1 */
4936 pAhciReq->cbATAPISector = 2048;
4937 break;
4938 case 0x5: /* Mode 2 form 2 */
4939 pAhciReq->cbATAPISector = 2324;
4940 break;
4941 default: /* Reserved */
4942 AssertMsgFailed(("Unknown sector type\n"));
4943 pAhciReq->cbATAPISector = 0; /** @todo we should probably fail the command here already. */
4944 }
4945
4946 if (pbPacket[0] == SCSI_READ_CD)
4947 cbTransfer = ataBE2H_U24(pbPacket + 6) * pAhciReq->cbATAPISector;
4948 else /* SCSI_READ_MSF */
4949 {
4950 cSectors = ataMSF2LBA(pbPacket + 6) - ataMSF2LBA(pbPacket + 3);
4951 if (cSectors > 32)
4952 cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
4953 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4954 }
4955 enmTxDir = AHCITXDIR_READ;
4956 goto sendcmd;
4957 }
4958 case SCSI_READ_DISC_INFORMATION:
4959 cbTransfer = ataBE2H_U16(pbPacket + 7);
4960 enmTxDir = AHCITXDIR_READ;
4961 goto sendcmd;
4962 case SCSI_READ_DVD_STRUCTURE:
4963 cbTransfer = ataBE2H_U16(pbPacket + 8);
4964 enmTxDir = AHCITXDIR_READ;
4965 goto sendcmd;
4966 case SCSI_READ_FORMAT_CAPACITIES:
4967 cbTransfer = ataBE2H_U16(pbPacket + 7);
4968 enmTxDir = AHCITXDIR_READ;
4969 goto sendcmd;
4970 case SCSI_READ_SUBCHANNEL:
4971 cbTransfer = ataBE2H_U16(pbPacket + 7);
4972 enmTxDir = AHCITXDIR_READ;
4973 goto sendcmd;
4974 case SCSI_READ_TOC_PMA_ATIP:
4975 cbTransfer = ataBE2H_U16(pbPacket + 7);
4976 enmTxDir = AHCITXDIR_READ;
4977 goto sendcmd;
4978 case SCSI_READ_TRACK_INFORMATION:
4979 cbTransfer = ataBE2H_U16(pbPacket + 7);
4980 enmTxDir = AHCITXDIR_READ;
4981 goto sendcmd;
4982 case SCSI_REPAIR_TRACK:
4983 goto sendcmd;
4984 case SCSI_REPORT_KEY:
4985 cbTransfer = ataBE2H_U16(pbPacket + 8);
4986 enmTxDir = AHCITXDIR_READ;
4987 goto sendcmd;
4988 case SCSI_REQUEST_SENSE:
4989 cbTransfer = pbPacket[4];
4990 if ((pAhciPort->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE)
4991 {
4992 pAhciReq->cbTransfer = cbTransfer;
4993 pAhciReq->enmTxDir = AHCITXDIR_READ;
4994 atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_REQUEST_SENSE);
4995 break;
4996 }
4997 enmTxDir = AHCITXDIR_READ;
4998 goto sendcmd;
4999 case SCSI_RESERVE_TRACK:
5000 goto sendcmd;
5001 case SCSI_SCAN:
5002 goto sendcmd;
5003 case SCSI_SEEK_10:
5004 goto sendcmd;
5005 case SCSI_SEND_CUE_SHEET:
5006 cbTransfer = ataBE2H_U24(pbPacket + 6);
5007 enmTxDir = AHCITXDIR_WRITE;
5008 goto sendcmd;
5009 case SCSI_SEND_DVD_STRUCTURE:
5010 cbTransfer = ataBE2H_U16(pbPacket + 8);
5011 enmTxDir = AHCITXDIR_WRITE;
5012 goto sendcmd;
5013 case SCSI_SEND_EVENT:
5014 cbTransfer = ataBE2H_U16(pbPacket + 8);
5015 enmTxDir = AHCITXDIR_WRITE;
5016 goto sendcmd;
5017 case SCSI_SEND_KEY:
5018 cbTransfer = ataBE2H_U16(pbPacket + 8);
5019 enmTxDir = AHCITXDIR_WRITE;
5020 goto sendcmd;
5021 case SCSI_SEND_OPC_INFORMATION:
5022 cbTransfer = ataBE2H_U16(pbPacket + 7);
5023 enmTxDir = AHCITXDIR_WRITE;
5024 goto sendcmd;
5025 case SCSI_SET_CD_SPEED:
5026 goto sendcmd;
5027 case SCSI_SET_READ_AHEAD:
5028 goto sendcmd;
5029 case SCSI_SET_STREAMING:
5030 cbTransfer = ataBE2H_U16(pbPacket + 9);
5031 enmTxDir = AHCITXDIR_WRITE;
5032 goto sendcmd;
5033 case SCSI_START_STOP_UNIT:
5034 goto sendcmd;
5035 case SCSI_STOP_PLAY_SCAN:
5036 goto sendcmd;
5037 case SCSI_SYNCHRONIZE_CACHE:
5038 goto sendcmd;
5039 case SCSI_TEST_UNIT_READY:
5040 goto sendcmd;
5041 case SCSI_VERIFY_10:
5042 goto sendcmd;
5043 case SCSI_WRITE_10:
5044 case SCSI_WRITE_AND_VERIFY_10:
5045 iATAPILBA = ataBE2H_U32(pbPacket + 2);
5046 cSectors = ataBE2H_U16(pbPacket + 7);
5047 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
5048 if (pAhciPort->pTrackList)
5049 pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iATAPILBA);
5050 else
5051 pAhciReq->cbATAPISector = 2048;
5052 cbTransfer = cSectors * pAhciReq->cbATAPISector;
5053 enmTxDir = AHCITXDIR_WRITE;
5054 goto sendcmd;
5055 case SCSI_WRITE_12:
5056 iATAPILBA = ataBE2H_U32(pbPacket + 2);
5057 cSectors = ataBE2H_U32(pbPacket + 6);
5058 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
5059 if (pAhciPort->pTrackList)
5060 pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iATAPILBA);
5061 else
5062 pAhciReq->cbATAPISector = 2048;
5063 cbTransfer = cSectors * pAhciReq->cbATAPISector;
5064 enmTxDir = AHCITXDIR_WRITE;
5065 goto sendcmd;
5066 case SCSI_WRITE_BUFFER:
5067 switch (pbPacket[1] & 0x1f)
5068 {
5069 case 0x04: /* download microcode */
5070 case 0x05: /* download microcode and save */
5071 case 0x06: /* download microcode with offsets */
5072 case 0x07: /* download microcode with offsets and save */
5073 case 0x0e: /* download microcode with offsets and defer activation */
5074 case 0x0f: /* activate deferred microcode */
5075 LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command attempted to update firmware, blocked\n", pAhciPort->iLUN));
5076 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
5077 break;
5078 default:
5079 cbTransfer = ataBE2H_U16(pbPacket + 6);
5080 enmTxDir = AHCITXDIR_WRITE;
5081 goto sendcmd;
5082 }
5083 break;
5084 case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */
5085 cbTransfer = ataBE2H_U32(pbPacket + 6);
5086 enmTxDir = AHCITXDIR_READ;
5087 goto sendcmd;
5088 case SCSI_REZERO_UNIT:
5089 /* Obsolete command used by cdrecord. What else would one expect?
5090 * This command is not sent to the drive, it is handled internally,
5091 * as the Linux kernel doesn't like it (message "scsi: unknown
5092 * opcode 0x01" in syslog) and replies with a sense code of 0,
5093 * which sends cdrecord to an endless loop. */
5094 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
5095 break;
5096 default:
5097 LogRel(("AHCI: LUN#%d: passthrough unimplemented for command %#x\n", pAhciPort->iLUN, pbPacket[0]));
5098 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
5099 break;
5100 sendcmd:
5101 /* Send a command to the drive, passing data in/out as required. */
5102 Log2(("ATAPI PT: max size %d\n", cbTransfer));
5103 if (cbTransfer == 0)
5104 enmTxDir = AHCITXDIR_NONE;
5105 pAhciReq->enmTxDir = enmTxDir;
5106 pAhciReq->cbTransfer = cbTransfer;
5107 atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_PASSTHROUGH);
5108 }
5109
5110 return AHCITXDIR_NONE;
5111}
5112
5113static AHCITXDIR atapiParseCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5114{
5115 AHCITXDIR enmTxDir = AHCITXDIR_NONE;
5116 const uint8_t *pbPacket;
5117
5118 pbPacket = pAhciReq->aATAPICmd;
5119 Log(("%s: LUN#%d CMD=%#04x \"%s\"\n", __FUNCTION__, pAhciPort->iLUN, pbPacket[0], SCSICmdText(pbPacket[0])));
5120 Log2(("%s: limit=%#x packet: %.*Rhxs\n", __FUNCTION__, pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8), ATAPI_PACKET_SIZE, pbPacket));
5121
5122 if (pAhciPort->fATAPIPassthrough)
5123 enmTxDir = atapiParseCmdPassthrough(pAhciPort, pAhciReq);
5124 else
5125 enmTxDir = atapiParseCmdVirtualATAPI(pAhciPort, pAhciReq);
5126
5127 return enmTxDir;
5128}
5129
5130/**
5131 * Reset all values after a reset of the attached storage device.
5132 *
5133 * @returns nothing
5134 * @param pAhciPort The port the device is attached to.
5135 * @param pAhciReq The state to get the tag number from.
5136 */
5137static void ahciFinishStorageDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5138{
5139 int rc;
5140
5141 /* Send a status good D2H FIS. */
5142 ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_UNCHANGED);
5143 pAhciPort->fResetDevice = false;
5144 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5145 ahciPostFirstD2HFisIntoMemory(pAhciPort);
5146
5147 /* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
5148 if (pAhciPort->fATAPI)
5149 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
5150 else
5151 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
5152 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
5153
5154 rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
5155 AssertRC(rc);
5156}
5157
5158/**
5159 * Initiates a device reset caused by ATA_DEVICE_RESET (ATAPI only).
5160 *
5161 * @returns nothing.
5162 * @param pAhciPort The device to reset.
5163 * @param pAhciReq The task state.
5164 */
5165static void ahciDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5166{
5167 ASMAtomicWriteBool(&pAhciPort->fResetDevice, true);
5168
5169 /*
5170 * Because this ATAPI only and ATAPI can't have
5171 * more than one command active at a time the task counter should be 0
5172 * and it is possible to finish the reset now.
5173 */
5174 Assert(ASMAtomicReadU32(&pAhciPort->cTasksActive) == 0);
5175 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
5176}
5177
5178/**
5179 * Create a PIO setup FIS and post it into the memory area of the guest.
5180 *
5181 * @returns nothing.
5182 * @param pAhciPort The port of the SATA controller.
5183 * @param pAhciReq The state of the task.
5184 * @param pCmdFis Pointer to the command FIS from the guest.
5185 * @param fInterrupt If an interrupt should be send to the guest.
5186 */
5187static void ahciSendPioSetupFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis,
5188 bool fInterrupt)
5189{
5190 uint8_t abPioSetupFis[20];
5191 bool fAssertIntr = false;
5192 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5193
5194 ahciLog(("%s: building PIO setup Fis\n", __FUNCTION__));
5195
5196 AssertMsg( pAhciReq->cbTransfer > 0
5197 && pAhciReq->cbTransfer <= 65534,
5198 ("Can't send PIO setup FIS for requests with 0 bytes to transfer or greater than 65534\n"));
5199
5200 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5201 {
5202 memset(&abPioSetupFis[0], 0, sizeof(abPioSetupFis));
5203 abPioSetupFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_PIOSETUP;
5204 abPioSetupFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
5205 if (pAhciReq->enmTxDir == AHCITXDIR_READ)
5206 abPioSetupFis[AHCI_CMDFIS_BITS] |= AHCI_CMDFIS_D;
5207 abPioSetupFis[AHCI_CMDFIS_STS] = pAhciReq->uATARegStatus;
5208 abPioSetupFis[AHCI_CMDFIS_ERR] = pAhciReq->uATARegError;
5209 abPioSetupFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
5210 abPioSetupFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
5211 abPioSetupFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
5212 abPioSetupFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
5213 abPioSetupFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
5214 abPioSetupFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
5215 abPioSetupFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
5216 abPioSetupFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
5217 abPioSetupFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
5218
5219 /* Set transfer count. */
5220 abPioSetupFis[16] = (pAhciReq->cbTransfer >> 8) & 0xff;
5221 abPioSetupFis[17] = pAhciReq->cbTransfer & 0xff;
5222
5223 /* Update registers. */
5224 pAhciPort->regTFD = (pAhciReq->uATARegError << 8) | pAhciReq->uATARegStatus;
5225
5226 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_PIOSETUP, abPioSetupFis);
5227
5228 if (fInterrupt)
5229 {
5230 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PSS);
5231 /* Check if we should assert an interrupt */
5232 if (pAhciPort->regIE & AHCI_PORT_IE_PSE)
5233 fAssertIntr = true;
5234 }
5235
5236 if (fAssertIntr)
5237 {
5238 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5239 AssertRC(rc);
5240 }
5241 }
5242}
5243
5244/**
5245 * Build a D2H FIS and post into the memory area of the guest.
5246 *
5247 * @returns Nothing
5248 * @param pAhciPort The port of the SATA controller.
5249 * @param pAhciReq The state of the task.
5250 * @param pCmdFis Pointer to the command FIS from the guest.
5251 * @param fInterrupt If an interrupt should be send to the guest.
5252 */
5253static void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis, bool fInterrupt)
5254{
5255 uint8_t d2hFis[20];
5256 bool fAssertIntr = false;
5257 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5258
5259 ahciLog(("%s: building D2H Fis\n", __FUNCTION__));
5260
5261 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5262 {
5263 memset(&d2hFis[0], 0, sizeof(d2hFis));
5264 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
5265 d2hFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
5266 d2hFis[AHCI_CMDFIS_STS] = pAhciReq->uATARegStatus;
5267 d2hFis[AHCI_CMDFIS_ERR] = pAhciReq->uATARegError;
5268 d2hFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
5269 d2hFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
5270 d2hFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
5271 d2hFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
5272 d2hFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
5273 d2hFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
5274 d2hFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
5275 d2hFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
5276 d2hFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
5277
5278 /* Update registers. */
5279 pAhciPort->regTFD = (pAhciReq->uATARegError << 8) | pAhciReq->uATARegStatus;
5280
5281 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
5282
5283 if (pAhciReq->uATARegStatus & ATA_STAT_ERR)
5284 {
5285 /* Error bit is set. */
5286 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
5287 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
5288 fAssertIntr = true;
5289 /*
5290 * Don't mark the command slot as completed because the guest
5291 * needs it to identify the failed command.
5292 */
5293 }
5294 else if (fInterrupt)
5295 {
5296 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
5297 /* Check if we should assert an interrupt */
5298 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
5299 fAssertIntr = true;
5300
5301 /* Mark command as completed. */
5302 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
5303 }
5304
5305 if (fAssertIntr)
5306 {
5307 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5308 AssertRC(rc);
5309 }
5310 }
5311}
5312
5313/**
5314 * Build a SDB Fis and post it into the memory area of the guest.
5315 *
5316 * @returns Nothing
5317 * @param pAhciPort The port for which the SDB Fis is send.
5318 * @param uFinishedTasks Bitmask of finished tasks.
5319 * @param fInterrupt If an interrupt should be asserted.
5320 */
5321static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, bool fInterrupt)
5322{
5323 uint32_t sdbFis[2];
5324 bool fAssertIntr = false;
5325 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5326 PAHCIREQ pTaskErr = ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ);
5327
5328 ahciLog(("%s: Building SDB FIS\n", __FUNCTION__));
5329
5330 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5331 {
5332 memset(&sdbFis[0], 0, sizeof(sdbFis));
5333 sdbFis[0] = AHCI_CMDFIS_TYPE_SETDEVBITS;
5334 sdbFis[0] |= (fInterrupt ? (1 << 14) : 0);
5335 if (RT_UNLIKELY(pTaskErr))
5336 {
5337 sdbFis[0] = pTaskErr->uATARegError;
5338 sdbFis[0] |= (pTaskErr->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
5339
5340 /* Update registers. */
5341 pAhciPort->regTFD = (pTaskErr->uATARegError << 8) | pTaskErr->uATARegStatus;
5342 }
5343 else
5344 {
5345 sdbFis[0] = 0;
5346 sdbFis[0] |= (ATA_STAT_READY | ATA_STAT_SEEK) << 16;
5347 pAhciPort->regTFD = ATA_STAT_READY | ATA_STAT_SEEK;
5348 }
5349
5350 sdbFis[1] = pAhciPort->u32QueuedTasksFinished | uFinishedTasks;
5351
5352 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
5353
5354 if (RT_UNLIKELY(pTaskErr))
5355 {
5356 /* Error bit is set. */
5357 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
5358 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
5359 fAssertIntr = true;
5360 }
5361
5362 if (fInterrupt)
5363 {
5364 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_SDBS);
5365 /* Check if we should assert an interrupt */
5366 if (pAhciPort->regIE & AHCI_PORT_IE_SDBE)
5367 fAssertIntr = true;
5368 }
5369
5370 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, uFinishedTasks);
5371
5372 if (fAssertIntr)
5373 {
5374 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5375 AssertRC(rc);
5376 }
5377 }
5378}
5379
5380static uint32_t ahciGetNSectors(uint8_t *pCmdFis, bool fLBA48)
5381{
5382 /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
5383 if (fLBA48)
5384 {
5385 if (!pCmdFis[AHCI_CMDFIS_SECTC] && !pCmdFis[AHCI_CMDFIS_SECTCEXP])
5386 return 65536;
5387 else
5388 return pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8 | pCmdFis[AHCI_CMDFIS_SECTC];
5389 }
5390 else
5391 {
5392 if (!pCmdFis[AHCI_CMDFIS_SECTC])
5393 return 256;
5394 else
5395 return pCmdFis[AHCI_CMDFIS_SECTC];
5396 }
5397}
5398
5399static uint64_t ahciGetSector(PAHCIPort pAhciPort, uint8_t *pCmdFis, bool fLBA48)
5400{
5401 uint64_t iLBA;
5402 if (pCmdFis[AHCI_CMDFIS_HEAD] & 0x40)
5403 {
5404 /* any LBA variant */
5405 if (fLBA48)
5406 {
5407 /* LBA48 */
5408 iLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
5409 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
5410 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
5411 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5412 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
5413 pCmdFis[AHCI_CMDFIS_SECTN];
5414 }
5415 else
5416 {
5417 /* LBA */
5418 iLBA = ((pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) << 24) | (pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5419 (pCmdFis[AHCI_CMDFIS_CYLL] << 8) | pCmdFis[AHCI_CMDFIS_SECTN];
5420 }
5421 }
5422 else
5423 {
5424 /* CHS */
5425 iLBA = ((pCmdFis[AHCI_CMDFIS_CYLH] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors +
5426 (pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) * pAhciPort->PCHSGeometry.cSectors +
5427 (pCmdFis[AHCI_CMDFIS_SECTN] - 1);
5428 }
5429 return iLBA;
5430}
5431
5432static uint64_t ahciGetSectorQueued(uint8_t *pCmdFis)
5433{
5434 uint64_t uLBA;
5435
5436 uLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
5437 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
5438 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
5439 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5440 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
5441 pCmdFis[AHCI_CMDFIS_SECTN];
5442
5443 return uLBA;
5444}
5445
5446DECLINLINE(uint32_t) ahciGetNSectorsQueued(uint8_t *pCmdFis)
5447{
5448 if (!pCmdFis[AHCI_CMDFIS_FETEXP] && !pCmdFis[AHCI_CMDFIS_FET])
5449 return 65536;
5450 else
5451 return pCmdFis[AHCI_CMDFIS_FETEXP] << 8 | pCmdFis[AHCI_CMDFIS_FET];
5452}
5453
5454DECLINLINE(uint8_t) ahciGetTagQueued(uint8_t *pCmdFis)
5455{
5456 return pCmdFis[AHCI_CMDFIS_SECTC] >> 3;
5457}
5458
5459/**
5460 * Allocates memory for the given request using already allocated memory if possible.
5461 *
5462 * @returns Pointer to the memory or NULL on failure
5463 * @param pAhciPort The AHCI port.
5464 * @param pAhciReq The request to allocate memory for.
5465 * @param cb The amount of memory to allocate.
5466 */
5467static void *ahciReqMemAlloc(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cb)
5468{
5469 if (pAhciReq->cbAlloc > cb)
5470 {
5471 pAhciReq->cAllocTooMuch++;
5472 }
5473 else if (pAhciReq->cbAlloc < cb)
5474 {
5475 if (pAhciReq->cbAlloc)
5476 pAhciPort->pDrvMedia->pfnIoBufFree(pAhciPort->pDrvMedia, pAhciReq->pvAlloc, pAhciReq->cbAlloc);
5477
5478 pAhciReq->pvAlloc = NULL;
5479 pAhciReq->cbAlloc = RT_ALIGN_Z(cb, _4K);
5480 int rc = pAhciPort->pDrvMedia->pfnIoBufAlloc(pAhciPort->pDrvMedia, pAhciReq->cbAlloc, &pAhciReq->pvAlloc);
5481 if (RT_FAILURE(rc))
5482 pAhciReq->pvAlloc = NULL;
5483
5484 pAhciReq->cAllocTooMuch = 0;
5485 if (RT_UNLIKELY(!pAhciReq->pvAlloc))
5486 pAhciReq->cbAlloc = 0;
5487 }
5488
5489 return pAhciReq->pvAlloc;
5490}
5491
5492/**
5493 * Frees memory allocated for the given request.
5494 *
5495 * @returns nothing.
5496 * @param pAhciPort The AHCI port.
5497 * @param pAhciReq The request.
5498 * @param fForceFree Flag whether to force a free
5499 */
5500static void ahciReqMemFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, bool fForceFree)
5501{
5502 if ( pAhciReq->cAllocTooMuch >= AHCI_MAX_ALLOC_TOO_MUCH
5503 || fForceFree)
5504 {
5505 if (pAhciReq->cbAlloc)
5506 {
5507 pAhciPort->pDrvMedia->pfnIoBufFree(pAhciPort->pDrvMedia, pAhciReq->pvAlloc, pAhciReq->cbAlloc);
5508 pAhciReq->cbAlloc = 0;
5509 pAhciReq->cAllocTooMuch = 0;
5510 }
5511 }
5512}
5513
5514/**
5515 * Copies a data buffer into the S/G buffer set up by the guest.
5516 *
5517 * @returns Amount of bytes copied to the PRDTL.
5518 * @param pDevIns Pointer to the device instance data.
5519 * @param pAhciReq AHCI request structure.
5520 * @param pvBuf The buffer to copy from.
5521 * @param cbBuf The size of the buffer.
5522 */
5523static size_t ahciCopyToPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
5524 void *pvBuf, size_t cbBuf)
5525{
5526 uint8_t *pbBuf = (uint8_t *)pvBuf;
5527 SGLEntry aPrdtlEntries[32];
5528 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5529 unsigned cPrdtlEntries = pAhciReq->cPrdtlEntries;
5530 size_t cbCopied = 0;
5531
5532 AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
5533
5534 do
5535 {
5536 uint32_t cPrdtlEntriesRead = cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries)
5537 ? cPrdtlEntries
5538 : RT_ELEMENTS(aPrdtlEntries);
5539
5540 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5541
5542 for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbBuf; i++)
5543 {
5544 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5545 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5546
5547 cbThisCopy = RT_MIN(cbThisCopy, cbBuf);
5548
5549 /* Copy into SG entry. */
5550 PDMDevHlpPCIPhysWrite(pDevIns, GCPhysAddrDataBase, pbBuf, cbThisCopy);
5551
5552 pbBuf += cbThisCopy;
5553 cbBuf -= cbThisCopy;
5554 cbCopied += cbThisCopy;
5555 }
5556
5557 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5558 cPrdtlEntries -= cPrdtlEntriesRead;
5559 } while (cPrdtlEntries && cbBuf);
5560
5561 if (cbCopied < cbBuf)
5562 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5563
5564 return cbCopied;
5565}
5566
5567/**
5568 * Copies the S/G buffer into a data buffer.
5569 *
5570 * @returns Amount of bytes copied to the PRDTL.
5571 * @param pDevIns Pointer to the device instance data.
5572 * @param pAhciReq AHCI request structure.
5573 * @param pvBuf The buffer to copy to.
5574 * @param cbBuf The size of the buffer.
5575 */
5576static size_t ahciCopyFromPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
5577 void *pvBuf, size_t cbBuf)
5578{
5579 uint8_t *pbBuf = (uint8_t *)pvBuf;
5580 SGLEntry aPrdtlEntries[32];
5581 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5582 unsigned cPrdtlEntries = pAhciReq->cPrdtlEntries;
5583 size_t cbCopied = 0;
5584
5585 AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
5586
5587 do
5588 {
5589 uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
5590 ? cPrdtlEntries
5591 : RT_ELEMENTS(aPrdtlEntries);
5592
5593 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5594
5595 for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbBuf; i++)
5596 {
5597 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5598 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5599
5600 cbThisCopy = RT_MIN(cbThisCopy, cbBuf);
5601
5602 /* Copy into buffer. */
5603 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, pbBuf, cbThisCopy);
5604
5605 pbBuf += cbThisCopy;
5606 cbBuf -= cbThisCopy;
5607 cbCopied += cbThisCopy;
5608 }
5609
5610 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5611 cPrdtlEntries -= cPrdtlEntriesRead;
5612 } while (cPrdtlEntries && cbBuf);
5613
5614 if (cbCopied < cbBuf)
5615 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5616
5617 return cbCopied;
5618}
5619
5620/**
5621 * Allocate I/O memory and copies the guest buffer for writes.
5622 *
5623 * @returns VBox status code.
5624 * @param pAhciPort The AHCI port.
5625 * @param pAhciReq The request state.
5626 * @param cbTransfer Amount of bytes to allocate.
5627 */
5628static int ahciIoBufAllocate(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cbTransfer)
5629{
5630 AssertMsg( pAhciReq->enmTxDir == AHCITXDIR_READ
5631 || pAhciReq->enmTxDir == AHCITXDIR_WRITE,
5632 ("Allocating I/O memory for a non I/O request is not allowed\n"));
5633
5634 pAhciReq->u.Io.DataSeg.pvSeg = ahciReqMemAlloc(pAhciPort, pAhciReq, cbTransfer);
5635 if (!pAhciReq->u.Io.DataSeg.pvSeg)
5636 return VERR_NO_MEMORY;
5637
5638 pAhciReq->u.Io.DataSeg.cbSeg = cbTransfer;
5639 if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
5640 {
5641 ahciCopyFromPrdtl(pAhciPort->pDevInsR3, pAhciReq,
5642 pAhciReq->u.Io.DataSeg.pvSeg,
5643 cbTransfer);
5644 }
5645 return VINF_SUCCESS;
5646}
5647
5648/**
5649 * Frees the I/O memory of the given request and updates the guest buffer if necessary.
5650 *
5651 * @returns nothing.
5652 * @param pAhciPort The AHCI port.
5653 * @param pAhciReq The request state.
5654 * @param fCopyToGuest Flag whether to update the guest buffer if necessary.
5655 * Nothing is copied if false even if the request was a read.
5656 */
5657static void ahciIoBufFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq,
5658 bool fCopyToGuest)
5659{
5660 AssertMsg( pAhciReq->enmTxDir == AHCITXDIR_READ
5661 || pAhciReq->enmTxDir == AHCITXDIR_WRITE,
5662 ("Freeing I/O memory for a non I/O request is not allowed\n"));
5663
5664 if ( pAhciReq->enmTxDir == AHCITXDIR_READ
5665 && fCopyToGuest)
5666 {
5667 if (pAhciReq->u.Io.pfnPostProcess)
5668 {
5669 void *pv = NULL;
5670 size_t cb = 0;
5671 int rc = pAhciReq->u.Io.pfnPostProcess(pAhciReq, &pv, &cb);
5672
5673 if (RT_SUCCESS(rc))
5674 {
5675 pAhciReq->cbTransfer = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, pv, cb);
5676 RTMemFree(pv);
5677 }
5678 }
5679 else
5680 ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
5681 pAhciReq->u.Io.DataSeg.pvSeg,
5682 pAhciReq->u.Io.DataSeg.cbSeg);
5683 }
5684
5685 ahciReqMemFree(pAhciPort, pAhciReq, false /* fForceFree */);
5686 pAhciReq->u.Io.DataSeg.pvSeg = NULL;
5687 pAhciReq->u.Io.DataSeg.cbSeg = 0;
5688}
5689
5690
5691/**
5692 * Free all cached tasks on the given port.
5693 *
5694 * @returns nothing.
5695 * @param pAhciPort The AHCI port.
5696 */
5697static void ahciR3PortCachedReqsFree(PAHCIPort pAhciPort)
5698{
5699 if (pAhciPort->pListReqsFree)
5700 {
5701 PAHCIREQ pReq = NULL;
5702 PAHCIREQ pReqNext = NULL;
5703
5704 RTCritSectEnter(&pAhciPort->CritSectReqsFree);
5705 RTListForEachSafe(pAhciPort->pListReqsFree, pReq, pReqNext, AHCIREQ, NodeList)
5706 {
5707 RTListNodeRemove(&pReq->NodeList);
5708 ahciReqMemFree(pAhciPort, pReq, true /* fForceFree */);
5709 RTMemFree(pReq);
5710 }
5711 RTCritSectLeave(&pAhciPort->CritSectReqsFree);
5712 }
5713}
5714
5715/**
5716 * Cancels all active tasks on the port.
5717 *
5718 * @returns Whether all active tasks were canceled.
5719 * @param pAhciPort The ahci port.
5720 * @param pAhciReqExcept The given request is excepted from the cancelling
5721 * (used for error page reading).
5722 */
5723static bool ahciCancelActiveTasks(PAHCIPort pAhciPort, PAHCIREQ pAhciReqExcept)
5724{
5725 for (unsigned i = 0; i < RT_ELEMENTS(pAhciPort->aActiveTasks); i++)
5726 {
5727 PAHCIREQ pAhciReq = ASMAtomicReadPtrT(&pAhciPort->aActiveTasks[i], PAHCIREQ);
5728 if (pAhciReq != pAhciReqExcept)
5729 {
5730 pAhciReq = (PAHCIREQ)ASMAtomicXchgPtr((void * volatile *)&pAhciPort->aActiveTasks[i], NULL);
5731
5732 if (VALID_PTR(pAhciReq))
5733 {
5734 bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_CANCELED, AHCITXSTATE_ACTIVE);
5735 if (fXchg)
5736 {
5737 /* Task is active and was canceled. */
5738 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0,
5739 ("Task was canceled but none is active\n"));
5740 ASMAtomicDecU32(&pAhciPort->cTasksActive);
5741
5742 /*
5743 * Clear the pointer in the cached array. The controller will allocate a
5744 * a new task structure for this tag.
5745 */
5746 ASMAtomicWriteNullPtr(&pAhciPort->aActiveTasks[i]);
5747 LogRel(("AHCI#%uP%u: Cancelled task %u\n", pAhciPort->CTX_SUFF(pDevIns)->iInstance,
5748 pAhciPort->iLUN, pAhciReq->uTag));
5749 }
5750 else
5751 AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_FREE,
5752 ("Invalid task state, must be free!\n"));
5753 }
5754 }
5755 }
5756
5757 return true; /* always true for now because tasks don't use guest memory as the buffer which makes canceling a task impossible. */
5758}
5759
5760/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
5761
5762/** Makes a PAHCIPort out of a PPDMIMEDIAASYNCPORT. */
5763#define PDMIMEDIAASYNCPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) )
5764
5765static void ahciWarningDiskFull(PPDMDEVINS pDevIns)
5766{
5767 int rc;
5768 LogRel(("AHCI: Host disk full\n"));
5769 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_DISKFULL",
5770 N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
5771 AssertRC(rc);
5772}
5773
5774static void ahciWarningFileTooBig(PPDMDEVINS pDevIns)
5775{
5776 int rc;
5777 LogRel(("AHCI: File too big\n"));
5778 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_FILETOOBIG",
5779 N_("Host system reported that the file size limit of the host file system has been exceeded. VM execution is suspended. You need to move your virtual hard disk to a filesystem which allows bigger files"));
5780 AssertRC(rc);
5781}
5782
5783static void ahciWarningISCSI(PPDMDEVINS pDevIns)
5784{
5785 int rc;
5786 LogRel(("AHCI: iSCSI target unavailable\n"));
5787 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_ISCSIDOWN",
5788 N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
5789 AssertRC(rc);
5790}
5791
5792bool ahciIsRedoSetWarning(PAHCIPort pAhciPort, int rc)
5793{
5794 if (rc == VERR_DISK_FULL)
5795 {
5796 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5797 ahciWarningDiskFull(pAhciPort->CTX_SUFF(pDevIns));
5798 return true;
5799 }
5800 if (rc == VERR_FILE_TOO_BIG)
5801 {
5802 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5803 ahciWarningFileTooBig(pAhciPort->CTX_SUFF(pDevIns));
5804 return true;
5805 }
5806 if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
5807 {
5808 /* iSCSI connection abort (first error) or failure to reestablish
5809 * connection (second error). Pause VM. On resume we'll retry. */
5810 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5811 ahciWarningISCSI(pAhciPort->CTX_SUFF(pDevIns));
5812 return true;
5813 }
5814 if (rc == VERR_VD_DEK_MISSING)
5815 {
5816 /* Error message already set. */
5817 ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false);
5818 return true;
5819 }
5820
5821 return false;
5822}
5823
5824/**
5825 * Creates the array of ranges to trim.
5826 *
5827 * @returns VBox status code.
5828 * @param pAhciPort AHCI port state.
5829 * @param pAhciReq The request handling the TRIM request.
5830 */
5831static int ahciTrimRangesCreate(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5832{
5833 SGLEntry aPrdtlEntries[32];
5834 uint64_t aRanges[64];
5835 unsigned cRangesMax;
5836 unsigned cRanges = 0;
5837 uint32_t cPrdtlEntries = pAhciReq->cPrdtlEntries;
5838 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5839 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
5840 int rc = VINF_SUCCESS;
5841
5842 LogFlowFunc(("pAhciPort=%#p pAhciReq=%#p\n", pAhciPort, pAhciReq));
5843
5844 AssertMsgReturn(pAhciReq->enmTxDir == AHCITXDIR_TRIM, ("This is not a trim request\n"), VERR_INVALID_PARAMETER);
5845
5846 /* The data buffer contains LBA range entries. Each range is 8 bytes big. */
5847 if (!pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] && !pAhciReq->cmdFis[AHCI_CMDFIS_SECTCEXP])
5848 cRangesMax = 65536 * 512 / 8;
5849 else
5850 cRangesMax = pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] * 512 / 8;
5851
5852 if (!cPrdtlEntries)
5853 {
5854 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5855 return VINF_SUCCESS;
5856 }
5857
5858 do
5859 {
5860 uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
5861 ? cPrdtlEntries
5862 : RT_ELEMENTS(aPrdtlEntries);
5863
5864 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5865
5866 for (uint32_t i = 0; i < cPrdtlEntriesRead; i++)
5867 {
5868 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5869 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5870
5871 cbThisCopy = RT_MIN(cbThisCopy, sizeof(aRanges));
5872
5873 /* Copy into buffer. */
5874 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
5875
5876 for (unsigned idxRange = 0; idxRange < RT_ELEMENTS(aRanges); idxRange++)
5877 {
5878 aRanges[idxRange] = RT_H2LE_U64(aRanges[idxRange]);
5879 if (AHCI_RANGE_LENGTH_GET(aRanges[idxRange]) != 0)
5880 cRanges++;
5881 else
5882 break;
5883 }
5884 }
5885
5886 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5887 cPrdtlEntries -= cPrdtlEntriesRead;
5888 } while (cPrdtlEntries);
5889
5890 if (RT_UNLIKELY(!cRanges))
5891 {
5892 return VERR_BUFFER_OVERFLOW;
5893 }
5894
5895 pAhciReq->u.Trim.cRanges = cRanges;
5896 pAhciReq->u.Trim.paRanges = (PRTRANGE)RTMemAllocZ(sizeof(RTRANGE) * cRanges);
5897 if (pAhciReq->u.Trim.paRanges)
5898 {
5899 uint32_t idxRange = 0;
5900
5901 cPrdtlEntries = pAhciReq->cPrdtlEntries;
5902 GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5903
5904 /* Convert the ranges from the guest to our format. */
5905 do
5906 {
5907 uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
5908 ? cPrdtlEntries
5909 : RT_ELEMENTS(aPrdtlEntries);
5910
5911 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5912
5913 for (uint32_t i = 0; i < cPrdtlEntriesRead; i++)
5914 {
5915 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5916 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5917
5918 cbThisCopy = RT_MIN(cbThisCopy, sizeof(aRanges));
5919
5920 /* Copy into buffer. */
5921 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
5922
5923 for (unsigned idxRangeSrc = 0; idxRangeSrc < RT_ELEMENTS(aRanges); idxRangeSrc++)
5924 {
5925 aRanges[idxRangeSrc] = RT_H2LE_U64(aRanges[idxRangeSrc]);
5926 if (AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) != 0)
5927 {
5928 pAhciReq->u.Trim.paRanges[idxRange].offStart = (aRanges[idxRangeSrc] & AHCI_RANGE_LBA_MASK) * pAhciPort->cbSector;
5929 pAhciReq->u.Trim.paRanges[idxRange].cbRange = AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) * pAhciPort->cbSector;
5930 idxRange++;
5931 }
5932 else
5933 break;
5934 }
5935 }
5936
5937 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5938 cPrdtlEntries -= cPrdtlEntriesRead;
5939 } while (idxRange < cRanges);
5940 }
5941 else
5942 rc = VERR_NO_MEMORY;
5943
5944 LogFlowFunc(("returns rc=%Rrc\n", rc));
5945 return rc;
5946}
5947
5948/**
5949 * Destroy the trim range list.
5950 *
5951 * @returns nothing.
5952 * @param pAhciReq The task state.
5953 */
5954static void ahciTrimRangesDestroy(PAHCIREQ pAhciReq)
5955{
5956 AssertReturnVoid(pAhciReq->enmTxDir == AHCITXDIR_TRIM);
5957 RTMemFree(pAhciReq->u.Trim.paRanges);
5958}
5959
5960/**
5961 * Allocates a new AHCI request.
5962 *
5963 * @returns A new AHCI request structure or NULL if out of memory.
5964 * @param pAhciPort The AHCI port.
5965 */
5966static PAHCIREQ ahciR3ReqAlloc(PAHCIPort pAhciPort)
5967{
5968 PAHCIREQ pAhciReq = NULL;
5969
5970 /* Check the global free list first. */
5971 RTCritSectEnter(&pAhciPort->CritSectReqsFree);
5972 pAhciReq = RTListGetFirst(pAhciPort->pListReqsFree, AHCIREQ, NodeList);
5973 if (pAhciReq)
5974 {
5975 AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_FREE, ("Should be free!\n"));
5976 RTListNodeRemove(&pAhciReq->NodeList);
5977 }
5978 RTCritSectLeave(&pAhciPort->CritSectReqsFree);
5979
5980 if (!pAhciReq)
5981 pAhciReq = (PAHCIREQ)RTMemAllocZ(sizeof(AHCIREQ));
5982
5983 pAhciReq->enmTxState = AHCITXSTATE_ACTIVE;
5984 return pAhciReq;
5985}
5986
5987/**
5988 * Frees a given AHCI request structure.
5989 *
5990 * @returns nothing.
5991 * @param pAhciPort The AHCI port.
5992 */
5993static void ahciR3ReqFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5994{
5995 AssertMsg(pAhciReq->enmTxState != AHCITXSTATE_FREE, ("Double free!\n"));
5996 pAhciReq->enmTxState = AHCITXSTATE_FREE;
5997
5998 RTCritSectEnter(&pAhciPort->CritSectReqsFree);
5999 RTListAppend(pAhciPort->pListReqsFree, &pAhciReq->NodeList);
6000 RTCritSectLeave(&pAhciPort->CritSectReqsFree);
6001}
6002
6003/**
6004 * Complete a data transfer task by freeing all occupied resources
6005 * and notifying the guest.
6006 *
6007 * @returns Flag whether the given request was canceled inbetween;
6008 *
6009 * @param pAhciPort Pointer to the port where to request completed.
6010 * @param pAhciReq Pointer to the task which finished.
6011 * @param rcReq IPRT status code of the completed request.
6012 */
6013static bool ahciTransferComplete(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, int rcReq)
6014{
6015 bool fRedo = false;
6016 bool fCanceled = false;
6017 uint64_t tsNow = RTTimeMilliTS();
6018 AHCITXSTATE enmTxState = AHCITXSTATE_INVALID;
6019
6020 LogFlowFunc(("pAhciPort=%p pAhciReq=%p rcReq=%d\n",
6021 pAhciPort, pAhciReq, rcReq));
6022
6023 enmTxState = (AHCITXSTATE)ASMAtomicReadU32((volatile uint32_t *)&pAhciReq->enmTxState);
6024 VBOXDD_AHCI_REQ_COMPLETED(pAhciReq, rcReq, enmTxState, pAhciReq->uOffset, pAhciReq->cbTransfer);
6025 VBOXDD_AHCI_REQ_COMPLETED_TIMESTAMP(pAhciReq, tsNow);
6026
6027 /*
6028 * Clear the request structure from the active request list first so it doesn't get cancelled
6029 * while we complete it. If the request is not in the active list anymore it was already canceled
6030 * and we have to make sure to not copy anything to guest memory because the guest might use it
6031 * for other things already.
6032 */
6033 bool fPortReset = ASMAtomicReadBool(&pAhciPort->fPortReset);
6034 bool fXchg = ASMAtomicCmpXchgPtr(&pAhciPort->aActiveTasks[pAhciReq->uTag], NULL, pAhciReq);
6035 bool fReqErrSaved = false;
6036
6037 /*
6038 * Leave a release log entry if the request was active for more than 25 seconds
6039 * (30 seconds is the timeout of the guest).
6040 */
6041 if (tsNow - pAhciReq->tsStart >= 25 * 1000)
6042 {
6043 const char *pcszReq = NULL;
6044
6045 switch (pAhciReq->enmTxDir)
6046 {
6047 case AHCITXDIR_READ:
6048 pcszReq = "Read";
6049 break;
6050 case AHCITXDIR_WRITE:
6051 pcszReq = "Write";
6052 break;
6053 case AHCITXDIR_FLUSH:
6054 pcszReq = "Flush";
6055 break;
6056 case AHCITXDIR_TRIM:
6057 pcszReq = "Trim";
6058 break;
6059 default:
6060 pcszReq = "<Invalid>";
6061 }
6062
6063 LogRel(("AHCI#%uP%u: %s request was active for %llu seconds\n",
6064 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, pcszReq, (tsNow - pAhciReq->tsStart) / 1000));
6065 }
6066
6067 if (fXchg && !fPortReset)
6068 {
6069 if (pAhciReq->enmTxDir == AHCITXDIR_READ)
6070 {
6071 ahciIoBufFree(pAhciPort, pAhciReq, true /* fCopyToGuest */);
6072 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciReq->cbTransfer);
6073 pAhciPort->Led.Actual.s.fReading = 0;
6074 }
6075 else if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
6076 {
6077 ahciIoBufFree(pAhciPort, pAhciReq, false /* fCopyToGuest */);
6078 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciReq->cbTransfer);
6079 pAhciPort->Led.Actual.s.fWriting = 0;
6080 }
6081 else if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
6082 {
6083 ahciTrimRangesDestroy(pAhciReq);
6084 pAhciPort->Led.Actual.s.fWriting = 0;
6085 }
6086
6087 if (RT_FAILURE(rcReq))
6088 {
6089 /* Log the error. */
6090 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
6091 {
6092 if (pAhciReq->enmTxDir == AHCITXDIR_FLUSH)
6093 LogRel(("AHCI#%uP%u: Flush returned rc=%Rrc\n",
6094 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
6095 else if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
6096 LogRel(("AHCI#%uP%u: Trim returned rc=%Rrc\n",
6097 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
6098 else
6099 LogRel(("AHCI#%uP%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
6100 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN,
6101 pAhciReq->enmTxDir == AHCITXDIR_READ
6102 ? "Read"
6103 : "Write",
6104 pAhciReq->uOffset,
6105 pAhciReq->cbTransfer, rcReq));
6106 }
6107
6108 fRedo = ahciIsRedoSetWarning(pAhciPort, rcReq);
6109 if (!fRedo)
6110 {
6111 pAhciReq->cmdHdr.u32PRDBC = 0;
6112 pAhciReq->uATARegError = ID_ERR;
6113 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6114 fReqErrSaved = ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciReq, NULL);
6115 }
6116 else
6117 ASMAtomicOrU32(&pAhciPort->u32TasksRedo, RT_BIT_32(pAhciReq->uTag));
6118 }
6119 else
6120 {
6121 pAhciReq->cmdHdr.u32PRDBC = pAhciReq->cbTransfer;
6122
6123 /* Status will be set already for non I/O requests. */
6124 if (pAhciReq->enmTxDir != AHCITXDIR_NONE)
6125 {
6126 pAhciReq->uATARegError = 0;
6127 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6128 }
6129
6130 /* Write updated command header into memory of the guest. */
6131 PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
6132
6133 if (pAhciReq->fFlags & AHCI_REQ_OVERFLOW)
6134 {
6135 /*
6136 * The guest tried to transfer more data than there is space in the buffer.
6137 * Terminate task and set the overflow bit.
6138 */
6139 /* Notify the guest. */
6140 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_OFS);
6141 if (pAhciPort->regIE & AHCI_PORT_IE_OFE)
6142 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
6143 }
6144 }
6145
6146 if (!fRedo)
6147 {
6148
6149 /* Post a PIO setup FIS first if this is a PIO command which transfers data. */
6150 if (pAhciReq->fFlags & AHCI_REQ_PIO_DATA)
6151 ahciSendPioSetupFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false /* fInterrupt */);
6152
6153 if (pAhciReq->fFlags & AHCI_REQ_CLEAR_SACT)
6154 {
6155 if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ))
6156 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, RT_BIT_32(pAhciReq->uTag));
6157 }
6158
6159 if (pAhciReq->fFlags & AHCI_REQ_IS_QUEUED)
6160 {
6161 /*
6162 * Always raise an interrupt after task completion; delaying
6163 * this (interrupt coalescing) increases latency and has a significant
6164 * impact on performance (see @bugref{5071})
6165 */
6166 ahciSendSDBFis(pAhciPort, 0, true);
6167 }
6168 else
6169 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
6170 }
6171 }
6172 else
6173 {
6174 /*
6175 * Task was canceled, do the cleanup but DO NOT access the guest memory!
6176 * The guest might use it for other things now because it doesn't know about that task anymore.
6177 */
6178 AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_CANCELED || fPortReset,
6179 ("Task is not active but wasn't canceled and no port reset is active!\n"));
6180
6181 fCanceled = true;
6182
6183 if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
6184 ahciTrimRangesDestroy(pAhciReq);
6185 else if (pAhciReq->enmTxDir != AHCITXDIR_FLUSH)
6186 ahciIoBufFree(pAhciPort, pAhciReq, false /* fCopyToGuest */);
6187
6188 /* Leave a log message about the canceled request. */
6189 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
6190 {
6191 if (pAhciReq->enmTxDir == AHCITXDIR_FLUSH)
6192 LogRel(("AHCI#%uP%u: Canceled flush returned rc=%Rrc\n",
6193 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
6194 else if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
6195 LogRel(("AHCI#%uP%u: Canceled trim returned rc=%Rrc\n",
6196 pAhciPort->CTX_SUFF(pDevIns)->iInstance,pAhciPort->iLUN, rcReq));
6197 else
6198 LogRel(("AHCI#%uP%u: Canceled %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
6199 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN,
6200 pAhciReq->enmTxDir == AHCITXDIR_READ
6201 ? "read"
6202 : "write",
6203 pAhciReq->uOffset,
6204 pAhciReq->cbTransfer, rcReq));
6205 }
6206 }
6207
6208 /*
6209 * Decrement the active task counter as the last step or we might run into a
6210 * hang during power off otherwise (see @bugref{7859}).
6211 * Before it could happen that we signal PDM that we are done while we still have to
6212 * copy the data to the guest but EMT might be busy destroying the driver chains
6213 * below us while we have to delegate copying data to EMT instead of doing it
6214 * on this thread.
6215 */
6216 if (fXchg)
6217 {
6218 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0,
6219 ("Inconsistent request counter\n"));
6220 ASMAtomicDecU32(&pAhciPort->cTasksActive);
6221 }
6222
6223 if (pAhciPort->cTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
6224 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
6225
6226 /* Don't free the request yet when it is saved for the error log page. */
6227 if ( pAhciReq
6228 && !(pAhciReq->fFlags & AHCI_REQ_IS_ON_STACK)
6229 && !fReqErrSaved)
6230 ahciR3ReqFree(pAhciPort, pAhciReq);
6231 return fCanceled;
6232}
6233
6234/**
6235 * Notification callback for a completed transfer.
6236 *
6237 * @returns VBox status code.
6238 * @param pInterface Pointer to the interface.
6239 * @param pvUser User data.
6240 * @param rcReq IPRT Status code of the completed request.
6241 */
6242static DECLCALLBACK(int) ahciR3TransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)
6243{
6244 PAHCIPort pAhciPort = PDMIMEDIAASYNCPORT_2_PAHCIPORT(pInterface);
6245 PAHCIREQ pAhciReq = (PAHCIREQ)pvUser;
6246
6247 ahciLog(("%s: pInterface=%p pvUser=%p uTag=%u\n",
6248 __FUNCTION__, pInterface, pvUser, pAhciReq->uTag));
6249
6250 ahciTransferComplete(pAhciPort, pAhciReq, rcReq);
6251
6252 return VINF_SUCCESS;
6253}
6254
6255/**
6256 * Process an non read/write ATA command.
6257 *
6258 * @returns The direction of the data transfer
6259 * @param pCmdHdr Pointer to the command header.
6260 */
6261static AHCITXDIR ahciProcessCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis)
6262{
6263 AHCITXDIR enmTxDir = AHCITXDIR_NONE;
6264 bool fLBA48 = false;
6265 CmdHdr *pCmdHdr = &pAhciReq->cmdHdr;
6266
6267 AssertMsg(pCmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D, ("FIS is not a host to device Fis!!\n"));
6268
6269 pAhciReq->cbTransfer = 0;
6270
6271 switch (pCmdFis[AHCI_CMDFIS_CMD])
6272 {
6273 case ATA_IDENTIFY_DEVICE:
6274 {
6275 if (pAhciPort->pDrvMedia && !pAhciPort->fATAPI)
6276 {
6277 uint16_t u16Temp[256];
6278 size_t cbCopied;
6279
6280 /* Fill the buffer. */
6281 ahciIdentifySS(pAhciPort, u16Temp);
6282
6283 /* Copy the buffer. */
6284 cbCopied = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
6285 &u16Temp[0], sizeof(u16Temp));
6286
6287 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6288 pAhciReq->cbTransfer = cbCopied;
6289 }
6290 else
6291 {
6292 pAhciReq->uATARegError = ABRT_ERR;
6293 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK | ATA_STAT_ERR;
6294 }
6295 break;
6296 }
6297 case ATA_READ_NATIVE_MAX_ADDRESS_EXT:
6298 case ATA_READ_NATIVE_MAX_ADDRESS:
6299 break;
6300 case ATA_SET_FEATURES:
6301 {
6302 switch (pCmdFis[AHCI_CMDFIS_FET])
6303 {
6304 case 0x02: /* write cache enable */
6305 case 0xaa: /* read look-ahead enable */
6306 case 0x55: /* read look-ahead disable */
6307 case 0xcc: /* reverting to power-on defaults enable */
6308 case 0x66: /* reverting to power-on defaults disable */
6309 pAhciReq->uATARegError = 0;
6310 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6311 break;
6312 case 0x82: /* write cache disable */
6313 enmTxDir = AHCITXDIR_FLUSH;
6314 break;
6315 case 0x03:
6316 {
6317 /* set transfer mode */
6318 Log2(("%s: transfer mode %#04x\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
6319 switch (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8)
6320 {
6321 case 0x00: /* PIO default */
6322 case 0x08: /* PIO mode */
6323 break;
6324 case ATA_MODE_MDMA: /* MDMA mode */
6325 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_MDMA_MODE_MAX);
6326 break;
6327 case ATA_MODE_UDMA: /* UDMA mode */
6328 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_UDMA_MODE_MAX);
6329 break;
6330 }
6331 break;
6332 }
6333 default:
6334 pAhciReq->uATARegError = ABRT_ERR;
6335 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6336 }
6337 break;
6338 }
6339 case ATA_DEVICE_RESET:
6340 {
6341 if (!pAhciPort->fATAPI)
6342 {
6343 pAhciReq->uATARegError = ABRT_ERR;
6344 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6345 }
6346 else
6347 {
6348 /* Reset the device. */
6349 ahciDeviceReset(pAhciPort, pAhciReq);
6350 }
6351 break;
6352 }
6353 case ATA_FLUSH_CACHE_EXT:
6354 case ATA_FLUSH_CACHE:
6355 enmTxDir = AHCITXDIR_FLUSH;
6356 break;
6357 case ATA_PACKET:
6358 if (!pAhciPort->fATAPI)
6359 {
6360 pAhciReq->uATARegError = ABRT_ERR;
6361 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6362 }
6363 else
6364 enmTxDir = atapiParseCmd(pAhciPort, pAhciReq);
6365 break;
6366 case ATA_IDENTIFY_PACKET_DEVICE:
6367 if (!pAhciPort->fATAPI)
6368 {
6369 pAhciReq->uATARegError = ABRT_ERR;
6370 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6371 }
6372 else
6373 {
6374 atapiDoTransfer(pAhciPort, pAhciReq, 512, ATAFN_SS_ATAPI_IDENTIFY);
6375
6376 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6377 pAhciReq->uATARegError = 0;
6378 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6379 }
6380 break;
6381 case ATA_SET_MULTIPLE_MODE:
6382 if ( pCmdFis[AHCI_CMDFIS_SECTC] != 0
6383 && ( pCmdFis[AHCI_CMDFIS_SECTC] > ATA_MAX_MULT_SECTORS
6384 || (pCmdFis[AHCI_CMDFIS_SECTC] & (pCmdFis[AHCI_CMDFIS_SECTC] - 1)) != 0))
6385 {
6386 pAhciReq->uATARegError = ABRT_ERR;
6387 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6388 }
6389 else
6390 {
6391 Log2(("%s: set multi sector count to %d\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
6392 pAhciPort->cMultSectors = pCmdFis[AHCI_CMDFIS_SECTC];
6393 pAhciReq->uATARegError = 0;
6394 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6395 }
6396 break;
6397 case ATA_STANDBY_IMMEDIATE:
6398 break; /* Do nothing. */
6399 case ATA_CHECK_POWER_MODE:
6400 pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] = 0xff; /* drive active or idle */
6401 /* fall through */
6402 case ATA_INITIALIZE_DEVICE_PARAMETERS:
6403 case ATA_IDLE_IMMEDIATE:
6404 case ATA_RECALIBRATE:
6405 case ATA_NOP:
6406 case ATA_READ_VERIFY_SECTORS_EXT:
6407 case ATA_READ_VERIFY_SECTORS:
6408 case ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES:
6409 case ATA_SLEEP:
6410 pAhciReq->uATARegError = 0;
6411 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6412 break;
6413 case ATA_READ_DMA_EXT:
6414 fLBA48 = true;
6415 case ATA_READ_DMA:
6416 {
6417 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
6418 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
6419 enmTxDir = AHCITXDIR_READ;
6420 break;
6421 }
6422 case ATA_WRITE_DMA_EXT:
6423 fLBA48 = true;
6424 case ATA_WRITE_DMA:
6425 {
6426 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
6427 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
6428 enmTxDir = AHCITXDIR_WRITE;
6429 break;
6430 }
6431 case ATA_READ_FPDMA_QUEUED:
6432 {
6433 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
6434 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
6435 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
6436 enmTxDir = AHCITXDIR_READ;
6437 break;
6438 }
6439 case ATA_WRITE_FPDMA_QUEUED:
6440 {
6441 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
6442 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
6443 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
6444 enmTxDir = AHCITXDIR_WRITE;
6445 break;
6446 }
6447 case ATA_READ_LOG_EXT:
6448 {
6449 size_t cbLogRead = ((pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8) | pCmdFis[AHCI_CMDFIS_SECTC]) * 512;
6450 unsigned offLogRead = ((pCmdFis[AHCI_CMDFIS_CYLLEXP] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * 512;
6451 unsigned iPage = pCmdFis[AHCI_CMDFIS_SECTN];
6452 size_t cbCopied;
6453
6454 LogFlow(("Trying to read %zu bytes starting at offset %u from page %u\n", cbLogRead, offLogRead, iPage));
6455
6456 uint8_t aBuf[512];
6457
6458 memset(aBuf, 0, sizeof(aBuf));
6459
6460 if (offLogRead + cbLogRead <= sizeof(aBuf))
6461 {
6462 switch (iPage)
6463 {
6464 case 0x10:
6465 {
6466 LogFlow(("Reading error page\n"));
6467 PAHCIREQ pTaskErr = ASMAtomicXchgPtrT(&pAhciPort->pTaskErr, NULL, PAHCIREQ);
6468 if (pTaskErr)
6469 {
6470 aBuf[0] = (pTaskErr->fFlags & AHCI_REQ_IS_QUEUED) ? pTaskErr->uTag : (1 << 7);
6471 aBuf[2] = pTaskErr->uATARegStatus;
6472 aBuf[3] = pTaskErr->uATARegError;
6473 aBuf[4] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTN];
6474 aBuf[5] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLL];
6475 aBuf[6] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLH];
6476 aBuf[7] = pTaskErr->cmdFis[AHCI_CMDFIS_HEAD];
6477 aBuf[8] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTNEXP];
6478 aBuf[9] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLLEXP];
6479 aBuf[10] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLHEXP];
6480 aBuf[12] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTC];
6481 aBuf[13] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTCEXP];
6482
6483 /* Calculate checksum */
6484 uint8_t uChkSum = 0;
6485 for (unsigned i = 0; i < RT_ELEMENTS(aBuf)-1; i++)
6486 uChkSum += aBuf[i];
6487
6488 aBuf[511] = (uint8_t)-(int8_t)uChkSum;
6489
6490 if (pTaskErr->enmTxDir == AHCITXDIR_TRIM)
6491 ahciTrimRangesDestroy(pTaskErr);
6492 else if (pTaskErr->enmTxDir != AHCITXDIR_FLUSH)
6493 ahciReqMemFree(pAhciPort, pTaskErr, true /* fForceFree */);
6494
6495 /* Finally free the error task state structure because it is completely unused now. */
6496 RTMemFree(pTaskErr);
6497 }
6498
6499 /*
6500 * Reading this log page results in an abort of all outstanding commands
6501 * and clearing the SActive register and TaskFile register.
6502 *
6503 * See SATA2 1.2 spec chapter 4.2.3.4
6504 */
6505 bool fAbortedAll = ahciCancelActiveTasks(pAhciPort, pAhciReq);
6506 Assert(fAbortedAll);
6507 ahciSendSDBFis(pAhciPort, 0xffffffff, true);
6508
6509 break;
6510 }
6511 }
6512
6513 /* Copy the buffer. */
6514 cbCopied = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
6515 &aBuf[offLogRead], cbLogRead);
6516
6517 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6518 pAhciReq->cbTransfer = cbCopied;
6519 }
6520
6521 break;
6522 }
6523 case ATA_DATA_SET_MANAGEMENT:
6524 {
6525 if ( ( !pAhciPort->fAsyncInterface
6526 && pAhciPort->pDrvMedia->pfnDiscard)
6527 || ( pAhciPort->fAsyncInterface
6528 && pAhciPort->pDrvMediaAsync->pfnStartDiscard))
6529 {
6530 /* Check that the trim bit is set and all other bits are 0. */
6531 if ( !(pAhciReq->cmdFis[AHCI_CMDFIS_FET] & UINT16_C(0x01))
6532 || (pAhciReq->cmdFis[AHCI_CMDFIS_FET] & ~UINT16_C(0x1)))
6533 {
6534 pAhciReq->uATARegError = ABRT_ERR;
6535 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6536 }
6537 else
6538 enmTxDir = AHCITXDIR_TRIM;
6539 break;
6540 }
6541 /* else: fall through and report error to the guest. */
6542 }
6543 /* All not implemented commands go below. */
6544 case ATA_SECURITY_FREEZE_LOCK:
6545 case ATA_SMART:
6546 case ATA_NV_CACHE:
6547 case ATA_IDLE:
6548 case ATA_TRUSTED_RECEIVE_DMA: /* Windows 8+ */
6549 pAhciReq->uATARegError = ABRT_ERR;
6550 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6551 break;
6552 default: /* For debugging purposes. */
6553 AssertMsgFailed(("Unknown command issued (%#x)\n", pCmdFis[AHCI_CMDFIS_CMD]));
6554 pAhciReq->uATARegError = ABRT_ERR;
6555 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6556 }
6557
6558 return enmTxDir;
6559}
6560
6561/**
6562 * Retrieve a command FIS from guest memory.
6563 *
6564 * @returns whether the H2D FIS was successfully read from the guest memory.
6565 * @param pAhciReq The state of the actual task.
6566 */
6567static bool ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
6568{
6569 RTGCPHYS GCPhysAddrCmdTbl;
6570
6571 AssertMsgReturn(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb,
6572 ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__),
6573 false);
6574
6575 /*
6576 * First we are reading the command header pointed to by regCLB.
6577 * From this we get the address of the command table which we are reading too.
6578 * We can process the Command FIS afterwards.
6579 */
6580 pAhciReq->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciReq->uTag * sizeof(CmdHdr);
6581 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdLst=%RGp cbCmdHdr=%u\n", __FUNCTION__,
6582 pAhciReq->GCPhysCmdHdrAddr, sizeof(CmdHdr)));
6583 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
6584
6585#ifdef LOG_ENABLED
6586 /* Print some infos about the command header. */
6587 ahciDumpCmdHdrInfo(pAhciPort, &pAhciReq->cmdHdr);
6588#endif
6589
6590 GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr);
6591
6592 AssertMsgReturn((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
6593 ("This is not a command FIS!!\n"),
6594 false);
6595
6596 /* Read the command Fis. */
6597 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdTbl=%RGp cbCmdFis=%u\n", __FUNCTION__, GCPhysAddrCmdTbl, AHCI_CMDFIS_TYPE_H2D_SIZE));
6598 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
6599
6600 AssertMsgReturn(pAhciReq->cmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D,
6601 ("This is not a command FIS\n"),
6602 false);
6603
6604 /* Set transfer direction. */
6605 pAhciReq->enmTxDir = (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? AHCITXDIR_WRITE : AHCITXDIR_READ;
6606
6607 /* If this is an ATAPI command read the atapi command. */
6608 if (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_A)
6609 {
6610 GCPhysAddrCmdTbl += AHCI_CMDHDR_ACMD_OFFSET;
6611 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->aATAPICmd[0], ATAPI_PACKET_SIZE);
6612 }
6613
6614 /* We "received" the FIS. Clear the BSY bit in regTFD. */
6615 if ((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_C) && (pAhciReq->fFlags & AHCI_REQ_CLEAR_SACT))
6616 {
6617 /*
6618 * 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.
6619 * but this FIS does not assert an interrupt
6620 */
6621 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false);
6622 pAhciPort->regTFD &= ~AHCI_PORT_TFD_BSY;
6623 }
6624
6625 pAhciReq->GCPhysPrdtl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
6626 pAhciReq->cPrdtlEntries = AHCI_CMDHDR_PRDTL_ENTRIES(pAhciReq->cmdHdr.u32DescInf);
6627
6628#ifdef LOG_ENABLED
6629 /* Print some infos about the FIS. */
6630 ahciDumpFisInfo(pAhciPort, &pAhciReq->cmdFis[0]);
6631
6632 /* Print the PRDT */
6633 ahciLog(("PRDT address %RGp number of entries %u\n", pAhciReq->GCPhysPrdtl, pAhciReq->cPrdtlEntries));
6634 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
6635
6636 for (unsigned i = 0; i < pAhciReq->cPrdtlEntries; i++)
6637 {
6638 SGLEntry SGEntry;
6639
6640 ahciLog(("Entry %u at address %RGp\n", i, GCPhysPrdtl));
6641 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysPrdtl, &SGEntry, sizeof(SGLEntry));
6642
6643 RTGCPHYS GCPhysDataAddr = AHCI_RTGCPHYS_FROM_U32(SGEntry.u32DBAUp, SGEntry.u32DBA);
6644 ahciLog(("GCPhysAddr=%RGp Size=%u\n", GCPhysDataAddr, SGEntry.u32DescInf & SGLENTRY_DESCINF_DBC));
6645
6646 GCPhysPrdtl += sizeof(SGLEntry);
6647 }
6648#endif
6649
6650 return true;
6651}
6652
6653/**
6654 * Submits a given request for execution.
6655 *
6656 * @returns Flag whether the request was canceled inbetween.
6657 * @param pAhciPort The port the request is for.
6658 * @param pAhciReq The request to submit.
6659 * @param enmTxDir The request type.
6660 */
6661static bool ahciR3ReqSubmit(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, AHCITXDIR enmTxDir)
6662{
6663 int rc = VINF_SUCCESS;
6664 bool fReqCanceled = false;
6665
6666 if (pAhciPort->fAsyncInterface)
6667 {
6668 VBOXDD_AHCI_REQ_SUBMIT(pAhciReq, pAhciReq->enmTxDir, pAhciReq->uOffset, pAhciReq->cbTransfer);
6669 VBOXDD_AHCI_REQ_SUBMIT_TIMESTAMP(pAhciReq, pAhciReq->tsStart);
6670 if (enmTxDir == AHCITXDIR_FLUSH)
6671 {
6672 rc = pAhciPort->pDrvMediaAsync->pfnStartFlush(pAhciPort->pDrvMediaAsync,
6673 pAhciReq);
6674 }
6675 else if (enmTxDir == AHCITXDIR_TRIM)
6676 {
6677 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);
6678 if (RT_SUCCESS(rc))
6679 {
6680 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6681 rc = pAhciPort->pDrvMediaAsync->pfnStartDiscard(pAhciPort->pDrvMediaAsync, pAhciReq->u.Trim.paRanges,
6682 pAhciReq->u.Trim.cRanges, pAhciReq);
6683 }
6684 }
6685 else if (enmTxDir == AHCITXDIR_READ)
6686 {
6687 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
6688 rc = pAhciPort->pDrvMediaAsync->pfnStartRead(pAhciPort->pDrvMediaAsync, pAhciReq->uOffset,
6689 &pAhciReq->u.Io.DataSeg, 1,
6690 pAhciReq->cbTransfer,
6691 pAhciReq);
6692 }
6693 else
6694 {
6695 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6696 rc = pAhciPort->pDrvMediaAsync->pfnStartWrite(pAhciPort->pDrvMediaAsync, pAhciReq->uOffset,
6697 &pAhciReq->u.Io.DataSeg, 1,
6698 pAhciReq->cbTransfer,
6699 pAhciReq);
6700 }
6701 if (rc == VINF_VD_ASYNC_IO_FINISHED)
6702 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS);
6703 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
6704 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, rc);
6705 }
6706 else
6707 {
6708 if (enmTxDir == AHCITXDIR_FLUSH)
6709 rc = pAhciPort->pDrvMedia->pfnFlush(pAhciPort->pDrvMedia);
6710 else if (enmTxDir == AHCITXDIR_TRIM)
6711 {
6712 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);
6713 if (RT_SUCCESS(rc))
6714 {
6715 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6716 rc = pAhciPort->pDrvMedia->pfnDiscard(pAhciPort->pDrvMedia, pAhciReq->u.Trim.paRanges,
6717 pAhciReq->u.Trim.cRanges);
6718 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0;
6719 }
6720 }
6721 else if (enmTxDir == AHCITXDIR_READ)
6722 {
6723 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
6724 rc = pAhciPort->pDrvMedia->pfnRead(pAhciPort->pDrvMedia, pAhciReq->uOffset,
6725 pAhciReq->u.Io.DataSeg.pvSeg,
6726 pAhciReq->cbTransfer);
6727 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 0;
6728 }
6729 else
6730 {
6731 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6732 rc = pAhciPort->pDrvMedia->pfnWrite(pAhciPort->pDrvMedia, pAhciReq->uOffset,
6733 pAhciReq->u.Io.DataSeg.pvSeg,
6734 pAhciReq->cbTransfer);
6735 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0;
6736 }
6737 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, rc);
6738 }
6739
6740 return fReqCanceled;
6741}
6742
6743/**
6744 * Prepares the command for execution coping it from guest memory and doing a few
6745 * validation checks on it.
6746 *
6747 * @returns Whether the command was successfully fetched from guest memory and
6748 * can be continued.
6749 * @param pAhciPort The AHCI port the request is for.
6750 * @param pAhciReq Request structure to copy the command to.
6751 */
6752static bool ahciR3CmdPrepare(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
6753{
6754 pAhciReq->tsStart = RTTimeMilliTS();
6755 pAhciReq->uATARegStatus = 0;
6756 pAhciReq->uATARegError = 0;
6757
6758 /* Set current command slot */
6759 ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag);
6760 ASMAtomicWritePtr(&pAhciPort->aActiveTasks[pAhciReq->uTag], pAhciReq);
6761
6762 bool fContinue = ahciPortTaskGetCommandFis(pAhciPort, pAhciReq);
6763 if (fContinue)
6764 {
6765 /* 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. */
6766 if (pAhciPort->regSACT & RT_BIT_32(pAhciReq->uTag))
6767 {
6768 pAhciReq->fFlags |= AHCI_REQ_CLEAR_SACT;
6769 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, RT_BIT_32(pAhciReq->uTag));
6770 }
6771
6772 if (pAhciReq->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
6773 {
6774 /*
6775 * It is possible that the request counter can get one higher than the maximum because
6776 * the request counter is decremented after the guest was notified about the completed
6777 * request (see @bugref{7859}). If the completing thread is preempted in between the
6778 * guest might already issue another request before the request counter is decremented
6779 * which would trigger the following assertion incorrectly in the past.
6780 */
6781 AssertLogRelMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) <= AHCI_NR_COMMAND_SLOTS,
6782 ("AHCI#%uP%u: There are more than %u (+1) requests active",
6783 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN,
6784 AHCI_NR_COMMAND_SLOTS));
6785 ASMAtomicIncU32(&pAhciPort->cTasksActive);
6786 }
6787 else
6788 {
6789 /* If the reset bit is set put the device into reset state. */
6790 if (pAhciReq->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
6791 {
6792 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
6793 pAhciPort->fResetDevice = true;
6794 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
6795 }
6796 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
6797 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
6798 else /* We are not in a reset state update the control registers. */
6799 AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
6800
6801 fContinue = false;
6802 }
6803 }
6804 else
6805 {
6806 /*
6807 * Couldn't find anything in either the AHCI or SATA spec which
6808 * indicates what should be done if the FIS is not read successfully.
6809 * The closest thing is in the state machine, stating that the device
6810 * should go into idle state again (SATA spec 1.0 chapter 8.7.1).
6811 * Do the same here and ignore any corrupt FIS types, after all
6812 * the guest messed up everything and this behavior is undefined.
6813 */
6814 fContinue = false;
6815 }
6816
6817 return fContinue;
6818}
6819
6820/**
6821 * Transmit queue consumer
6822 * Queue a new async task.
6823 *
6824 * @returns Success indicator.
6825 * If false the item will not be removed and the flushing will stop.
6826 * @param pDevIns The device instance.
6827 * @param pItem The item to consume. Upon return this item will be freed.
6828 */
6829static DECLCALLBACK(bool) ahciNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
6830{
6831 PDEVPORTNOTIFIERQUEUEITEM pNotifierItem = (PDEVPORTNOTIFIERQUEUEITEM)pItem;
6832 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6833 PAHCIPort pAhciPort = &pThis->ahciPort[pNotifierItem->iPort];
6834 int rc = VINF_SUCCESS;
6835
6836 ahciLog(("%s: Got notification from GC\n", __FUNCTION__));
6837 /* Notify the async IO thread. */
6838 rc = SUPSemEventSignal(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
6839 AssertRC(rc);
6840
6841 return true;
6842}
6843
6844/* The async IO thread for one port. */
6845static DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
6846{
6847 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
6848 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
6849 int rc = VINF_SUCCESS;
6850 uint64_t u64StartTime = 0;
6851 uint64_t u64StopTime = 0;
6852 uint32_t uIORequestsProcessed = 0;
6853 uint32_t uIOsPerSec = 0;
6854 uint32_t fTasksToProcess = 0;
6855
6856 ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
6857
6858 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
6859 return VINF_SUCCESS;
6860
6861 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
6862 {
6863 unsigned idx = 0;
6864 uint32_t u32Tasks = 0;
6865 uint32_t u32RegHbaCtrl = 0;
6866
6867 ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, true);
6868 u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
6869 if (!u32Tasks)
6870 {
6871 Assert(ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping));
6872 rc = SUPSemEventWaitNoResume(pAhci->pSupDrvSession, pAhciPort->hEvtProcess, RT_INDEFINITE_WAIT);
6873 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
6874 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
6875 break;
6876 LogFlowFunc(("Woken up with rc=%Rrc\n", rc));
6877 u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
6878 }
6879
6880 ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, false);
6881 ASMAtomicIncU32(&pAhci->cThreadsActive);
6882
6883 /* Check whether the thread should be suspended. */
6884 if (pAhci->fSignalIdle)
6885 {
6886 if (!ASMAtomicDecU32(&pAhci->cThreadsActive))
6887 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
6888 continue;
6889 }
6890
6891 /*
6892 * Check whether the global host controller bit is set and go to sleep immediately again
6893 * if it is set.
6894 */
6895 u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
6896 if ( u32RegHbaCtrl & AHCI_HBA_CTRL_HR
6897 && !ASMAtomicDecU32(&pAhci->cThreadsActive))
6898 {
6899 ahciHBAReset(pAhci);
6900 if (pAhci->fSignalIdle)
6901 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
6902 continue;
6903 }
6904
6905 idx = ASMBitFirstSetU32(u32Tasks);
6906 while ( idx
6907 && !pAhciPort->fPortReset)
6908 {
6909 bool fReqCanceled = false;
6910 AHCITXDIR enmTxDir;
6911 PAHCIREQ pAhciReq;
6912
6913 /* Decrement to get the slot number. */
6914 idx--;
6915 ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, idx));
6916
6917 /* Check whether the request is already active and ignore. */
6918 if (ASMAtomicReadPtr((void * volatile *)&pAhciPort->aActiveTasks[idx]))
6919 {
6920 ahciLog(("%s: Ignoring command at slot %d because it is already active\n", __FUNCTION__, idx));
6921 continue;
6922 }
6923
6924 pAhciReq = ahciR3ReqAlloc(pAhciPort);
6925 if (RT_LIKELY(pAhciReq))
6926 {
6927 pAhciReq->uTag = idx;
6928 pAhciReq->fFlags = 0;
6929
6930 bool fContinue = ahciR3CmdPrepare(pAhciPort, pAhciReq);
6931 if (fContinue)
6932 {
6933 enmTxDir = ahciProcessCmd(pAhciPort, pAhciReq, pAhciReq->cmdFis);
6934 pAhciReq->enmTxDir = enmTxDir;
6935
6936 if (enmTxDir != AHCITXDIR_NONE)
6937 {
6938 if ( enmTxDir != AHCITXDIR_FLUSH
6939 && enmTxDir != AHCITXDIR_TRIM)
6940 {
6941 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
6942
6943 rc = ahciIoBufAllocate(pAhciPort, pAhciReq, pAhciReq->cbTransfer);
6944 if (RT_FAILURE(rc))
6945 {
6946 /* In case we can't allocate enough memory fail the request with an overflow error. */
6947 AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
6948 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
6949 }
6950 }
6951
6952 if (!(pAhciReq->fFlags & AHCI_REQ_OVERFLOW))
6953 fReqCanceled = ahciR3ReqSubmit(pAhciPort, pAhciReq, enmTxDir);
6954 else /* Overflow is handled in completion routine. */
6955 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS);
6956 }
6957 else
6958 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS);
6959 } /* Command */
6960 else
6961 {
6962 ASMAtomicWriteNullPtr(&pAhciPort->aActiveTasks[pAhciReq->uTag]);
6963 ahciR3ReqFree(pAhciPort, pAhciReq);
6964 }
6965 }
6966 else /* !Request allocated, use on stack variant to signal the error. */
6967 {
6968 AHCIREQ Req;
6969 Req.uTag = idx;
6970 Req.fFlags = AHCI_REQ_IS_ON_STACK;
6971
6972 bool fContinue = ahciR3CmdPrepare(pAhciPort, &Req);
6973 if (fContinue)
6974 fReqCanceled = ahciTransferComplete(pAhciPort, &Req, VERR_NO_MEMORY);
6975 }
6976
6977 /*
6978 * Don't process other requests if the last one was canceled,
6979 * the others are not valid anymore.
6980 */
6981 if (fReqCanceled)
6982 break;
6983
6984 u32Tasks &= ~RT_BIT_32(idx); /* Clear task bit. */
6985 idx = ASMBitFirstSetU32(u32Tasks);
6986 } /* while tasks available */
6987
6988 /* Check whether a port reset was active. */
6989 if ( ASMAtomicReadBool(&pAhciPort->fPortReset)
6990 && (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT)
6991 ahciPortResetFinish(pAhciPort);
6992
6993 /*
6994 * Check whether a host controller reset is pending and execute the reset
6995 * if this is the last active thread.
6996 */
6997 u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
6998 uint32_t cThreadsActive = ASMAtomicDecU32(&pAhci->cThreadsActive);
6999 if ( (u32RegHbaCtrl & AHCI_HBA_CTRL_HR)
7000 && !cThreadsActive)
7001 ahciHBAReset(pAhci);
7002
7003 if (!cThreadsActive && pAhci->fSignalIdle)
7004 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
7005 } /* While running */
7006
7007 ahciLog(("%s: Port %d async IO thread exiting\n", __FUNCTION__, pAhciPort->iLUN));
7008 return VINF_SUCCESS;
7009}
7010
7011/**
7012 * Unblock the async I/O thread so it can respond to a state change.
7013 *
7014 * @returns VBox status code.
7015 * @param pDevIns The device instance.
7016 * @param pThread The send thread.
7017 */
7018static DECLCALLBACK(int) ahciAsyncIOLoopWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
7019{
7020 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7021 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
7022 return SUPSemEventSignal(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
7023}
7024
7025/* -=-=-=-=- DBGF -=-=-=-=- */
7026
7027/**
7028 * AHCI status info callback.
7029 *
7030 * @param pDevIns The device instance.
7031 * @param pHlp The output helpers.
7032 * @param pszArgs The arguments.
7033 */
7034static DECLCALLBACK(void) ahciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
7035{
7036 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7037
7038 /*
7039 * Show info.
7040 */
7041 pHlp->pfnPrintf(pHlp,
7042 "%s#%d: mmio=%RGp ports=%u GC=%RTbool R0=%RTbool\n",
7043 pDevIns->pReg->szName,
7044 pDevIns->iInstance,
7045 pThis->MMIOBase,
7046 pThis->cPortsImpl,
7047 pThis->fGCEnabled ? true : false,
7048 pThis->fR0Enabled ? true : false);
7049
7050 /*
7051 * Show global registers.
7052 */
7053 pHlp->pfnPrintf(pHlp, "HbaCap=%#x\n", pThis->regHbaCap);
7054 pHlp->pfnPrintf(pHlp, "HbaCtrl=%#x\n", pThis->regHbaCtrl);
7055 pHlp->pfnPrintf(pHlp, "HbaIs=%#x\n", pThis->regHbaIs);
7056 pHlp->pfnPrintf(pHlp, "HbaPi=%#x", pThis->regHbaPi);
7057 pHlp->pfnPrintf(pHlp, "HbaVs=%#x\n", pThis->regHbaVs);
7058 pHlp->pfnPrintf(pHlp, "HbaCccCtl=%#x\n", pThis->regHbaCccCtl);
7059 pHlp->pfnPrintf(pHlp, "HbaCccPorts=%#x\n", pThis->regHbaCccPorts);
7060 pHlp->pfnPrintf(pHlp, "PortsInterrupted=%#x\n", pThis->u32PortsInterrupted);
7061
7062 /*
7063 * Per port data.
7064 */
7065 for (unsigned i = 0; i < pThis->cPortsImpl; i++)
7066 {
7067 PAHCIPort pThisPort = &pThis->ahciPort[i];
7068
7069 pHlp->pfnPrintf(pHlp, "Port %d: async=%RTbool device-attached=%RTbool\n",
7070 pThisPort->iLUN, pThisPort->fAsyncInterface, pThisPort->pDrvBase != NULL);
7071 pHlp->pfnPrintf(pHlp, "PortClb=%#x\n", pThisPort->regCLB);
7072 pHlp->pfnPrintf(pHlp, "PortClbU=%#x\n", pThisPort->regCLBU);
7073 pHlp->pfnPrintf(pHlp, "PortFb=%#x\n", pThisPort->regFB);
7074 pHlp->pfnPrintf(pHlp, "PortFbU=%#x\n", pThisPort->regFBU);
7075 pHlp->pfnPrintf(pHlp, "PortIs=%#x\n", pThisPort->regIS);
7076 pHlp->pfnPrintf(pHlp, "PortIe=%#x\n", pThisPort->regIE);
7077 pHlp->pfnPrintf(pHlp, "PortCmd=%#x\n", pThisPort->regCMD);
7078 pHlp->pfnPrintf(pHlp, "PortTfd=%#x\n", pThisPort->regTFD);
7079 pHlp->pfnPrintf(pHlp, "PortSig=%#x\n", pThisPort->regSIG);
7080 pHlp->pfnPrintf(pHlp, "PortSSts=%#x\n", pThisPort->regSSTS);
7081 pHlp->pfnPrintf(pHlp, "PortSCtl=%#x\n", pThisPort->regSCTL);
7082 pHlp->pfnPrintf(pHlp, "PortSErr=%#x\n", pThisPort->regSERR);
7083 pHlp->pfnPrintf(pHlp, "PortSAct=%#x\n", pThisPort->regSACT);
7084 pHlp->pfnPrintf(pHlp, "PortCi=%#x\n", pThisPort->regCI);
7085 pHlp->pfnPrintf(pHlp, "PortPhysClb=%RGp\n", pThisPort->GCPhysAddrClb);
7086 pHlp->pfnPrintf(pHlp, "PortPhysFb=%RGp\n", pThisPort->GCPhysAddrFb);
7087 pHlp->pfnPrintf(pHlp, "PortActTasksActive=%u\n", pThisPort->cTasksActive);
7088 pHlp->pfnPrintf(pHlp, "PortPoweredOn=%RTbool\n", pThisPort->fPoweredOn);
7089 pHlp->pfnPrintf(pHlp, "PortSpunUp=%RTbool\n", pThisPort->fSpunUp);
7090 pHlp->pfnPrintf(pHlp, "PortFirstD2HFisSend=%RTbool\n", pThisPort->fFirstD2HFisSend);
7091 pHlp->pfnPrintf(pHlp, "PortATAPI=%RTbool\n", pThisPort->fATAPI);
7092 pHlp->pfnPrintf(pHlp, "PortTasksFinished=%#x\n", pThisPort->u32TasksFinished);
7093 pHlp->pfnPrintf(pHlp, "PortQueuedTasksFinished=%#x\n", pThisPort->u32QueuedTasksFinished);
7094 pHlp->pfnPrintf(pHlp, "PortTasksNew=%#x\n", pThisPort->u32TasksNew);
7095 pHlp->pfnPrintf(pHlp, "\n");
7096 }
7097}
7098
7099/* -=-=-=-=- Helper -=-=-=-=- */
7100
7101/**
7102 * Checks if all asynchronous I/O is finished, both AHCI and IDE.
7103 *
7104 * Used by ahciR3Reset, ahciR3Suspend and ahciR3PowerOff. ahciR3SavePrep makes
7105 * use of it in strict builds (which is why it's up here).
7106 *
7107 * @returns true if quiesced, false if busy.
7108 * @param pDevIns The device instance.
7109 */
7110static bool ahciR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
7111{
7112 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7113
7114 if (pThis->cThreadsActive)
7115 return false;
7116
7117 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->ahciPort); i++)
7118 {
7119 PAHCIPort pThisPort = &pThis->ahciPort[i];
7120 if (pThisPort->pDrvBase)
7121 {
7122 if ( (pThisPort->cTasksActive != 0)
7123 || (pThisPort->u32TasksNew != 0))
7124 return false;
7125 }
7126 }
7127 return true;
7128}
7129
7130/* -=-=-=-=- Saved State -=-=-=-=- */
7131
7132/**
7133 * @callback_method_impl{FNSSMDEVSAVEPREP}
7134 */
7135static DECLCALLBACK(int) ahciR3SavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
7136{
7137 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
7138 return VINF_SUCCESS;
7139}
7140
7141/**
7142 * @callback_method_impl{FNSSMDEVLOADPREP}
7143 */
7144static DECLCALLBACK(int) ahciR3LoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
7145{
7146 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
7147 return VINF_SUCCESS;
7148}
7149
7150/**
7151 * @callback_method_impl{FNSSMDEVLIVEEXEC}
7152 */
7153static DECLCALLBACK(int) ahciR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
7154{
7155 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7156
7157 /* config. */
7158 SSMR3PutU32(pSSM, pThis->cPortsImpl);
7159 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7160 {
7161 SSMR3PutBool(pSSM, pThis->ahciPort[i].pDrvBase != NULL);
7162 SSMR3PutBool(pSSM, pThis->ahciPort[i].fHotpluggable);
7163 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szSerialNumber);
7164 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szFirmwareRevision);
7165 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szModelNumber);
7166 }
7167
7168 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
7169 for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
7170 {
7171 uint32_t iPort;
7172 int rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
7173 AssertRCReturn(rc, rc);
7174 SSMR3PutU32(pSSM, iPort);
7175 }
7176
7177 return VINF_SSM_DONT_CALL_AGAIN;
7178}
7179
7180/**
7181 * @callback_method_impl{FNSSMDEVSAVEEXEC}
7182 */
7183static DECLCALLBACK(int) ahciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
7184{
7185 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7186 uint32_t i;
7187 int rc;
7188
7189 Assert(!pThis->f8ByteMMIO4BytesWrittenSuccessfully);
7190
7191 /* The config */
7192 rc = ahciR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
7193 AssertRCReturn(rc, rc);
7194
7195 /* The main device structure. */
7196 SSMR3PutU32(pSSM, pThis->regHbaCap);
7197 SSMR3PutU32(pSSM, pThis->regHbaCtrl);
7198 SSMR3PutU32(pSSM, pThis->regHbaIs);
7199 SSMR3PutU32(pSSM, pThis->regHbaPi);
7200 SSMR3PutU32(pSSM, pThis->regHbaVs);
7201 SSMR3PutU32(pSSM, pThis->regHbaCccCtl);
7202 SSMR3PutU32(pSSM, pThis->regHbaCccPorts);
7203 SSMR3PutU8(pSSM, pThis->uCccPortNr);
7204 SSMR3PutU64(pSSM, pThis->uCccTimeout);
7205 SSMR3PutU32(pSSM, pThis->uCccNr);
7206 SSMR3PutU32(pSSM, pThis->uCccCurrentNr);
7207 SSMR3PutU32(pSSM, pThis->u32PortsInterrupted);
7208 SSMR3PutBool(pSSM, pThis->fReset);
7209 SSMR3PutBool(pSSM, pThis->f64BitAddr);
7210 SSMR3PutBool(pSSM, pThis->fR0Enabled);
7211 SSMR3PutBool(pSSM, pThis->fGCEnabled);
7212 SSMR3PutBool(pSSM, pThis->fLegacyPortResetMethod);
7213
7214 /* Now every port. */
7215 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7216 {
7217 Assert(pThis->ahciPort[i].cTasksActive == 0);
7218 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLB);
7219 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLBU);
7220 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFB);
7221 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFBU);
7222 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrClb);
7223 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrFb);
7224 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIS);
7225 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIE);
7226 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCMD);
7227 SSMR3PutU32(pSSM, pThis->ahciPort[i].regTFD);
7228 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSIG);
7229 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSSTS);
7230 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSCTL);
7231 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSERR);
7232 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSACT);
7233 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCI);
7234 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cCylinders);
7235 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cHeads);
7236 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cSectors);
7237 SSMR3PutU64(pSSM, pThis->ahciPort[i].cTotalSectors);
7238 SSMR3PutU32(pSSM, pThis->ahciPort[i].cMultSectors);
7239 SSMR3PutU8(pSSM, pThis->ahciPort[i].uATATransferMode);
7240 SSMR3PutBool(pSSM, pThis->ahciPort[i].fResetDevice);
7241 SSMR3PutBool(pSSM, pThis->ahciPort[i].fPoweredOn);
7242 SSMR3PutBool(pSSM, pThis->ahciPort[i].fSpunUp);
7243 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32TasksFinished);
7244 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32QueuedTasksFinished);
7245 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32CurrentCommandSlot);
7246
7247 /* ATAPI saved state. */
7248 SSMR3PutBool(pSSM, pThis->ahciPort[i].fATAPI);
7249 SSMR3PutMem(pSSM, &pThis->ahciPort[i].abATAPISense[0], sizeof(pThis->ahciPort[i].abATAPISense));
7250 SSMR3PutU8(pSSM, pThis->ahciPort[i].cNotifiedMediaChange);
7251 SSMR3PutU32(pSSM, pThis->ahciPort[i].MediaEventStatus);
7252 }
7253
7254 return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
7255}
7256
7257/**
7258 * Loads a saved legacy ATA emulated device state.
7259 *
7260 * @returns VBox status code.
7261 * @param pSSM The handle to the saved state.
7262 */
7263static int ahciR3LoadLegacyEmulationState(PSSMHANDLE pSSM)
7264{
7265 int rc;
7266 uint32_t u32Version;
7267 uint32_t u32;
7268 uint32_t u32IOBuffer;
7269
7270 /* Test for correct version. */
7271 rc = SSMR3GetU32(pSSM, &u32Version);
7272 AssertRCReturn(rc, rc);
7273 LogFlow(("LoadOldSavedStates u32Version = %d\n", u32Version));
7274
7275 if ( u32Version != ATA_CTL_SAVED_STATE_VERSION
7276 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE
7277 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
7278 {
7279 AssertMsgFailed(("u32Version=%d\n", u32Version));
7280 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
7281 }
7282
7283 SSMR3Skip(pSSM, 19 + 5 * sizeof(bool) + sizeof(BMDMAState));
7284
7285 for (uint32_t j = 0; j < 2; j++)
7286 {
7287 SSMR3Skip(pSSM, 88 + 5 * sizeof(bool) );
7288
7289 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE)
7290 SSMR3Skip(pSSM, 64);
7291 else
7292 SSMR3Skip(pSSM, 2);
7293 /** @todo triple-check this hack after passthrough is working */
7294 SSMR3Skip(pSSM, 1);
7295
7296 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
7297 SSMR3Skip(pSSM, 4);
7298
7299 SSMR3Skip(pSSM, sizeof(PDMLED));
7300 SSMR3GetU32(pSSM, &u32IOBuffer);
7301 if (u32IOBuffer)
7302 SSMR3Skip(pSSM, u32IOBuffer);
7303 }
7304
7305 rc = SSMR3GetU32(pSSM, &u32);
7306 if (RT_FAILURE(rc))
7307 return rc;
7308 if (u32 != ~0U)
7309 {
7310 AssertMsgFailed(("u32=%#x expected ~0\n", u32));
7311 rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
7312 return rc;
7313 }
7314
7315 return VINF_SUCCESS;
7316}
7317
7318/**
7319 * @callback_method_impl{FNSSMDEVLOADEXEC}
7320 */
7321static DECLCALLBACK(int) ahciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
7322{
7323 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7324 uint32_t u32;
7325 int rc;
7326
7327 if ( uVersion > AHCI_SAVED_STATE_VERSION
7328 || uVersion < AHCI_SAVED_STATE_VERSION_VBOX_30)
7329 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
7330
7331 /* Deal with the priod after removing the saved IDE bits where the saved
7332 state version remained unchanged. */
7333 if ( uVersion == AHCI_SAVED_STATE_VERSION_IDE_EMULATION
7334 && SSMR3HandleRevision(pSSM) >= 79045
7335 && SSMR3HandleRevision(pSSM) < 79201)
7336 uVersion++;
7337
7338 /*
7339 * Check whether we have to resort to the legacy port reset method to
7340 * prevent older BIOS versions from failing after a reset.
7341 */
7342 if (uVersion <= AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES)
7343 pThis->fLegacyPortResetMethod = true;
7344
7345 /* Verify config. */
7346 if (uVersion > AHCI_SAVED_STATE_VERSION_VBOX_30)
7347 {
7348 rc = SSMR3GetU32(pSSM, &u32);
7349 AssertRCReturn(rc, rc);
7350 if (u32 != pThis->cPortsImpl)
7351 {
7352 LogRel(("AHCI: Config mismatch: cPortsImpl - saved=%u config=%u\n", u32, pThis->cPortsImpl));
7353 if ( u32 < pThis->cPortsImpl
7354 || u32 > AHCI_MAX_NR_PORTS_IMPL)
7355 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: cPortsImpl - saved=%u config=%u"),
7356 u32, pThis->cPortsImpl);
7357 }
7358
7359 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7360 {
7361 bool fInUse;
7362 rc = SSMR3GetBool(pSSM, &fInUse);
7363 AssertRCReturn(rc, rc);
7364 if (fInUse != (pThis->ahciPort[i].pDrvBase != NULL))
7365 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
7366 N_("The %s VM is missing a device on port %u. Please make sure the source and target VMs have compatible storage configurations"),
7367 fInUse ? "target" : "source", i );
7368
7369 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_HOTPLUG_FLAG)
7370 {
7371 bool fHotpluggable;
7372 rc = SSMR3GetBool(pSSM, &fHotpluggable);
7373 AssertRCReturn(rc, rc);
7374 if (fHotpluggable != pThis->ahciPort[i].fHotpluggable)
7375 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
7376 N_("AHCI: Port %u config mismatch: Hotplug flag - saved=%RTbool config=%RTbool\n"),
7377 i, fHotpluggable, pThis->ahciPort[i].fHotpluggable);
7378 }
7379 else
7380 Assert(pThis->ahciPort[i].fHotpluggable);
7381
7382 char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1];
7383 rc = SSMR3GetStrZ(pSSM, szSerialNumber, sizeof(szSerialNumber));
7384 AssertRCReturn(rc, rc);
7385 if (strcmp(szSerialNumber, pThis->ahciPort[i].szSerialNumber))
7386 LogRel(("AHCI: Port %u config mismatch: Serial number - saved='%s' config='%s'\n",
7387 i, szSerialNumber, pThis->ahciPort[i].szSerialNumber));
7388
7389 char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1];
7390 rc = SSMR3GetStrZ(pSSM, szFirmwareRevision, sizeof(szFirmwareRevision));
7391 AssertRCReturn(rc, rc);
7392 if (strcmp(szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision))
7393 LogRel(("AHCI: Port %u config mismatch: Firmware revision - saved='%s' config='%s'\n",
7394 i, szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision));
7395
7396 char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1];
7397 rc = SSMR3GetStrZ(pSSM, szModelNumber, sizeof(szModelNumber));
7398 AssertRCReturn(rc, rc);
7399 if (strcmp(szModelNumber, pThis->ahciPort[i].szModelNumber))
7400 LogRel(("AHCI: Port %u config mismatch: Model number - saved='%s' config='%s'\n",
7401 i, szModelNumber, pThis->ahciPort[i].szModelNumber));
7402 }
7403
7404 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
7405 for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
7406 {
7407 uint32_t iPort;
7408 rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
7409 AssertRCReturn(rc, rc);
7410
7411 uint32_t iPortSaved;
7412 rc = SSMR3GetU32(pSSM, &iPortSaved);
7413 AssertRCReturn(rc, rc);
7414
7415 if (iPortSaved != iPort)
7416 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IDE %s config mismatch: saved=%u config=%u"),
7417 s_apszIdeEmuPortNames[i], iPortSaved, iPort);
7418 }
7419 }
7420
7421 if (uPass == SSM_PASS_FINAL)
7422 {
7423 /* Restore data. */
7424
7425 /* The main device structure. */
7426 SSMR3GetU32(pSSM, &pThis->regHbaCap);
7427 SSMR3GetU32(pSSM, &pThis->regHbaCtrl);
7428 SSMR3GetU32(pSSM, &pThis->regHbaIs);
7429 SSMR3GetU32(pSSM, &pThis->regHbaPi);
7430 SSMR3GetU32(pSSM, &pThis->regHbaVs);
7431 SSMR3GetU32(pSSM, &pThis->regHbaCccCtl);
7432 SSMR3GetU32(pSSM, &pThis->regHbaCccPorts);
7433 SSMR3GetU8(pSSM, &pThis->uCccPortNr);
7434 SSMR3GetU64(pSSM, &pThis->uCccTimeout);
7435 SSMR3GetU32(pSSM, &pThis->uCccNr);
7436 SSMR3GetU32(pSSM, &pThis->uCccCurrentNr);
7437
7438 SSMR3GetU32(pSSM, (uint32_t *)&pThis->u32PortsInterrupted);
7439 SSMR3GetBool(pSSM, &pThis->fReset);
7440 SSMR3GetBool(pSSM, &pThis->f64BitAddr);
7441 SSMR3GetBool(pSSM, &pThis->fR0Enabled);
7442 SSMR3GetBool(pSSM, &pThis->fGCEnabled);
7443 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES)
7444 SSMR3GetBool(pSSM, &pThis->fLegacyPortResetMethod);
7445
7446 /* Now every port. */
7447 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7448 {
7449 PAHCIPort pAhciPort = &pThis->ahciPort[i];
7450
7451 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLB);
7452 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLBU);
7453 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFB);
7454 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFBU);
7455 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrClb);
7456 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrFb);
7457 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regIS);
7458 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regIE);
7459 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCMD);
7460 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regTFD);
7461 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSIG);
7462 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSSTS);
7463 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSCTL);
7464 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSERR);
7465 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regSACT);
7466 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regCI);
7467 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cCylinders);
7468 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cHeads);
7469 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cSectors);
7470 SSMR3GetU64(pSSM, &pThis->ahciPort[i].cTotalSectors);
7471 SSMR3GetU32(pSSM, &pThis->ahciPort[i].cMultSectors);
7472 SSMR3GetU8(pSSM, &pThis->ahciPort[i].uATATransferMode);
7473 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fResetDevice);
7474
7475 if (uVersion <= AHCI_SAVED_STATE_VERSION_VBOX_30)
7476 SSMR3Skip(pSSM, AHCI_NR_COMMAND_SLOTS * sizeof(uint8_t)); /* no active data here */
7477
7478 if (uVersion < AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7479 {
7480 /* The old positions in the FIFO, not required. */
7481 SSMR3Skip(pSSM, 2*sizeof(uint8_t));
7482 }
7483 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fPoweredOn);
7484 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fSpunUp);
7485 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32TasksFinished);
7486 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32QueuedTasksFinished);
7487
7488 if (uVersion >= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7489 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32CurrentCommandSlot);
7490
7491 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_ATAPI)
7492 {
7493 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fATAPI);
7494 SSMR3GetMem(pSSM, pThis->ahciPort[i].abATAPISense, sizeof(pThis->ahciPort[i].abATAPISense));
7495 SSMR3GetU8(pSSM, &pThis->ahciPort[i].cNotifiedMediaChange);
7496 SSMR3GetU32(pSSM, (uint32_t*)&pThis->ahciPort[i].MediaEventStatus);
7497 }
7498 else if (pThis->ahciPort[i].fATAPI)
7499 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: atapi - saved=false config=true"));
7500
7501 /* Check if we have tasks pending. */
7502 uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished;
7503 uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
7504
7505 pAhciPort->u32TasksNew = fTasksOutstanding | fQueuedTasksOutstanding;
7506
7507 if (pAhciPort->u32TasksNew)
7508 {
7509 /*
7510 * There are tasks pending. The VM was saved after a task failed
7511 * because of non-fatal error. Set the redo flag.
7512 */
7513 pAhciPort->fRedo = true;
7514 }
7515 }
7516
7517 if (uVersion <= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7518 {
7519 for (uint32_t i = 0; i < 2; i++)
7520 {
7521 rc = ahciR3LoadLegacyEmulationState(pSSM);
7522 if(RT_FAILURE(rc))
7523 return rc;
7524 }
7525 }
7526
7527 rc = SSMR3GetU32(pSSM, &u32);
7528 if (RT_FAILURE(rc))
7529 return rc;
7530 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
7531 }
7532
7533 return VINF_SUCCESS;
7534}
7535
7536/* -=-=-=-=- device PDM interface -=-=-=-=- */
7537
7538static DECLCALLBACK(void) ahciR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
7539{
7540 uint32_t i;
7541 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7542
7543 pAhci->pDevInsRC += offDelta;
7544 pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
7545 pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
7546
7547 /* Relocate every port. */
7548 for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7549 {
7550 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
7551 pAhciPort->pAhciRC += offDelta;
7552 pAhciPort->pDevInsRC += offDelta;
7553 }
7554}
7555
7556/**
7557 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium removed" event
7558 * from now on, regardless if there was a medium inserted or not.
7559 */
7560static void ahciMediumRemoved(PAHCIPort pAhciPort)
7561{
7562 ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_MEDIA_REMOVED);
7563}
7564
7565/**
7566 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium inserted". If
7567 * there was already a medium inserted, don't forget to send the "medium
7568 * removed" event first.
7569 */
7570static void ahciMediumInserted(PAHCIPort pAhciPort)
7571{
7572 uint32_t OldStatus, NewStatus;
7573 do
7574 {
7575 OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
7576 switch (OldStatus)
7577 {
7578 case ATA_EVENT_STATUS_MEDIA_CHANGED:
7579 case ATA_EVENT_STATUS_MEDIA_REMOVED:
7580 /* no change, we will send "medium removed" + "medium inserted" */
7581 NewStatus = ATA_EVENT_STATUS_MEDIA_CHANGED;
7582 break;
7583 default:
7584 NewStatus = ATA_EVENT_STATUS_MEDIA_NEW;
7585 break;
7586 }
7587 } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
7588}
7589
7590/**
7591 * Called when a media is mounted.
7592 *
7593 * @param pInterface Pointer to the interface structure containing the called function pointer.
7594 */
7595static DECLCALLBACK(void) ahciR3MountNotify(PPDMIMOUNTNOTIFY pInterface)
7596{
7597 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
7598 Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
7599
7600 /* Ignore the call if we're called while being attached. */
7601 if (!pAhciPort->pDrvMedia)
7602 return;
7603
7604 if (pAhciPort->fATAPI)
7605 {
7606 pAhciPort->cTotalSectors = pAhciPort->pDrvMedia->pfnGetSize(pAhciPort->pDrvMedia) / 2048;
7607
7608 LogRel(("AHCI: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
7609
7610 /* Report media changed in TEST UNIT and other (probably incorrect) places. */
7611 if (pAhciPort->cNotifiedMediaChange < 2)
7612 pAhciPort->cNotifiedMediaChange = 2;
7613 ahciMediumInserted(pAhciPort);
7614 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7615 }
7616 else
7617 AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
7618}
7619
7620/**
7621 * Called when a media is unmounted
7622 * @param pInterface Pointer to the interface structure containing the called function pointer.
7623 */
7624static DECLCALLBACK(void) ahciR3UnmountNotify(PPDMIMOUNTNOTIFY pInterface)
7625{
7626 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
7627 Log(("%s:\n", __FUNCTION__));
7628
7629 /* Free all cached I/O tasks. */
7630 ahciR3PortCachedReqsFree(pAhciPort);
7631
7632 pAhciPort->cTotalSectors = 0;
7633
7634 if (pAhciPort->fATAPI)
7635 {
7636 /*
7637 * Whatever I do, XP will not use the GET MEDIA STATUS nor the EVENT stuff.
7638 * However, it will respond to TEST UNIT with a 0x6 0x28 (media changed) sense code.
7639 * So, we'll give it 4 TEST UNIT command to catch up, two which the media is not
7640 * present and 2 in which it is changed.
7641 */
7642 pAhciPort->cNotifiedMediaChange = 4;
7643 ahciMediumRemoved(pAhciPort);
7644 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7645 }
7646 else
7647 AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
7648}
7649
7650/**
7651 * Configure the attached device for a port.
7652 *
7653 * Used by ahciR3Construct and ahciR3Attach.
7654 *
7655 * @returns VBox status code
7656 * @param pDevIns The device instance data.
7657 * @param pAhciPort The port for which the device is to be configured.
7658 */
7659static int ahciR3ConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
7660{
7661 int rc = VINF_SUCCESS;
7662 PDMMEDIATYPE enmType;
7663
7664 /*
7665 * Query the block and blockbios interfaces.
7666 */
7667 pAhciPort->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMEDIA);
7668 if (!pAhciPort->pDrvMedia)
7669 {
7670 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
7671 return VERR_PDM_MISSING_INTERFACE;
7672 }
7673
7674 pAhciPort->pDrvMount = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMOUNT);
7675
7676 /* Try to get the optional async block interface. */
7677 pAhciPort->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMEDIAASYNC);
7678
7679 /*
7680 * Validate type.
7681 */
7682 enmType = pAhciPort->pDrvMedia->pfnGetType(pAhciPort->pDrvMedia);
7683
7684 if ( enmType != PDMMEDIATYPE_HARD_DISK
7685 && enmType != PDMMEDIATYPE_CDROM
7686 && enmType != PDMMEDIATYPE_DVD)
7687 {
7688 AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
7689 return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
7690 }
7691
7692 if ( (enmType == PDMMEDIATYPE_CDROM || enmType == PDMMEDIATYPE_DVD)
7693 && !pAhciPort->pDrvMount)
7694 {
7695 AssertMsgFailed(("Internal error: CD/DVD-ROM without a mountable interface\n"));
7696 return VERR_INTERNAL_ERROR;
7697 }
7698 pAhciPort->fATAPI = (enmType == PDMMEDIATYPE_CDROM || enmType == PDMMEDIATYPE_DVD);
7699 pAhciPort->fATAPIPassthrough = pAhciPort->fATAPI ? (pAhciPort->pDrvMedia->pfnSendCmd != NULL) : false;
7700
7701 rc = RTCritSectInit(&pAhciPort->CritSectReqsFree);
7702 if (RT_FAILURE(rc))
7703 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
7704 N_("AHCI initialisation error: Failed to create critical section for free request list"));
7705
7706 pAhciPort->pListReqsFree = (PRTLISTANCHOR)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(RTLISTANCHOR));
7707 if (!pAhciPort->pListReqsFree)
7708 return PDMDevHlpVMSetError(pDevIns, VERR_NO_MEMORY, RT_SRC_POS,
7709 N_("AHCI initialisation error: Failed to allocate memory for free request list"));
7710
7711 RTListInit(pAhciPort->pListReqsFree);
7712
7713 if (pAhciPort->fATAPI)
7714 {
7715 pAhciPort->cTotalSectors = pAhciPort->pDrvMedia->pfnGetSize(pAhciPort->pDrvMedia) / 2048;
7716 pAhciPort->PCHSGeometry.cCylinders = 0;
7717 pAhciPort->PCHSGeometry.cHeads = 0;
7718 pAhciPort->PCHSGeometry.cSectors = 0;
7719 LogRel(("AHCI: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pAhciPort->iLUN,
7720 pAhciPort->cTotalSectors, (pAhciPort->fATAPIPassthrough ? "enabled" : "disabled")));
7721 }
7722 else
7723 {
7724 pAhciPort->cbSector = pAhciPort->pDrvMedia->pfnGetSectorSize(pAhciPort->pDrvMedia);
7725 pAhciPort->cTotalSectors = pAhciPort->pDrvMedia->pfnGetSize(pAhciPort->pDrvMedia) / pAhciPort->cbSector;
7726 rc = pAhciPort->pDrvMedia->pfnBiosGetPCHSGeometry(pAhciPort->pDrvMedia, &pAhciPort->PCHSGeometry);
7727 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
7728 {
7729 pAhciPort->PCHSGeometry.cCylinders = 0;
7730 pAhciPort->PCHSGeometry.cHeads = 16; /*??*/
7731 pAhciPort->PCHSGeometry.cSectors = 63; /*??*/
7732 }
7733 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
7734 {
7735 pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
7736 rc = VINF_SUCCESS;
7737 }
7738 AssertRC(rc);
7739
7740 if ( pAhciPort->PCHSGeometry.cCylinders == 0
7741 || pAhciPort->PCHSGeometry.cHeads == 0
7742 || pAhciPort->PCHSGeometry.cSectors == 0)
7743 {
7744 uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
7745 pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
7746 pAhciPort->PCHSGeometry.cHeads = 16;
7747 pAhciPort->PCHSGeometry.cSectors = 63;
7748 /* Set the disk geometry information. Ignore errors. */
7749 pAhciPort->pDrvMedia->pfnBiosSetPCHSGeometry(pAhciPort->pDrvMedia, &pAhciPort->PCHSGeometry);
7750 rc = VINF_SUCCESS;
7751 }
7752 LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
7753 pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
7754 pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
7755 pAhciPort->cTotalSectors));
7756 if (pAhciPort->pDrvMedia->pfnDiscard)
7757 LogRel(("AHCI: LUN#%d: Enabled TRIM support\n", pAhciPort->iLUN));
7758 }
7759 return rc;
7760}
7761
7762/**
7763 * Callback employed by ahciR3Suspend and ahciR3PowerOff..
7764 *
7765 * @returns true if we've quiesced, false if we're still working.
7766 * @param pDevIns The device instance.
7767 */
7768static DECLCALLBACK(bool) ahciR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
7769{
7770 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7771 return false;
7772
7773 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7774 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7775 /*
7776 * Free all cached tasks here, not possible on destruct because the driver
7777 * is destroyed before us.
7778 */
7779 for (unsigned iPort = 0; iPort < pThis->cPortsImpl; iPort++)
7780 ahciR3PortCachedReqsFree(&pThis->ahciPort[iPort]);
7781 return true;
7782}
7783
7784/**
7785 * Common worker for ahciR3Suspend and ahciR3PowerOff.
7786 */
7787static void ahciR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
7788{
7789 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7790
7791 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
7792 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7793 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncSuspendOrPowerOffDone);
7794 else
7795 {
7796 /*
7797 * Free all cached tasks here, not possible on destruct because the driver
7798 * is destroyed before us.
7799 */
7800 for (unsigned iPort = 0; iPort < pThis->cPortsImpl; iPort++)
7801 ahciR3PortCachedReqsFree(&pThis->ahciPort[iPort]);
7802
7803 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7804 }
7805}
7806
7807/**
7808 * Suspend notification.
7809 *
7810 * @param pDevIns The device instance data.
7811 */
7812static DECLCALLBACK(void) ahciR3Suspend(PPDMDEVINS pDevIns)
7813{
7814 Log(("ahciR3Suspend\n"));
7815 ahciR3SuspendOrPowerOff(pDevIns);
7816}
7817
7818/**
7819 * Resume notification.
7820 *
7821 * @param pDevIns The device instance data.
7822 */
7823static DECLCALLBACK(void) ahciR3Resume(PPDMDEVINS pDevIns)
7824{
7825 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7826
7827 /*
7828 * Check if one of the ports has pending tasks.
7829 * Queue a notification item again in this case.
7830 */
7831 for (unsigned i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7832 {
7833 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
7834
7835 if (pAhciPort->u32TasksRedo)
7836 {
7837 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
7838 AssertMsg(pItem, ("Allocating item for queue failed\n"));
7839
7840 pAhciPort->u32TasksNew |= pAhciPort->u32TasksRedo;
7841 pAhciPort->u32TasksRedo = 0;
7842
7843 Assert(pAhciPort->fRedo);
7844 pAhciPort->fRedo = false;
7845
7846 pItem->iPort = pAhci->ahciPort[i].iLUN;
7847 PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
7848 }
7849 }
7850
7851 Log(("%s:\n", __FUNCTION__));
7852}
7853
7854/**
7855 * Initializes the VPD data of a attached device.
7856 *
7857 * @returns VBox status code.
7858 * @param pDevIns The device instance.
7859 * @param pAhciPort The attached device.
7860 * @param szName Name of the port to get the CFGM node.
7861 */
7862static int ahciR3VpdInit(PPDMDEVINS pDevIns, PAHCIPort pAhciPort, const char *pszName)
7863{
7864 int rc = VINF_SUCCESS;
7865 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7866
7867 /* Generate a default serial number. */
7868 char szSerial[AHCI_SERIAL_NUMBER_LENGTH+1];
7869 RTUUID Uuid;
7870
7871 if (pAhciPort->pDrvMedia)
7872 rc = pAhciPort->pDrvMedia->pfnGetUuid(pAhciPort->pDrvMedia, &Uuid);
7873 else
7874 RTUuidClear(&Uuid);
7875
7876 if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
7877 {
7878 /* Generate a predictable serial for drives which don't have a UUID. */
7879 RTStrPrintf(szSerial, sizeof(szSerial), "VB%x-1a2b3c4d",
7880 pAhciPort->iLUN);
7881 }
7882 else
7883 RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
7884
7885 /* Get user config if present using defaults otherwise. */
7886 PCFGMNODE pCfgNode = CFGMR3GetChild(pDevIns->pCfg, pszName);
7887 rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
7888 szSerial);
7889 if (RT_FAILURE(rc))
7890 {
7891 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7892 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7893 N_("AHCI configuration error: \"SerialNumber\" is longer than 20 bytes"));
7894 return PDMDEV_SET_ERROR(pDevIns, rc,
7895 N_("AHCI configuration error: failed to read \"SerialNumber\" as string"));
7896 }
7897
7898 rc = CFGMR3QueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision, sizeof(pAhciPort->szFirmwareRevision),
7899 "1.0");
7900 if (RT_FAILURE(rc))
7901 {
7902 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7903 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7904 N_("AHCI configuration error: \"FirmwareRevision\" is longer than 8 bytes"));
7905 return PDMDEV_SET_ERROR(pDevIns, rc,
7906 N_("AHCI configuration error: failed to read \"FirmwareRevision\" as string"));
7907 }
7908
7909 rc = CFGMR3QueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
7910 pAhciPort->fATAPI ? "VBOX CD-ROM" : "VBOX HARDDISK");
7911 if (RT_FAILURE(rc))
7912 {
7913 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7914 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7915 N_("AHCI configuration error: \"ModelNumber\" is longer than 40 bytes"));
7916 return PDMDEV_SET_ERROR(pDevIns, rc,
7917 N_("AHCI configuration error: failed to read \"ModelNumber\" as string"));
7918 }
7919
7920 rc = CFGMR3QueryBoolDef(pCfgNode, "NonRotationalMedium", &pAhciPort->fNonRotational, false);
7921 if (RT_FAILURE(rc))
7922 return PDMDEV_SET_ERROR(pDevIns, rc,
7923 N_("AHCI configuration error: failed to read \"NonRotationalMedium\" as boolean"));
7924
7925 rc = CFGMR3QueryU8Def(pCfgNode, "LogicalSectorsPerPhysical", &pAhciPort->cLogSectorsPerPhysicalExp, 0);
7926 if (RT_FAILURE(rc))
7927 return PDMDEV_SET_ERROR(pDevIns, rc,
7928 N_("AHCI configuration error: failed to read \"LogicalSectorsPerPhysical\" as integer"));
7929 if (pAhciPort->cLogSectorsPerPhysicalExp >= 16)
7930 return PDMDEV_SET_ERROR(pDevIns, rc,
7931 N_("AHCI configuration error: \"LogicalSectorsPerPhysical\" must be between 0 and 15"));
7932
7933 /* There are three other identification strings for CD drives used for INQUIRY */
7934 if (pAhciPort->fATAPI)
7935 {
7936 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIVendorId", pAhciPort->szInquiryVendorId, sizeof(pAhciPort->szInquiryVendorId),
7937 "VBOX");
7938 if (RT_FAILURE(rc))
7939 {
7940 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7941 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7942 N_("AHCI configuration error: \"ATAPIVendorId\" is longer than 16 bytes"));
7943 return PDMDEV_SET_ERROR(pDevIns, rc,
7944 N_("AHCI configuration error: failed to read \"ATAPIVendorId\" as string"));
7945 }
7946
7947 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIProductId", pAhciPort->szInquiryProductId, sizeof(pAhciPort->szInquiryProductId),
7948 "CD-ROM");
7949 if (RT_FAILURE(rc))
7950 {
7951 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7952 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7953 N_("AHCI configuration error: \"ATAPIProductId\" is longer than 16 bytes"));
7954 return PDMDEV_SET_ERROR(pDevIns, rc,
7955 N_("AHCI configuration error: failed to read \"ATAPIProductId\" as string"));
7956 }
7957
7958 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIRevision", pAhciPort->szInquiryRevision, sizeof(pAhciPort->szInquiryRevision),
7959 "1.0");
7960 if (RT_FAILURE(rc))
7961 {
7962 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7963 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7964 N_("AHCI configuration error: \"ATAPIRevision\" is longer than 4 bytes"));
7965 return PDMDEV_SET_ERROR(pDevIns, rc,
7966 N_("AHCI configuration error: failed to read \"ATAPIRevision\" as string"));
7967 }
7968 }
7969
7970 return rc;
7971}
7972
7973
7974/**
7975 * Detach notification.
7976 *
7977 * One harddisk at one port has been unplugged.
7978 * The VM is suspended at this point.
7979 *
7980 * @param pDevIns The device instance.
7981 * @param iLUN The logical unit which is being detached.
7982 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
7983 */
7984static DECLCALLBACK(void) ahciR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
7985{
7986 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7987 PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
7988 int rc = VINF_SUCCESS;
7989
7990 Log(("%s:\n", __FUNCTION__));
7991
7992 AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
7993 AssertMsgReturnVoid( pAhciPort->fHotpluggable
7994 || (fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
7995 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN));
7996
7997
7998 if (pAhciPort->pAsyncIOThread)
7999 {
8000 int rcThread;
8001 /* Destroy the thread. */
8002 rc = PDMR3ThreadDestroy(pAhciPort->pAsyncIOThread, &rcThread);
8003 if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
8004 AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
8005
8006 pAhciPort->pAsyncIOThread = NULL;
8007 pAhciPort->fWrkThreadSleeping = true;
8008 }
8009
8010 if (pAhciPort->fATAPI)
8011 ahciMediumRemoved(pAhciPort);
8012
8013 /* Free all cached I/O tasks. */
8014 ahciR3PortCachedReqsFree(pAhciPort);
8015
8016 if (RTCritSectIsInitialized(&pAhciPort->CritSectReqsFree))
8017 RTCritSectDelete(&pAhciPort->CritSectReqsFree);
8018
8019 if (pAhciPort->pListReqsFree)
8020 MMR3HeapFree(pAhciPort->pListReqsFree);
8021
8022 pAhciPort->pListReqsFree = NULL;
8023
8024 if (!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
8025 {
8026 /*
8027 * Inform the guest about the removed device.
8028 */
8029 pAhciPort->regSSTS = 0;
8030 pAhciPort->regSIG = 0;
8031 /*
8032 * Clear CR bit too to prevent submission of new commands when CI is written
8033 * (AHCI Spec 1.2: 7.4 Interaction of the Command List and Port Change Status).
8034 */
8035 ASMAtomicAndU32(&pAhciPort->regCMD, ~(AHCI_PORT_CMD_CPS | AHCI_PORT_CMD_CR));
8036 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
8037 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
8038 if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
8039 || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
8040 || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
8041 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
8042 }
8043
8044 /*
8045 * Zero some important members.
8046 */
8047 pAhciPort->pDrvBase = NULL;
8048 pAhciPort->pDrvMedia = NULL;
8049 pAhciPort->pDrvMediaAsync = NULL;
8050}
8051
8052/**
8053 * Attach command.
8054 *
8055 * This is called when we change block driver for one port.
8056 * The VM is suspended at this point.
8057 *
8058 * @returns VBox status code.
8059 * @param pDevIns The device instance.
8060 * @param iLUN The logical unit which is being detached.
8061 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
8062 */
8063static DECLCALLBACK(int) ahciR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
8064{
8065 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8066 PAHCIPort pAhciPort = &pThis->ahciPort[iLUN];
8067 int rc;
8068
8069 Log(("%s:\n", __FUNCTION__));
8070
8071 /* the usual paranoia */
8072 AssertMsg(iLUN < pThis->cPortsImpl, ("iLUN=%u", iLUN));
8073 AssertRelease(!pAhciPort->pDrvBase);
8074 AssertRelease(!pAhciPort->pDrvMedia);
8075 AssertRelease(!pAhciPort->pDrvMediaAsync);
8076 Assert(pAhciPort->iLUN == iLUN);
8077
8078 AssertMsgReturn( pAhciPort->fHotpluggable
8079 || (fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
8080 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
8081 VERR_INVALID_PARAMETER);
8082
8083 /*
8084 * Try attach the block device and get the interfaces,
8085 * required as well as optional.
8086 */
8087 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, NULL);
8088 if (RT_SUCCESS(rc))
8089 {
8090 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
8091
8092 /*
8093 * In case there is a medium inserted.
8094 */
8095 ahciMediumInserted(pAhciPort);
8096 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
8097 }
8098 else
8099 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pAhciPort->iLUN, rc));
8100
8101 if (RT_FAILURE(rc))
8102 {
8103 pAhciPort->pDrvBase = NULL;
8104 pAhciPort->pDrvMedia = NULL;
8105 }
8106 else
8107 {
8108 char szName[24];
8109 RTStrPrintf(szName, sizeof(szName), "Port%d", iLUN);
8110
8111 if ( pAhciPort->pDrvMediaAsync
8112 && !pAhciPort->fATAPI)
8113 pAhciPort->fAsyncInterface = true;
8114 else
8115 pAhciPort->fAsyncInterface = false;
8116
8117 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pAhciPort->hEvtProcess);
8118 if (RT_FAILURE(rc))
8119 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8120 N_("AHCI: Failed to create SUP event semaphore"));
8121
8122 /* Create the async IO thread. */
8123 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
8124 RTTHREADTYPE_IO, szName);
8125 if (RT_FAILURE(rc))
8126 return rc;
8127
8128 /*
8129 * Init vendor product data.
8130 */
8131 if (RT_SUCCESS(rc))
8132 rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
8133
8134 /* Inform the guest about the added device in case of hotplugging. */
8135 if ( RT_SUCCESS(rc)
8136 && !(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
8137 {
8138 AssertMsgReturn(pAhciPort->fHotpluggable,
8139 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
8140 VERR_NOT_SUPPORTED);
8141
8142 /*
8143 * Initialize registers
8144 */
8145 ASMAtomicOrU32(&pAhciPort->regCMD, AHCI_PORT_CMD_CPS);
8146 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
8147 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
8148
8149 if (pAhciPort->fATAPI)
8150 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
8151 else
8152 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
8153 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
8154 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
8155 (0x03 << 0); /* Device detected and communication established. */
8156
8157 if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
8158 || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
8159 || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
8160 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
8161 }
8162
8163 }
8164
8165 return rc;
8166}
8167
8168/**
8169 * Common reset worker.
8170 *
8171 * @param pDevIns The device instance data.
8172 */
8173static int ahciR3ResetCommon(PPDMDEVINS pDevIns, bool fConstructor)
8174{
8175 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
8176
8177 ahciHBAReset(pAhci);
8178
8179 /* Hardware reset for the ports. */
8180 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
8181 ahciPortHwReset(&pAhci->ahciPort[i]);
8182 return VINF_SUCCESS;
8183}
8184
8185/**
8186 * Callback employed by ahciR3Reset.
8187 *
8188 * @returns true if we've quiesced, false if we're still working.
8189 * @param pDevIns The device instance.
8190 */
8191static DECLCALLBACK(bool) ahciR3IsAsyncResetDone(PPDMDEVINS pDevIns)
8192{
8193 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8194
8195 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
8196 return false;
8197 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
8198
8199 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
8200 return true;
8201}
8202
8203/**
8204 * Reset notification.
8205 *
8206 * @param pDevIns The device instance data.
8207 */
8208static DECLCALLBACK(void) ahciR3Reset(PPDMDEVINS pDevIns)
8209{
8210 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8211
8212 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
8213 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
8214 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncResetDone);
8215 else
8216 {
8217 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
8218 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
8219 }
8220}
8221
8222/**
8223 * Poweroff notification.
8224 *
8225 * @param pDevIns Pointer to the device instance
8226 */
8227static DECLCALLBACK(void) ahciR3PowerOff(PPDMDEVINS pDevIns)
8228{
8229 Log(("achiR3PowerOff\n"));
8230 ahciR3SuspendOrPowerOff(pDevIns);
8231}
8232
8233/**
8234 * Destroy a driver instance.
8235 *
8236 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
8237 * resources can be freed correctly.
8238 *
8239 * @param pDevIns The device instance data.
8240 */
8241static DECLCALLBACK(int) ahciR3Destruct(PPDMDEVINS pDevIns)
8242{
8243 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8244 int rc = VINF_SUCCESS;
8245 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
8246
8247 /*
8248 * At this point the async I/O thread is suspended and will not enter
8249 * this module again. So, no coordination is needed here and PDM
8250 * will take care of terminating and cleaning up the thread.
8251 */
8252 if (PDMCritSectIsInitialized(&pThis->lock))
8253 {
8254 TMR3TimerDestroy(pThis->CTX_SUFF(pHbaCccTimer));
8255 pThis->CTX_SUFF(pHbaCccTimer) = NULL;
8256
8257 Log(("%s: Destruct every port\n", __FUNCTION__));
8258 for (unsigned iActPort = 0; iActPort < pThis->cPortsImpl; iActPort++)
8259 {
8260 PAHCIPort pAhciPort = &pThis->ahciPort[iActPort];
8261
8262 if (pAhciPort->hEvtProcess != NIL_SUPSEMEVENT)
8263 {
8264 SUPSemEventClose(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
8265 pAhciPort->hEvtProcess = NIL_SUPSEMEVENT;
8266 }
8267
8268 if (RTCritSectIsInitialized(&pAhciPort->CritSectReqsFree))
8269 RTCritSectDelete(&pAhciPort->CritSectReqsFree);
8270
8271#ifdef VBOX_STRICT
8272 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
8273 Assert(!pAhciPort->aActiveTasks[i]);
8274#endif
8275 }
8276
8277 PDMR3CritSectDelete(&pThis->lock);
8278 }
8279
8280 return rc;
8281}
8282
8283/**
8284 * @interface_method_impl{PDMDEVREG,pfnConstruct}
8285 */
8286static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
8287{
8288 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8289 PPDMIBASE pBase;
8290 int rc = VINF_SUCCESS;
8291 unsigned i = 0;
8292 bool fGCEnabled = false;
8293 bool fR0Enabled = false;
8294 uint32_t cbTotalBufferSize = 0;
8295 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
8296
8297 LogFlowFunc(("pThis=%#p\n", pThis));
8298
8299 /*
8300 * Validate and read configuration.
8301 */
8302 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0"
8303 "R0Enabled\0"
8304 "PrimaryMaster\0"
8305 "PrimarySlave\0"
8306 "SecondaryMaster\0"
8307 "SecondarySlave\0"
8308 "PortCount\0"
8309 "UseAsyncInterfaceIfAvailable\0"
8310 "Bootable\0"
8311 "CmdSlotsAvail\0"))
8312 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
8313 N_("AHCI configuration error: unknown option specified"));
8314
8315 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
8316 if (RT_FAILURE(rc))
8317 return PDMDEV_SET_ERROR(pDevIns, rc,
8318 N_("AHCI configuration error: failed to read GCEnabled as boolean"));
8319 Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
8320
8321 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
8322 if (RT_FAILURE(rc))
8323 return PDMDEV_SET_ERROR(pDevIns, rc,
8324 N_("AHCI configuration error: failed to read R0Enabled as boolean"));
8325 Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
8326
8327 rc = CFGMR3QueryU32Def(pCfg, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
8328 if (RT_FAILURE(rc))
8329 return PDMDEV_SET_ERROR(pDevIns, rc,
8330 N_("AHCI configuration error: failed to read PortCount as integer"));
8331 Log(("%s: cPortsImpl=%u\n", __FUNCTION__, pThis->cPortsImpl));
8332 if (pThis->cPortsImpl > AHCI_MAX_NR_PORTS_IMPL)
8333 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8334 N_("AHCI configuration error: PortCount=%u should not exceed %u"),
8335 pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
8336 if (pThis->cPortsImpl < 1)
8337 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8338 N_("AHCI configuration error: PortCount=%u should be at least 1"),
8339 pThis->cPortsImpl);
8340
8341 rc = CFGMR3QueryBoolDef(pCfg, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
8342 if (RT_FAILURE(rc))
8343 return PDMDEV_SET_ERROR(pDevIns, rc,
8344 N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
8345
8346 rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &pThis->fBootable, true);
8347 if (RT_FAILURE(rc))
8348 return PDMDEV_SET_ERROR(pDevIns, rc,
8349 N_("AHCI configuration error: failed to read Bootable as boolean"));
8350
8351 rc = CFGMR3QueryU32Def(pCfg, "CmdSlotsAvail", &pThis->cCmdSlotsAvail, AHCI_NR_COMMAND_SLOTS);
8352 if (RT_FAILURE(rc))
8353 return PDMDEV_SET_ERROR(pDevIns, rc,
8354 N_("AHCI configuration error: failed to read CmdSlotsAvail as integer"));
8355 Log(("%s: cCmdSlotsAvail=%u\n", __FUNCTION__, pThis->cCmdSlotsAvail));
8356 if (pThis->cCmdSlotsAvail > AHCI_NR_COMMAND_SLOTS)
8357 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8358 N_("AHCI configuration error: CmdSlotsAvail=%u should not exceed %u"),
8359 pThis->cPortsImpl, AHCI_NR_COMMAND_SLOTS);
8360 if (pThis->cCmdSlotsAvail < 1)
8361 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8362 N_("AHCI configuration error: CmdSlotsAvail=%u should be at least 1"),
8363 pThis->cCmdSlotsAvail);
8364
8365 /*
8366 * Initialize the instance data (everything touched by the destructor need
8367 * to be initialized here!).
8368 */
8369 pThis->fR0Enabled = fR0Enabled;
8370 pThis->fGCEnabled = fGCEnabled;
8371 pThis->pDevInsR3 = pDevIns;
8372 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
8373 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
8374 pThis->pSupDrvSession = PDMDevHlpGetSupDrvSession(pDevIns);
8375
8376 PCIDevSetVendorId (&pThis->dev, 0x8086); /* Intel */
8377 PCIDevSetDeviceId (&pThis->dev, 0x2829); /* ICH-8M */
8378 PCIDevSetCommand (&pThis->dev, 0x0000);
8379#ifdef VBOX_WITH_MSI_DEVICES
8380 PCIDevSetStatus (&pThis->dev, VBOX_PCI_STATUS_CAP_LIST);
8381 PCIDevSetCapabilityList(&pThis->dev, 0x80);
8382#else
8383 PCIDevSetCapabilityList(&pThis->dev, 0x70);
8384#endif
8385 PCIDevSetRevisionId (&pThis->dev, 0x02);
8386 PCIDevSetClassProg (&pThis->dev, 0x01);
8387 PCIDevSetClassSub (&pThis->dev, 0x06);
8388 PCIDevSetClassBase (&pThis->dev, 0x01);
8389 PCIDevSetBaseAddress (&pThis->dev, 5, false, false, false, 0x00000000);
8390
8391 PCIDevSetInterruptLine(&pThis->dev, 0x00);
8392 PCIDevSetInterruptPin (&pThis->dev, 0x01);
8393
8394 pThis->dev.config[0x70] = VBOX_PCI_CAP_ID_PM; /* Capability ID: PCI Power Management Interface */
8395 pThis->dev.config[0x71] = 0xa8; /* next */
8396 pThis->dev.config[0x72] = 0x03; /* version ? */
8397
8398 pThis->dev.config[0x90] = 0x40; /* AHCI mode. */
8399 pThis->dev.config[0x92] = 0x3f;
8400 pThis->dev.config[0x94] = 0x80;
8401 pThis->dev.config[0x95] = 0x01;
8402 pThis->dev.config[0x97] = 0x78;
8403
8404 pThis->dev.config[0xa8] = 0x12; /* SATACR capability */
8405 pThis->dev.config[0xa9] = 0x00; /* next */
8406 PCIDevSetWord(&pThis->dev, 0xaa, 0x0010); /* Revision */
8407 PCIDevSetDWord(&pThis->dev, 0xac, 0x00000028); /* SATA Capability Register 1 */
8408
8409 pThis->cThreadsActive = 0;
8410
8411 /* Initialize port members. */
8412 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
8413 {
8414 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8415 pAhciPort->pDevInsR3 = pDevIns;
8416 pAhciPort->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
8417 pAhciPort->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
8418 pAhciPort->iLUN = i;
8419 pAhciPort->pAhciR3 = pThis;
8420 pAhciPort->pAhciR0 = PDMINS_2_DATA_R0PTR(pDevIns);
8421 pAhciPort->pAhciRC = PDMINS_2_DATA_RCPTR(pDevIns);
8422 pAhciPort->Led.u32Magic = PDMLED_MAGIC;
8423 pAhciPort->pDrvBase = NULL;
8424 pAhciPort->pAsyncIOThread = NULL;
8425 pAhciPort->hEvtProcess = NIL_SUPSEMEVENT;
8426 pAhciPort->fHotpluggable = true;
8427 }
8428
8429 /*
8430 * Init locks, using explicit locking where necessary.
8431 */
8432 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
8433 if (RT_FAILURE(rc))
8434 return rc;
8435
8436 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, RT_SRC_POS, "AHCI#%u", iInstance);
8437 if (RT_FAILURE(rc))
8438 {
8439 Log(("%s: Failed to create critical section.\n", __FUNCTION__));
8440 return rc;
8441 }
8442
8443 /*
8444 * Register the PCI device, it's I/O regions.
8445 */
8446 rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev);
8447 if (RT_FAILURE(rc))
8448 return rc;
8449
8450#ifdef VBOX_WITH_MSI_DEVICES
8451 PDMMSIREG MsiReg;
8452 RT_ZERO(MsiReg);
8453 MsiReg.cMsiVectors = 1;
8454 MsiReg.iMsiCapOffset = 0x80;
8455 MsiReg.iMsiNextOffset = 0x70;
8456 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
8457 if (RT_FAILURE(rc))
8458 {
8459 PCIDevSetCapabilityList(&pThis->dev, 0x70);
8460 /* That's OK, we can work without MSI */
8461 }
8462#endif
8463
8464 /*
8465 * Solaris 10 U5 fails to map the AHCI register space when the sets (0..5) for the legacy
8466 * IDE registers are not available.
8467 * We set up "fake" entries in the PCI configuration register.
8468 * That means they are available but read and writes from/to them have no effect.
8469 * No guest should access them anyway because the controller is marked as AHCI in the Programming interface
8470 * and we don't have an option to change to IDE emulation (real hardware provides an option in the BIOS
8471 * to switch to it which also changes device Id and other things in the PCI configuration space).
8472 */
8473 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8474 if (RT_FAILURE(rc))
8475 return PDMDEV_SET_ERROR(pDevIns, rc,
8476 N_("AHCI cannot register PCI I/O region"));
8477
8478 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8479 if (RT_FAILURE(rc))
8480 return PDMDEV_SET_ERROR(pDevIns, rc,
8481 N_("AHCI cannot register PCI I/O region"));
8482
8483 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8484 if (RT_FAILURE(rc))
8485 return PDMDEV_SET_ERROR(pDevIns, rc,
8486 N_("AHCI cannot register PCI I/O region"));
8487
8488 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8489 if (RT_FAILURE(rc))
8490 return PDMDEV_SET_ERROR(pDevIns, rc,
8491 N_("AHCI cannot register PCI I/O region"));
8492
8493 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciR3IdxDataIORangeMap);
8494 if (RT_FAILURE(rc))
8495 return PDMDEV_SET_ERROR(pDevIns, rc,
8496 N_("AHCI cannot register PCI I/O region for BMDMA"));
8497
8498 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciR3MMIOMap);
8499 if (RT_FAILURE(rc))
8500 return PDMDEV_SET_ERROR(pDevIns, rc,
8501 N_("AHCI cannot register PCI memory region for registers"));
8502
8503 /* Create the timer for command completion coalescing feature. */
8504 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ahciCccTimer, pThis,
8505 TMTIMER_FLAGS_NO_CRIT_SECT, "AHCI CCC Timer", &pThis->pHbaCccTimerR3);
8506 if (RT_FAILURE(rc))
8507 {
8508 AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
8509 return rc;
8510 }
8511 pThis->pHbaCccTimerR0 = TMTimerR0Ptr(pThis->pHbaCccTimerR3);
8512 pThis->pHbaCccTimerRC = TMTimerRCPtr(pThis->pHbaCccTimerR3);
8513
8514 /* Status LUN. */
8515 pThis->IBase.pfnQueryInterface = ahciR3Status_QueryInterface;
8516 pThis->ILeds.pfnQueryStatusLed = ahciR3Status_QueryStatusLed;
8517
8518 /*
8519 * Create the notification queue.
8520 *
8521 * We need 2 items for every port because of SMP races.
8522 */
8523 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), AHCI_MAX_NR_PORTS_IMPL * 2, 0,
8524 ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
8525 if (RT_FAILURE(rc))
8526 return rc;
8527 pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
8528 pThis->pNotifierQueueRC = PDMQueueRCPtr(pThis->pNotifierQueueR3);
8529
8530 /* Initialize static members on every port. */
8531 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
8532 {
8533 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8534
8535 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatDMA, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
8536 "Number of DMA transfers.", "/Devices/SATA%d/Port%d/DMA", iInstance, i);
8537 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
8538 "Amount of data read.", "/Devices/SATA%d/Port%d/ReadBytes", iInstance, i);
8539 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
8540 "Amount of data written.", "/Devices/SATA%d/Port%d/WrittenBytes", iInstance, i);
8541 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
8542 "Number of processed I/O requests per second.", "/Devices/SATA%d/Port%d/IORequestsPerSecond", iInstance, i);
8543#ifdef VBOX_WITH_STATISTICS
8544 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileProcessTime, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8545 "Amount of time to process one request.", "/Devices/SATA%d/Port%d/ProfileProcessTime", iInstance, i);
8546 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileReadWrite, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8547 "Amount of time for the read/write operation to complete.", "/Devices/SATA%d/Port%d/ProfileReadWrite", iInstance, i);
8548#endif
8549
8550 ahciPortHwReset(pAhciPort);
8551 }
8552
8553 /* Attach drivers to every available port. */
8554 for (i = 0; i < pThis->cPortsImpl; i++)
8555 {
8556 char szName[24];
8557 RTStrPrintf(szName, sizeof(szName), "Port%u", i);
8558
8559 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8560 /*
8561 * Init interfaces.
8562 */
8563 pAhciPort->IBase.pfnQueryInterface = ahciR3PortQueryInterface;
8564 pAhciPort->IPortAsync.pfnTransferCompleteNotify = ahciR3TransferCompleteNotify;
8565 pAhciPort->IPort.pfnQueryDeviceLocation = ahciR3PortQueryDeviceLocation;
8566 pAhciPort->IMountNotify.pfnMountNotify = ahciR3MountNotify;
8567 pAhciPort->IMountNotify.pfnUnmountNotify = ahciR3UnmountNotify;
8568 pAhciPort->fWrkThreadSleeping = true;
8569
8570 /* Query per port configuration options if available. */
8571 PCFGMNODE pCfgPort = CFGMR3GetChild(pDevIns->pCfg, szName);
8572 if (pCfgPort)
8573 {
8574 rc = CFGMR3QueryBoolDef(pCfgPort, "Hotpluggable", &pAhciPort->fHotpluggable, true);
8575 if (RT_FAILURE(rc))
8576 return PDMDEV_SET_ERROR(pDevIns, rc,
8577 N_("AHCI configuration error: failed to read Hotpluggable as boolean"));
8578 }
8579
8580 /*
8581 * Attach the block driver
8582 */
8583 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
8584 if (RT_SUCCESS(rc))
8585 {
8586 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
8587 if (RT_FAILURE(rc))
8588 {
8589 Log(("%s: Failed to configure the %s.\n", __FUNCTION__, szName));
8590 return rc;
8591 }
8592
8593 /* Mark that a device is present on that port */
8594 if (i < 6)
8595 pThis->dev.config[0x93] |= (1 << i);
8596
8597 /*
8598 * Init vendor product data.
8599 */
8600 rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
8601 if (RT_FAILURE(rc))
8602 return rc;
8603
8604 /*
8605 * If the new async interface is available we use a PDMQueue to transmit
8606 * the requests into R3.
8607 * Otherwise we use a event semaphore and a async I/O thread which processes them.
8608 */
8609 if (pAhciPort->pDrvMediaAsync && pThis->fUseAsyncInterfaceIfAvailable)
8610 {
8611 LogRel(("AHCI: LUN#%d: using async I/O\n", pAhciPort->iLUN));
8612 pAhciPort->fAsyncInterface = true;
8613 }
8614 else
8615 {
8616 LogRel(("AHCI: LUN#%d: using normal I/O\n", pAhciPort->iLUN));
8617 pAhciPort->fAsyncInterface = false;
8618 }
8619
8620 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pAhciPort->hEvtProcess);
8621 if (RT_FAILURE(rc))
8622 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8623 N_("AHCI: Failed to create SUP event semaphore"));
8624
8625 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop,
8626 ahciAsyncIOLoopWakeUp, 0, RTTHREADTYPE_IO, szName);
8627 if (RT_FAILURE(rc))
8628 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8629 N_("AHCI: Failed to create worker thread %s"), szName);
8630 }
8631 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
8632 {
8633 pAhciPort->pDrvBase = NULL;
8634 rc = VINF_SUCCESS;
8635 LogRel(("AHCI: %s: No driver attached\n", szName));
8636 }
8637 else
8638 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8639 N_("AHCI: Failed to attach drive to %s"), szName);
8640 }
8641
8642 /*
8643 * Attach status driver (optional).
8644 */
8645 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
8646 if (RT_SUCCESS(rc))
8647 {
8648 pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
8649 pThis->pMediaNotify = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIANOTIFY);
8650 }
8651 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
8652 {
8653 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
8654 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot attach to status driver"));
8655 }
8656 rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis) + cbTotalBufferSize, NULL,
8657 NULL, ahciR3LiveExec, NULL,
8658 ahciR3SavePrep, ahciR3SaveExec, NULL,
8659 ahciR3LoadPrep, ahciR3LoadExec, NULL);
8660 if (RT_FAILURE(rc))
8661 return rc;
8662
8663 /*
8664 * Register the info item.
8665 */
8666 char szTmp[128];
8667 RTStrPrintf(szTmp, sizeof(szTmp), "%s%d", pDevIns->pReg->szName, pDevIns->iInstance);
8668 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "AHCI info", ahciR3Info);
8669
8670 return ahciR3ResetCommon(pDevIns, true /*fConstructor*/);
8671}
8672
8673/**
8674 * The device registration structure.
8675 */
8676const PDMDEVREG g_DeviceAHCI =
8677{
8678 /* u32Version */
8679 PDM_DEVREG_VERSION,
8680 /* szName */
8681 "ahci",
8682 /* szRCMod */
8683 "VBoxDDRC.rc",
8684 /* szR0Mod */
8685 "VBoxDDR0.r0",
8686 /* pszDescription */
8687 "Intel AHCI controller.\n",
8688 /* fFlags */
8689 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
8690 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION |
8691 PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION,
8692 /* fClass */
8693 PDM_DEVREG_CLASS_STORAGE,
8694 /* cMaxInstances */
8695 ~0U,
8696 /* cbInstance */
8697 sizeof(AHCI),
8698 /* pfnConstruct */
8699 ahciR3Construct,
8700 /* pfnDestruct */
8701 ahciR3Destruct,
8702 /* pfnRelocate */
8703 ahciR3Relocate,
8704 /* pfnMemSetup */
8705 NULL,
8706 /* pfnPowerOn */
8707 NULL,
8708 /* pfnReset */
8709 ahciR3Reset,
8710 /* pfnSuspend */
8711 ahciR3Suspend,
8712 /* pfnResume */
8713 ahciR3Resume,
8714 /* pfnAttach */
8715 ahciR3Attach,
8716 /* pfnDetach */
8717 ahciR3Detach,
8718 /* pfnQueryInterface. */
8719 NULL,
8720 /* pfnInitComplete */
8721 NULL,
8722 /* pfnPowerOff */
8723 ahciR3PowerOff,
8724 /* pfnSoftReset */
8725 NULL,
8726 /* u32VersionEnd */
8727 PDM_DEVREG_VERSION
8728};
8729
8730#endif /* IN_RING3 */
8731#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

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