VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvHostBase.cpp@ 65620

Last change on this file since 65620 was 64839, checked in by vboxsync, 8 years ago

Devices/Storage/DrvHostBase: Statistics for common things (request count, number of bytes read/written, etc.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 49.0 KB
Line 
1/* $Id: DrvHostBase.cpp 64839 2016-12-12 17:32:06Z vboxsync $ */
2/** @file
3 * DrvHostBase - Host base drive access driver.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_HOST_BASE
23
24#include <VBox/vmm/pdmdrv.h>
25#include <VBox/vmm/pdmstorageifs.h>
26#include <iprt/assert.h>
27#include <iprt/file.h>
28#include <iprt/path.h>
29#include <iprt/string.h>
30#include <iprt/thread.h>
31#include <iprt/semaphore.h>
32#include <iprt/uuid.h>
33#include <iprt/asm.h>
34#include <iprt/critsect.h>
35#include <iprt/ctype.h>
36#include <iprt/mem.h>
37
38#include "DrvHostBase.h"
39
40
41
42
43/* -=-=-=-=- IBlock -=-=-=-=- */
44
45/** @interface_method_impl{PDMIMEDIA,pfnRead} */
46static DECLCALLBACK(int) drvHostBaseRead(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead)
47{
48 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
49 LogFlow(("%s-%d: drvHostBaseRead: off=%#llx pvBuf=%p cbRead=%#x (%s)\n",
50 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, pvBuf, cbRead, pThis->pszDevice));
51 RTCritSectEnter(&pThis->CritSect);
52
53 STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
54 STAM_REL_COUNTER_INC(&pThis->StatReqsRead);
55
56 /*
57 * Check the state.
58 */
59 int rc;
60 if (pThis->fMediaPresent)
61 {
62 /*
63 * Seek and read.
64 */
65 rc = drvHostBaseReadOs(pThis, off, pvBuf, cbRead);
66 if (RT_SUCCESS(rc))
67 {
68 Log2(("%s-%d: drvHostBaseReadOs: off=%#llx cbRead=%#x\n"
69 "%16.*Rhxd\n",
70 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, cbRead, cbRead, pvBuf));
71 }
72 else
73 Log(("%s-%d: drvHostBaseRead: drvHostBaseReadOs(%#llx, %p, %#x) -> %Rrc ('%s')\n",
74 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance,
75 off, pvBuf, cbRead, rc, pThis->pszDevice));
76 }
77 else
78 rc = VERR_MEDIA_NOT_PRESENT;
79
80 if (RT_SUCCESS(rc))
81 {
82 STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
83 STAM_REL_COUNTER_ADD(&pThis->StatBytesRead, cbRead);
84 }
85 else
86 STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
87
88 RTCritSectLeave(&pThis->CritSect);
89 LogFlow(("%s-%d: drvHostBaseRead: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
90 return rc;
91}
92
93
94/** @interface_method_impl{PDMIMEDIA,pfnWrite} */
95static DECLCALLBACK(int) drvHostBaseWrite(PPDMIMEDIA pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)
96{
97 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
98 LogFlow(("%s-%d: drvHostBaseWrite: off=%#llx pvBuf=%p cbWrite=%#x (%s)\n",
99 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, pvBuf, cbWrite, pThis->pszDevice));
100 Log2(("%s-%d: drvHostBaseWrite: off=%#llx cbWrite=%#x\n"
101 "%16.*Rhxd\n",
102 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, cbWrite, cbWrite, pvBuf));
103 RTCritSectEnter(&pThis->CritSect);
104
105 STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
106 STAM_REL_COUNTER_INC(&pThis->StatReqsWrite);
107
108 /*
109 * Check the state.
110 */
111 int rc;
112 if (!pThis->fReadOnly)
113 {
114 if (pThis->fMediaPresent)
115 {
116 /*
117 * Seek and write.
118 */
119 rc = drvHostBaseWriteOs(pThis, off, pvBuf, cbWrite);
120 if (RT_FAILURE(rc))
121 Log(("%s-%d: drvHostBaseWrite: drvHostBaseWriteOs(%#llx, %p, %#x) -> %Rrc ('%s')\n",
122 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance,
123 off, pvBuf, cbWrite, rc, pThis->pszDevice));
124 }
125 else
126 rc = VERR_MEDIA_NOT_PRESENT;
127 }
128 else
129 rc = VERR_WRITE_PROTECT;
130
131 if (RT_SUCCESS(rc))
132 {
133 STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
134 STAM_REL_COUNTER_ADD(&pThis->StatBytesWritten, cbWrite);
135 }
136 else
137 STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
138
139 RTCritSectLeave(&pThis->CritSect);
140 LogFlow(("%s-%d: drvHostBaseWrite: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
141 return rc;
142}
143
144
145/** @interface_method_impl{PDMIMEDIA,pfnFlush} */
146static DECLCALLBACK(int) drvHostBaseFlush(PPDMIMEDIA pInterface)
147{
148 int rc;
149 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
150 LogFlow(("%s-%d: drvHostBaseFlush: (%s)\n",
151 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice));
152 RTCritSectEnter(&pThis->CritSect);
153
154 STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
155 STAM_REL_COUNTER_INC(&pThis->StatReqsFlush);
156
157 if (pThis->fMediaPresent)
158 rc = drvHostBaseFlushOs(pThis);
159 else
160 rc = VERR_MEDIA_NOT_PRESENT;
161
162 if (RT_SUCCESS(rc))
163 STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
164 else
165 STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
166
167 RTCritSectLeave(&pThis->CritSect);
168 LogFlow(("%s-%d: drvHostBaseFlush: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
169 return rc;
170}
171
172
173/** @interface_method_impl{PDMIMEDIA,pfnIsReadOnly} */
174static DECLCALLBACK(bool) drvHostBaseIsReadOnly(PPDMIMEDIA pInterface)
175{
176 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
177 return pThis->fReadOnly;
178}
179
180
181/** @interface_method_impl{PDMIMEDIA,pfnIsNonRotational} */
182static DECLCALLBACK(bool) drvHostBaseIsNonRotational(PPDMIMEDIA pInterface)
183{
184 RT_NOREF1(pInterface);
185 return false;
186}
187
188
189/** @interface_method_impl{PDMIMEDIA,pfnGetSize} */
190static DECLCALLBACK(uint64_t) drvHostBaseGetSize(PPDMIMEDIA pInterface)
191{
192 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
193 RTCritSectEnter(&pThis->CritSect);
194
195 uint64_t cb = 0;
196 if (pThis->fMediaPresent)
197 cb = pThis->cbSize;
198
199 RTCritSectLeave(&pThis->CritSect);
200 LogFlow(("%s-%d: drvHostBaseGetSize: returns %llu\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, cb));
201 return cb;
202}
203
204
205/** @interface_method_impl{PDMIMEDIA,pfnGetType} */
206static DECLCALLBACK(PDMMEDIATYPE) drvHostBaseGetType(PPDMIMEDIA pInterface)
207{
208 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
209 LogFlow(("%s-%d: drvHostBaseGetType: returns %d\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->enmType));
210 return pThis->enmType;
211}
212
213
214/** @interface_method_impl{PDMIMEDIA,pfnGetUuid} */
215static DECLCALLBACK(int) drvHostBaseGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
216{
217 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
218
219 *pUuid = pThis->Uuid;
220
221 LogFlow(("%s-%d: drvHostBaseGetUuid: returns VINF_SUCCESS *pUuid=%RTuuid\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pUuid));
222 return VINF_SUCCESS;
223}
224
225
226/** @interface_method_impl{PDMIMEDIA,pfnBiosGetPCHSGeometry} */
227static DECLCALLBACK(int) drvHostBaseGetPCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
228{
229 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
230 RTCritSectEnter(&pThis->CritSect);
231
232 int rc = VINF_SUCCESS;
233 if (pThis->fMediaPresent)
234 {
235 if ( pThis->PCHSGeometry.cCylinders > 0
236 && pThis->PCHSGeometry.cHeads > 0
237 && pThis->PCHSGeometry.cSectors > 0)
238 {
239 *pPCHSGeometry = pThis->PCHSGeometry;
240 }
241 else
242 rc = VERR_PDM_GEOMETRY_NOT_SET;
243 }
244 else
245 rc = VERR_PDM_MEDIA_NOT_MOUNTED;
246
247 RTCritSectLeave(&pThis->CritSect);
248 LogFlow(("%s-%d: %s: returns %Rrc CHS={%d,%d,%d}\n",
249 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, __FUNCTION__, rc,
250 pThis->PCHSGeometry.cCylinders, pThis->PCHSGeometry.cHeads, pThis->PCHSGeometry.cSectors));
251 return rc;
252}
253
254
255/** @interface_method_impl{PDMIMEDIA,pfnBiosSetPCHSGeometry} */
256static DECLCALLBACK(int) drvHostBaseSetPCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
257{
258 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
259 LogFlow(("%s-%d: %s: cCylinders=%d cHeads=%d cSectors=%d\n",
260 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, __FUNCTION__,
261 pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
262 RTCritSectEnter(&pThis->CritSect);
263
264 int rc = VINF_SUCCESS;
265 if (pThis->fMediaPresent)
266 {
267 pThis->PCHSGeometry = *pPCHSGeometry;
268 }
269 else
270 {
271 AssertMsgFailed(("Invalid state! Not mounted!\n"));
272 rc = VERR_PDM_MEDIA_NOT_MOUNTED;
273 }
274
275 RTCritSectLeave(&pThis->CritSect);
276 return rc;
277}
278
279
280/** @interface_method_impl{PDMIMEDIA,pfnBiosGetLCHSGeometry} */
281static DECLCALLBACK(int) drvHostBaseGetLCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
282{
283 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
284 RTCritSectEnter(&pThis->CritSect);
285
286 int rc = VINF_SUCCESS;
287 if (pThis->fMediaPresent)
288 {
289 if ( pThis->LCHSGeometry.cCylinders > 0
290 && pThis->LCHSGeometry.cHeads > 0
291 && pThis->LCHSGeometry.cSectors > 0)
292 {
293 *pLCHSGeometry = pThis->LCHSGeometry;
294 }
295 else
296 rc = VERR_PDM_GEOMETRY_NOT_SET;
297 }
298 else
299 rc = VERR_PDM_MEDIA_NOT_MOUNTED;
300
301 RTCritSectLeave(&pThis->CritSect);
302 LogFlow(("%s-%d: %s: returns %Rrc CHS={%d,%d,%d}\n",
303 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, __FUNCTION__, rc,
304 pThis->LCHSGeometry.cCylinders, pThis->LCHSGeometry.cHeads, pThis->LCHSGeometry.cSectors));
305 return rc;
306}
307
308
309/** @interface_method_impl{PDMIMEDIA,pfnBiosSetLCHSGeometry} */
310static DECLCALLBACK(int) drvHostBaseSetLCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
311{
312 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
313 LogFlow(("%s-%d: %s: cCylinders=%d cHeads=%d cSectors=%d\n",
314 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, __FUNCTION__,
315 pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
316 RTCritSectEnter(&pThis->CritSect);
317
318 int rc = VINF_SUCCESS;
319 if (pThis->fMediaPresent)
320 {
321 pThis->LCHSGeometry = *pLCHSGeometry;
322 }
323 else
324 {
325 AssertMsgFailed(("Invalid state! Not mounted!\n"));
326 rc = VERR_PDM_MEDIA_NOT_MOUNTED;
327 }
328
329 RTCritSectLeave(&pThis->CritSect);
330 return rc;
331}
332
333
334/** @interface_method_impl{PDMIMEDIA,pfnBiosIsVisible} */
335static DECLCALLBACK(bool) drvHostBaseIsVisible(PPDMIMEDIA pInterface)
336{
337 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
338 return pThis->fBiosVisible;
339}
340
341
342
343/* -=-=-=-=- IMediaEx -=-=-=-=- */
344
345DECLHIDDEN(int) drvHostBaseBufferRetain(PDRVHOSTBASE pThis, PDRVHOSTBASEREQ pReq, size_t cbBuf, bool fWrite, void **ppvBuf)
346{
347 int rc = VINF_SUCCESS;
348
349 if (pThis->cbBuf < cbBuf)
350 {
351 RTMemFree(pThis->pvBuf);
352 pThis->cbBuf = 0;
353 pThis->pvBuf = RTMemAlloc(cbBuf);
354 if (pThis->pvBuf)
355 pThis->cbBuf = cbBuf;
356 else
357 rc = VERR_NO_MEMORY;
358 }
359
360 if (RT_SUCCESS(rc) && fWrite)
361 {
362 RTSGSEG Seg;
363 RTSGBUF SgBuf;
364
365 Seg.pvSeg = pThis->pvBuf;
366 Seg.cbSeg = cbBuf;
367 RTSgBufInit(&SgBuf, &Seg, 1);
368 rc = pThis->pDrvMediaExPort->pfnIoReqCopyToBuf(pThis->pDrvMediaExPort, (PDMMEDIAEXIOREQ)pReq,
369 &pReq->abAlloc[0], 0, &SgBuf, cbBuf);
370 }
371
372 if (RT_SUCCESS(rc))
373 *ppvBuf = pThis->pvBuf;
374
375 return rc;
376}
377
378DECLHIDDEN(int) drvHostBaseBufferRelease(PDRVHOSTBASE pThis, PDRVHOSTBASEREQ pReq, size_t cbBuf, bool fWrite, void *pvBuf)
379{
380 int rc = VINF_SUCCESS;
381
382 if (!fWrite)
383 {
384 RTSGSEG Seg;
385 RTSGBUF SgBuf;
386
387 Seg.pvSeg = pvBuf;
388 Seg.cbSeg = cbBuf;
389 RTSgBufInit(&SgBuf, &Seg, 1);
390 rc = pThis->pDrvMediaExPort->pfnIoReqCopyFromBuf(pThis->pDrvMediaExPort, (PDMMEDIAEXIOREQ)pReq,
391 &pReq->abAlloc[0], 0, &SgBuf, cbBuf);
392 }
393
394 return rc;
395}
396
397/** @interface_method_impl{PDMIMEDIAEX,pfnQueryFeatures} */
398static DECLCALLBACK(int) drvHostBaseQueryFeatures(PPDMIMEDIAEX pInterface, uint32_t *pfFeatures)
399{
400 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMediaEx);
401
402 *pfFeatures = pThis->IMediaEx.pfnIoReqSendScsiCmd ? PDMIMEDIAEX_FEATURE_F_RAWSCSICMD : 0;
403 return VINF_SUCCESS;
404}
405
406/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqAllocSizeSet} */
407static DECLCALLBACK(int) drvHostBaseIoReqAllocSizeSet(PPDMIMEDIAEX pInterface, size_t cbIoReqAlloc)
408{
409 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMediaEx);
410
411 pThis->cbIoReqAlloc = RT_OFFSETOF(DRVHOSTBASEREQ, abAlloc[cbIoReqAlloc]);
412 return VINF_SUCCESS;
413}
414
415/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqAlloc} */
416static DECLCALLBACK(int) drvHostBaseIoReqAlloc(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc,
417 PDMMEDIAEXIOREQID uIoReqId, uint32_t fFlags)
418{
419 RT_NOREF2(uIoReqId, fFlags);
420
421 int rc = VINF_SUCCESS;
422 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMediaEx);
423 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)RTMemAllocZ(pThis->cbIoReqAlloc);
424 if (RT_LIKELY(pReq))
425 {
426 pReq->cbReq = 0;
427 pReq->cbResidual = 0;
428 *phIoReq = (PDMMEDIAEXIOREQ)pReq;
429 *ppvIoReqAlloc = &pReq->abAlloc[0];
430 }
431 else
432 rc = VERR_NO_MEMORY;
433
434 return rc;
435}
436
437/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqFree} */
438static DECLCALLBACK(int) drvHostBaseIoReqFree(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
439{
440 RT_NOREF1(pInterface);
441 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)hIoReq;
442
443 RTMemFree(pReq);
444 return VINF_SUCCESS;
445}
446
447/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQueryResidual} */
448static DECLCALLBACK(int) drvHostBaseIoReqQueryResidual(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbResidual)
449{
450 RT_NOREF1(pInterface);
451 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)hIoReq;
452
453 *pcbResidual = pReq->cbResidual;
454 return VINF_SUCCESS;
455}
456
457/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQueryXferSize} */
458static DECLCALLBACK(int) drvHostBaseIoReqQueryXferSize(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbXfer)
459{
460 RT_NOREF1(pInterface);
461 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)hIoReq;
462
463 *pcbXfer = pReq->cbReq;
464 return VINF_SUCCESS;
465}
466
467/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancelAll} */
468static DECLCALLBACK(int) drvHostBaseIoReqCancelAll(PPDMIMEDIAEX pInterface)
469{
470 RT_NOREF1(pInterface);
471 return VINF_SUCCESS;
472}
473
474/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancel} */
475static DECLCALLBACK(int) drvHostBaseIoReqCancel(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQID uIoReqId)
476{
477 RT_NOREF2(pInterface, uIoReqId);
478 return VERR_PDM_MEDIAEX_IOREQID_NOT_FOUND;
479}
480
481/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqRead} */
482static DECLCALLBACK(int) drvHostBaseIoReqRead(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbRead)
483{
484 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMediaEx);
485 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)hIoReq;
486 LogFlow(("%s-%d: drvHostBaseIoReqRead: off=%#llx cbRead=%#x (%s)\n",
487 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, cbRead, pThis->pszDevice));
488 RTCritSectEnter(&pThis->CritSect);
489
490 pReq->cbReq = cbRead;
491 pReq->cbResidual = cbRead;
492
493 STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
494 STAM_REL_COUNTER_INC(&pThis->StatReqsRead);
495
496 /*
497 * Check the state.
498 */
499 int rc;
500 if (pThis->fMediaPresent)
501 {
502 void *pvBuf;
503 rc = drvHostBaseBufferRetain(pThis, pReq, cbRead, false, &pvBuf);
504 if (RT_SUCCESS(rc))
505 {
506 /*
507 * Seek and read.
508 */
509 rc = drvHostBaseReadOs(pThis, off, pvBuf, cbRead);
510 if (RT_SUCCESS(rc))
511 {
512 Log2(("%s-%d: drvHostBaseReadOs: off=%#llx cbRead=%#x\n"
513 "%16.*Rhxd\n",
514 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, cbRead, cbRead, pvBuf));
515
516 pReq->cbResidual = 0;
517 }
518 else
519 Log(("%s-%d: drvHostBaseIoReqRead: drvHostBaseReadOs(%#llx, %p, %#x) -> %Rrc ('%s')\n",
520 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance,
521 off, pvBuf, cbRead, rc, pThis->pszDevice));
522
523 rc = drvHostBaseBufferRelease(pThis, pReq, cbRead, false, pvBuf);
524 }
525 else
526 Log(("%s-%d: drvHostBaseIoReqRead: drvHostBaseBufferRetain(%#llx, %p, %#x) -> %Rrc ('%s')\n",
527 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance,
528 off, pvBuf, cbRead, rc, pThis->pszDevice));
529 }
530 else
531 rc = VERR_MEDIA_NOT_PRESENT;
532
533 if (RT_SUCCESS(rc))
534 {
535 STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
536 STAM_REL_COUNTER_INC(&pThis->StatBytesRead);
537 }
538 else
539 STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
540
541 RTCritSectLeave(&pThis->CritSect);
542 LogFlow(("%s-%d: drvHostBaseIoReqRead: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
543 return rc;
544}
545
546/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqWrite} */
547static DECLCALLBACK(int) drvHostBaseIoReqWrite(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbWrite)
548{
549 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMediaEx);
550 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)hIoReq;
551 LogFlow(("%s-%d: drvHostBaseIoReqWrite: off=%#llx cbWrite=%#x (%s)\n",
552 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, cbWrite, pThis->pszDevice));
553 RTCritSectEnter(&pThis->CritSect);
554
555 pReq->cbReq = cbWrite;
556 pReq->cbResidual = cbWrite;
557
558 STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
559 STAM_REL_COUNTER_INC(&pThis->StatReqsWrite);
560
561 /*
562 * Check the state.
563 */
564 int rc;
565 if (!pThis->fReadOnly)
566 {
567 if (pThis->fMediaPresent)
568 {
569 void *pvBuf;
570 rc = drvHostBaseBufferRetain(pThis, pReq, cbWrite, true, &pvBuf);
571 if (RT_SUCCESS(rc))
572 {
573 Log2(("%s-%d: drvHostBaseIoReqWrite: off=%#llx cbWrite=%#x\n"
574 "%16.*Rhxd\n",
575 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, cbWrite, cbWrite, pvBuf));
576 /*
577 * Seek and write.
578 */
579 rc = drvHostBaseWriteOs(pThis, off, pvBuf, cbWrite);
580 if (RT_FAILURE(rc))
581 Log(("%s-%d: drvHostBaseIoReqWrite: drvHostBaseWriteOs(%#llx, %p, %#x) -> %Rrc ('%s')\n",
582 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance,
583 off, pvBuf, cbWrite, rc, pThis->pszDevice));
584 else
585 pReq->cbResidual = 0;
586
587 rc = drvHostBaseBufferRelease(pThis, pReq, cbWrite, true, pvBuf);
588 }
589 }
590 else
591 rc = VERR_MEDIA_NOT_PRESENT;
592 }
593 else
594 rc = VERR_WRITE_PROTECT;
595
596 if (RT_SUCCESS(rc))
597 {
598 STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
599 STAM_REL_COUNTER_INC(&pThis->StatBytesWritten);
600 }
601 else
602 STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
603
604 RTCritSectLeave(&pThis->CritSect);
605 LogFlow(("%s-%d: drvHostBaseIoReqWrite: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
606 return rc;
607}
608
609/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqFlush} */
610static DECLCALLBACK(int) drvHostBaseIoReqFlush(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
611{
612 RT_NOREF1(hIoReq);
613
614 int rc;
615 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMediaEx);
616 LogFlow(("%s-%d: drvHostBaseIoReqFlush: (%s)\n",
617 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice));
618 RTCritSectEnter(&pThis->CritSect);
619
620 STAM_REL_COUNTER_INC(&pThis->StatReqsSubmitted);
621 STAM_REL_COUNTER_INC(&pThis->StatReqsFlush);
622
623 if (pThis->fMediaPresent)
624 rc = drvHostBaseFlushOs(pThis);
625 else
626 rc = VERR_MEDIA_NOT_PRESENT;
627
628 if (RT_SUCCESS(rc))
629 STAM_REL_COUNTER_INC(&pThis->StatReqsSucceeded);
630 else
631 STAM_REL_COUNTER_INC(&pThis->StatReqsFailed);
632
633 RTCritSectLeave(&pThis->CritSect);
634 LogFlow(("%s-%d: drvHostBaseFlush: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
635 return rc;
636}
637
638/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqDiscard} */
639static DECLCALLBACK(int) drvHostBaseIoReqDiscard(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, unsigned cRangesMax)
640{
641 RT_NOREF3(pInterface, hIoReq, cRangesMax);
642 return VERR_NOT_SUPPORTED;
643}
644
645/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetActiveCount} */
646static DECLCALLBACK(uint32_t) drvHostBaseIoReqGetActiveCount(PPDMIMEDIAEX pInterface)
647{
648 RT_NOREF1(pInterface);
649 return 0;
650}
651
652/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetSuspendedCount} */
653static DECLCALLBACK(uint32_t) drvHostBaseIoReqGetSuspendedCount(PPDMIMEDIAEX pInterface)
654{
655 RT_NOREF1(pInterface);
656 return 0;
657}
658
659/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedStart} */
660static DECLCALLBACK(int) drvHostBaseIoReqQuerySuspendedStart(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc)
661{
662 RT_NOREF3(pInterface, phIoReq, ppvIoReqAlloc);
663 return VERR_NOT_IMPLEMENTED;
664}
665
666/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedNext} */
667static DECLCALLBACK(int) drvHostBaseIoReqQuerySuspendedNext(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq,
668 PPDMMEDIAEXIOREQ phIoReqNext, void **ppvIoReqAllocNext)
669{
670 RT_NOREF4(pInterface, hIoReq, phIoReqNext, ppvIoReqAllocNext);
671 return VERR_NOT_IMPLEMENTED;
672}
673
674/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedSave} */
675static DECLCALLBACK(int) drvHostBaseIoReqSuspendedSave(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
676{
677 RT_NOREF3(pInterface, pSSM, hIoReq);
678 return VERR_NOT_IMPLEMENTED;
679}
680
681/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedLoad} */
682static DECLCALLBACK(int) drvHostBaseIoReqSuspendedLoad(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
683{
684 RT_NOREF3(pInterface, pSSM, hIoReq);
685 return VERR_NOT_IMPLEMENTED;
686}
687
688
689
690/* -=-=-=-=- IMount -=-=-=-=- */
691
692/** @interface_method_impl{PDMIMOUNT,pfnUnmount} */
693static DECLCALLBACK(int) drvHostBaseUnmount(PPDMIMOUNT pInterface, bool fForce, bool fEject)
694{
695 RT_NOREF(fEject);
696 /* While we're not mountable (see drvHostBaseMount), we're unmountable. */
697 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
698 RTCritSectEnter(&pThis->CritSect);
699
700 /*
701 * Validate state.
702 */
703 int rc = VINF_SUCCESS;
704 if (!pThis->fLocked || fForce)
705 {
706 /* Unlock drive if necessary. */
707 if (pThis->fLocked)
708 {
709 if (pThis->pfnDoLock)
710 rc = pThis->pfnDoLock(pThis, false);
711 if (RT_SUCCESS(rc))
712 pThis->fLocked = false;
713 }
714
715 if (fEject)
716 {
717 /*
718 * Eject the disc.
719 */
720 rc = drvHostBaseEjectOs(pThis);
721 }
722
723 /*
724 * Media is no longer present.
725 */
726 DRVHostBaseMediaNotPresent(pThis);
727 }
728 else
729 {
730 Log(("drvHostBaseUnmount: Locked\n"));
731 rc = VERR_PDM_MEDIA_LOCKED;
732 }
733
734 RTCritSectLeave(&pThis->CritSect);
735 LogFlow(("drvHostBaseUnmount: returns %Rrc\n", rc));
736 return rc;
737}
738
739
740/** @interface_method_impl{PDMIMOUNT,pfnIsMounted} */
741static DECLCALLBACK(bool) drvHostBaseIsMounted(PPDMIMOUNT pInterface)
742{
743 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
744 RTCritSectEnter(&pThis->CritSect);
745
746 bool fRc = pThis->fMediaPresent;
747
748 RTCritSectLeave(&pThis->CritSect);
749 return fRc;
750}
751
752
753/** @interface_method_impl{PDMIMOUNT,pfnIsLocked} */
754static DECLCALLBACK(int) drvHostBaseLock(PPDMIMOUNT pInterface)
755{
756 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
757 RTCritSectEnter(&pThis->CritSect);
758
759 int rc = VINF_SUCCESS;
760 if (!pThis->fLocked)
761 {
762 if (pThis->pfnDoLock)
763 rc = pThis->pfnDoLock(pThis, true);
764 if (RT_SUCCESS(rc))
765 pThis->fLocked = true;
766 }
767 else
768 LogFlow(("%s-%d: drvHostBaseLock: already locked\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
769
770 RTCritSectLeave(&pThis->CritSect);
771 LogFlow(("%s-%d: drvHostBaseLock: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
772 return rc;
773}
774
775
776/** @interface_method_impl{PDMIMOUNT,pfnIsLocked} */
777static DECLCALLBACK(int) drvHostBaseUnlock(PPDMIMOUNT pInterface)
778{
779 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
780 RTCritSectEnter(&pThis->CritSect);
781
782 int rc = VINF_SUCCESS;
783 if (pThis->fLocked)
784 {
785 if (pThis->pfnDoLock)
786 rc = pThis->pfnDoLock(pThis, false);
787 if (RT_SUCCESS(rc))
788 pThis->fLocked = false;
789 }
790 else
791 LogFlow(("%s-%d: drvHostBaseUnlock: not locked\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
792
793 RTCritSectLeave(&pThis->CritSect);
794 LogFlow(("%s-%d: drvHostBaseUnlock: returns %Rrc\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, rc));
795 return rc;
796}
797
798
799/** @interface_method_impl{PDMIMOUNT,pfnIsLocked} */
800static DECLCALLBACK(bool) drvHostBaseIsLocked(PPDMIMOUNT pInterface)
801{
802 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
803 RTCritSectEnter(&pThis->CritSect);
804
805 bool fRc = pThis->fLocked;
806
807 RTCritSectLeave(&pThis->CritSect);
808 return fRc;
809}
810
811
812/* -=-=-=-=- IBase -=-=-=-=- */
813
814/**
815 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
816 */
817static DECLCALLBACK(void *) drvHostBaseQueryInterface(PPDMIBASE pInterface, const char *pszIID)
818{
819 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
820 PDRVHOSTBASE pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTBASE);
821
822 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
823 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
824 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNT, &pThis->IMount);
825 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEX, pThis->pDrvMediaExPort ? &pThis->IMediaEx : NULL);
826 return NULL;
827}
828
829
830/* -=-=-=-=- poller thread -=-=-=-=- */
831
832
833/**
834 * Media present.
835 * Query the size and notify the above driver / device.
836 *
837 * @param pThis The instance data.
838 */
839DECLHIDDEN(int) DRVHostBaseMediaPresent(PDRVHOSTBASE pThis)
840{
841 /*
842 * Open the drive.
843 */
844 int rc = drvHostBaseMediaRefreshOs(pThis);
845 if (RT_FAILURE(rc))
846 return rc;
847
848 /*
849 * Determine the size.
850 */
851 uint64_t cb;
852 rc = drvHostBaseGetMediaSizeOs(pThis, &cb);
853 if (RT_FAILURE(rc))
854 {
855 LogFlow(("%s-%d: failed to figure media size of %s, rc=%Rrc\n",
856 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice, rc));
857 return rc;
858 }
859
860 /*
861 * Update the data and inform the unit.
862 */
863 pThis->cbSize = cb;
864 pThis->fMediaPresent = true;
865 if (pThis->pDrvMountNotify)
866 pThis->pDrvMountNotify->pfnMountNotify(pThis->pDrvMountNotify);
867 LogFlow(("%s-%d: drvHostBaseMediaPresent: cbSize=%lld (%#llx)\n",
868 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->cbSize, pThis->cbSize));
869 return VINF_SUCCESS;
870}
871
872
873/**
874 * Media no longer present.
875 * @param pThis The instance data.
876 */
877DECLHIDDEN(void) DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis)
878{
879 pThis->fMediaPresent = false;
880 pThis->fLocked = false;
881 pThis->PCHSGeometry.cCylinders = 0;
882 pThis->PCHSGeometry.cHeads = 0;
883 pThis->PCHSGeometry.cSectors = 0;
884 pThis->LCHSGeometry.cCylinders = 0;
885 pThis->LCHSGeometry.cHeads = 0;
886 pThis->LCHSGeometry.cSectors = 0;
887 if (pThis->pDrvMountNotify)
888 pThis->pDrvMountNotify->pfnUnmountNotify(pThis->pDrvMountNotify);
889}
890
891
892static int drvHostBaseMediaPoll(PDRVHOSTBASE pThis)
893{
894 /*
895 * Poll for media change.
896 */
897 bool fMediaPresent = false;
898 bool fMediaChanged = false;
899 drvHostBaseQueryMediaStatusOs(pThis, &fMediaChanged, &fMediaPresent);
900
901 RTCritSectEnter(&pThis->CritSect);
902
903 int rc = VINF_SUCCESS;
904 if (pThis->fMediaPresent != fMediaPresent)
905 {
906 LogFlow(("drvHostDvdPoll: %d -> %d\n", pThis->fMediaPresent, fMediaPresent));
907 pThis->fMediaPresent = false;
908 if (fMediaPresent)
909 rc = DRVHostBaseMediaPresent(pThis);
910 else
911 DRVHostBaseMediaNotPresent(pThis);
912 }
913 else if (fMediaPresent)
914 {
915 /*
916 * Poll for media change.
917 */
918 if (fMediaChanged)
919 {
920 LogFlow(("drvHostDVDMediaThread: Media changed!\n"));
921 DRVHostBaseMediaNotPresent(pThis);
922 rc = DRVHostBaseMediaPresent(pThis);
923 }
924 }
925
926 RTCritSectLeave(&pThis->CritSect);
927 return rc;
928}
929
930
931/**
932 * This thread will periodically poll the device for media presence.
933 *
934 * @returns Ignored.
935 * @param ThreadSelf Handle of this thread. Ignored.
936 * @param pvUser Pointer to the driver instance structure.
937 */
938static DECLCALLBACK(int) drvHostBaseMediaThread(RTTHREAD ThreadSelf, void *pvUser)
939{
940 PDRVHOSTBASE pThis = (PDRVHOSTBASE)pvUser;
941 LogFlow(("%s-%d: drvHostBaseMediaThread: ThreadSelf=%p pvUser=%p\n",
942 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, ThreadSelf, pvUser));
943 bool fFirst = true;
944 int cRetries = 10;
945 while (!pThis->fShutdownPoller)
946 {
947 /*
948 * Perform the polling (unless we've run out of 50ms retries).
949 */
950 if (cRetries-- > 0)
951 {
952
953 int rc = drvHostBaseMediaPoll(pThis);
954 if (RT_FAILURE(rc))
955 {
956 RTSemEventWait(pThis->EventPoller, 50);
957 continue;
958 }
959 }
960
961 /*
962 * Signal EMT after the first go.
963 */
964 if (fFirst)
965 {
966 RTThreadUserSignal(ThreadSelf);
967 fFirst = false;
968 }
969
970 /*
971 * Sleep.
972 */
973 int rc = RTSemEventWait(pThis->EventPoller, pThis->cMilliesPoller);
974 if ( RT_FAILURE(rc)
975 && rc != VERR_TIMEOUT)
976 {
977 AssertMsgFailed(("rc=%Rrc\n", rc));
978 pThis->ThreadPoller = NIL_RTTHREAD;
979 LogFlow(("drvHostBaseMediaThread: returns %Rrc\n", rc));
980 return rc;
981 }
982 cRetries = 10;
983 }
984
985 /* (Don't clear the thread handle here, the destructor thread is using it to wait.) */
986 LogFlow(("%s-%d: drvHostBaseMediaThread: returns VINF_SUCCESS\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
987 return VINF_SUCCESS;
988}
989
990/**
991 * Registers statistics associated with the given media driver.
992 *
993 * @returns VBox status code.
994 * @param pThis The media driver instance.
995 */
996static int drvHostBaseStatsRegister(PDRVHOSTBASE pThis)
997{
998 PPDMDRVINS pDrvIns = pThis->pDrvIns;
999 uint32_t iInstance, iLUN;
1000 const char *pcszController;
1001
1002 int rc = pThis->pDrvMediaPort->pfnQueryDeviceLocation(pThis->pDrvMediaPort, &pcszController,
1003 &iInstance, &iLUN);
1004 if (RT_SUCCESS(rc))
1005 {
1006 char *pszCtrlUpper = RTStrDup(pcszController);
1007 if (pszCtrlUpper)
1008 {
1009 RTStrToUpper(pszCtrlUpper);
1010
1011 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
1012 "Amount of data read.", "/Devices/%s%u/Port%u/ReadBytes", pszCtrlUpper, iInstance, iLUN);
1013 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
1014 "Amount of data written.", "/Devices/%s%u/Port%u/WrittenBytes", pszCtrlUpper, iInstance, iLUN);
1015
1016 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsSubmitted, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
1017 "Number of I/O requests submitted.", "/Devices/%s%u/Port%u/ReqsSubmitted", pszCtrlUpper, iInstance, iLUN);
1018 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsFailed, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
1019 "Number of I/O requests failed.", "/Devices/%s%u/Port%u/ReqsFailed", pszCtrlUpper, iInstance, iLUN);
1020 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsSucceeded, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
1021 "Number of I/O requests succeeded.", "/Devices/%s%u/Port%u/ReqsSucceeded", pszCtrlUpper, iInstance, iLUN);
1022 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsFlush, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
1023 "Number of flush I/O requests submitted.", "/Devices/%s%u/Port%u/ReqsFlush", pszCtrlUpper, iInstance, iLUN);
1024 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsWrite, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
1025 "Number of write I/O requests submitted.", "/Devices/%s%u/Port%u/ReqsWrite", pszCtrlUpper, iInstance, iLUN);
1026 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReqsRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT,
1027 "Number of read I/O requests submitted.", "/Devices/%s%u/Port%u/ReqsRead", pszCtrlUpper, iInstance, iLUN);
1028
1029 RTStrFree(pszCtrlUpper);
1030 }
1031 else
1032 rc = VERR_NO_STR_MEMORY;
1033 }
1034
1035 return rc;
1036}
1037
1038/**
1039 * Deregisters statistics associated with the given media driver.
1040 *
1041 * @returns nothing.
1042 * @param pThis The media driver instance.
1043 */
1044static void drvhostBaseStatsDeregister(PDRVHOSTBASE pThis)
1045{
1046 PPDMDRVINS pDrvIns = pThis->pDrvIns;
1047
1048 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatBytesRead);
1049 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatBytesWritten);
1050 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsSubmitted);
1051 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsFailed);
1052 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsSucceeded);
1053 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsFlush);
1054 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsWrite);
1055 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReqsRead);
1056}
1057
1058/* -=-=-=-=- driver interface -=-=-=-=- */
1059
1060
1061/**
1062 * Done state load operation.
1063 *
1064 * @returns VBox load code.
1065 * @param pDrvIns Driver instance of the driver which registered the data unit.
1066 * @param pSSM SSM operation handle.
1067 */
1068static DECLCALLBACK(int) drvHostBaseLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
1069{
1070 RT_NOREF(pSSM);
1071 PDRVHOSTBASE pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTBASE);
1072 LogFlow(("%s-%d: drvHostBaseMediaThread:\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
1073 RTCritSectEnter(&pThis->CritSect);
1074
1075 /*
1076 * Tell the device/driver above us that the media status is uncertain.
1077 */
1078 if (pThis->pDrvMountNotify)
1079 {
1080 pThis->pDrvMountNotify->pfnUnmountNotify(pThis->pDrvMountNotify);
1081 if (pThis->fMediaPresent)
1082 pThis->pDrvMountNotify->pfnMountNotify(pThis->pDrvMountNotify);
1083 }
1084
1085 RTCritSectLeave(&pThis->CritSect);
1086 return VINF_SUCCESS;
1087}
1088
1089
1090/** @copydoc FNPDMDRVDESTRUCT */
1091DECLCALLBACK(void) DRVHostBaseDestruct(PPDMDRVINS pDrvIns)
1092{
1093 PDRVHOSTBASE pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTBASE);
1094 LogFlow(("%s-%d: drvHostBaseDestruct: iInstance=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pDrvIns->iInstance));
1095
1096 /*
1097 * Terminate the thread.
1098 */
1099 if (pThis->ThreadPoller != NIL_RTTHREAD)
1100 {
1101 pThis->fShutdownPoller = true;
1102 int rc;
1103 int cTimes = 50;
1104 do
1105 {
1106 RTSemEventSignal(pThis->EventPoller);
1107 rc = RTThreadWait(pThis->ThreadPoller, 100, NULL);
1108 } while (cTimes-- > 0 && rc == VERR_TIMEOUT);
1109
1110 if (!rc)
1111 pThis->ThreadPoller = NIL_RTTHREAD;
1112 }
1113
1114 /*
1115 * Cleanup the other resources.
1116 */
1117 drvHostBaseDestructOs(pThis);
1118
1119 if (pThis->EventPoller != NULL)
1120 {
1121 RTSemEventDestroy(pThis->EventPoller);
1122 pThis->EventPoller = NULL;
1123 }
1124
1125 if (pThis->pszDevice)
1126 {
1127 MMR3HeapFree(pThis->pszDevice);
1128 pThis->pszDevice = NULL;
1129 }
1130
1131 if (pThis->pszDeviceOpen)
1132 {
1133 RTStrFree(pThis->pszDeviceOpen);
1134 pThis->pszDeviceOpen = NULL;
1135 }
1136
1137 if (pThis->pvBuf)
1138 {
1139 RTMemFree(pThis->pvBuf);
1140 pThis->pvBuf = NULL;
1141 pThis->cbBuf = 0;
1142 }
1143
1144 /* Forget about the notifications. */
1145 pThis->pDrvMountNotify = NULL;
1146
1147 drvhostBaseStatsDeregister(pThis);
1148
1149 /* Leave the instance operational if this is just a cleanup of the state
1150 * after an attach error happened. So don't destroy the critsect then. */
1151 if (!pThis->fKeepInstance && RTCritSectIsInitialized(&pThis->CritSect))
1152 RTCritSectDelete(&pThis->CritSect);
1153 LogFlow(("%s-%d: drvHostBaseDestruct completed\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
1154}
1155
1156
1157/**
1158 * Initializes the instance data .
1159 *
1160 * On failure call DRVHostBaseDestruct().
1161 *
1162 * @returns VBox status code.
1163 * @param pDrvIns Driver instance.
1164 * @param pszCfgValid Pointer to a string of valid CFGM options.
1165 * @param pCfg Configuration handle.
1166 * @param enmType Device type.
1167 */
1168DECLHIDDEN(int) DRVHostBaseInit(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, const char *pszCfgValid, PDMMEDIATYPE enmType)
1169{
1170 int src = VINF_SUCCESS;
1171 PDRVHOSTBASE pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTBASE);
1172 LogFlow(("%s-%d: DRVHostBaseInit: iInstance=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pDrvIns->iInstance));
1173
1174 /*
1175 * Initialize most of the data members.
1176 */
1177 pThis->pDrvIns = pDrvIns;
1178 pThis->fKeepInstance = false;
1179 pThis->ThreadPoller = NIL_RTTHREAD;
1180 pThis->enmType = enmType;
1181 pThis->fAttachFailError = true; /* It's an error until we've read the config. */
1182
1183 /* IBase. */
1184 pDrvIns->IBase.pfnQueryInterface = drvHostBaseQueryInterface;
1185
1186 /* IMedia. */
1187 pThis->IMedia.pfnRead = drvHostBaseRead;
1188 pThis->IMedia.pfnWrite = drvHostBaseWrite;
1189 pThis->IMedia.pfnFlush = drvHostBaseFlush;
1190 pThis->IMedia.pfnIsReadOnly = drvHostBaseIsReadOnly;
1191 pThis->IMedia.pfnIsNonRotational = drvHostBaseIsNonRotational;
1192 pThis->IMedia.pfnGetSize = drvHostBaseGetSize;
1193 pThis->IMedia.pfnGetType = drvHostBaseGetType;
1194 pThis->IMedia.pfnGetUuid = drvHostBaseGetUuid;
1195 pThis->IMedia.pfnBiosGetPCHSGeometry = drvHostBaseGetPCHSGeometry;
1196 pThis->IMedia.pfnBiosSetPCHSGeometry = drvHostBaseSetPCHSGeometry;
1197 pThis->IMedia.pfnBiosGetLCHSGeometry = drvHostBaseGetLCHSGeometry;
1198 pThis->IMedia.pfnBiosSetLCHSGeometry = drvHostBaseSetLCHSGeometry;
1199 pThis->IMedia.pfnBiosIsVisible = drvHostBaseIsVisible;
1200
1201 /* IMediaEx */
1202 pThis->IMediaEx.pfnQueryFeatures = drvHostBaseQueryFeatures;
1203 pThis->IMediaEx.pfnIoReqAllocSizeSet = drvHostBaseIoReqAllocSizeSet;
1204 pThis->IMediaEx.pfnIoReqAlloc = drvHostBaseIoReqAlloc;
1205 pThis->IMediaEx.pfnIoReqFree = drvHostBaseIoReqFree;
1206 pThis->IMediaEx.pfnIoReqQueryResidual = drvHostBaseIoReqQueryResidual;
1207 pThis->IMediaEx.pfnIoReqQueryXferSize = drvHostBaseIoReqQueryXferSize;
1208 pThis->IMediaEx.pfnIoReqCancelAll = drvHostBaseIoReqCancelAll;
1209 pThis->IMediaEx.pfnIoReqCancel = drvHostBaseIoReqCancel;
1210 pThis->IMediaEx.pfnIoReqRead = drvHostBaseIoReqRead;
1211 pThis->IMediaEx.pfnIoReqWrite = drvHostBaseIoReqWrite;
1212 pThis->IMediaEx.pfnIoReqFlush = drvHostBaseIoReqFlush;
1213 pThis->IMediaEx.pfnIoReqDiscard = drvHostBaseIoReqDiscard;
1214 pThis->IMediaEx.pfnIoReqGetActiveCount = drvHostBaseIoReqGetActiveCount;
1215 pThis->IMediaEx.pfnIoReqGetSuspendedCount = drvHostBaseIoReqGetSuspendedCount;
1216 pThis->IMediaEx.pfnIoReqQuerySuspendedStart = drvHostBaseIoReqQuerySuspendedStart;
1217 pThis->IMediaEx.pfnIoReqQuerySuspendedNext = drvHostBaseIoReqQuerySuspendedNext;
1218 pThis->IMediaEx.pfnIoReqSuspendedSave = drvHostBaseIoReqSuspendedSave;
1219 pThis->IMediaEx.pfnIoReqSuspendedLoad = drvHostBaseIoReqSuspendedLoad;
1220
1221 /* IMount. */
1222 pThis->IMount.pfnUnmount = drvHostBaseUnmount;
1223 pThis->IMount.pfnIsMounted = drvHostBaseIsMounted;
1224 pThis->IMount.pfnLock = drvHostBaseLock;
1225 pThis->IMount.pfnUnlock = drvHostBaseUnlock;
1226 pThis->IMount.pfnIsLocked = drvHostBaseIsLocked;
1227
1228 drvHostBaseInitOs(pThis);
1229
1230 if (!CFGMR3AreValuesValid(pCfg, pszCfgValid))
1231 {
1232 pThis->fAttachFailError = true;
1233 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
1234 }
1235
1236 /*
1237 * Get the IMediaPort & IMountNotify interfaces of the above driver/device.
1238 */
1239 pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
1240 if (!pThis->pDrvMediaPort)
1241 {
1242 AssertMsgFailed(("Configuration error: No media port interface above!\n"));
1243 return VERR_PDM_MISSING_INTERFACE_ABOVE;
1244 }
1245 pThis->pDrvMediaExPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAEXPORT);
1246 pThis->pDrvMountNotify = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMOUNTNOTIFY);
1247
1248 /*
1249 * Query configuration.
1250 */
1251 /* Device */
1252 int rc = CFGMR3QueryStringAlloc(pCfg, "Path", &pThis->pszDevice);
1253 if (RT_FAILURE(rc))
1254 {
1255 AssertMsgFailed(("Configuration error: query for \"Path\" string returned %Rra.\n", rc));
1256 return rc;
1257 }
1258
1259 /* Mountable */
1260 uint32_t u32;
1261 rc = CFGMR3QueryU32Def(pCfg, "Interval", &u32, 1000);
1262 if (RT_SUCCESS(rc))
1263 pThis->cMilliesPoller = u32;
1264 else
1265 {
1266 AssertMsgFailed(("Configuration error: Query \"Mountable\" resulted in %Rrc.\n", rc));
1267 return rc;
1268 }
1269
1270 /* ReadOnly - passthrough mode requires read/write access in any case. */
1271 if ( (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD)
1272 && pThis->IMedia.pfnSendCmd)
1273 pThis->fReadOnlyConfig = false;
1274 else
1275 {
1276 rc = CFGMR3QueryBoolDef(pCfg, "ReadOnly", &pThis->fReadOnlyConfig,
1277 enmType == PDMMEDIATYPE_DVD || enmType == PDMMEDIATYPE_CDROM
1278 ? true
1279 : false);
1280 if (RT_FAILURE(rc))
1281 {
1282 AssertMsgFailed(("Configuration error: Query \"ReadOnly\" resulted in %Rrc.\n", rc));
1283 return rc;
1284 }
1285 }
1286
1287 /* Locked */
1288 rc = CFGMR3QueryBoolDef(pCfg, "Locked", &pThis->fLocked, false);
1289 if (RT_FAILURE(rc))
1290 {
1291 AssertMsgFailed(("Configuration error: Query \"Locked\" resulted in %Rrc.\n", rc));
1292 return rc;
1293 }
1294
1295 /* BIOS visible */
1296 rc = CFGMR3QueryBoolDef(pCfg, "BIOSVisible", &pThis->fBiosVisible, true);
1297 if (RT_FAILURE(rc))
1298 {
1299 AssertMsgFailed(("Configuration error: Query \"BIOSVisible\" resulted in %Rrc.\n", rc));
1300 return rc;
1301 }
1302
1303 /* Uuid */
1304 char *psz;
1305 rc = CFGMR3QueryStringAlloc(pCfg, "Uuid", &psz);
1306 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1307 RTUuidClear(&pThis->Uuid);
1308 else if (RT_SUCCESS(rc))
1309 {
1310 rc = RTUuidFromStr(&pThis->Uuid, psz);
1311 if (RT_FAILURE(rc))
1312 {
1313 AssertMsgFailed(("Configuration error: Uuid from string failed on \"%s\", rc=%Rrc.\n", psz, rc));
1314 MMR3HeapFree(psz);
1315 return rc;
1316 }
1317 MMR3HeapFree(psz);
1318 }
1319 else
1320 {
1321 AssertMsgFailed(("Configuration error: Failed to obtain the uuid, rc=%Rrc.\n", rc));
1322 return rc;
1323 }
1324
1325 /* Define whether attach failure is an error (default) or not. */
1326 bool fAttachFailError = true;
1327 rc = CFGMR3QueryBoolDef(pCfg, "AttachFailError", &fAttachFailError, true);
1328 pThis->fAttachFailError = fAttachFailError;
1329
1330 /* log config summary */
1331 Log(("%s-%d: pszDevice='%s' (%s) cMilliesPoller=%d fReadOnlyConfig=%d fLocked=%d fBIOSVisible=%d Uuid=%RTuuid\n",
1332 pDrvIns->pReg->szName, pDrvIns->iInstance, pThis->pszDevice, pThis->pszDeviceOpen, pThis->cMilliesPoller,
1333 pThis->fReadOnlyConfig, pThis->fLocked, pThis->fBiosVisible, &pThis->Uuid));
1334
1335 /*
1336 * Check that there are no drivers below us.
1337 */
1338 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
1339 ("Configuration error: Not possible to attach anything to this driver!\n"),
1340 VERR_PDM_DRVINS_NO_ATTACH);
1341
1342 /*
1343 * Register saved state.
1344 */
1345 rc = PDMDrvHlpSSMRegisterLoadDone(pDrvIns, drvHostBaseLoadDone);
1346 if (RT_FAILURE(rc))
1347 return rc;
1348
1349 /*
1350 * Initialize the critical section used for serializing the access to the media.
1351 */
1352 rc = RTCritSectInit(&pThis->CritSect);
1353 if (RT_FAILURE(rc))
1354 return rc;
1355
1356 /*
1357 * Open the device.
1358 */
1359 rc = drvHostBaseOpenOs(pThis, pThis->fReadOnlyConfig);
1360 if (RT_FAILURE(rc))
1361 {
1362 char *pszDevice = pThis->pszDevice;
1363#ifndef RT_OS_DARWIN
1364 char szPathReal[256];
1365 if ( RTPathExists(pszDevice)
1366 && RT_SUCCESS(RTPathReal(pszDevice, szPathReal, sizeof(szPathReal))))
1367 pszDevice = szPathReal;
1368#endif
1369
1370 /*
1371 * Disable CD/DVD passthrough in case it was enabled. Would cause
1372 * weird failures later when the guest issues commands. These would
1373 * all fail because of the invalid file handle. So use the normal
1374 * virtual CD/DVD code, which deals more gracefully with unavailable
1375 * "media" - actually a complete drive in this case.
1376 */
1377 pThis->IMedia.pfnSendCmd = NULL;
1378 AssertMsgFailed(("Could not open host device %s, rc=%Rrc\n", pszDevice, rc));
1379 switch (rc)
1380 {
1381 case VERR_ACCESS_DENIED:
1382 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1383#ifdef RT_OS_LINUX
1384 N_("Cannot open host device '%s' for %s access. Check the permissions "
1385 "of that device ('/bin/ls -l %s'): Most probably you need to be member "
1386 "of the device group. Make sure that you logout/login after changing "
1387 "the group settings of the current user"),
1388#else
1389 N_("Cannot open host device '%s' for %s access. Check the permissions "
1390 "of that device"),
1391#endif
1392 pszDevice, pThis->fReadOnlyConfig ? "readonly" : "read/write",
1393 pszDevice);
1394 default:
1395 {
1396 if (pThis->fAttachFailError)
1397 return rc;
1398 int erc = PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/,
1399 "DrvHost_MOUNTFAIL",
1400 N_("Cannot attach to host device '%s'"), pszDevice);
1401 AssertRC(erc);
1402 src = rc;
1403 }
1404 }
1405 }
1406
1407 /*
1408 * Lock the drive if that's required by the configuration.
1409 */
1410 if (pThis->fLocked)
1411 {
1412 if (pThis->pfnDoLock)
1413 rc = pThis->pfnDoLock(pThis, true);
1414 if (RT_FAILURE(rc))
1415 {
1416 AssertMsgFailed(("Failed to lock the dvd drive. rc=%Rrc\n", rc));
1417 return rc;
1418 }
1419 }
1420
1421 if (RT_SUCCESS(src) && drvHostBaseIsMediaPollingRequiredOs(pThis))
1422 {
1423 /*
1424 * Create the event semaphore which the poller thread will wait on.
1425 */
1426 rc = RTSemEventCreate(&pThis->EventPoller);
1427 if (RT_FAILURE(rc))
1428 return rc;
1429
1430 /*
1431 * Start the thread which will poll for the media.
1432 */
1433 rc = RTThreadCreate(&pThis->ThreadPoller, drvHostBaseMediaThread, pThis, 0,
1434 RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "DVDMEDIA");
1435 if (RT_FAILURE(rc))
1436 {
1437 AssertMsgFailed(("Failed to create poller thread. rc=%Rrc\n", rc));
1438 return rc;
1439 }
1440
1441 /*
1442 * Wait for the thread to start up (!w32:) and do one detection loop.
1443 */
1444 rc = RTThreadUserWait(pThis->ThreadPoller, 10000);
1445 AssertRC(rc);
1446 }
1447
1448 if (RT_SUCCESS(rc))
1449 drvHostBaseStatsRegister(pThis);
1450
1451 if (RT_FAILURE(rc))
1452 {
1453 if (!pThis->fAttachFailError)
1454 {
1455 /* Suppressing the attach failure error must not affect the normal
1456 * DRVHostBaseDestruct, so reset this flag below before leaving. */
1457 pThis->fKeepInstance = true;
1458 rc = VINF_SUCCESS;
1459 }
1460 DRVHostBaseDestruct(pDrvIns);
1461 pThis->fKeepInstance = false;
1462 }
1463
1464 if (RT_FAILURE(src))
1465 return src;
1466
1467 return rc;
1468}
1469
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