VirtualBox

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

Last change on this file since 3160 was 3113, checked in by vboxsync, 17 years ago

Implement virtual paperclip (forced unmounting of media, currently
unused) and non-fatal error when media is not available on powerup.

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