VirtualBox

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

Last change on this file since 44591 was 44574, checked in by vboxsync, 12 years ago

DevAHCI: Let IOM do the complicated reads. Let IOM filter out unaligned and odd sized writes as well, though we still need to split QWORD writes our selves.

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