VirtualBox

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

Last change on this file since 44534 was 44465, checked in by vboxsync, 12 years ago

DevAHCI.cpp: Used RT_SUCCESS instead of RT_FAILURE. Duh!

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