VirtualBox

source: vbox/trunk/src/VBox/Main/StorageControllerImpl.cpp@ 35263

Last change on this file since 35263 was 34010, checked in by vboxsync, 14 years ago

Main, FE/VBoxManage: Make it possible to mark specific controllers as bootable which means that the BIOS can access devices attached to the controller to boot from it

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.3 KB
Line 
1/* $Id: StorageControllerImpl.cpp 34010 2010-11-11 20:17:47Z vboxsync $ */
2
3/** @file
4 *
5 * Implementation of IStorageController.
6 */
7
8/*
9 * Copyright (C) 2008-2010 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include "StorageControllerImpl.h"
21#include "MachineImpl.h"
22#include "VirtualBoxImpl.h"
23#include "SystemPropertiesImpl.h"
24
25#include <iprt/string.h>
26#include <iprt/cpp/utils.h>
27
28#include <VBox/err.h>
29#include <VBox/settings.h>
30
31#include <algorithm>
32
33#include "AutoStateDep.h"
34#include "AutoCaller.h"
35#include "Logging.h"
36
37// defines
38/////////////////////////////////////////////////////////////////////////////
39
40struct BackupableStorageControllerData
41{
42 /* Constructor. */
43 BackupableStorageControllerData()
44 : mStorageBus(StorageBus_IDE),
45 mStorageControllerType(StorageControllerType_PIIX4),
46 mInstance(0),
47 mPortCount(2),
48 fUseHostIOCache(true),
49 fBootable(false),
50 mPortIde0Master(0),
51 mPortIde0Slave(1),
52 mPortIde1Master(2),
53 mPortIde1Slave(3)
54 { }
55
56 /** Unique name of the storage controller. */
57 Utf8Str strName;
58 /** The connection type of the storage controller. */
59 StorageBus_T mStorageBus;
60 /** Type of the Storage controller. */
61 StorageControllerType_T mStorageControllerType;
62 /** Instance number of the storage controller. */
63 ULONG mInstance;
64 /** Number of usable ports. */
65 ULONG mPortCount;
66 /** Whether to use the host IO caches. */
67 BOOL fUseHostIOCache;
68 /** Whether it is possible to boot from disks attached to this controller. */
69 BOOL fBootable;
70
71 /** The following is only for the SATA controller atm. */
72 /** Port which acts as primary master for ide emulation. */
73 ULONG mPortIde0Master;
74 /** Port which acts as primary slave for ide emulation. */
75 ULONG mPortIde0Slave;
76 /** Port which acts as secondary master for ide emulation. */
77 ULONG mPortIde1Master;
78 /** Port which acts as secondary slave for ide emulation. */
79 ULONG mPortIde1Slave;
80};
81
82struct StorageController::Data
83{
84 Data(Machine * const aMachine)
85 : pVirtualBox(NULL),
86 pSystemProperties(NULL),
87 pParent(aMachine)
88 {
89 unconst(pVirtualBox) = aMachine->getVirtualBox();
90 unconst(pSystemProperties) = pVirtualBox->getSystemProperties();
91 }
92
93 VirtualBox * const pVirtualBox;
94 SystemProperties * const pSystemProperties;
95
96 Machine * const pParent;
97 const ComObjPtr<StorageController> pPeer;
98
99 Backupable<BackupableStorageControllerData> bd;
100};
101
102// constructor / destructor
103/////////////////////////////////////////////////////////////////////////////
104
105HRESULT StorageController::FinalConstruct()
106{
107 return S_OK;
108}
109
110void StorageController::FinalRelease()
111{
112 uninit();
113}
114
115// public initializer/uninitializer for internal purposes only
116/////////////////////////////////////////////////////////////////////////////
117
118/**
119 * Initializes the storage controller object.
120 *
121 * @returns COM result indicator.
122 * @param aParent Pointer to our parent object.
123 * @param aName Name of the storage controller.
124 * @param aInstance Instance number of the storage controller.
125 */
126HRESULT StorageController::init(Machine *aParent,
127 const Utf8Str &aName,
128 StorageBus_T aStorageBus,
129 ULONG aInstance, bool fBootable)
130{
131 LogFlowThisFunc(("aParent=%p aName=\"%s\" aInstance=%u\n",
132 aParent, aName.c_str(), aInstance));
133
134 ComAssertRet(aParent && !aName.isEmpty(), E_INVALIDARG);
135 if ( (aStorageBus <= StorageBus_Null)
136 || (aStorageBus > StorageBus_SAS))
137 return setError(E_INVALIDARG,
138 tr("Invalid storage connection type"));
139
140 ULONG maxInstances;
141 ChipsetType_T chipsetType;
142 HRESULT rc = aParent->COMGETTER(ChipsetType)(&chipsetType);
143 if (FAILED(rc))
144 return rc;
145 rc = aParent->getVirtualBox()->getSystemProperties()->GetMaxInstancesOfStorageBus(chipsetType, aStorageBus, &maxInstances);
146 if (FAILED(rc))
147 return rc;
148 if (aInstance >= maxInstances)
149 return setError(E_INVALIDARG,
150 tr("Too many storage controllers of this type"));
151
152 /* Enclose the state transition NotReady->InInit->Ready */
153 AutoInitSpan autoInitSpan(this);
154 AssertReturn(autoInitSpan.isOk(), E_FAIL);
155
156 m = new Data(aParent);
157
158 /* m->pPeer is left null */
159
160 m->bd.allocate();
161
162 m->bd->strName = aName;
163 m->bd->mInstance = aInstance;
164 m->bd->fBootable = fBootable;
165 m->bd->mStorageBus = aStorageBus;
166 if ( aStorageBus != StorageBus_IDE
167 && aStorageBus != StorageBus_Floppy)
168 m->bd->fUseHostIOCache = false;
169 else
170 m->bd->fUseHostIOCache = true;
171
172 switch (aStorageBus)
173 {
174 case StorageBus_IDE:
175 m->bd->mPortCount = 2;
176 m->bd->mStorageControllerType = StorageControllerType_PIIX4;
177 break;
178 case StorageBus_SATA:
179 m->bd->mPortCount = 30;
180 m->bd->mStorageControllerType = StorageControllerType_IntelAhci;
181 break;
182 case StorageBus_SCSI:
183 m->bd->mPortCount = 16;
184 m->bd->mStorageControllerType = StorageControllerType_LsiLogic;
185 break;
186 case StorageBus_Floppy:
187 m->bd->mPortCount = 1;
188 m->bd->mStorageControllerType = StorageControllerType_I82078;
189 break;
190 case StorageBus_SAS:
191 m->bd->mPortCount = 8;
192 m->bd->mStorageControllerType = StorageControllerType_LsiLogicSas;
193 break;
194 }
195
196 /* Confirm a successful initialization */
197 autoInitSpan.setSucceeded();
198
199 return S_OK;
200}
201
202/**
203 * Initializes the object given another object
204 * (a kind of copy constructor). This object shares data with
205 * the object passed as an argument.
206 *
207 * @param aReshare
208 * When false, the original object will remain a data owner.
209 * Otherwise, data ownership will be transferred from the original
210 * object to this one.
211 *
212 * @note This object must be destroyed before the original object
213 * it shares data with is destroyed.
214 *
215 * @note Locks @a aThat object for writing if @a aReshare is @c true, or for
216 * reading if @a aReshare is false.
217 */
218HRESULT StorageController::init(Machine *aParent,
219 StorageController *aThat,
220 bool aReshare /* = false */)
221{
222 LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n",
223 aParent, aThat, aReshare));
224
225 ComAssertRet(aParent && aThat, E_INVALIDARG);
226
227 /* Enclose the state transition NotReady->InInit->Ready */
228 AutoInitSpan autoInitSpan(this);
229 AssertReturn(autoInitSpan.isOk(), E_FAIL);
230
231 m = new Data(aParent);
232
233 /* sanity */
234 AutoCaller thatCaller(aThat);
235 AssertComRCReturnRC(thatCaller.rc());
236
237 if (aReshare)
238 {
239 AutoWriteLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
240
241 unconst(aThat->m->pPeer) = this;
242 m->bd.attach (aThat->m->bd);
243 }
244 else
245 {
246 unconst(m->pPeer) = aThat;
247
248 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
249 m->bd.share (aThat->m->bd);
250 }
251
252 /* Confirm successful initialization */
253 autoInitSpan.setSucceeded();
254
255 return S_OK;
256}
257
258/**
259 * Initializes the storage controller object given another guest object
260 * (a kind of copy constructor). This object makes a private copy of data
261 * of the original object passed as an argument.
262 */
263HRESULT StorageController::initCopy(Machine *aParent, StorageController *aThat)
264{
265 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
266
267 ComAssertRet(aParent && aThat, E_INVALIDARG);
268
269 /* Enclose the state transition NotReady->InInit->Ready */
270 AutoInitSpan autoInitSpan(this);
271 AssertReturn(autoInitSpan.isOk(), E_FAIL);
272
273 m = new Data(aParent);
274 /* m->pPeer is left null */
275
276 AutoCaller thatCaller(aThat);
277 AssertComRCReturnRC(thatCaller.rc());
278
279 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
280 m->bd.attachCopy(aThat->m->bd);
281
282 /* Confirm a successful initialization */
283 autoInitSpan.setSucceeded();
284
285 return S_OK;
286}
287
288
289/**
290 * Uninitializes the instance and sets the ready flag to FALSE.
291 * Called either from FinalRelease() or by the parent when it gets destroyed.
292 */
293void StorageController::uninit()
294{
295 LogFlowThisFunc(("\n"));
296
297 /* Enclose the state transition Ready->InUninit->NotReady */
298 AutoUninitSpan autoUninitSpan(this);
299 if (autoUninitSpan.uninitDone())
300 return;
301
302 m->bd.free();
303
304 unconst(m->pPeer) = NULL;
305 unconst(m->pParent) = NULL;
306
307 delete m;
308 m = NULL;
309}
310
311
312// IStorageController properties
313/////////////////////////////////////////////////////////////////////////////
314STDMETHODIMP StorageController::COMGETTER(Name) (BSTR *aName)
315{
316 CheckComArgOutPointerValid(aName);
317
318 AutoCaller autoCaller(this);
319 if (FAILED(autoCaller.rc())) return autoCaller.rc();
320
321 /* mName is constant during life time, no need to lock */
322 m->bd.data()->strName.cloneTo(aName);
323
324 return S_OK;
325}
326
327STDMETHODIMP StorageController::COMGETTER(Bus) (StorageBus_T *aBus)
328{
329 CheckComArgOutPointerValid(aBus);
330
331 AutoCaller autoCaller(this);
332 if (FAILED(autoCaller.rc())) return autoCaller.rc();
333
334 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
335
336 *aBus = m->bd->mStorageBus;
337
338 return S_OK;
339}
340
341STDMETHODIMP StorageController::COMGETTER(ControllerType) (StorageControllerType_T *aControllerType)
342{
343 CheckComArgOutPointerValid(aControllerType);
344
345 AutoCaller autoCaller(this);
346 if (FAILED(autoCaller.rc())) return autoCaller.rc();
347
348 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
349
350 *aControllerType = m->bd->mStorageControllerType;
351
352 return S_OK;
353}
354
355STDMETHODIMP StorageController::COMSETTER(ControllerType) (StorageControllerType_T aControllerType)
356{
357 AutoCaller autoCaller(this);
358 if (FAILED(autoCaller.rc())) return autoCaller.rc();
359
360 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
361
362 HRESULT rc = S_OK;
363
364 switch (m->bd->mStorageBus)
365 {
366 case StorageBus_IDE:
367 {
368 if ( (aControllerType != StorageControllerType_PIIX3)
369 && (aControllerType != StorageControllerType_PIIX4)
370 && (aControllerType != StorageControllerType_ICH6))
371 rc = E_INVALIDARG;
372 break;
373 }
374 case StorageBus_SATA:
375 {
376 if (aControllerType != StorageControllerType_IntelAhci)
377 rc = E_INVALIDARG;
378 break;
379 }
380 case StorageBus_SCSI:
381 {
382 if ( (aControllerType != StorageControllerType_LsiLogic)
383 && (aControllerType != StorageControllerType_BusLogic))
384 rc = E_INVALIDARG;
385 break;
386 }
387 case StorageBus_Floppy:
388 {
389 if (aControllerType != StorageControllerType_I82078)
390 rc = E_INVALIDARG;
391 break;
392 }
393 case StorageBus_SAS:
394 {
395 if (aControllerType != StorageControllerType_LsiLogicSas)
396 rc = E_INVALIDARG;
397 break;
398 }
399 default:
400 AssertMsgFailed(("Invalid controller type %d\n", m->bd->mStorageBus));
401 }
402
403 if (!SUCCEEDED(rc))
404 return setError(rc,
405 tr ("Invalid controller type %d"),
406 aControllerType);
407
408 m->bd->mStorageControllerType = aControllerType;
409
410 return S_OK;
411}
412
413STDMETHODIMP StorageController::COMGETTER(MaxDevicesPerPortCount) (ULONG *aMaxDevices)
414{
415 CheckComArgOutPointerValid(aMaxDevices);
416
417 AutoCaller autoCaller(this);
418 if (FAILED(autoCaller.rc())) return autoCaller.rc();
419
420 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
421 HRESULT rc = m->pSystemProperties->GetMaxDevicesPerPortForStorageBus(m->bd->mStorageBus, aMaxDevices);
422
423 return rc;
424}
425
426STDMETHODIMP StorageController::COMGETTER(MinPortCount) (ULONG *aMinPortCount)
427{
428 CheckComArgOutPointerValid(aMinPortCount);
429
430 AutoCaller autoCaller(this);
431 if (FAILED(autoCaller.rc())) return autoCaller.rc();
432
433 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
434 HRESULT rc = m->pSystemProperties->GetMinPortCountForStorageBus(m->bd->mStorageBus, aMinPortCount);
435
436 return rc;
437}
438
439STDMETHODIMP StorageController::COMGETTER(MaxPortCount) (ULONG *aMaxPortCount)
440{
441 CheckComArgOutPointerValid(aMaxPortCount);
442
443 AutoCaller autoCaller(this);
444 if (FAILED(autoCaller.rc())) return autoCaller.rc();
445
446 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
447 HRESULT rc = m->pSystemProperties->GetMaxPortCountForStorageBus(m->bd->mStorageBus, aMaxPortCount);
448
449 return rc;
450}
451
452
453STDMETHODIMP StorageController::COMGETTER(PortCount) (ULONG *aPortCount)
454{
455 CheckComArgOutPointerValid(aPortCount);
456
457 AutoCaller autoCaller(this);
458 if (FAILED(autoCaller.rc())) return autoCaller.rc();
459
460 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
461
462 *aPortCount = m->bd->mPortCount;
463
464 return S_OK;
465}
466
467
468STDMETHODIMP StorageController::COMSETTER(PortCount) (ULONG aPortCount)
469{
470 LogFlowThisFunc(("aPortCount=%u\n", aPortCount));
471
472 switch (m->bd->mStorageBus)
473 {
474 case StorageBus_SATA:
475 {
476 /* AHCI SATA supports a maximum of 30 ports. */
477 if ((aPortCount < 1) || (aPortCount > 30))
478 return setError(E_INVALIDARG,
479 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
480 aPortCount, 1, 30);
481 break;
482 }
483 case StorageBus_SCSI:
484 {
485 /*
486 * SCSI does not support setting different ports.
487 * (doesn't make sense here either).
488 * The maximum and minimum is 16 and unless the callee
489 * tries to set a different value we return an error.
490 */
491 if (aPortCount != 16)
492 return setError(E_INVALIDARG,
493 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
494 aPortCount, 16, 16);
495 break;
496 }
497 case StorageBus_IDE:
498 {
499 /*
500 * The port count is fixed to 2.
501 */
502 if (aPortCount != 2)
503 return setError(E_INVALIDARG,
504 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
505 aPortCount, 2, 2);
506 break;
507 }
508 case StorageBus_Floppy:
509 {
510 /*
511 * The port count is fixed to 1.
512 */
513 if (aPortCount != 1)
514 return setError(E_INVALIDARG,
515 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
516 aPortCount, 1, 1);
517 break;
518 }
519 case StorageBus_SAS:
520 {
521 /*
522 * The port count is fixed to 8.
523 */
524 if (aPortCount != 8)
525 return setError(E_INVALIDARG,
526 tr("Invalid port count: %lu (must be in range [%lu, %lu])"),
527 aPortCount, 8, 8);
528 break;
529 }
530 default:
531 AssertMsgFailed(("Invalid controller type %d\n", m->bd->mStorageBus));
532 }
533
534 AutoCaller autoCaller(this);
535 if (FAILED(autoCaller.rc())) return autoCaller.rc();
536
537 /* the machine needs to be mutable */
538 AutoMutableStateDependency adep(m->pParent);
539 if (FAILED(adep.rc())) return adep.rc();
540
541 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
542
543 if (m->bd->mPortCount != aPortCount)
544 {
545 m->bd.backup();
546 m->bd->mPortCount = aPortCount;
547
548 alock.release();
549 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
550 m->pParent->setModified(Machine::IsModified_Storage);
551 mlock.release();
552
553 m->pParent->onStorageControllerChange();
554 }
555
556 return S_OK;
557}
558
559STDMETHODIMP StorageController::COMGETTER(Instance) (ULONG *aInstance)
560{
561 AutoCaller autoCaller(this);
562 if (FAILED(autoCaller.rc())) return autoCaller.rc();
563
564 /* The machine doesn't need to be mutable. */
565
566 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
567
568 *aInstance = m->bd->mInstance;
569
570 return S_OK;
571}
572
573STDMETHODIMP StorageController::COMSETTER(Instance) (ULONG aInstance)
574{
575 AutoCaller autoCaller(this);
576 if (FAILED(autoCaller.rc())) return autoCaller.rc();
577
578 /* The machine doesn't need to be mutable. */
579
580 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
581
582 m->bd->mInstance = aInstance;
583
584 return S_OK;
585}
586
587STDMETHODIMP StorageController::COMGETTER(UseHostIOCache) (BOOL *fUseHostIOCache)
588{
589 AutoCaller autoCaller(this);
590 if (FAILED(autoCaller.rc())) return autoCaller.rc();
591
592 /* The machine doesn't need to be mutable. */
593
594 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
595
596 *fUseHostIOCache = m->bd->fUseHostIOCache;
597
598 return S_OK;
599}
600
601STDMETHODIMP StorageController::COMSETTER(UseHostIOCache) (BOOL fUseHostIOCache)
602{
603 AutoCaller autoCaller(this);
604 if (FAILED(autoCaller.rc())) return autoCaller.rc();
605
606 /* the machine needs to be mutable */
607 AutoMutableStateDependency adep(m->pParent);
608 if (FAILED(adep.rc())) return adep.rc();
609
610 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
611
612 if (m->bd->fUseHostIOCache != !!fUseHostIOCache)
613 {
614 m->bd.backup();
615 m->bd->fUseHostIOCache = !!fUseHostIOCache;
616
617 alock.release();
618 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); // m->pParent is const, needs no locking
619 m->pParent->setModified(Machine::IsModified_Storage);
620 mlock.release();
621
622 m->pParent->onStorageControllerChange();
623 }
624
625 return S_OK;
626}
627
628STDMETHODIMP StorageController::COMGETTER(Bootable) (BOOL *fBootable)
629{
630 AutoCaller autoCaller(this);
631 if (FAILED(autoCaller.rc())) return autoCaller.rc();
632
633 /* The machine doesn't need to be mutable. */
634
635 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
636
637 *fBootable = m->bd->fBootable;
638
639 return S_OK;
640}
641
642// IStorageController methods
643/////////////////////////////////////////////////////////////////////////////
644
645STDMETHODIMP StorageController::GetIDEEmulationPort(LONG DevicePosition, LONG *aPortNumber)
646{
647 CheckComArgOutPointerValid(aPortNumber);
648
649 AutoCaller autoCaller(this);
650 if (FAILED(autoCaller.rc())) return autoCaller.rc();
651
652 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
653
654 if (m->bd->mStorageControllerType != StorageControllerType_IntelAhci)
655 return setError(E_NOTIMPL,
656 tr("Invalid controller type"));
657
658 switch (DevicePosition)
659 {
660 case 0:
661 *aPortNumber = m->bd->mPortIde0Master;
662 break;
663 case 1:
664 *aPortNumber = m->bd->mPortIde0Slave;
665 break;
666 case 2:
667 *aPortNumber = m->bd->mPortIde1Master;
668 break;
669 case 3:
670 *aPortNumber = m->bd->mPortIde1Slave;
671 break;
672 default:
673 return E_INVALIDARG;
674 }
675
676 return S_OK;
677}
678
679STDMETHODIMP StorageController::SetIDEEmulationPort(LONG DevicePosition, LONG aPortNumber)
680{
681 AutoCaller autoCaller(this);
682 if (FAILED(autoCaller.rc())) return autoCaller.rc();
683
684 /* the machine needs to be mutable */
685 AutoMutableStateDependency adep(m->pParent);
686 if (FAILED(adep.rc())) return adep.rc();
687 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
688
689 if (m->bd->mStorageControllerType != StorageControllerType_IntelAhci)
690 return setError(E_NOTIMPL,
691 tr("Invalid controller type"));
692
693 if ((aPortNumber < 0) || (aPortNumber >= 30))
694 return setError(E_INVALIDARG,
695 tr("Invalid port number: %l (must be in range [%lu, %lu])"),
696 aPortNumber, 0, 29);
697
698 switch (DevicePosition)
699 {
700 case 0:
701 m->bd->mPortIde0Master = aPortNumber;
702 break;
703 case 1:
704 m->bd->mPortIde0Slave = aPortNumber;
705 break;
706 case 2:
707 m->bd->mPortIde1Master = aPortNumber;
708 break;
709 case 3:
710 m->bd->mPortIde1Slave = aPortNumber;
711 break;
712 default:
713 return E_INVALIDARG;
714 }
715
716 return S_OK;
717}
718
719// public methods only for internal purposes
720/////////////////////////////////////////////////////////////////////////////
721
722
723const Utf8Str& StorageController::getName() const
724{
725 return m->bd->strName;
726}
727
728StorageControllerType_T StorageController::getControllerType() const
729{
730 return m->bd->mStorageControllerType;
731}
732
733StorageBus_T StorageController::getStorageBus() const
734{
735 return m->bd->mStorageBus;
736}
737
738ULONG StorageController::getInstance() const
739{
740 return m->bd->mInstance;
741}
742
743bool StorageController::getBootable() const
744{
745 return !!m->bd->fBootable;
746}
747
748/**
749 * Returns S_OK if the given port and device numbers are within the range supported
750 * by this controller. If not, it sets an error and returns E_INVALIDARG.
751 * @param ulPort
752 * @param ulDevice
753 * @return
754 */
755HRESULT StorageController::checkPortAndDeviceValid(LONG aControllerPort,
756 LONG aDevice)
757{
758 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
759
760 ULONG portCount = m->bd->mPortCount;
761 ULONG devicesPerPort;
762 HRESULT rc = m->pSystemProperties->GetMaxDevicesPerPortForStorageBus(m->bd->mStorageBus, &devicesPerPort);
763 if (FAILED(rc)) return rc;
764
765 if ( (aControllerPort < 0)
766 || (aControllerPort >= (LONG)portCount)
767 || (aDevice < 0)
768 || (aDevice >= (LONG)devicesPerPort)
769 )
770 return setError(E_INVALIDARG,
771 tr("The port and/or count parameter are out of range [%lu:%lu]"),
772 portCount,
773 devicesPerPort);
774
775 return S_OK;
776}
777
778/** @note Locks objects for writing! */
779void StorageController::setBootable(BOOL fBootable)
780{
781 AutoCaller autoCaller(this);
782 AssertComRCReturnVoid(autoCaller.rc());
783
784 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
785
786 m->bd.backup();
787 m->bd->fBootable = fBootable;
788}
789
790/** @note Locks objects for writing! */
791void StorageController::rollback()
792{
793 AutoCaller autoCaller(this);
794 AssertComRCReturnVoid(autoCaller.rc());
795
796 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
797
798 m->bd.rollback();
799}
800
801/**
802 * @note Locks this object for writing, together with the peer object (also
803 * for writing) if there is one.
804 */
805void StorageController::commit()
806{
807 /* sanity */
808 AutoCaller autoCaller(this);
809 AssertComRCReturnVoid (autoCaller.rc());
810
811 /* sanity too */
812 AutoCaller peerCaller (m->pPeer);
813 AssertComRCReturnVoid (peerCaller.rc());
814
815 /* lock both for writing since we modify both (m->pPeer is "master" so locked
816 * first) */
817 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
818
819 if (m->bd.isBackedUp())
820 {
821 m->bd.commit();
822 if (m->pPeer)
823 {
824 // attach new data to the peer and reshare it
825 m->pPeer->m->bd.attach (m->bd);
826 }
827 }
828}
829
830/**
831 * Cancels sharing (if any) by making an independent copy of data.
832 * This operation also resets this object's peer to NULL.
833 *
834 * @note Locks this object for writing, together with the peer object
835 * represented by @a aThat (locked for reading).
836 */
837void StorageController::unshare()
838{
839 /* sanity */
840 AutoCaller autoCaller(this);
841 AssertComRCReturnVoid (autoCaller.rc());
842
843 /* sanity too */
844 AutoCaller peerCaller (m->pPeer);
845 AssertComRCReturnVoid (peerCaller.rc());
846
847 /* peer is not modified, lock it for reading (m->pPeer is "master" so locked
848 * first) */
849 AutoReadLock rl(m->pPeer COMMA_LOCKVAL_SRC_POS);
850 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
851
852 if (m->bd.isShared())
853 {
854 if (!m->bd.isBackedUp())
855 m->bd.backup();
856
857 m->bd.commit();
858 }
859
860 unconst(m->pPeer) = NULL;
861}
862
863Machine* StorageController::getMachine()
864{
865 return m->pParent;
866}
867
868ComObjPtr<StorageController> StorageController::getPeer()
869{
870 return m->pPeer;
871}
872
873// private methods
874/////////////////////////////////////////////////////////////////////////////
875
876
877/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use