VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/StorageControllerImpl.cpp@ 49312

Last change on this file since 49312 was 48985, checked in by vboxsync, 11 years ago

Main, Frontends: Make the port count of the SAS controller configurable and support up to 255 storage devices

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