VirtualBox

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

Last change on this file since 48823 was 48744, checked in by vboxsync, 11 years ago

Devices/Storage: Support different sector sizes, booting from images with a sector size != 512 is not supported

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