VirtualBox

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

Last change on this file since 11187 was 11187, checked in by vboxsync, 16 years ago

DrvBlock: Report failures! Use CFGMR3*Def().

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