Commit d65aa48d authored by Steven Murray's avatar Steven Murray
Browse files

Added castor::mediachanger::MediaChangerFacade

parent 6429081f
......@@ -60,9 +60,9 @@ public:
virtual void mountTapeReadWrite(const std::string &vid,
const mediachanger::TapeLibrarySlot &librarySlot) = 0;
/**
* Requests the media changer to mount of the specified tape for read/write
* access into the drive in the specified library slot.
/**
* Requests the media changer to dismount of the specified tape from the
* drive in the specifed library slot.
*
* @param vid The volume identifier of the tape.
* @param librarySlot The library slot containing the tape drive.
......
......@@ -75,9 +75,9 @@ public:
void mountTapeReadWrite(const std::string &vid,
const mediachanger::TapeLibrarySlot &librarySlot);
/**
* Requests the media changer to mount of the specified tape for read/write
* access into the drive in the specified library slot.
/**
* Requests the media changer to dismount of the specified tape from the
* drive in the specifed library slot.
*
* @param vid The volume identifier of the tape.
* @param librarySlot The library slot containing the tape drive.
......@@ -114,7 +114,7 @@ protected:
*
* @param vid The volume identifier of the tape.
* @param librarySlot The library slot in the following form:
* "acs@rmc_host,ACS_NUMBER,LSM_NUMBER,PANEL_NUMBER,TRANSPORT_NUMBER".
* "acsACS_NUMBER,LSM_NUMBER,PANEL_NUMBER,TRANSPORT_NUMBER".
*/
void mountTapeAcs(const std::string &vid, const std::string &librarySlot) ;
......@@ -141,7 +141,7 @@ protected:
*
* @param vid The volume identifier of the tape.
* @param librarySlot The library slot in the following form:
* "acs@rmc_host,ACS_NUMBER,LSM_NUMBER,PANEL_NUMBER,TRANSPORT_NUMBER".
* "acsACS_NUMBER,LSM_NUMBER,PANEL_NUMBER,TRANSPORT_NUMBER".
*/
void unmountTapeAcs(const std::string &vid, const std::string &librarySlot) ;
......
......@@ -20,6 +20,7 @@
cmake_minimum_required (VERSION 2.6)
set (MEDIA_CHANGER_CLIENT_LIB_SRC_FILES
MediaChangerFacade.cpp
MediaChangerProxy.cpp
MediaChangerProxyDummy.cpp
TapeLibrarySlot.cpp
......
/******************************************************************************
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#include "castor/exception/Exception.hpp"
#include "castor/mediachanger/MediaChangerFacade.hpp"
#include "h/Castor_limits.h"
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
castor::mediachanger::MediaChangerFacade::MediaChangerFacade(
MediaChangerProxy &acs,
MediaChangerProxy &mmc,
MediaChangerProxy &rmc) throw():
m_acs(acs),
m_mmc(mmc),
m_rmc(rmc) {
}
//------------------------------------------------------------------------------
// mountTapeReadOnly
//------------------------------------------------------------------------------
void castor::mediachanger::MediaChangerFacade::mountTapeReadOnly(
const std::string &vid, const TapeLibrarySlot &librarySlot) {
try {
const TapeLibraryType libraryType = librarySlot.getLibraryType();
// Dispatch the appropriate helper method depending on library slot type
switch(libraryType) {
case TAPE_LIBRARY_TYPE_ACS:
return m_acs.mountTapeReadOnly(vid, librarySlot);
case TAPE_LIBRARY_TYPE_MANUAL:
return m_mmc.mountTapeReadOnly(vid, librarySlot);
case TAPE_LIBRARY_TYPE_SCSI:
return m_rmc.mountTapeReadOnly(vid, librarySlot);
default:
{
// Should never get here
castor::exception::Exception ex;
ex.getMessage() << "Library slot has an unexpected library type";
throw ex;
}
}
} catch(castor::exception::Exception &ex) {
castor::exception::Exception ex;
ex.getMessage() << "Failed to mount tape for read-only access"
": vid=" << vid << " librarySlot=" << librarySlot.str();
throw ex;
}
}
//------------------------------------------------------------------------------
// mountTapeReadWrite
//------------------------------------------------------------------------------
void castor::mediachanger::MediaChangerFacade::mountTapeReadWrite(
const std::string &vid, const TapeLibrarySlot &librarySlot) {
try {
const TapeLibraryType libraryType = librarySlot.getLibraryType();
// Dispatch the appropriate helper method depending on library slot type
switch(libraryType) {
case TAPE_LIBRARY_TYPE_ACS:
return m_acs.mountTapeReadWrite(vid, librarySlot);
case TAPE_LIBRARY_TYPE_MANUAL:
return m_mmc.mountTapeReadWrite(vid, librarySlot);
case TAPE_LIBRARY_TYPE_SCSI:
return m_rmc.mountTapeReadWrite(vid, librarySlot);
default:
{
// Should never get here
castor::exception::Exception ex;
ex.getMessage() << "Library slot has an unexpected library type";
throw ex;
}
}
} catch(castor::exception::Exception &ex) {
castor::exception::Exception ex;
ex.getMessage() << "Failed to mount tape for read/write access"
": vid=" << vid << " librarySlot=" << librarySlot.str();
throw ex;
}
}
//------------------------------------------------------------------------------
// dismountTape
//------------------------------------------------------------------------------
void castor::mediachanger::MediaChangerFacade::dismountTape(
const std::string &vid, const TapeLibrarySlot &librarySlot) {
try {
const TapeLibraryType libraryType = librarySlot.getLibraryType();
// Dispatch the appropriate helper method depending on library slot type
switch(libraryType) {
case TAPE_LIBRARY_TYPE_ACS:
return m_acs.dismountTape(vid, librarySlot);
case TAPE_LIBRARY_TYPE_MANUAL:
return m_mmc.dismountTape(vid, librarySlot);
case TAPE_LIBRARY_TYPE_SCSI:
return m_rmc.dismountTape(vid, librarySlot);
default:
{
// Should never get here
castor::exception::Exception ex;
ex.getMessage() << "Library slot has an unexpected library type";
throw ex;
}
}
} catch(castor::exception::Exception &ex) {
castor::exception::Exception ex;
ex.getMessage() << "Failed to dismount tape"
": vid=" << vid << " librarySlot=" << librarySlot.str();
throw ex;
}
}
/******************************************************************************
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#pragma once
#include "castor/mediachanger/MediaChangerProxy.hpp"
#include <unistd.h>
#include <sys/types.h>
namespace castor {
namespace mediachanger {
/**
* Provides a facade to three communications proxies: acs, manual and rmc.
*
* This facade will forward requests to mount and dismount tapes to the
* appropriate communications proxy based on the type of library slot.
*/
class MediaChangerFacade: public MediaChangerProxy {
public:
/**
* Constructor.
*
* @param acs Proxy object representing the CASTOR ACS daemon.
* @param mmc Proxy object representing the manual media-changer.
* @param rmc Proxy object representing the rmcd daemon.
*/
MediaChangerFacade(
MediaChangerProxy &acs,
MediaChangerProxy &mmc,
MediaChangerProxy &rmc) throw();
/**
* Requests the media changer to mount of the specified tape for read-only
* access into the drive in the specified library slot.
*
* @param vid The volume identifier of the tape.
* @param librarySlot The library slot containing the tape drive.
*/
void mountTapeReadOnly(const std::string &vid,
const TapeLibrarySlot &librarySlot);
/**
* Requests the media changer to mount of the specified tape for read/write
* access into the drive in the specified library slot.
*
* @param vid The volume identifier of the tape.
* @param librarySlot The library slot containing the tape drive.
*/
void mountTapeReadWrite(const std::string &vid,
const TapeLibrarySlot &librarySlot);
/**
* Requests the media changer to dismount of the specified tape from the
* drive in the specifed library slot.
*
* @param vid The volume identifier of the tape.
* @param librarySlot The library slot containing the tape drive.
*/
void dismountTape(const std::string &vid,
const TapeLibrarySlot &librarySlot);
private:
/**
* Proxy object representing the CASTOR ACS daemon.
*/
MediaChangerProxy &m_acs;
/**
* Proxy object representing the manual media-changer.
*/
MediaChangerProxy &m_mmc;
/**
* Proxy object representing the rmcd daemon.
*/
MediaChangerProxy &m_rmc;
}; // class MediaChangerFacade
} // namespace mediachanger
} // namespace castor
/******************************************************************************
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
* @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#include "castor/mediachanger/MediaChangerFacade.hpp"
#include "castor/mediachanger/MediaChangerProxy.hpp"
#include "castor/mediachanger/TapeLibrarySlot.hpp"
#include <gtest/gtest.h>
#include <iostream>
#include <memory>
#include <sstream>
namespace unitTests {
class castor_mediachanger_MediaChangerFacadeTest : public ::testing::Test {
protected:
struct MockMediaChangerProxy: public castor::mediachanger::MediaChangerProxy {
unsigned int nbTimesMountTapeReadOnlyCalled;
unsigned int nbTimesMountTapeReadWriteCalled;
unsigned int nbTimesDismountTapeCalled;
MockMediaChangerProxy():
nbTimesMountTapeReadOnlyCalled(0),
nbTimesMountTapeReadWriteCalled(0),
nbTimesDismountTapeCalled(0) {
}
void mountTapeReadOnly(const std::string &vid,
const castor::mediachanger::TapeLibrarySlot &librarySlot) {
nbTimesMountTapeReadOnlyCalled++;
}
void mountTapeReadWrite(const std::string &vid,
const castor::mediachanger::TapeLibrarySlot &librarySlot) {
nbTimesMountTapeReadWriteCalled++;
}
void dismountTape(const std::string &vid,
const castor::mediachanger::TapeLibrarySlot &librarySlot) {
nbTimesDismountTapeCalled++;
}
}; // struct MockMediaChangerProxy
MockMediaChangerProxy m_acs; // ACS
MockMediaChangerProxy m_mmc; // Manual
MockMediaChangerProxy m_rmc; // SCSI
const std::string m_vid;
const castor::mediachanger::TapeLibrarySlot m_acsSlot;
const castor::mediachanger::TapeLibrarySlot m_mmcSlot;
const castor::mediachanger::TapeLibrarySlot m_rmcSlot;
castor_mediachanger_MediaChangerFacadeTest():
m_vid("123456"),
m_acsSlot("acs1,2,3,4"),
m_mmcSlot("manual"),
m_rmcSlot("smc@rmc_host,1") {
}
virtual void SetUp() {
m_acs.nbTimesMountTapeReadOnlyCalled = 0;
m_acs.nbTimesMountTapeReadWriteCalled = 0;
m_acs.nbTimesDismountTapeCalled = 0;
m_mmc.nbTimesMountTapeReadOnlyCalled = 0;
m_mmc.nbTimesMountTapeReadWriteCalled = 0;
m_mmc.nbTimesDismountTapeCalled = 0;
m_rmc.nbTimesMountTapeReadOnlyCalled = 0;
m_rmc.nbTimesMountTapeReadWriteCalled = 0;
m_rmc.nbTimesDismountTapeCalled = 0;
}
virtual void TearDown() {
SetUp();
}
}; // class castor_mediachanger_MediaChangerFacadeTest
TEST_F(castor_mediachanger_MediaChangerFacadeTest, mountTapeReadOnlyAcs) {
using namespace castor::mediachanger;
MediaChangerFacade facade(m_acs, m_mmc, m_rmc);
facade.mountTapeReadOnly(m_vid, m_acsSlot);
ASSERT_EQ(1, m_acs.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_acs.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_mmc.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_rmc.nbTimesDismountTapeCalled);
}
TEST_F(castor_mediachanger_MediaChangerFacadeTest, mountTapeReadOnlyMmc) {
using namespace castor::mediachanger;
MediaChangerFacade facade(m_acs, m_mmc, m_rmc);
facade.mountTapeReadOnly(m_vid, m_mmcSlot);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_acs.nbTimesDismountTapeCalled);
ASSERT_EQ(1, m_mmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_mmc.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_rmc.nbTimesDismountTapeCalled);
}
TEST_F(castor_mediachanger_MediaChangerFacadeTest, mountTapeReadOnlyRmc) {
using namespace castor::mediachanger;
MediaChangerFacade facade(m_acs, m_mmc, m_rmc);
facade.mountTapeReadOnly(m_vid, m_rmcSlot);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_acs.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_mmc.nbTimesDismountTapeCalled);
ASSERT_EQ(1, m_rmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_rmc.nbTimesDismountTapeCalled);
}
TEST_F(castor_mediachanger_MediaChangerFacadeTest, mountTapeReadWriteAcs) {
using namespace castor::mediachanger;
MediaChangerFacade facade(m_acs, m_mmc, m_rmc);
facade.mountTapeReadWrite(m_vid, m_acsSlot);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(1, m_acs.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_acs.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_mmc.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_rmc.nbTimesDismountTapeCalled);
}
TEST_F(castor_mediachanger_MediaChangerFacadeTest, mountTapeReadWriteMmc) {
using namespace castor::mediachanger;
MediaChangerFacade facade(m_acs, m_mmc, m_rmc);
facade.mountTapeReadWrite(m_vid, m_mmcSlot);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_acs.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(1, m_mmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_mmc.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_rmc.nbTimesDismountTapeCalled);
}
TEST_F(castor_mediachanger_MediaChangerFacadeTest, mountTapeReadWriteRmc) {
using namespace castor::mediachanger;
MediaChangerFacade facade(m_acs, m_mmc, m_rmc);
facade.mountTapeReadWrite(m_vid, m_rmcSlot);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_acs.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_mmc.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(1, m_rmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_rmc.nbTimesDismountTapeCalled);
}
TEST_F(castor_mediachanger_MediaChangerFacadeTest, dismountTapeAcs) {
using namespace castor::mediachanger;
MediaChangerFacade facade(m_acs, m_mmc, m_rmc);
facade.dismountTape(m_vid, m_acsSlot);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(1, m_acs.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_mmc.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_rmc.nbTimesDismountTapeCalled);
}
TEST_F(castor_mediachanger_MediaChangerFacadeTest, dismountTapeMmc) {
using namespace castor::mediachanger;
MediaChangerFacade facade(m_acs, m_mmc, m_rmc);
facade.dismountTape(m_vid, m_mmcSlot);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_acs.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(1, m_mmc.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_rmc.nbTimesDismountTapeCalled);
}
TEST_F(castor_mediachanger_MediaChangerFacadeTest, dismountTapeRmc) {
using namespace castor::mediachanger;
MediaChangerFacade facade(m_acs, m_mmc, m_rmc);
facade.dismountTape(m_vid, m_rmcSlot);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_acs.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_acs.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_mmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(0, m_mmc.nbTimesDismountTapeCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadOnlyCalled);
ASSERT_EQ(0, m_rmc.nbTimesMountTapeReadWriteCalled);
ASSERT_EQ(1, m_rmc.nbTimesDismountTapeCalled);
}
} // namespace unitTests
......@@ -59,9 +59,9 @@ public:
virtual void mountTapeReadWrite(const std::string &vid,
const TapeLibrarySlot &librarySlot) = 0;
/**
* Requests the media changer to mount of the specified tape for read/write
* access into the drive in the specified library slot.
/**
* Requests the media changer to dismount of the specified tape from the
* drive in the specifed library slot.
*
* @param vid The volume identifier of the tape.
* @param librarySlot The library slot containing the tape drive.
......
......@@ -44,8 +44,8 @@ castor::mediachanger::TapeLibrarySlot::TapeLibrarySlot(const std::string &str):
//------------------------------------------------------------------------------
castor::mediachanger::TapeLibraryType castor::mediachanger::TapeLibrarySlot::
getLibraryTypeOfSlot(const std::string &slot) {
if(0 == slot.find("acs@")) return TAPE_LIBRARY_TYPE_ACS;
if(0 == slot.find("manual@")) return TAPE_LIBRARY_TYPE_MANUAL;
if(0 == slot.find("acs")) return TAPE_LIBRARY_TYPE_ACS;
if(0 == slot.find("manual")) return TAPE_LIBRARY_TYPE_MANUAL;
if(0 == slot.find("smc@")) return TAPE_LIBRARY_TYPE_SCSI;
castor::exception::Exception ex;
......
......@@ -43,7 +43,13 @@ public:
/**
* Constructs a TapeLibrarySlot object from the specified string
* reprsentation.
* representation.
*
* The string representation of a tape library-slot must be in one of the
* following three forms:
* - acsACS_NUMBER,LSM_NUMBER,PANEL_NUMBER,TRANSPORT_NUMBER
* - manual
* - smc@rmc_host,drive_ordinal
*