VirtualBox

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

Last change on this file since 24322 was 24250, checked in by vboxsync, 15 years ago

StorageController: added support for Instance number

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.4 KB
Line 
1/* $Id: StorageControllerImpl.cpp 24250 2009-11-02 13:00:58Z vboxsync $ */
2
3/** @file
4 *
5 * Implementation of IStorageController.
6 */
7
8/*
9 * Copyright (C) 2008-2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24#include "StorageControllerImpl.h"
25#include "MachineImpl.h"
26#include "VirtualBoxImpl.h"
27#include "Logging.h"
28
29#include <iprt/string.h>
30#include <iprt/cpputils.h>
31
32#include <VBox/err.h>
33#include <VBox/settings.h>
34
35#include <algorithm>
36
37// defines
38/////////////////////////////////////////////////////////////////////////////
39
40// constructor / destructor
41/////////////////////////////////////////////////////////////////////////////
42
43DEFINE_EMPTY_CTOR_DTOR (StorageController)
44
45HRESULT StorageController::FinalConstruct()
46{
47 return S_OK;
48}
49
50void StorageController::FinalRelease()
51{
52 uninit();
53}
54
55// public initializer/uninitializer for internal purposes only
56/////////////////////////////////////////////////////////////////////////////
57
58/**
59 * Initializes the storage controller object.
60 *
61 * @returns COM result indicator.
62 * @param aParent Pointer to our parent object.
63 * @param aName Name of the storage controller.
64 * @param aInstance Instance number of the storage controller.
65 */
66HRESULT StorageController::init(Machine *aParent,
67 const Utf8Str &aName,
68 StorageBus_T aStorageBus,
69 ULONG aInstance)
70{
71 LogFlowThisFunc(("aParent=%p aName=\"%s\" aInstance=%u\n",
72 aParent, aName.raw(), aInstance));
73
74 ComAssertRet(aParent && !aName.isEmpty(), E_INVALIDARG);
75 if ( (aStorageBus <= StorageBus_Null)
76 || (aStorageBus > StorageBus_Floppy))
77 return setError (E_INVALIDARG,
78 tr ("Invalid storage connection type"));
79
80 /* Enclose the state transition NotReady->InInit->Ready */
81 AutoInitSpan autoInitSpan(this);
82 AssertReturn(autoInitSpan.isOk(), E_FAIL);
83
84 unconst(mParent) = aParent;
85 /* mPeer is left null */
86
87 /* register with parent early, since uninit() will unconditionally
88 * unregister on failure */
89 mParent->addDependentChild (this);
90
91 mData.allocate();
92
93 mData->strName = aName;
94 mData->mInstance = aInstance;
95 mData->mStorageBus = aStorageBus;
96
97 switch (aStorageBus)
98 {
99 case StorageBus_IDE:
100 mData->mPortCount = 2;
101 mData->mStorageControllerType = StorageControllerType_PIIX4;
102 break;
103 case StorageBus_SATA:
104 mData->mPortCount = 30;
105 mData->mStorageControllerType = StorageControllerType_IntelAhci;
106 break;
107 case StorageBus_SCSI:
108 mData->mPortCount = 16;
109 mData->mStorageControllerType = StorageControllerType_LsiLogic;
110 break;
111 case StorageBus_Floppy:
112 /** @todo allow 2 floppies later */
113 mData->mPortCount = 1;
114 mData->mStorageControllerType = StorageControllerType_I82078;
115 break;
116 }
117
118 /* Confirm a successful initialization */
119 autoInitSpan.setSucceeded();
120
121 return S_OK;
122}
123
124/**
125 * Initializes the object given another object
126 * (a kind of copy constructor). This object shares data with
127 * the object passed as an argument.
128 *
129 * @param aReshare
130 * When false, the original object will remain a data owner.
131 * Otherwise, data ownership will be transferred from the original
132 * object to this one.
133 *
134 * @note This object must be destroyed before the original object
135 * it shares data with is destroyed.
136 *
137 * @note Locks @a aThat object for writing if @a aReshare is @c true, or for
138 * reading if @a aReshare is false.
139 */
140HRESULT StorageController::init (Machine *aParent,
141 StorageController *aThat,
142 bool aReshare /* = false */)
143{
144 LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n",
145 aParent, aThat, aReshare));
146
147 ComAssertRet (aParent && aThat, E_INVALIDARG);
148
149 /* Enclose the state transition NotReady->InInit->Ready */
150 AutoInitSpan autoInitSpan(this);
151 AssertReturn(autoInitSpan.isOk(), E_FAIL);
152
153 unconst(mParent) = aParent;
154
155 /* register with parent early, since uninit() will unconditionally
156 * unregister on failure */
157 mParent->addDependentChild (this);
158
159 /* sanity */
160 AutoCaller thatCaller (aThat);
161 AssertComRCReturnRC(thatCaller.rc());
162
163 if (aReshare)
164 {
165 AutoWriteLock thatLock (aThat);
166
167 unconst(aThat->mPeer) = this;
168 mData.attach (aThat->mData);
169 }
170 else
171 {
172 unconst(mPeer) = aThat;
173
174 AutoReadLock thatLock (aThat);
175 mData.share (aThat->mData);
176 }
177
178 /* Confirm successful initialization */
179 autoInitSpan.setSucceeded();
180
181 return S_OK;
182}
183
184/**
185 * Initializes the storage controller object given another guest object
186 * (a kind of copy constructor). This object makes a private copy of data
187 * of the original object passed as an argument.
188 */
189HRESULT StorageController::initCopy (Machine *aParent, StorageController *aThat)
190{
191 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
192
193 ComAssertRet (aParent && aThat, E_INVALIDARG);
194
195 /* Enclose the state transition NotReady->InInit->Ready */
196 AutoInitSpan autoInitSpan(this);
197 AssertReturn(autoInitSpan.isOk(), E_FAIL);
198
199 unconst(mParent) = aParent;
200 /* mPeer is left null */
201
202 mParent->addDependentChild (this);
203
204 AutoCaller thatCaller (aThat);
205 AssertComRCReturnRC(thatCaller.rc());
206
207 AutoReadLock thatlock (aThat);
208 mData.attachCopy (aThat->mData);
209
210 /* Confirm a successful initialization */
211 autoInitSpan.setSucceeded();
212
213 return S_OK;
214}
215
216
217/**
218 * Uninitializes the instance and sets the ready flag to FALSE.
219 * Called either from FinalRelease() or by the parent when it gets destroyed.
220 */
221void StorageController::uninit()
222{
223 LogFlowThisFunc(("\n"));
224
225 /* Enclose the state transition Ready->InUninit->NotReady */
226 AutoUninitSpan autoUninitSpan(this);
227 if (autoUninitSpan.uninitDone())
228 return;
229
230 mData.free();
231
232 mParent->removeDependentChild (this);
233
234 unconst(mPeer).setNull();
235 unconst(mParent).setNull();
236}
237
238
239// IStorageController properties
240/////////////////////////////////////////////////////////////////////////////
241STDMETHODIMP StorageController::COMGETTER(Name) (BSTR *aName)
242{
243 CheckComArgOutPointerValid(aName);
244
245 AutoCaller autoCaller(this);
246 CheckComRCReturnRC(autoCaller.rc());
247
248 /* mName is constant during life time, no need to lock */
249 mData.data()->strName.cloneTo(aName);
250
251 return S_OK;
252}
253
254STDMETHODIMP StorageController::COMGETTER(Bus) (StorageBus_T *aBus)
255{
256 CheckComArgOutPointerValid(aBus);
257
258 AutoCaller autoCaller(this);
259 CheckComRCReturnRC(autoCaller.rc());
260
261 AutoReadLock alock(this);
262
263 *aBus = mData->mStorageBus;
264
265 return S_OK;
266}
267
268STDMETHODIMP StorageController::COMGETTER(ControllerType) (StorageControllerType_T *aControllerType)
269{
270 CheckComArgOutPointerValid(aControllerType);
271
272 AutoCaller autoCaller(this);
273 CheckComRCReturnRC(autoCaller.rc());
274
275 AutoReadLock alock(this);
276
277 *aControllerType = mData->mStorageControllerType;
278
279 return S_OK;
280}
281
282STDMETHODIMP StorageController::COMSETTER(ControllerType) (StorageControllerType_T aControllerType)
283{
284 AutoCaller autoCaller(this);
285 CheckComRCReturnRC(autoCaller.rc());
286
287 AutoWriteLock alock(this);
288
289 HRESULT rc = S_OK;
290
291 switch (mData->mStorageBus)
292 {
293 case StorageBus_IDE:
294 {
295 if ( (aControllerType != StorageControllerType_PIIX3)
296 && (aControllerType != StorageControllerType_PIIX4)
297 && (aControllerType != StorageControllerType_ICH6))
298 rc = E_INVALIDARG;
299 break;
300 }
301 case StorageBus_SATA:
302 {
303 if (aControllerType != StorageControllerType_IntelAhci)
304 rc = E_INVALIDARG;
305 break;
306 }
307 case StorageBus_SCSI:
308 {
309 if ( (aControllerType != StorageControllerType_LsiLogic)
310 && (aControllerType != StorageControllerType_BusLogic))
311 rc = E_INVALIDARG;
312 break;
313 }
314 case StorageBus_Floppy:
315 {
316 if (aControllerType != StorageControllerType_I82078)
317 rc = E_INVALIDARG;
318 break;
319 }
320 default:
321 AssertMsgFailed(("Invalid controller type %d\n", mData->mStorageBus));
322 }
323
324 if (!SUCCEEDED(rc))
325 return setError(rc,
326 tr ("Invalid controller type %d"),
327 aControllerType);
328
329 mData->mStorageControllerType = aControllerType;
330
331 return S_OK;
332}
333
334STDMETHODIMP StorageController::COMGETTER(MaxDevicesPerPortCount) (ULONG *aMaxDevices)
335{
336 CheckComArgOutPointerValid(aMaxDevices);
337
338 AutoCaller autoCaller(this);
339 CheckComRCReturnRC(autoCaller.rc());
340
341 AutoReadLock alock(this);
342
343 ComPtr<IVirtualBox> VBox;
344 HRESULT rc = mParent->COMGETTER(Parent)(VBox.asOutParam());
345 if (FAILED(rc))
346 return rc;
347
348 ComPtr<ISystemProperties> sysProps;
349 rc = VBox->COMGETTER(SystemProperties)(sysProps.asOutParam());
350 if (FAILED(rc))
351 return rc;
352
353 rc = sysProps->GetMaxDevicesPerPortForStorageBus(mData->mStorageBus, aMaxDevices);
354 return rc;
355}
356
357STDMETHODIMP StorageController::COMGETTER(MinPortCount) (ULONG *aMinPortCount)
358{
359 CheckComArgOutPointerValid(aMinPortCount);
360
361 AutoCaller autoCaller(this);
362 CheckComRCReturnRC(autoCaller.rc());
363
364 AutoReadLock alock(this);
365
366 ComPtr<IVirtualBox> VBox;
367 HRESULT rc = mParent->COMGETTER(Parent)(VBox.asOutParam());
368 if (FAILED(rc))
369 return rc;
370
371 ComPtr<ISystemProperties> sysProps;
372 rc = VBox->COMGETTER(SystemProperties)(sysProps.asOutParam());
373 if (FAILED(rc))
374 return rc;
375
376 rc = sysProps->GetMinPortCountForStorageBus(mData->mStorageBus, aMinPortCount);
377 return rc;
378}
379
380STDMETHODIMP StorageController::COMGETTER(MaxPortCount) (ULONG *aMaxPortCount)
381{
382 CheckComArgOutPointerValid(aMaxPortCount);
383
384 AutoCaller autoCaller(this);
385 CheckComRCReturnRC(autoCaller.rc());
386
387 AutoReadLock alock(this);
388
389 ComPtr<IVirtualBox> VBox;
390 HRESULT rc = mParent->COMGETTER(Parent)(VBox.asOutParam());
391 if (FAILED(rc))
392 return rc;
393
394 ComPtr<ISystemProperties> sysProps;
395 rc = VBox->COMGETTER(SystemProperties)(sysProps.asOutParam());
396 if (FAILED(rc))
397 return rc;
398
399 rc = sysProps->GetMaxPortCountForStorageBus(mData->mStorageBus, aMaxPortCount);
400 return rc;
401}
402
403
404STDMETHODIMP StorageController::COMGETTER(PortCount) (ULONG *aPortCount)
405{
406 CheckComArgOutPointerValid(aPortCount);
407
408 AutoCaller autoCaller(this);
409 CheckComRCReturnRC(autoCaller.rc());
410
411 AutoReadLock alock(this);
412
413 *aPortCount = mData->mPortCount;
414
415 return S_OK;
416}
417
418
419STDMETHODIMP StorageController::COMSETTER(PortCount) (ULONG aPortCount)
420{
421 LogFlowThisFunc(("aPortCount=%u\n", aPortCount));
422
423 switch (mData->mStorageBus)
424 {
425 case StorageBus_SATA:
426 {
427 /* AHCI SATA supports a maximum of 30 ports. */
428 if ((aPortCount < 1) || (aPortCount > 30))
429 return setError (E_INVALIDARG,
430 tr ("Invalid port count: %lu (must be in range [%lu, %lu])"),
431 aPortCount, 1, 30);
432 break;
433 }
434 case StorageBus_SCSI:
435 {
436 /*
437 * SCSI does not support setting different ports.
438 * (doesn't make sense here either).
439 * The maximum and minimum is 16 and unless the callee
440 * tries to set a different value we return an error.
441 */
442 if (aPortCount != 16)
443 return setError (E_INVALIDARG,
444 tr ("Invalid port count: %lu (must be in range [%lu, %lu])"),
445 aPortCount, 16, 16);
446 break;
447 }
448 case StorageBus_IDE:
449 {
450 /*
451 * The port count is fixed to 2.
452 */
453 if (aPortCount != 2)
454 return setError (E_INVALIDARG,
455 tr ("Invalid port count: %lu (must be in range [%lu, %lu])"),
456 aPortCount, 2, 2);
457 break;
458 }
459 case StorageBus_Floppy:
460 {
461 /** @todo allow 2 floppies later */
462 /*
463 * The port count is fixed to 1.
464 */
465 if (aPortCount != 1)
466 return setError (E_INVALIDARG,
467 tr ("Invalid port count: %lu (must be in range [%lu, %lu])"),
468 aPortCount, 1, 1);
469 break;
470 }
471 default:
472 AssertMsgFailed(("Invalid controller type %d\n", mData->mStorageBus));
473 }
474
475 AutoCaller autoCaller(this);
476 CheckComRCReturnRC(autoCaller.rc());
477
478 /* the machine needs to be mutable */
479 Machine::AutoMutableStateDependency adep (mParent);
480 CheckComRCReturnRC(adep.rc());
481
482 AutoWriteLock alock(this);
483
484 if (mData->mPortCount != aPortCount)
485 {
486 mData.backup();
487 mData->mPortCount = aPortCount;
488
489 /* leave the lock for safety */
490 alock.leave();
491
492 mParent->onStorageControllerChange ();
493 }
494
495 return S_OK;
496}
497
498STDMETHODIMP StorageController::COMGETTER(Instance) (ULONG *aInstance)
499{
500 AutoCaller autoCaller(this);
501 CheckComRCReturnRC(autoCaller.rc());
502
503 /* The machine doesn't need to be mutable. */
504
505 AutoReadLock alock(this);
506
507 *aInstance = mData->mInstance;
508
509 return S_OK;
510}
511
512STDMETHODIMP StorageController::COMSETTER(Instance) (ULONG aInstance)
513{
514 AutoCaller autoCaller(this);
515 CheckComRCReturnRC(autoCaller.rc());
516
517 /* The machine doesn't need to be mutable. */
518
519 AutoWriteLock alock(this);
520
521 mData->mInstance = aInstance;
522
523 return S_OK;
524}
525
526// IStorageController methods
527/////////////////////////////////////////////////////////////////////////////
528
529STDMETHODIMP StorageController::GetIDEEmulationPort(LONG DevicePosition, LONG *aPortNumber)
530{
531 CheckComArgOutPointerValid(aPortNumber);
532
533 AutoCaller autoCaller(this);
534 CheckComRCReturnRC(autoCaller.rc());
535
536 AutoReadLock alock(this);
537
538 if (mData->mStorageControllerType != StorageControllerType_IntelAhci)
539 return setError (E_NOTIMPL,
540 tr ("Invalid controller type"));
541
542 switch (DevicePosition)
543 {
544 case 0:
545 *aPortNumber = mData->mPortIde0Master;
546 break;
547 case 1:
548 *aPortNumber = mData->mPortIde0Slave;
549 break;
550 case 2:
551 *aPortNumber = mData->mPortIde1Master;
552 break;
553 case 3:
554 *aPortNumber = mData->mPortIde1Slave;
555 break;
556 default:
557 return E_INVALIDARG;
558 }
559
560 return S_OK;
561}
562
563STDMETHODIMP StorageController::SetIDEEmulationPort(LONG DevicePosition, LONG aPortNumber)
564{
565 AutoCaller autoCaller(this);
566 CheckComRCReturnRC(autoCaller.rc());
567
568 /* the machine needs to be mutable */
569 Machine::AutoMutableStateDependency adep (mParent);
570 CheckComRCReturnRC(adep.rc());
571 AutoWriteLock alock(this);
572
573 if (mData->mStorageControllerType != StorageControllerType_IntelAhci)
574 return setError (E_NOTIMPL,
575 tr ("Invalid controller type"));
576
577 if ((aPortNumber < 0) || (aPortNumber >= 30))
578 return setError (E_INVALIDARG,
579 tr ("Invalid port number: %l (must be in range [%lu, %lu])"),
580 aPortNumber, 0, 29);
581
582 switch (DevicePosition)
583 {
584 case 0:
585 mData->mPortIde0Master = aPortNumber;
586 break;
587 case 1:
588 mData->mPortIde0Slave = aPortNumber;
589 break;
590 case 2:
591 mData->mPortIde1Master = aPortNumber;
592 break;
593 case 3:
594 mData->mPortIde1Slave = aPortNumber;
595 break;
596 default:
597 return E_INVALIDARG;
598 }
599
600 return S_OK;
601}
602
603// public methods only for internal purposes
604/////////////////////////////////////////////////////////////////////////////
605
606/** @note Locks objects for writing! */
607bool StorageController::rollback()
608{
609 AutoCaller autoCaller(this);
610 AssertComRCReturn (autoCaller.rc(), false);
611
612 AutoWriteLock alock(this);
613
614 bool dataChanged = false;
615
616 if (mData.isBackedUp())
617 {
618 /* we need to check all data to see whether anything will be changed
619 * after rollback */
620 dataChanged = mData.hasActualChanges();
621 mData.rollback();
622 }
623
624 return dataChanged;
625}
626
627/**
628 * @note Locks this object for writing, together with the peer object (also
629 * for writing) if there is one.
630 */
631void StorageController::commit()
632{
633 /* sanity */
634 AutoCaller autoCaller(this);
635 AssertComRCReturnVoid (autoCaller.rc());
636
637 /* sanity too */
638 AutoCaller peerCaller (mPeer);
639 AssertComRCReturnVoid (peerCaller.rc());
640
641 /* lock both for writing since we modify both (mPeer is "master" so locked
642 * first) */
643 AutoMultiWriteLock2 alock (mPeer, this);
644
645 if (mData.isBackedUp())
646 {
647 mData.commit();
648 if (mPeer)
649 {
650 // attach new data to the peer and reshare it
651 mPeer->mData.attach (mData);
652 }
653 }
654}
655
656/**
657 * Cancels sharing (if any) by making an independent copy of data.
658 * This operation also resets this object's peer to NULL.
659 *
660 * @note Locks this object for writing, together with the peer object
661 * represented by @a aThat (locked for reading).
662 */
663void StorageController::unshare()
664{
665 /* sanity */
666 AutoCaller autoCaller(this);
667 AssertComRCReturnVoid (autoCaller.rc());
668
669 /* sanity too */
670 AutoCaller peerCaller (mPeer);
671 AssertComRCReturnVoid (peerCaller.rc());
672
673 /* peer is not modified, lock it for reading (mPeer is "master" so locked
674 * first) */
675 AutoMultiLock2 alock (mPeer->rlock(), this->wlock());
676
677 if (mData.isShared())
678 {
679 if (!mData.isBackedUp())
680 mData.backup();
681
682 mData.commit();
683 }
684
685 unconst(mPeer).setNull();
686}
687
688// private methods
689/////////////////////////////////////////////////////////////////////////////
690/* 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