VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvBlock.cpp@ 26515

Last change on this file since 26515 was 26173, checked in by vboxsync, 15 years ago

PDM: s/pCfgHandle/pCfg/g - part 2.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.7 KB
Line 
1/* $Id: DrvBlock.cpp 26173 2010-02-02 21:11:09Z vboxsync $ */
2/** @file
3 * VBox storage devices: Generic block driver
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_DRV_BLOCK
27#include <VBox/pdmdrv.h>
28#include <iprt/assert.h>
29#include <iprt/string.h>
30#include <iprt/uuid.h>
31
32#include "Builtins.h"
33
34
35/** @def VBOX_PERIODIC_FLUSH
36 * Enable support for periodically flushing the VDI to disk. This may prove
37 * useful for those nasty problems with the ultra-slow host filesystems.
38 * If this is enabled, it can be configured via the CFGM key
39 * "VBoxInternal/Devices/piix3ide/0/LUN#<x>/Config/FlushInterval". <x>
40 * must be replaced with the correct LUN number of the disk that should
41 * do the periodic flushes. The value of the key is the number of bytes
42 * written between flushes. A value of 0 (the default) denotes no flushes. */
43#define VBOX_PERIODIC_FLUSH
44
45/** @def VBOX_IGNORE_FLUSH
46 * Enable support for ignoring VDI flush requests. This can be useful for
47 * filesystems that show bad guest IDE write performance (especially with
48 * Windows guests). NOTE that this does not disable the flushes caused by
49 * the periodic flush cache feature above.
50 * If this feature is enabled, it can be configured via the CFGM key
51 * "VBoxInternal/Devices/piix3ide/0/LUN#<x>/Config/IgnoreFlush". <x>
52 * must be replaced with the correct LUN number of the disk that should
53 * ignore flush requests. The value of the key is a boolean. The default
54 * is to ignore flushes, i.e. true. */
55#define VBOX_IGNORE_FLUSH
56
57
58/*******************************************************************************
59* Structures and Typedefs *
60*******************************************************************************/
61/**
62 * Block driver instance data.
63 *
64 * @implements PDMIBLOCK
65 * @implements PDMIBLOCKBIOS
66 * @implements PDMIMOUNT
67 * @implements PDMIMEDIAASYNCPORT
68 * @implements PDMIBLOCKASYNC
69 */
70typedef struct DRVBLOCK
71{
72 /** Pointer driver instance. */
73 PPDMDRVINS pDrvIns;
74 /** Drive type. */
75 PDMBLOCKTYPE enmType;
76 /** Locked indicator. */
77 bool fLocked;
78 /** Mountable indicator. */
79 bool fMountable;
80 /** Visible to the BIOS. */
81 bool fBiosVisible;
82#ifdef VBOX_PERIODIC_FLUSH
83 /** HACK: Configuration value for number of bytes written after which to flush. */
84 uint32_t cbFlushInterval;
85 /** HACK: Current count for the number of bytes written since the last flush. */
86 uint32_t cbDataWritten;
87#endif /* VBOX_PERIODIC_FLUSH */
88#ifdef VBOX_IGNORE_FLUSH
89 /** HACK: Disable flushes for this drive. */
90 bool fIgnoreFlush;
91#endif /* VBOX_IGNORE_FLUSH */
92 /** Pointer to the media driver below us.
93 * This is NULL if the media is not mounted. */
94 PPDMIMEDIA pDrvMedia;
95 /** Pointer to the block port interface above us. */
96 PPDMIBLOCKPORT pDrvBlockPort;
97 /** Pointer to the mount notify interface above us. */
98 PPDMIMOUNTNOTIFY pDrvMountNotify;
99 /** Our block interface. */
100 PDMIBLOCK IBlock;
101 /** Our block interface. */
102 PDMIBLOCKBIOS IBlockBios;
103 /** Our mountable interface. */
104 PDMIMOUNT IMount;
105
106 /** Pointer to the async media driver below us.
107 * This is NULL if the media is not mounted. */
108 PPDMIMEDIAASYNC pDrvMediaAsync;
109 /** Our media async port. */
110 PDMIMEDIAASYNCPORT IMediaAsyncPort;
111 /** Pointer to the async block port interface above us. */
112 PPDMIBLOCKASYNCPORT pDrvBlockAsyncPort;
113 /** Our async block interface. */
114 PDMIBLOCKASYNC IBlockAsync;
115
116 /** Uuid of the drive. */
117 RTUUID Uuid;
118
119 /** BIOS PCHS Geometry. */
120 PDMMEDIAGEOMETRY PCHSGeometry;
121 /** BIOS LCHS Geometry. */
122 PDMMEDIAGEOMETRY LCHSGeometry;
123} DRVBLOCK, *PDRVBLOCK;
124
125
126/* -=-=-=-=- IBlock -=-=-=-=- */
127
128/** Makes a PDRVBLOCK out of a PPDMIBLOCK. */
129#define PDMIBLOCK_2_DRVBLOCK(pInterface) ( (PDRVBLOCK)((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IBlock)) )
130
131/** @copydoc PDMIBLOCK::pfnRead */
132static DECLCALLBACK(int) drvblockRead(PPDMIBLOCK pInterface, uint64_t off, void *pvBuf, size_t cbRead)
133{
134 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
135
136 /*
137 * Check the state.
138 */
139 if (!pThis->pDrvMedia)
140 {
141 AssertMsgFailed(("Invalid state! Not mounted!\n"));
142 return VERR_PDM_MEDIA_NOT_MOUNTED;
143 }
144
145 int rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, pvBuf, cbRead);
146 return rc;
147}
148
149
150/** @copydoc PDMIBLOCK::pfnWrite */
151static DECLCALLBACK(int) drvblockWrite(PPDMIBLOCK pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)
152{
153 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
154
155 /*
156 * Check the state.
157 */
158 if (!pThis->pDrvMedia)
159 {
160 AssertMsgFailed(("Invalid state! Not mounted!\n"));
161 return VERR_PDM_MEDIA_NOT_MOUNTED;
162 }
163
164 int rc = pThis->pDrvMedia->pfnWrite(pThis->pDrvMedia, off, pvBuf, cbWrite);
165#ifdef VBOX_PERIODIC_FLUSH
166 if (pThis->cbFlushInterval)
167 {
168 pThis->cbDataWritten += (uint32_t)cbWrite;
169 if (pThis->cbDataWritten > pThis->cbFlushInterval)
170 {
171 pThis->cbDataWritten = 0;
172 pThis->pDrvMedia->pfnFlush(pThis->pDrvMedia);
173 }
174 }
175#endif /* VBOX_PERIODIC_FLUSH */
176
177 return rc;
178}
179
180
181/** @copydoc PDMIBLOCK::pfnFlush */
182static DECLCALLBACK(int) drvblockFlush(PPDMIBLOCK pInterface)
183{
184 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
185
186 /*
187 * Check the state.
188 */
189 if (!pThis->pDrvMedia)
190 {
191 AssertMsgFailed(("Invalid state! Not mounted!\n"));
192 return VERR_PDM_MEDIA_NOT_MOUNTED;
193 }
194
195#ifdef VBOX_IGNORE_FLUSH
196 if (pThis->fIgnoreFlush)
197 return VINF_SUCCESS;
198#endif /* VBOX_IGNORE_FLUSH */
199
200 int rc = pThis->pDrvMedia->pfnFlush(pThis->pDrvMedia);
201 if (rc == VERR_NOT_IMPLEMENTED)
202 rc = VINF_SUCCESS;
203 return rc;
204}
205
206
207/** @copydoc PDMIBLOCK::pfnIsReadOnly */
208static DECLCALLBACK(bool) drvblockIsReadOnly(PPDMIBLOCK pInterface)
209{
210 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
211
212 /*
213 * Check the state.
214 */
215 if (!pThis->pDrvMedia)
216 return false;
217
218 bool fRc = pThis->pDrvMedia->pfnIsReadOnly(pThis->pDrvMedia);
219 return fRc;
220}
221
222
223/** @copydoc PDMIBLOCK::pfnGetSize */
224static DECLCALLBACK(uint64_t) drvblockGetSize(PPDMIBLOCK pInterface)
225{
226 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
227
228 /*
229 * Check the state.
230 */
231 if (!pThis->pDrvMedia)
232 return 0;
233
234 uint64_t cb = pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
235 LogFlow(("drvblockGetSize: returns %llu\n", cb));
236 return cb;
237}
238
239
240/** @copydoc PDMIBLOCK::pfnGetType */
241static DECLCALLBACK(PDMBLOCKTYPE) drvblockGetType(PPDMIBLOCK pInterface)
242{
243 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
244 LogFlow(("drvblockGetType: returns %d\n", pThis->enmType));
245 return pThis->enmType;
246}
247
248
249/** @copydoc PDMIBLOCK::pfnGetUuid */
250static DECLCALLBACK(int) drvblockGetUuid(PPDMIBLOCK pInterface, PRTUUID pUuid)
251{
252 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
253
254 /*
255 * Copy the uuid.
256 */
257 *pUuid = pThis->Uuid;
258 return VINF_SUCCESS;
259}
260
261/* -=-=-=-=- IBlockAsync -=-=-=-=- */
262
263/** Makes a PDRVBLOCK out of a PPDMIBLOCKASYNC. */
264#define PDMIBLOCKASYNC_2_DRVBLOCK(pInterface) ( (PDRVBLOCK)((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IBlockAsync)) )
265
266/** @copydoc PDMIBLOCKASYNC::pfnStartRead */
267static DECLCALLBACK(int) drvblockAsyncReadStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMDATASEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser)
268{
269 PDRVBLOCK pThis = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
270
271 /*
272 * Check the state.
273 */
274 if (!pThis->pDrvMediaAsync)
275 {
276 AssertMsgFailed(("Invalid state! Not mounted!\n"));
277 return VERR_PDM_MEDIA_NOT_MOUNTED;
278 }
279
280 int rc = pThis->pDrvMediaAsync->pfnStartRead(pThis->pDrvMediaAsync, off, pSeg, cSeg, cbRead, pvUser);
281 return rc;
282}
283
284
285/** @copydoc PDMIBLOCKASYNC::pfnStartWrite */
286static DECLCALLBACK(int) drvblockAsyncWriteStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMDATASEG pSeg, unsigned cSeg, size_t cbWrite, void *pvUser)
287{
288 PDRVBLOCK pThis = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
289
290 /*
291 * Check the state.
292 */
293 if (!pThis->pDrvMediaAsync)
294 {
295 AssertMsgFailed(("Invalid state! Not mounted!\n"));
296 return VERR_PDM_MEDIA_NOT_MOUNTED;
297 }
298
299 int rc = pThis->pDrvMediaAsync->pfnStartWrite(pThis->pDrvMediaAsync, off, pSeg, cSeg, cbWrite, pvUser);
300
301 return rc;
302}
303
304/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
305
306/** Makes a PDRVBLOCKASYNC out of a PPDMIMEDIAASYNCPORT. */
307#define PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface) ( (PDRVBLOCK((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IMediaAsyncPort))) )
308
309static DECLCALLBACK(int) drvblockAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser)
310{
311 PDRVBLOCK pThis = PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface);
312
313 return pThis->pDrvBlockAsyncPort->pfnTransferCompleteNotify(pThis->pDrvBlockAsyncPort, pvUser);
314}
315
316/* -=-=-=-=- IBlockBios -=-=-=-=- */
317
318/** Makes a PDRVBLOCK out of a PPDMIBLOCKBIOS. */
319#define PDMIBLOCKBIOS_2_DRVBLOCK(pInterface) ( (PDRVBLOCK((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IBlockBios))) )
320
321
322/** @copydoc PDMIBLOCKBIOS::pfnGetPCHSGeometry */
323static DECLCALLBACK(int) drvblockGetPCHSGeometry(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
324{
325 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
326
327 /*
328 * Check the state.
329 */
330 if (!pThis->pDrvMedia)
331 return VERR_PDM_MEDIA_NOT_MOUNTED;
332
333 /*
334 * Use configured/cached values if present.
335 */
336 if ( pThis->PCHSGeometry.cCylinders > 0
337 && pThis->PCHSGeometry.cHeads > 0
338 && pThis->PCHSGeometry.cSectors > 0)
339 {
340 *pPCHSGeometry = pThis->PCHSGeometry;
341 LogFlow(("%s: returns VINF_SUCCESS {%d,%d,%d}\n", __FUNCTION__, pThis->PCHSGeometry.cCylinders, pThis->PCHSGeometry.cHeads, pThis->PCHSGeometry.cSectors));
342 return VINF_SUCCESS;
343 }
344
345 /*
346 * Call media.
347 */
348 int rc = pThis->pDrvMedia->pfnBiosGetPCHSGeometry(pThis->pDrvMedia, &pThis->PCHSGeometry);
349
350 if (RT_SUCCESS(rc))
351 {
352 *pPCHSGeometry = pThis->PCHSGeometry;
353 LogFlow(("%s: returns %Rrc {%d,%d,%d}\n", __FUNCTION__, rc, pThis->PCHSGeometry.cCylinders, pThis->PCHSGeometry.cHeads, pThis->PCHSGeometry.cSectors));
354 }
355 else if (rc == VERR_NOT_IMPLEMENTED)
356 {
357 rc = VERR_PDM_GEOMETRY_NOT_SET;
358 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
359 }
360 return rc;
361}
362
363
364/** @copydoc PDMIBLOCKBIOS::pfnSetPCHSGeometry */
365static DECLCALLBACK(int) drvblockSetPCHSGeometry(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
366{
367 LogFlow(("%s: cCylinders=%d cHeads=%d cSectors=%d\n", __FUNCTION__, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
368 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
369
370 /*
371 * Check the state.
372 */
373 if (!pThis->pDrvMedia)
374 {
375 AssertMsgFailed(("Invalid state! Not mounted!\n"));
376 return VERR_PDM_MEDIA_NOT_MOUNTED;
377 }
378
379 /*
380 * Call media. Ignore the not implemented return code.
381 */
382 int rc = pThis->pDrvMedia->pfnBiosSetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
383
384 if ( RT_SUCCESS(rc)
385 || rc == VERR_NOT_IMPLEMENTED)
386 {
387 pThis->PCHSGeometry = *pPCHSGeometry;
388 rc = VINF_SUCCESS;
389 }
390 return rc;
391}
392
393
394/** @copydoc PDMIBLOCKBIOS::pfnGetLCHSGeometry */
395static DECLCALLBACK(int) drvblockGetLCHSGeometry(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
396{
397 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
398
399 /*
400 * Check the state.
401 */
402 if (!pThis->pDrvMedia)
403 return VERR_PDM_MEDIA_NOT_MOUNTED;
404
405 /*
406 * Use configured/cached values if present.
407 */
408 if ( pThis->LCHSGeometry.cCylinders > 0
409 && pThis->LCHSGeometry.cHeads > 0
410 && pThis->LCHSGeometry.cSectors > 0)
411 {
412 *pLCHSGeometry = pThis->LCHSGeometry;
413 LogFlow(("%s: returns VINF_SUCCESS {%d,%d,%d}\n", __FUNCTION__, pThis->LCHSGeometry.cCylinders, pThis->LCHSGeometry.cHeads, pThis->LCHSGeometry.cSectors));
414 return VINF_SUCCESS;
415 }
416
417 /*
418 * Call media.
419 */
420 int rc = pThis->pDrvMedia->pfnBiosGetLCHSGeometry(pThis->pDrvMedia, &pThis->LCHSGeometry);
421
422 if (RT_SUCCESS(rc))
423 {
424 *pLCHSGeometry = pThis->LCHSGeometry;
425 LogFlow(("%s: returns %Rrc {%d,%d,%d}\n", __FUNCTION__, rc, pThis->LCHSGeometry.cCylinders, pThis->LCHSGeometry.cHeads, pThis->LCHSGeometry.cSectors));
426 }
427 else if (rc == VERR_NOT_IMPLEMENTED)
428 {
429 rc = VERR_PDM_GEOMETRY_NOT_SET;
430 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
431 }
432 return rc;
433}
434
435
436/** @copydoc PDMIBLOCKBIOS::pfnSetLCHSGeometry */
437static DECLCALLBACK(int) drvblockSetLCHSGeometry(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
438{
439 LogFlow(("%s: cCylinders=%d cHeads=%d cSectors=%d\n", __FUNCTION__, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
440 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
441
442 /*
443 * Check the state.
444 */
445 if (!pThis->pDrvMedia)
446 {
447 AssertMsgFailed(("Invalid state! Not mounted!\n"));
448 return VERR_PDM_MEDIA_NOT_MOUNTED;
449 }
450
451 /*
452 * Call media. Ignore the not implemented return code.
453 */
454 int rc = pThis->pDrvMedia->pfnBiosSetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
455
456 if ( RT_SUCCESS(rc)
457 || rc == VERR_NOT_IMPLEMENTED)
458 {
459 pThis->LCHSGeometry = *pLCHSGeometry;
460 rc = VINF_SUCCESS;
461 }
462 return rc;
463}
464
465
466/** @copydoc PDMIBLOCKBIOS::pfnIsVisible */
467static DECLCALLBACK(bool) drvblockIsVisible(PPDMIBLOCKBIOS pInterface)
468{
469 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
470 LogFlow(("drvblockIsVisible: returns %d\n", pThis->fBiosVisible));
471 return pThis->fBiosVisible;
472}
473
474
475/** @copydoc PDMIBLOCKBIOS::pfnGetType */
476static DECLCALLBACK(PDMBLOCKTYPE) drvblockBiosGetType(PPDMIBLOCKBIOS pInterface)
477{
478 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
479 LogFlow(("drvblockBiosGetType: returns %d\n", pThis->enmType));
480 return pThis->enmType;
481}
482
483
484
485/* -=-=-=-=- IMount -=-=-=-=- */
486
487/** Makes a PDRVBLOCK out of a PPDMIMOUNT. */
488#define PDMIMOUNT_2_DRVBLOCK(pInterface) ( (PDRVBLOCK)((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IMount)) )
489
490
491/** @copydoc PDMIMOUNT::pfnMount */
492static DECLCALLBACK(int) drvblockMount(PPDMIMOUNT pInterface, const char *pszFilename, const char *pszCoreDriver)
493{
494 LogFlow(("drvblockMount: pszFilename=%p:{%s} pszCoreDriver=%p:{%s}\n", pszFilename, pszFilename, pszCoreDriver, pszCoreDriver));
495 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
496
497 /*
498 * Validate state.
499 */
500 if (pThis->pDrvMedia)
501 {
502 AssertMsgFailed(("Already mounted\n"));
503 return VERR_PDM_MEDIA_MOUNTED;
504 }
505
506 /*
507 * Prepare configuration.
508 */
509 if (pszFilename)
510 {
511 int rc = PDMDrvHlpMountPrepare(pThis->pDrvIns, pszFilename, pszCoreDriver);
512 if (RT_FAILURE(rc))
513 {
514 Log(("drvblockMount: Prepare failed for \"%s\" rc=%Rrc\n", pszFilename, rc));
515 return rc;
516 }
517 }
518
519 /*
520 * Attach the media driver and query it's interface.
521 */
522 uint32_t fTachFlags = 0; /** @todo figure attachment flags for mount. */
523 PPDMIBASE pBase;
524 int rc = PDMDrvHlpAttach(pThis->pDrvIns, fTachFlags, &pBase);
525 if (RT_FAILURE(rc))
526 {
527 Log(("drvblockMount: Attach failed rc=%Rrc\n", rc));
528 return rc;
529 }
530
531 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
532 if (pThis->pDrvMedia)
533 {
534 /** @todo r=klaus missing async handling, this is just a band aid to
535 * avoid using stale information */
536 pThis->pDrvMediaAsync = NULL;
537
538 /*
539 * Initialize state.
540 */
541 pThis->fLocked = false;
542 pThis->PCHSGeometry.cCylinders = 0;
543 pThis->PCHSGeometry.cHeads = 0;
544 pThis->PCHSGeometry.cSectors = 0;
545 pThis->LCHSGeometry.cCylinders = 0;
546 pThis->LCHSGeometry.cHeads = 0;
547 pThis->LCHSGeometry.cSectors = 0;
548#ifdef VBOX_PERIODIC_FLUSH
549 pThis->cbDataWritten = 0;
550#endif /* VBOX_PERIODIC_FLUSH */
551
552 /*
553 * Notify driver/device above us.
554 */
555 if (pThis->pDrvMountNotify)
556 pThis->pDrvMountNotify->pfnMountNotify(pThis->pDrvMountNotify);
557 Log(("drvblockMount: Success\n"));
558 return VINF_SUCCESS;
559 }
560 else
561 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
562
563 /*
564 * Failed, detatch the media driver.
565 */
566 AssertMsgFailed(("No media interface!\n"));
567 int rc2 = PDMDrvHlpDetach(pThis->pDrvIns, fTachFlags);
568 AssertRC(rc2);
569 pThis->pDrvMedia = NULL;
570 return rc;
571}
572
573
574/** @copydoc PDMIMOUNT::pfnUnmount */
575static DECLCALLBACK(int) drvblockUnmount(PPDMIMOUNT pInterface, bool fForce)
576{
577 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
578
579 /*
580 * Validate state.
581 */
582 if (!pThis->pDrvMedia)
583 {
584 Log(("drvblockUmount: Not mounted\n"));
585 return VERR_PDM_MEDIA_NOT_MOUNTED;
586 }
587 if (pThis->fLocked && !fForce)
588 {
589 Log(("drvblockUmount: Locked\n"));
590 return VERR_PDM_MEDIA_LOCKED;
591 }
592
593 /* Media is no longer locked even if it was previously. */
594 pThis->fLocked = false;
595
596 /*
597 * Detach the media driver and query it's interface.
598 */
599 int rc = PDMDrvHlpDetach(pThis->pDrvIns, 0 /*fFlags*/);
600 if (RT_FAILURE(rc))
601 {
602 Log(("drvblockUnmount: Detach failed rc=%Rrc\n", rc));
603 return rc;
604 }
605 Assert(!pThis->pDrvMedia);
606
607 /*
608 * Notify driver/device above us.
609 */
610 if (pThis->pDrvMountNotify)
611 pThis->pDrvMountNotify->pfnUnmountNotify(pThis->pDrvMountNotify);
612 Log(("drvblockUnmount: success\n"));
613 return VINF_SUCCESS;
614}
615
616
617/** @copydoc PDMIMOUNT::pfnIsMounted */
618static DECLCALLBACK(bool) drvblockIsMounted(PPDMIMOUNT pInterface)
619{
620 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
621 return pThis->pDrvMedia != NULL;
622}
623
624/** @copydoc PDMIMOUNT::pfnLock */
625static DECLCALLBACK(int) drvblockLock(PPDMIMOUNT pInterface)
626{
627 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
628 Log(("drvblockLock: %d -> %d\n", pThis->fLocked, true));
629 pThis->fLocked = true;
630 return VINF_SUCCESS;
631}
632
633/** @copydoc PDMIMOUNT::pfnUnlock */
634static DECLCALLBACK(int) drvblockUnlock(PPDMIMOUNT pInterface)
635{
636 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
637 Log(("drvblockUnlock: %d -> %d\n", pThis->fLocked, false));
638 pThis->fLocked = false;
639 return VINF_SUCCESS;
640}
641
642/** @copydoc PDMIMOUNT::pfnIsLocked */
643static DECLCALLBACK(bool) drvblockIsLocked(PPDMIMOUNT pInterface)
644{
645 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
646 return pThis->fLocked;
647}
648
649
650/* -=-=-=-=- IBase -=-=-=-=- */
651
652/**
653 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
654 */
655static DECLCALLBACK(void *) drvblockQueryInterface(PPDMIBASE pInterface, const char *pszIID)
656{
657 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
658 PDRVBLOCK pThis = PDMINS_2_DATA(pDrvIns, PDRVBLOCK);
659
660 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
661 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCK, &pThis->IBlock);
662 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKBIOS, pThis->fBiosVisible ? &pThis->IBlockBios : NULL);
663 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNT, pThis->fMountable ? &pThis->IMount : NULL);
664 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKASYNC, pThis->pDrvMediaAsync ? &pThis->IBlockAsync : NULL);
665 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNCPORT, pThis->pDrvBlockAsyncPort ? &pThis->IMediaAsyncPort : NULL);
666 return NULL;
667}
668
669
670/* -=-=-=-=- driver interface -=-=-=-=- */
671
672/** @copydoc FNPDMDRVDETACH. */
673static DECLCALLBACK(void) drvblockDetach(PPDMDRVINS pDrvIns, uint32_t fFlags)
674{
675 PDRVBLOCK pThis = PDMINS_2_DATA(pDrvIns, PDRVBLOCK);
676 pThis->pDrvMedia = NULL;
677 pThis->pDrvMediaAsync = NULL;
678 NOREF(fFlags);
679}
680
681/**
682 * Reset notification.
683 *
684 * @returns VBox status.
685 * @param pDevIns The driver instance data.
686 */
687static DECLCALLBACK(void) drvblockReset(PPDMDRVINS pDrvIns)
688{
689 PDRVBLOCK pThis = PDMINS_2_DATA(pDrvIns, PDRVBLOCK);
690
691 pThis->fLocked = false;
692}
693
694/**
695 * Construct a block driver instance.
696 *
697 * @copydoc FNPDMDRVCONSTRUCT
698 */
699static DECLCALLBACK(int) drvblockConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
700{
701 PDRVBLOCK pThis = PDMINS_2_DATA(pDrvIns, PDRVBLOCK);
702 LogFlow(("drvblockConstruct: iInstance=%d\n", pDrvIns->iInstance));
703 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
704
705 /*
706 * Validate configuration.
707 */
708#if defined(VBOX_PERIODIC_FLUSH) || defined(VBOX_IGNORE_FLUSH)
709 if (!CFGMR3AreValuesValid(pCfg, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Mountable\0FlushInterval\0IgnoreFlush\0"))
710#else /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
711 if (!CFGMR3AreValuesValid(pCfg, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Mountable\0"))
712#endif /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
713 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
714
715 /*
716 * Initialize most of the data members.
717 */
718 pThis->pDrvIns = pDrvIns;
719
720 /* IBase. */
721 pDrvIns->IBase.pfnQueryInterface = drvblockQueryInterface;
722
723 /* IBlock. */
724 pThis->IBlock.pfnRead = drvblockRead;
725 pThis->IBlock.pfnWrite = drvblockWrite;
726 pThis->IBlock.pfnFlush = drvblockFlush;
727 pThis->IBlock.pfnIsReadOnly = drvblockIsReadOnly;
728 pThis->IBlock.pfnGetSize = drvblockGetSize;
729 pThis->IBlock.pfnGetType = drvblockGetType;
730 pThis->IBlock.pfnGetUuid = drvblockGetUuid;
731
732 /* IBlockBios. */
733 pThis->IBlockBios.pfnGetPCHSGeometry = drvblockGetPCHSGeometry;
734 pThis->IBlockBios.pfnSetPCHSGeometry = drvblockSetPCHSGeometry;
735 pThis->IBlockBios.pfnGetLCHSGeometry = drvblockGetLCHSGeometry;
736 pThis->IBlockBios.pfnSetLCHSGeometry = drvblockSetLCHSGeometry;
737 pThis->IBlockBios.pfnIsVisible = drvblockIsVisible;
738 pThis->IBlockBios.pfnGetType = drvblockBiosGetType;
739
740 /* IMount. */
741 pThis->IMount.pfnMount = drvblockMount;
742 pThis->IMount.pfnUnmount = drvblockUnmount;
743 pThis->IMount.pfnIsMounted = drvblockIsMounted;
744 pThis->IMount.pfnLock = drvblockLock;
745 pThis->IMount.pfnUnlock = drvblockUnlock;
746 pThis->IMount.pfnIsLocked = drvblockIsLocked;
747
748 /* IBlockAsync. */
749 pThis->IBlockAsync.pfnStartRead = drvblockAsyncReadStart;
750 pThis->IBlockAsync.pfnStartWrite = drvblockAsyncWriteStart;
751
752 /* IMediaAsyncPort. */
753 pThis->IMediaAsyncPort.pfnTransferCompleteNotify = drvblockAsyncTransferCompleteNotify;
754
755 /*
756 * Get the IBlockPort & IMountNotify interfaces of the above driver/device.
757 */
758 pThis->pDrvBlockPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIBLOCKPORT);
759 if (!pThis->pDrvBlockPort)
760 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
761 N_("No block port interface above"));
762
763 /* Try to get the optional async block port interface above. */
764 pThis->pDrvBlockAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIBLOCKASYNCPORT);
765 pThis->pDrvMountNotify = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMOUNTNOTIFY);
766
767 /*
768 * Query configuration.
769 */
770 /* type */
771 char *psz;
772 int rc = CFGMR3QueryStringAlloc(pCfg, "Type", &psz);
773 if (RT_FAILURE(rc))
774 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_BLOCK_NO_TYPE, N_("Failed to obtain the type"));
775 if (!strcmp(psz, "HardDisk"))
776 pThis->enmType = PDMBLOCKTYPE_HARD_DISK;
777 else if (!strcmp(psz, "DVD"))
778 pThis->enmType = PDMBLOCKTYPE_DVD;
779 else if (!strcmp(psz, "CDROM"))
780 pThis->enmType = PDMBLOCKTYPE_CDROM;
781 else if (!strcmp(psz, "Floppy 2.88"))
782 pThis->enmType = PDMBLOCKTYPE_FLOPPY_2_88;
783 else if (!strcmp(psz, "Floppy 1.44"))
784 pThis->enmType = PDMBLOCKTYPE_FLOPPY_1_44;
785 else if (!strcmp(psz, "Floppy 1.20"))
786 pThis->enmType = PDMBLOCKTYPE_FLOPPY_1_20;
787 else if (!strcmp(psz, "Floppy 720"))
788 pThis->enmType = PDMBLOCKTYPE_FLOPPY_720;
789 else if (!strcmp(psz, "Floppy 360"))
790 pThis->enmType = PDMBLOCKTYPE_FLOPPY_360;
791 else
792 {
793 PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_BLOCK_UNKNOWN_TYPE, RT_SRC_POS,
794 N_("Unknown type \"%s\""), psz);
795 MMR3HeapFree(psz);
796 return VERR_PDM_BLOCK_UNKNOWN_TYPE;
797 }
798 Log2(("drvblockConstruct: enmType=%d\n", pThis->enmType));
799 MMR3HeapFree(psz); psz = NULL;
800
801 /* Mountable */
802 rc = CFGMR3QueryBoolDef(pCfg, "Mountable", &pThis->fMountable, false);
803 if (RT_FAILURE(rc))
804 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Mountable\" from the config"));
805
806 /* Locked */
807 rc = CFGMR3QueryBoolDef(pCfg, "Locked", &pThis->fLocked, false);
808 if (RT_FAILURE(rc))
809 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Locked\" from the config"));
810
811 /* BIOS visible */
812 rc = CFGMR3QueryBoolDef(pCfg, "BIOSVisible", &pThis->fBiosVisible, true);
813 if (RT_FAILURE(rc))
814 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"BIOSVisible\" from the config"));
815
816 /** @todo AttachFailError is currently completely ignored. */
817
818 /* Cylinders */
819 rc = CFGMR3QueryU32Def(pCfg, "Cylinders", &pThis->LCHSGeometry.cCylinders, 0);
820 if (RT_FAILURE(rc))
821 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Cylinders\" from the config"));
822
823 /* Heads */
824 rc = CFGMR3QueryU32Def(pCfg, "Heads", &pThis->LCHSGeometry.cHeads, 0);
825 if (RT_FAILURE(rc))
826 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Heads\" from the config"));
827
828 /* Sectors */
829 rc = CFGMR3QueryU32Def(pCfg, "Sectors", &pThis->LCHSGeometry.cSectors, 0);
830 if (RT_FAILURE(rc))
831 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Sectors\" from the config"));
832
833 /* Uuid */
834 rc = CFGMR3QueryStringAlloc(pCfg, "Uuid", &psz);
835 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
836 RTUuidClear(&pThis->Uuid);
837 else if (RT_SUCCESS(rc))
838 {
839 rc = RTUuidFromStr(&pThis->Uuid, psz);
840 if (RT_FAILURE(rc))
841 {
842 PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, "%s",
843 N_("Uuid from string failed on \"%s\""), psz);
844 MMR3HeapFree(psz);
845 return rc;
846 }
847 MMR3HeapFree(psz); psz = NULL;
848 }
849 else
850 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Uuid\" from the config"));
851
852#ifdef VBOX_PERIODIC_FLUSH
853 rc = CFGMR3QueryU32Def(pCfg, "FlushInterval", &pThis->cbFlushInterval, 0);
854 if (RT_FAILURE(rc))
855 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"FlushInterval\" from the config"));
856#endif /* VBOX_PERIODIC_FLUSH */
857
858#ifdef VBOX_IGNORE_FLUSH
859 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreFlush", &pThis->fIgnoreFlush, true);
860 if (RT_FAILURE(rc))
861 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"IgnoreFlush\" from the config"));
862#endif /* VBOX_IGNORE_FLUSH */
863
864 /*
865 * Try attach driver below and query it's media interface.
866 */
867 PPDMIBASE pBase;
868 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
869 if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
870 && pThis->enmType != PDMBLOCKTYPE_HARD_DISK)
871 return VINF_SUCCESS;
872 if (RT_FAILURE(rc))
873 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
874 N_("Failed to attach driver below us! %Rrf"), rc);
875
876 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
877 if (!pThis->pDrvMedia)
878 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
879 N_("No media or async media interface below"));
880
881 /* Try to get the optional async interface. */
882 pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);
883
884 if (RTUuidIsNull(&pThis->Uuid))
885 {
886 if (pThis->enmType == PDMBLOCKTYPE_HARD_DISK)
887 pThis->pDrvMedia->pfnGetUuid(pThis->pDrvMedia, &pThis->Uuid);
888 }
889
890 return VINF_SUCCESS;
891}
892
893
894/**
895 * Block driver registration record.
896 */
897const PDMDRVREG g_DrvBlock =
898{
899 /* u32Version */
900 PDM_DRVREG_VERSION,
901 /* szName */
902 "Block",
903 /* szRCMod */
904 "",
905 /* szR0Mod */
906 "",
907 /* pszDescription */
908 "Generic block driver.",
909 /* fFlags */
910 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
911 /* fClass. */
912 PDM_DRVREG_CLASS_BLOCK,
913 /* cMaxInstances */
914 ~0,
915 /* cbInstance */
916 sizeof(DRVBLOCK),
917 /* pfnConstruct */
918 drvblockConstruct,
919 /* pfnDestruct */
920 NULL,
921 /* pfnRelocate */
922 NULL,
923 /* pfnIOCtl */
924 NULL,
925 /* pfnPowerOn */
926 NULL,
927 /* pfnReset */
928 drvblockReset,
929 /* pfnSuspend */
930 NULL,
931 /* pfnResume */
932 NULL,
933 /* pfnAttach */
934 NULL,
935 /* pfnDetach */
936 drvblockDetach,
937 /* pfnPowerOff */
938 NULL,
939 /* pfnSoftReset */
940 NULL,
941 /* u32EndVersion */
942 PDM_DRVREG_VERSION
943};
944
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