diff --git a/CMakeLists.txt b/CMakeLists.txt
index 19faead6aea16314f12fba2b06f331341d6909c4..916c774bf757eb24284d510faf3d130693ad33a2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -147,6 +147,7 @@ ELSE(DEFINED PackageOnly)
   add_subdirectory(rdbms)
   add_subdirectory(scheduler)
   add_subdirectory(tapeserver)
+  add_subdirectory(XRootdSSiRmcd)
   
   #Generate version information
   configure_file(${PROJECT_SOURCE_DIR}/version.hpp.in
diff --git a/XRootdSSiRmcd/CMakeLists.txt b/XRootdSSiRmcd/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c2524e1fe66a0e702d6e18de86973aaab5b00b17
--- /dev/null
+++ b/XRootdSSiRmcd/CMakeLists.txt
@@ -0,0 +1,69 @@
+# XRootD SSI/Protocol Buffer Interface Project
+# Copyright 2018 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 3 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, see <http://www.gnu.org/licenses/>.
+
+cmake_minimum_required (VERSION 2.6)
+
+find_package(xrootdclient REQUIRED)
+find_package(xrootd REQUIRED)
+find_package(Protobuf3 REQUIRED)
+
+add_subdirectory(protobuf)
+
+#
+# XRootD SSI
+#
+include_directories(${XROOTD_INCLUDE_DIR} ${XROOTD_INCLUDE_DIR}/private)
+
+#
+# XRootD SSI Protocol Buffer bindings
+#
+include_directories(${CMAKE_SOURCE_DIR}/)
+
+include_directories (${CMAKE_SOURCE_DIR}/xrootd-ssi-protobuf-interface/include)
+
+#
+# Compiled protocol buffers
+#
+include_directories(${CMAKE_BINARY_DIR}/XRootdSSiRmcd ${PROTOBUF3_INCLUDE_DIRS})
+
+#
+# Test Client
+#
+add_executable(cta-xsmc RmcdClient.cpp)
+target_link_libraries(cta-xsmc XrdSsi-4 XrdSsiLib XrdSsiPbRmcd XrdUtils)
+set_property(TARGET cta-xsmc APPEND PROPERTY INSTALL_RPATH ${PROTOBUF3_RPATH})
+install (TARGETS cta-xsmc DESTINATION /usr/bin)
+install (FILES cta-xsmc-mount.1cta DESTINATION /usr/share/man/man1)
+install (FILES cta-xsmc-dismount.1cta DESTINATION /usr/share/man/man1)
+
+#
+# XRootD SSI plugin for Test Server
+#
+add_library(XrdSsiRmcd MODULE
+  RmcdServiceProvider.cpp
+  RmcdRequestProc.cpp
+  rmc_send_scsi_cmd.cpp
+  serrno.cpp
+  rmc_smcsubr.cpp
+)
+target_link_libraries(XrdSsiRmcd XrdSsi-4 XrdSsiLib XrdSsiPbRmcd XrdUtils)
+set_property(TARGET XrdSsiRmcd APPEND PROPERTY INSTALL_RPATH ${PROTOBUF3_RPATH})
+install(TARGETS XrdSsiRmcd DESTINATION usr/${CMAKE_INSTALL_LIBDIR})
+
+install (FILES cta-xrmcd.conf DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/cta)
+install (FILES cta-xrmcd.logrotate DESTINATION /etc/logrotate.d RENAME cta-xrmcd)
+install (FILES cta-xrmcd.sysconfig DESTINATION /etc/sysconfig RENAME cta-xrmcd)
+install (FILES cta-xrmcd.service DESTINATION /etc/systemd/system)
diff --git a/XRootdSSiRmcd/Castor_limits.h b/XRootdSSiRmcd/Castor_limits.h
new file mode 100644
index 0000000000000000000000000000000000000000..be7c898a4fd88278265f117e4ece4d2f4715f932
--- /dev/null
+++ b/XRootdSSiRmcd/Castor_limits.h
@@ -0,0 +1,71 @@
+/*
+ * Castor_limits.h,v 1.27 2004/02/12 15:38:08 obarring Exp
+ */
+
+/*
+ * Copyright (C) 1999-2003 by CERN/IT/PDP/DM
+ * All rights reserved
+ */
+
+/*
+ * @(#)Castor_limits.h,v 1.27 2004/02/12 15:38:08 CERN IT-PDP/DM Jean-Philippe Baud
+ */
+
+#pragma once
+
+	/* all maximum lengths defined below do not include the trailing null */
+
+#define CA_MAXACLENTRIES 300	/* maximum number of ACL entries for a file/dir */
+#define CA_MAXCLASNAMELEN 15	/* maximum length for a fileclass name */
+#define	CA_MAXCOMMENTLEN 255	/* maximum length for user comments in metadata */
+#define	CA_MAXDENLEN       8	/* maximum length for a alphanumeric density */
+#define	CA_MAXDGNLEN       6	/* maximum length for a device group name */
+#define CA_MAXDVNLEN      63	/* maximum length for a device name */
+#define	CA_MAXDVTLEN       8	/* maximum length for a device type */
+#define	CA_MAXFIDLEN      17	/* maximum length for a fid (DSN) */
+#define	CA_MAXFSEQLEN     14	/* maximum length for a fseq string */
+#define	CA_MAXGRPNAMELEN   2	/* maximum length for a group name */
+#define	CA_MAXGUIDLEN     36	/* maximum length for a guid */
+#define CA_MAXHOSTNAMELEN 63	/* maximum length for a hostname */
+#define CA_MAXSVCCLASSNAMELEN 63	/* maximum length for a svc class name */
+#define	CA_MAXLBLTYPLEN    3	/* maximum length for a label type */
+#define CA_MAXLINELEN   1023	/* maximum length for a line in a log */
+#define	CA_MAXMANUFLEN    12	/* maximum length for a cartridge manufacturer */
+#define	CA_MAXMIGPNAMELEN 15	/* maximum length for a migration policy name */
+#define	CA_MAXMIGRNAMELEN 15	/* maximum length for a migrator name */
+#define	CA_MAXMLLEN        1	/* maximum length for a cartridge media_letter */
+#define	CA_MAXMODELLEN     6	/* maximum length for a cartridge model */
+#define	CA_MAXNAMELEN    255	/* maximum length for a pathname component */
+#define	CA_MAXNBDRIVES     4	/* maximum number of tape drives per server */
+#define	CA_MAXPATHLEN   1023	/* maximum length for a pathname */
+#define CA_MAXPOOLNAMELEN 15	/* maximum length for a pool name */
+#define CA_MAXPROTOLEN     7	/* maximum length for a protocol name */
+#define	CA_MAXRBTNAMELEN  17	/* maximum length for a robot name */
+#define	CA_MAXRECFMLEN     3	/* maximum length for a record format */
+#define CA_MAXREGEXPLEN   63    /* Maximum length for a regular expression */
+#define CA_MAXCSECNAMELEN 512	/* Maximum length for a Csec authorization id */
+#define CA_MAXCSECPROTOLEN 20	/* Maximum length for a Csec mechanism */
+#define	CA_MAXSFNLEN    1103	/* maximum length for a replica */
+#define CA_MAXSHORTHOSTLEN 10	/* maximum length for a hostname without domain */
+#define	CA_MAXSNLEN       24	/* maximum length for a cartridge serial nb */
+#define	CA_MAXSTGRIDLEN   77	/* maximum length for a stager full request id */
+				/* must be >= nb digits in CA_MAXSTGREQID +
+				   CA_MAXHOSTNAMELEN + 8 */
+#define	CA_MAXSTGREQID 999999	/* maximum value for a stager request id */
+#define	CA_MAXSYMLINKS     5	/* maximum number of symbolic links */
+#define	CA_MAXTAGLEN     255	/* maximum length for a volume tag */
+#define	CA_MAXTAPELIBLEN   8	/* maximum length for a tape library name */
+#define	CA_MAXUNMLEN       8	/* maximum length for a drive name */
+#define	CA_MAXUSRNAMELEN  14	/* maximum length for a login name */
+#define	CA_MAXVIDLEN       6	/* maximum length for a VID */
+#define	CA_MAXVSNLEN       6	/* maximum length for a VSN */
+#define CA_MAXCKSUMNAMELEN 15   /* maximum length for a checksum algorithm name */
+#define CA_MAXCKSUMLEN     32   /* maximum length for a checksum value in an asci form */
+#define CA_MAXDMPROTNAMELEN 15  /* maximum length for Disk Mover protocol name */
+#define CA_MAXJOBIDLEN     36   /* Maximum length for the representation of the Cuuid */
+#define CA_MAXUSERTAGLEN    63  /* Maximum length for a user tag (stage request) */
+#define CA_MAXRFSLINELEN 2047   /* maximum length for the requested filesystem string */
+
+/* Max allowed uid/gif */
+#define CA_MAXUID    0x7FFFFFFF /* Maximum uid */
+#define CA_MAXGID    0x7FFFFFFF /* Maximum gid */
diff --git a/XRootdSSiRmcd/RmcdApi.hpp b/XRootdSSiRmcd/RmcdApi.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..2d2ca0995a2e76d11dfa429b2444c27ce10493c8
--- /dev/null
+++ b/XRootdSSiRmcd/RmcdApi.hpp
@@ -0,0 +1,41 @@
+/*!
+ * @project        XRootD SSI/Protocol Buffer Interface Project
+ * @brief          XRootD SSI/Google Protocol Buffer bindings for the rmc_test client/server
+ * @copyright      Copyright 2018 CERN
+ * @license        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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "XrdSsiPbServiceClientSide.hpp"                   //!< XRootD SSI/Protocol Buffer Service, client-side bindings
+#include "protobuf/rmc_test.pb.h"                                       //!< Auto-generated message types from .proto file
+
+/*!
+ * Bind the type of the XrdSsiService to the types defined in the .proto file
+ */
+typedef XrdSsiPb::ServiceClientSide<rmc_test::Request,     //!< XrdSSi Request message type
+                                    rmc_test::Response,    //!< XrdSsi Metadata message type
+                                    rmc_test::Data,        //!< XrdSsi Data message type
+                                    rmc_test::Alert>       //!< XrdSsi Alert message type
+        XrdSsiPbServiceType;
+
+/*!
+ * Bind the type of the XrdSsiRequest to the types defined in the .proto file
+ */
+typedef XrdSsiPb::Request<rmc_test::Request,               //!< XrdSSi Request message type
+                          rmc_test::Response,              //!< XrdSsi Metadata message type
+                          rmc_test::Data,                  //!< XrdSsi Data message type
+                          rmc_test::Alert>                 //!< XrdSsi Alert message type
+        XrdSsiPbRequestType;
+
diff --git a/XRootdSSiRmcd/RmcdClient.cpp b/XRootdSSiRmcd/RmcdClient.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d54ed881491fe070903ab26621baf5ab4e36d0e4
--- /dev/null
+++ b/XRootdSSiRmcd/RmcdClient.cpp
@@ -0,0 +1,401 @@
+/*!
+ * @project        XRootD SSI/Protocol Buffer Interface Project
+ * @brief          Command-line rmc_test client for XRootD SSI/Protocol Buffers
+ * @copyright      Copyright 2018 CERN
+ * @license        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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+#include <algorithm>
+
+#include "XrdSsiPbIStreamBuffer.hpp"
+#include "RmcdClient.hpp"
+
+#include <getopt.h>
+
+bool is_metadata_done = false;
+
+// note: this implementation does not disable this overload for array types
+ template<typename T, typename... Args>
+ std::unique_ptr<T> make_unique(Args&&... args)
+ {
+     return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+     }
+
+
+// Define XRootD SSI callbacks
+
+namespace XrdSsiPb {
+
+/*
+ * Alert callback.
+ *
+ * Defines how Alert messages should be logged
+ */
+template<>
+void RequestCallback<rmc_test::Alert>::operator()(const rmc_test::Alert &alert)
+{
+   Log::Msg(Log::INFO, LOG_SUFFIX, "Alert received:");
+
+   // Output message in Json format
+   Log::DumpProtobuf(Log::INFO, &alert);
+}
+
+} // namespace XrdSsiPb
+
+
+//
+// RmcdClient implementation
+//
+
+const std::string DEFAULT_ENDPOINT = "localhost:10956";
+
+// Change console text colour
+
+const char* const TEXT_RED    = "\x1b[31;1m";
+const char* const TEXT_NORMAL = "\x1b[0m\n";
+
+
+
+// Convert string to bool
+
+bool to_bool(std::string str) {
+   std::transform(str.begin(), str.end(), str.begin(), ::tolower);
+   if(str == "true") return true;
+   if(str == "false") return false;
+
+   throw std::runtime_error(str + " is not a valid boolean value");
+}
+
+void RmcdClientCmd::throwUsage(const std::string &error_txt) const
+{ 
+   std::stringstream help;
+   if(error_txt != "") {
+      help << m_execname << ": " << error_txt << std::endl << std::endl;
+   }
+   help << "Usage:\n"
+   "\n"
+   "rmcd-client [cmdOptions]\n"
+   "Where cmdOptions can be one of those:\n"
+   "\n"
+   "\tmount -V vid -D drive_ordinal\n"
+   "\tdismount\n"
+   "\timport\n"
+   "\texport\n"
+   "\tread_elem  [-N nbelem] [-S starting_slot] [-v]\n"
+   "\tfind_cartridge V [-N nbelem] [-V vid] [-v]\n"
+   "\tget_geom\n"
+   "\n";
+   throw std::runtime_error(help.str());
+}
+
+void RmcdClientCmd::mountUsage(const std::string &error_txt) const
+{
+   std::stringstream help;
+   if(error_txt != "") {
+      help << m_execname << ": " << error_txt << std::endl << std::endl;
+   }
+
+   help <<"Usage:\n"
+   "\n"
+   "  mount [options] -V VID -D DRIVE_SLOT\n"
+   "\n"
+   "Where:\n"
+   "\n"
+   "  VID        The VID of the volume to be mounted.\n"
+   "  DRIVE_SLOT The slot in the tape library where the drive is located.\n"
+   "             The format of DRIVE_SLOT is as follows:\n"
+   "\n"
+   "               ACS:LSM:panel:transport\n"
+   "\n"
+   "Options:\n"
+   "  -h|--help             Print this help message and exit.\n"
+   "\n"
+   "  -t|--timeout SECONDS  Time to wait for the mount to conclude. SECONDS\n"
+   "                        must be an integer value greater than 0.  The\n"
+   "                        default value of SECONDS is "
+   "\n";
+   throw std::runtime_error(help.str());
+}
+
+void RmcdClientCmd::dismountUsage(const std::string &error_txt) const
+{
+   std::stringstream help;
+
+   if(error_txt != "") {
+      help << m_execname << ": " << error_txt << std::endl << std::endl;
+   }
+
+   help <<"Usage:\n"
+   "\n"
+   "  dismount [options] -V VID -D DRIVE_SLOT\n"
+   "\n"
+   "Where:\n"
+   "\n"
+   "  VID        The VID of the volume to be dismounted.\n"
+   "  DRIVE_SLOT The slot in the tape library where the drive is located.\n"
+   "             The format of DRIVE_SLOT is as follows:\n"
+   "\n"
+   "               ACS:LSM:panel:transport\n"
+   "\n"
+   "Options:\n"
+   "  -h|--help             Print this help message and exit.\n"
+   "\n"
+   "  -t|--timeout SECONDS  Time to wait for the dismount to conclude. SECONDS\n"
+   "                        must be an integer value greater than 0.  The\n"
+   "                        default value of SECONDS is "
+   "\n";
+   throw std::runtime_error(help.str());
+}
+
+RmcdClientCmd::RmcdClientCmd(int argc, char *const *const argv) :
+   m_execname(argv[0]),
+   m_endpoint(DEFAULT_ENDPOINT)
+{
+   // Strip path from execname
+
+   size_t p = m_execname.find_last_of('/');
+   if(p != std::string::npos) m_execname.erase(0, p+1);
+
+   // Parse the command
+   if(argc<2) {
+      RmcdClientCmd::throwUsage("Missing command option");
+      return; 
+   }
+
+ std::string cmdOptions(argv[1]);
+
+   if(cmdOptions == "help") {
+      throwUsage("help");
+   } 
+   else if(cmdOptions == "mount") {
+     if(argc==3) {
+       std::string cmdh(argv[2]);
+
+       if(cmdh == "help") {
+         mountUsage("helping in mount");
+         return;
+       }
+   }
+   processMount(argc, argv);
+   } else if(cmdOptions == "dismount") {
+       if(argc==3) {
+         std::string cmdh(argv[2]);
+
+       if(cmdh == "help") {
+         dismountUsage("helping in dismount");
+         return;
+       }
+   }
+   processDismount(argc, argv);
+   } else {
+      throwUsage("Unrecognized command: ");
+   }
+
+   // Read environment variables
+
+   XrdSsiPb::Config config;
+
+   // If XRDDEBUG=1, switch on all logging
+   if(getenv("XRDDEBUG")) {
+      config.set("log", "all");
+   }
+
+   // XrdSsiPbLogLevel gives more fine-grained control over log level
+   config.getEnv("log", "XrdSsiPbLogLevel");
+
+   // Default response timeout
+   config.getEnv("request_timeout", "XRD_REQUESTTIMEOUT");
+
+   // Obtain a Service Provider
+   std::string resource("/rmc_test");
+   m_rmc_test_service_ptr = make_unique<XrdSsiPbServiceType>(m_endpoint, resource, config);
+}
+
+void RmcdClientCmd::processMount(int argc, char *const *const argv) {
+     int errflg = 0;
+     int drvord = -1;
+     int n;
+     char vid[7];
+     char *dp;
+     char c=0;
+     static struct option longopts[] = {
+       { "help", no_argument, NULL, 'h'},
+       { "Vid", required_argument, NULL, 'V'},
+       { "Drive_original", required_argument, NULL, 'D' },
+       { NULL, 0, NULL, '\0' }
+     };
+     memset (vid, '\0', sizeof(vid));
+     if (argc<6) {
+       RmcdClientCmd::mountUsage("less arguments provided");
+       return;
+     }
+     if(*argv[2]!= '-') {
+         RmcdClientCmd::mountUsage("Unrecognised command format given\n");
+     }
+
+    while ((c = getopt_long(argc, argv, "hV:D:",longopts, NULL))!= -1) {
+       switch (c) {
+       case 'h':
+	 RmcdClientCmd::mountUsage("help");
+         break;
+       case 'D':       /* drive ordinal */
+         {
+         drvord = strtol (optarg, &dp, 10);
+         if (*dp != '\0' || drvord < 0) {
+            errflg++;
+         }
+            strcpy (dp, optarg);
+            printf("drive slot = %s\n",dp);
+      	    m_request.mutable_mount()->set_drvord(drvord);
+	 break;
+         }
+       case 'V':       /* vid */
+         {
+         n = strlen (optarg);
+         if (n > 6) {
+            errflg++;
+         } else {
+            strcpy (vid, optarg);
+         printf("vid = %s\n",vid);
+      	 m_request.mutable_mount()->set_vid(vid);}
+         break;
+         }
+       case '?': /* Unrecognized option */
+       default:{
+         RmcdClientCmd::mountUsage("Unrecognised commands\n");
+	 break;
+       }
+       }
+    }
+}
+
+void RmcdClientCmd::processDismount(int argc, char *const *const argv) {
+     int errflg = 0;
+     int drvord = -1;
+     int n;
+     char vid[7];
+     char *dp;
+     char c;
+     static struct option longopts[] = {
+       { "help", required_argument, NULL, 'h'},
+       { "Vid", required_argument, NULL, 'V'},
+       { "Drive_original", required_argument, NULL, 'D' },
+       { NULL, 0, NULL, '\0' }
+     };
+     memset (vid, '\0', sizeof(vid));
+     if (argc<6) {
+       RmcdClientCmd::dismountUsage("less arguments provided");
+       return;
+     }
+     if(*argv[2]!= '-') {
+         RmcdClientCmd::dismountUsage("Unrecognised command format given\n");
+     }
+     while ((c = getopt_long(argc, argv, "hV:D:",longopts, NULL))!= -1) {
+       switch (c) {
+       case 'h':
+	 RmcdClientCmd::dismountUsage("help");
+         break;
+       case 'D': {      /* drive ordinal */
+         drvord = strtol (optarg, &dp, 10);
+         if (*dp != '\0' || drvord < 0) {
+            errflg++;}
+         strcpy (dp, optarg);
+         printf("drive slot = %s\n",dp);
+      	 m_request.mutable_dismount()->set_drvord(drvord);
+         break;
+         }
+       case 'V': {      /* vid */
+         n = strlen (optarg);
+         if (n > 6) {
+            errflg++;
+         } else {
+            strcpy (vid, optarg);
+         printf("vid = %s\n",vid);
+      	 m_request.mutable_dismount()->set_vid(vid);}
+         break;
+         }
+       case '?':
+       default:{
+        RmcdClientCmd::dismountUsage("Unrecognised command");
+	break;
+	}
+       }
+     }
+}
+
+
+void RmcdClientCmd::Send()
+{
+      // Send the Request to the Service and get a Response
+      rmc_test::Response response;
+      m_rmc_test_service_ptr->Send(m_request, response);
+      // Handle responses
+      switch(response.type())
+      {
+         using namespace rmc_test;
+   
+         case Response::RSP_SUCCESS:         std::cout << response.message_txt(); break;
+         case Response::RSP_ERR_PROTOBUF:    throw XrdSsiPb::PbException(response.message_txt());
+         case Response::RSP_ERR_USER:
+         case Response::RSP_ERR_SERVER:      throw std::runtime_error(response.message_txt());
+         default:                            throw XrdSsiPb::PbException("Invalid response type.");
+      }
+      is_metadata_done = true;
+}
+
+
+/*!
+ * Start here
+ *
+ * @param    argc[in]    The number of command-line arguments
+ * @param    argv[in]    The command-line arguments
+ *
+ * @retval 0    Success
+ * @retval 1    The client threw an exception
+ */
+int main(int argc, char **argv)
+{
+   try {
+      // Test uninitialised logging : logging is not available until the rmc_test_service object is
+      // instantiated, so this message should be silently ignored
+      XrdSsiPb::Log::Msg(XrdSsiPb::Log::ERROR, "main", "Logging is not initialised");
+
+      // Parse the command line arguments
+      RmcdClientCmd cmd(argc, argv);
+
+      // Send the protocol buffer
+      cmd.Send();
+
+      // Delete all global objects allocated by libprotobuf
+      google::protobuf::ShutdownProtobufLibrary();
+
+      return 0;
+   } catch (XrdSsiPb::PbException &ex) {
+      std::cerr << "Error in Google Protocol Buffers: " << ex.what() << std::endl;
+   } catch (XrdSsiPb::XrdSsiException &ex) {
+      std::cerr << "Error from XRootD SSI Framework: " << ex.what() << std::endl;
+   } catch (std::runtime_error &ex) {
+      std::cerr << ex.what() << std::endl;
+   } catch (std::exception &ex) {
+      std::cerr << "Caught exception: " << ex.what() << std::endl;
+   } catch (...) {
+      std::cerr << "Caught an unknown exception" << std::endl;
+   }
+
+   return 1;
+}
+
diff --git a/XRootdSSiRmcd/RmcdClient.hpp b/XRootdSSiRmcd/RmcdClient.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d73d0b7d47208d8bc66250459f0a513afe867da5
--- /dev/null
+++ b/XRootdSSiRmcd/RmcdClient.hpp
@@ -0,0 +1,51 @@
+/*!
+ * @project        XRootD SSI/Protocol Buffer Interface Project
+ * @brief          Command-line rmc_test client for XRootD SSI/Protocol Buffers
+ * @copyright      Copyright 2018 CERN
+ * @license        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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "RmcdApi.hpp"
+
+class RmcdClientCmd
+{
+public:
+   RmcdClientCmd(int argc, char *const *const argv);
+
+   /*!
+    * Send the protocol buffer across the XRootD SSI transport
+    */
+   void Send();
+   /*!
+    * Throw an exception with usage help
+    */
+   void  mountUsage(const std::string &error_txt = "") const;
+   void  dismountUsage(const std::string &error_txt = "") const;
+   void  throwUsage(const std::string &error_txt = "") const;
+   void  processMount(int, char * const *const);
+   void  processDismount(int, char * const *const);
+
+private:
+
+   /*
+    * Member variables
+    */
+   std::unique_ptr<XrdSsiPbServiceType> m_rmc_test_service_ptr;    //!< Pointer to Service object
+   std::string                          m_execname;            //!< Executable name of this program
+   std::string                          m_endpoint;            //!< hostname:port of XRootD server
+   rmc_test::Request                    m_request;             //!< Protocol Buffer for the command to send to the server
+};
+
diff --git a/XRootdSSiRmcd/RmcdRequestProc.cpp b/XRootdSSiRmcd/RmcdRequestProc.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f8ac90eaf44259ea1e790a64a384b752df48150f
--- /dev/null
+++ b/XRootdSSiRmcd/RmcdRequestProc.cpp
@@ -0,0 +1,192 @@
+/*!
+ * @project        XRootD SSI/Protocol Buffer Interface Project
+ * @brief          XRootD SSI Responder class implementation
+ * @copyright      Copyright 2018 CERN
+ * @license        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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "XrdSsiPbConfig.hpp"
+#include <sstream>
+#include <XrdSsi/XrdSsiEntity.hh>
+#include "XrdSsiPbLog.hpp"
+#include "XrdSsiPbException.hpp"
+#include "XrdSsiPbRequestProc.hpp"
+#include "RmcdServiceProvider.hpp"
+#include <iostream>
+#include "rmc_smcsubr.h"
+#include "rmc_smcsubr2.h"
+#include "smc_struct.h"
+#include <string>
+
+/*
+ * Class to process Request Messages
+ */
+class RequestMessage
+{
+public:
+   char* device_file = new char();
+   RequestMessage(const XrdSsiEntity &client, const RmcdServiceProvider *service) {
+      using namespace XrdSsiPb;
+      Log::Msg(Log::DEBUG, LOG_SUFFIX, "RequestMessage() constructor: request received from client ",
+               client.name, '@', client.host);
+   }
+
+   /*!
+    * Process a Notification request or an Admin command request
+    *
+    * @param[in]     request
+    * @param[out]    response        Response protocol buffer
+    * @param[out]    stream          Reference to Response stream pointer
+    */
+   void process(const rmc_test::Request &request, rmc_test::Response &response, std::string &data_buffer, XrdSsiStream* &stream) {
+         
+      using namespace XrdSsiPb;
+      using namespace rmc_test;
+      if (request.has_mount()) {
+         std::stringstream message;
+         response.set_message_txt(message.str());
+         response.set_type(Response::RSP_SUCCESS);
+         /* get robot geometry */
+         int c;
+	 robot_info m_robot_info;
+         
+         const int max_nb_attempts = 3;
+         int attempt_nb = 1;
+         for(attempt_nb = 1; attempt_nb <= max_nb_attempts; attempt_nb++) {
+         std::cout<<"The device file before the get_geometry is "<<device_file<<std::endl;
+         c = smc_get_geometry (-1,
+                device_file,              ///dev/sgx for example
+                &m_robot_info);
+         if (c==0){
+            message << "Got geometry of tape library"<< std::endl;
+         }
+    	 std::string driverStr = std::to_string (request.mount().drvord());
+         int n = (request.mount().vid()).length();  
+         // declaring character array 
+         char *ch_array = new char[n+1]; 
+           
+         // copying the contents of the string to char array 
+         strcpy(ch_array, (request.mount().vid()).c_str());  
+                             
+         c = smc_mount (-1,-1, device_file, &m_robot_info, 
+                request.mount().drvord(), ch_array,  0);    
+         }      
+      } else if (request.has_dismount()) {
+         std::stringstream message;
+         response.set_message_txt(message.str());
+         response.set_type(Response::RSP_SUCCESS);
+
+         /* get robot geometry */
+         int c;
+	 robot_info m_robot_info;
+         const int max_nb_attempts = 3;
+         int attempt_nb = 1;
+         for(attempt_nb = 1; attempt_nb <= max_nb_attempts; attempt_nb++) {
+            c = smc_get_geometry (-1,
+               device_file, &m_robot_info);
+            if (c==0){
+               message << "Got geometry of tape library"<< std::endl;
+            }
+            std::string driverStr = std::to_string (request.dismount().drvord());
+            int n = (request.dismount().vid()).length();  
+      
+            /* declaring character array */
+            char *ch_array = new char[n+1]; 
+               
+            /* copying the contents of the string to char array */
+            strcpy(ch_array, (request.dismount().vid()).c_str());  
+                                
+            c = smc_dismount (-1,-1, device_file, &m_robot_info, 
+                   request.dismount().drvord(), ch_array);
+         }
+      }
+   }
+
+private:
+  
+    // Set reply header in metadata
+  
+   void set_header(rmc_test::Response &response) {
+      const char* const TEXT_RED    = "\x1b[31;1m";
+      const char* const TEXT_NORMAL = "\x1b[0m\n";
+
+      std::stringstream header;
+
+      header << TEXT_RED << "Count "
+                         << "Int64 Value "
+                         << "Double Value "
+                         << "Bool  String Value" << TEXT_NORMAL;
+
+      response.set_message_txt(header.str());
+   }
+
+   static constexpr const char* const LOG_SUFFIX = "Pb::RequestMessage";    //!< Identifier for log messages
+};
+
+
+
+/*
+ * Implementation of XRootD SSI subclasses
+ */
+namespace XrdSsiPb {
+
+/*
+ * Convert a framework exception into a Response
+ */
+
+template<>
+void ExceptionHandler<rmc_test::Response, PbException>::operator()(rmc_test::Response &response, const PbException &ex)
+{
+   response.set_type(rmc_test::Response::RSP_ERR_PROTOBUF);
+   response.set_message_txt(ex.what());
+}
+
+
+
+/*
+ * Process the Notification Request
+ */
+template <>
+void RequestProc<rmc_test::Request, rmc_test::Response, rmc_test::Alert>::ExecuteAction()
+{
+   try {
+      // Perform a capability query on the XrdSsiProviderServer object: it must be a RmcdServiceProvider
+
+      RmcdServiceProvider *rmc_test_service_ptr;
+     
+      if(!(rmc_test_service_ptr = dynamic_cast<RmcdServiceProvider*>(XrdSsiProviderServer)))
+      {
+         throw std::runtime_error("XRootD Service is not the Test Service");
+      }
+      RequestMessage request_msg(*(m_resource.client), rmc_test_service_ptr);
+      strcpy(request_msg.device_file,((rmc_test_service_ptr->scsi_device).c_str()));   //get the filename to mount/dismount from the configuration file
+      request_msg.process(m_request, m_metadata, m_response_str, m_response_stream_ptr);
+   } catch(PbException &ex) {
+      m_metadata.set_type(rmc_test::Response::RSP_ERR_PROTOBUF);
+      m_metadata.set_message_txt(ex.what());
+   } catch(std::exception &ex) {
+      // Serialize and send a log message
+
+      rmc_test::Alert alert_msg;
+      alert_msg.set_message_txt("Something bad happened");
+      Alert(alert_msg);
+
+      // Send the metadata response
+
+      m_metadata.set_type(rmc_test::Response::RSP_ERR_SERVER);
+      m_metadata.set_message_txt(ex.what());
+   }
+}
+
+} // namespace XrdSsiPb
diff --git a/XRootdSSiRmcd/RmcdServiceProvider.cpp b/XRootdSSiRmcd/RmcdServiceProvider.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4ab8465c36f64a7b3d0a5cd9ef54224483aa4304
--- /dev/null
+++ b/XRootdSSiRmcd/RmcdServiceProvider.cpp
@@ -0,0 +1,114 @@
+/*!
+ * @project        XRootD SSI/Protocol Buffer Interface Project
+ * @brief          XRootD Service Provider class implementation
+ * @copyright      Copyright 2018 CERN
+ * @license        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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "XrdSsiPbConfig.hpp"
+#include "XrdSsiPbAlert.hpp"
+#include "XrdSsiPbService.hpp"
+#include <iostream>
+#include <string>
+
+#include "protobuf/rmc_test.pb.h"
+#include "RmcdServiceProvider.hpp"
+
+
+
+/*!
+ * Global pointer to the Service Provider object.
+ *
+ * This must be defined at library load time (i.e. it is a file-level global static symbol). When the
+ * shared library is loaded, XRootD initialization fails if the appropriate symbol cannot be found (or
+ * it is a null pointer).
+ */
+XrdSsiProvider *XrdSsiProviderServer = new RmcdServiceProvider;
+
+
+
+/*!
+ * Initialise the Service Provider
+ */
+bool RmcdServiceProvider::Init(XrdSsiLogger *logP, XrdSsiCluster *clsP, const std::string cfgFn, const std::string parms, int argc, char **argv)
+{
+   using namespace XrdSsiPb;
+
+   Log::Say("Called Init(\"", cfgFn, "\",\"", parms, "\")");
+
+   // Extract configuration items from config file
+   Config config(cfgFn, "rmc_test");
+   auto test_log = config.getOptionList("log");
+   if(!test_log.empty()) {
+      Log::SetLogLevel(test_log);
+   } else {
+      Log::SetLogLevel("info");
+   }
+   
+   auto v_scsi_devices = config.getOptionList("cta.xrmcd.smcdev");
+   scsi_device = v_scsi_devices[0];
+     Log::SetLogLevel(scsi_device);
+   if(scsi_device.empty()) {
+      Log::SetLogLevel("name of the device_file not specified by the user in the configuration file");
+   }
+   return true;
+}
+
+
+
+/*!
+ * Instantiate a Service object
+ */
+
+XrdSsiService* RmcdServiceProvider::GetService(XrdSsiErrInfo &eInfo, const std::string &contact, int oHold)
+{
+   using namespace XrdSsiPb;
+
+   Log::Msg(Log::INFO, LOG_SUFFIX, "Called GetService(", contact, ',', oHold, ')');
+
+   XrdSsiService *ptr = new XrdSsiPb::Service<rmc_test::Request, rmc_test::Response, rmc_test::Alert>;
+
+   return ptr;
+}
+
+
+
+/*!
+ * Query whether a resource exists on a server.
+ *
+ * @param[in]    rName      The resource name
+ * @param[in]    contact    Used by client-initiated queries for a resource at a particular endpoint.
+ *                          It is set to NULL for server-initiated queries.
+ *
+ * @retval    XrdSsiProvider::notPresent    The resource does not exist
+ * @retval    XrdSsiProvider::isPresent     The resource exists
+ * @retval    XrdSsiProvider::isPending     The resource exists but is not immediately available. (Useful
+ *                                          only in clustered environments where the resource may be
+ *                                          immediately available on some other node.)
+ */
+
+XrdSsiProvider::rStat RmcdServiceProvider::QueryResource(const char *rName, const char *contact)
+{
+   using namespace XrdSsiPb;
+
+   // We only have one resource
+   XrdSsiProvider::rStat resourcePresence = (strcmp(rName, "/rmc_test") == 0) ?
+                                            XrdSsiProvider::isPresent : XrdSsiProvider::notPresent;
+
+   Log::Msg(Log::INFO, LOG_SUFFIX, "QueryResource(", rName, "): ", 
+             ((resourcePresence == XrdSsiProvider::isPresent) ? "isPresent" : "notPresent"));
+
+   return resourcePresence;
+}
+
diff --git a/XRootdSSiRmcd/RmcdServiceProvider.hpp b/XRootdSSiRmcd/RmcdServiceProvider.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..270df1f26418f70672abd73f04e402c2ac1190aa
--- /dev/null
+++ b/XRootdSSiRmcd/RmcdServiceProvider.hpp
@@ -0,0 +1,76 @@
+/*!
+ * @project        XRootD SSI/Protocol Buffer Interface Project
+ * @brief          XRootD Service Provider class implementation
+ * @copyright      Copyright 2018 CERN
+ * @license        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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <XrdSsi/XrdSsiProvider.hh>
+#include "protobuf/rmc_test.pb.h"
+#include "XrdSsiPbConfig.hpp"
+
+
+
+/*!
+ * Global pointer to the Service Provider object.
+ */
+extern XrdSsiProvider *XrdSsiProviderServer;
+
+
+
+/*!
+ * Instantiates a Service to process client requests.
+ */
+class RmcdServiceProvider : public XrdSsiProvider
+{
+public:
+   RmcdServiceProvider() {
+      // No logging here as we don't set the log level until Init() is called
+   }
+
+   virtual ~RmcdServiceProvider() {
+      using namespace XrdSsiPb;
+
+      Log::Msg(Log::DEBUG, LOG_SUFFIX, "Called RmcdServiceProvider() destructor");
+   }
+
+   /*!
+    * Initialize the object.
+    *
+    * This is always called before any other method.
+    */
+   bool Init(XrdSsiLogger *logP, XrdSsiCluster *clsP, const std::string cfgFn,
+             const std::string parms, int argc, char **argv) override;
+
+   /*!
+    * Called exactly once after initialisation to obtain an instance of an XrdSsiService object
+    */
+   XrdSsiService *GetService(XrdSsiErrInfo &eInfo, const std::string &contact, int oHold=256) override;
+
+   /*!
+    * Determine resource availability. Can be called any time the client asks for the resource status.
+    */
+   XrdSsiProvider::rStat QueryResource(const char *rName, const char *contact=0) override;
+   
+   /*!
+    * Defines the device file to mount or dismount the volume
+    */
+   std::string scsi_device;
+
+private:
+   static constexpr const char* const LOG_SUFFIX  = "TestStream";    //!< Identifier for log messages
+};
+
diff --git a/XRootdSSiRmcd/cta-xrmcd.conf b/XRootdSSiRmcd/cta-xrmcd.conf
new file mode 100644
index 0000000000000000000000000000000000000000..14cdf95904280da1842f3a01e5d02e8c2179b0a0
--- /dev/null
+++ b/XRootdSSiRmcd/cta-xrmcd.conf
@@ -0,0 +1,41 @@
+#
+# XRootD SSI/Protocol Buffer Interface Project
+# Copyright 2018 CERN
+#
+
+# Set the log level for the XrdSsiPb messages.
+# This is a space-separated list of one or more of the following options:
+#
+#    none error warning info debug protobuf protoraw all
+rmc_test.log info protobuf
+
+# Set the debug level to off/debug/all for no debug/debug/verbose debug
+ssi.trace debug
+
+# Tell XRootD to use only the SSI framework. If you wish to also use the filesystem features of
+# XRootD then add the keyword "default", or specify a second plugin.
+xrootd.fslib libXrdSsi.so 
+
+# Turn off async processing as this does not work with SSI
+xrootd.async off
+
+# Specify the location of the shared library implementing the SSI service
+#ssi.svclib /home/akaracha/CTA_build/XRootdSSiRmcd/libXrdSsiRmcd.so
+ssi.svclib libXrdSsiRmcd.so
+
+# Specify the resource lookup function to be used
+#oss.statlib -2 libXrdSsi.so
+
+# Specify the endpoint
+#xrd.allow host localhost
+xrd.port 10956
+
+# Declare the valid prefix for resource names. You can have as many of these directives as you wish,
+# each specifying a different prefix. Use a question mark ? to split the resource into a name and a
+# CGI string.
+
+# Export the /test resource for SSI
+all.export /rmc_test nolock r/w
+
+# User has to specify the name of the device file
+cta.xrmcd.smcdev /dev/sg9
diff --git a/XRootdSSiRmcd/cta-xrmcd.logrotate b/XRootdSSiRmcd/cta-xrmcd.logrotate
new file mode 100644
index 0000000000000000000000000000000000000000..7625211eac53b7920ad775e046301b75f1e340a7
--- /dev/null
+++ b/XRootdSSiRmcd/cta-xrmcd.logrotate
@@ -0,0 +1,11 @@
+
+/var/log/cta/cta-xrmcd*.log {
+    compress
+    daily
+    missingok
+    rotate 500
+    delaycompress
+    postrotate
+        /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
+    endscript
+}
diff --git a/XRootdSSiRmcd/cta-xrmcd.service b/XRootdSSiRmcd/cta-xrmcd.service
new file mode 100644
index 0000000000000000000000000000000000000000..50d6d8c850fe66f0c5f45c15f978c832837e0f26
--- /dev/null
+++ b/XRootdSSiRmcd/cta-xrmcd.service
@@ -0,0 +1,16 @@
+
+[Unit]
+
+Description=CTA rmcd plugin for the XRoot deamon 
+After=network-online.target
+
+[Service]
+ExecStart=/usr/bin/xrootd -c /etc/cta/cta-xrmcd.conf -k fifo -n cta
+User=cta
+Type=simple
+Restart=no
+LimitCORE=infinity
+LimitNOFILE=65536
+
+[Install]
+WantedBy=default.target
diff --git a/XRootdSSiRmcd/cta-xrmcd.sysconfig b/XRootdSSiRmcd/cta-xrmcd.sysconfig
new file mode 100644
index 0000000000000000000000000000000000000000..01e494ed42bae981fb3c3fb5b7d433ad00fe908e
--- /dev/null
+++ b/XRootdSSiRmcd/cta-xrmcd.sysconfig
@@ -0,0 +1,5 @@
+
+# Arguments for the xrmcd server daemon
+#   -smc_ldr       is the picker device as defined in /dev.
+#   -f             keep process in the foreground, do not fork.
+#CTA_XRMCD_OPTIONS="smc_ldr"
diff --git a/XRootdSSiRmcd/cta-xsmc-dismount.1cta b/XRootdSSiRmcd/cta-xsmc-dismount.1cta
new file mode 100644
index 0000000000000000000000000000000000000000..81c426f6e317960c61c85d8b5fae5558dd8b9d19
--- /dev/null
+++ b/XRootdSSiRmcd/cta-xsmc-dismount.1cta
@@ -0,0 +1,47 @@
+.\" The CERN Tape Archive (CTA) project
+.\" Copyright (C) 2015  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 3 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, see <http://www.gnu.org/licenses/>.
+.TH CTA-XSMC DISMOUNT 1CTA "October 2018" CTA CTA
+.SH NAME
+cta-xsmc dismount \- dismount a volume
+.SH SYNOPSIS
+.BI "cta-xsmc dismount [options] -V VID -D DRIVE_SLOT"
+
+.SH DESCRIPTION
+\fBWarning\fP, \fBcta-xsmc dismount\fP is a command line tool for dismounting tapes in a library through XRootD SSI/Protocol Buffer Interface Project
+
+\fBcta-xsmc dismount\fP dismounts the volume with the specified
+\fBVID\fP from the drive located in the specified \fBDRIVE_SLOT\fP within the
+tape library.  \fBDRIVE_SLOT\fP must be in one of the following two forms:
+.IP
+.B acsACS_NUMBER,LSM_NUMBER,PANEL_NUMBER,TRANSPORT_NUMBER
+.IP
+.B smcDRIVE_ORDINAL
+
+.SH OPTIONS
+.TP
+\fB\-d, \-\-debug
+Turns on the printing of debug information.
+.TP
+\fB\-h, \-\-help
+Prints the usage message.
+.TP
+\fB\-f, \-\-force
+Force the dismount (rewind and eject the tape where necessary).
+
+.SH "RETURN CODES"
+.TP
+\fB 0
+Ok.
diff --git a/XRootdSSiRmcd/cta-xsmc-mount.1cta b/XRootdSSiRmcd/cta-xsmc-mount.1cta
new file mode 100644
index 0000000000000000000000000000000000000000..6ca8875d8ca18b777312a59c2159f5525109821b
--- /dev/null
+++ b/XRootdSSiRmcd/cta-xsmc-mount.1cta
@@ -0,0 +1,48 @@
+.\" The CERN Tape Archive (CTA) project
+.\" Copyright (C) 2015  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 3 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, see <http://www.gnu.org/licenses/>.
+.TH CTA-XSMC MOUNT 1CTA "October 2018" CTA CTA
+.SH NAME
+cta-xsmc mount \- mount a volume
+.SH SYNOPSIS
+.BI "cta-xsmc mount [options] -V VID -D DRIVE_SLOT"
+
+.SH DESCRIPTION
+\fBWarning\fP, \fBcta-xsmc mount\fP is a CTA command line tool to mount tapes in a tape library through XRootD SSI/Protocol Buffer Interface Project
+
+\fBcta-xsmc mount\fP mounts the volume with the specified
+\fBVID\fP into the drive located in the specified \fBDRIVE_SLOT\fP within the
+tape library.  \fBDRIVE_SLOT\fP must be in one of the following two forms:
+.IP
+.B acsACS_NUMBER,LSM_NUMBER,PANEL_NUMBER,TRANSPORT_NUMBER
+.IP
+.B smcDRIVE_ORDINAL
+
+.SH OPTIONS
+.TP
+\fB\-d, \-\-debug
+Turns on the printing of debug information.
+.TP
+\fB\-h, \-\-help
+Prints the usage message.
+.TP
+\fB\-r, \-\-readonly
+Request the volume is mounted for read-only access.
+
+.SH "RETURN CODES"
+.TP
+\fB 0
+Ok.
+.TP
diff --git a/XRootdSSiRmcd/protobuf/CMakeLists.txt b/XRootdSSiRmcd/protobuf/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ef46264164068afe6f2105719a254588ea102f84
--- /dev/null
+++ b/XRootdSSiRmcd/protobuf/CMakeLists.txt
@@ -0,0 +1,38 @@
+# XRootD SSI/Protocol Buffer Interface Project
+# Copyright 2018 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 3 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, see <http://www.gnu.org/licenses/>.
+cmake_minimum_required (VERSION 2.6)
+
+find_package(Protobuf3 REQUIRED)
+
+file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/*.proto")
+PROTOBUF3_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles})
+foreach(PROTO_SRC ${ProtoSources})
+  set_property(SOURCE ${PROTO_SRC} PROPERTY COMPILE_FLAGS " -Wno-missing-field-initializers -fPIC -Wno-narrowing -Wno-implicit-fallthrough")
+
+  # Add -Wno-narrowing -Wno-implicit-fallthrough compiler flags if using gcc
+  # version 7 or greater
+  if (CMAKE_COMPILER_IS_GNUCC)
+    if (GCC_VERSION VERSION_EQUAL 7 OR GCC_VERSION VERSION_GREATER 7)
+      set_property(SOURCE ${PROTO_SRC} APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-narrowing -Wno-implicit-fallthrough")
+    endif (GCC_VERSION VERSION_EQUAL 7 OR GCC_VERSION VERSION_GREATER 7)
+  endif (CMAKE_COMPILER_IS_GNUCC)
+endforeach(PROTO_SRC)
+set (TEST_PROTO_SRC_FILES ${ProtoSources})
+
+include_directories(${PROTOBUF3_INCLUDE_DIRS})
+add_library(XrdSsiPbRmcd ${TEST_PROTO_SRC_FILES})
+target_link_libraries(XrdSsiPbRmcd ${PROTOBUF3_LIBRARIES})
+
diff --git a/XRootdSSiRmcd/protobuf/rmc_test.proto b/XRootdSSiRmcd/protobuf/rmc_test.proto
new file mode 100644
index 0000000000000000000000000000000000000000..160ed19bff436f84332eb446ab02d3fe20f3ed8d
--- /dev/null
+++ b/XRootdSSiRmcd/protobuf/rmc_test.proto
@@ -0,0 +1,120 @@
+// @project        XRootD SSI/Protocol Buffer Interface Project
+// @brief          Protocol buffer definitions for test client/server
+// @copyright      Copyright 2018 CERN
+// @license        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 3 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, see <http://www.gnu.org/licenses/>.
+
+syntax = "proto3";
+package rmc_test;
+
+
+message MountOptions {
+  string      vid                     =  4;     // char * template
+  uint32      drvord		      = 6;
+}
+
+message DismountOptions {
+  string      vid                     =  4;     // char * template
+  uint32       drvord                  =  5;    // maybe given as a string
+}
+
+
+message FindcartOptions {
+  uint32      uid                     =  1;
+  uint32      gid                     =  2;
+  string      smc_ldr                 =  3;     // char *
+  string      template                =  4;     // char * 
+  int32       type                    =  5;
+  int64       startaddr               =  6;
+  int64       nbelem                  =  7;
+}
+
+message GetGeomOptions {
+  uint32      uid                     =  1;
+  uint32      gid                     =  2;
+  string      smc_ldr                 =  3;     // char *
+}
+
+message ImportExportOptions {
+  uint32      uid                     =  1;
+  uint32      gid                     =  2;
+  string      smc_ldr                 =  3;     // char *
+  string      vid                     =  4;     // char * template
+}
+
+message ReadelemOptions {
+  int32       uid                     =  1;
+  uint32      gid                     =  2;
+  string      smc_ldr                 =  3;     // char *
+  int32       type                    =  4;
+  int64       startaddr               =  5;
+  int64       nbelem                  =  6;
+}
+
+
+//
+// Requests sent to the Test Server
+//
+message Record {
+}
+
+
+//
+// Requests sent to the Test Server
+//
+message Request {
+  oneof cmdOptions {
+    MountOptions mount                = 1;
+    DismountOptions dismount          = 2;
+    FindcartOptions findcart          = 3;
+    GetGeomOptions getGeometry        = 4;      
+    ImportExportOptions export        = 5;
+    ImportExportOptions import        = 6;
+    ReadelemOptions readelem          = 7; 
+  }
+}
+
+
+//
+// Metadata responses sent by the Test Server
+//
+message Response {
+  enum ResponseType {
+    RSP_INVALID                       = 0;      //< Response type was not set
+    RSP_SUCCESS                       = 1;      //< Request is valid and was accepted for processing
+    RSP_ERR_PROTOBUF                  = 2;      //< Framework error caused by Google Protocol Buffers layer
+    RSP_ERR_SERVER                    = 3;      //< Server error
+    RSP_ERR_USER                      = 4;      //< User request is invalid
+  }
+  ResponseType type                   = 1;      //< Encode the type of this response
+  string message_txt                  = 2;      //< Optional response message text
+}
+
+  
+
+//
+// Stream/Data responses sent by the Test Server
+//
+message Data {
+  Response record                       = 1;      //< Response record
+}
+
+
+
+//
+// Alert Messages
+//
+message Alert {
+  string message_txt                  = 1;      //< Text of the alert message
+}
+
diff --git a/XRootdSSiRmcd/rbtsubr_constants.h b/XRootdSSiRmcd/rbtsubr_constants.h
new file mode 100644
index 0000000000000000000000000000000000000000..9cce18c281994db51c59bf83f7a65df4c97f02b2
--- /dev/null
+++ b/XRootdSSiRmcd/rbtsubr_constants.h
@@ -0,0 +1,39 @@
+/******************************************************************************
+ *
+ * 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
+
+			/* rbtsubr return codes */
+
+#define	RBT_OK		0	/* Ok or error should be ignored */
+#define	RBT_NORETRY	1	/* Unrecoverable error (just log it) */
+#define	RBT_SLOW_RETRY	2	/* Should release drive & retry in 600 seconds */
+#define	RBT_FAST_RETRY	3	/* Should retry in 60 seconds */
+#define	RBT_DMNT_FORCE	4	/* Should do first a demount force */
+#define	RBT_CONF_DRV_DN	5	/* Should configure the drive down */
+#define	RBT_OMSG_NORTRY	6	/* Should send a msg to operator and exit */
+#define	RBT_OMSG_SLOW_R 7	/* Ops msg (nowait) + release drive + slow retry */
+#define	RBT_OMSGR	8	/* Should send a msg to operator and wait */
+#define	RBT_UNLD_DMNT	9	/* Should unload the tape and retry demount */
+ 
diff --git a/XRootdSSiRmcd/rmc_constants.h b/XRootdSSiRmcd/rmc_constants.h
new file mode 100644
index 0000000000000000000000000000000000000000..684b45dddaf2ecb599dcf8216add6fb85a43d9c1
--- /dev/null
+++ b/XRootdSSiRmcd/rmc_constants.h
@@ -0,0 +1,66 @@
+/*
+ * $Id: rmc_constants.h,v 1.1 2002/12/01 07:31:57 baud Exp $
+ */
+
+/*
+ * Copyright (C) 2001 by CERN/IT/PDP/DM
+ * All rights reserved
+ */
+
+/*
+ */
+
+#pragma once
+#include "Castor_limits.h"
+
+#define RMC_CHECKI  5   /* max interval to check for work to be done */
+#define RMC_PRTBUFSZ 180
+#define RMC_REPBUFSZ 524288 /* must be >= max media changer server reply size */
+#define RMC_REQBUFSZ 256    /* must be >= max media changer server request size */
+#define RMC_MAGIC	0x120D0301
+#define RMC_TIMEOUT	5	/* netread timeout while receiving a request */
+#define	RMC_RETRYI	60
+#define	RMC_LOGBUFSZ 1024
+
+#define RMC_PORT 5014
+
+#define RMC_MAXRQSTATTEMPTS 10 /* Maximum number of attempts a retriable RMC request should be issued */
+
+			/* SCSI media changer utilities exit codes */
+
+#define	USERR	  1	/* user error */
+#define	SYERR 	  2	/* system error */
+#define	CONFERR	  4	/* configuration error */
+
+			/* Request types */
+
+#define	RMC_GETGEOM        1 /* Get robot geometry */
+#define	RMC_FINDCART       2 /* Find cartridge(s) */
+#define RMC_READELEM       3 /* Read element status */
+#define	RMC_MOUNT          4 /* Mount request */
+#define	RMC_UNMOUNT        5 /* Unmount request */
+#define	RMC_EXPORT         6 /* Export tape request */
+#define	RMC_IMPORT         7 /* Import tape request */
+#define	RMC_GENERICMOUNT   8 /* Generic (SCSI or ACS) mount request */
+#define	RMC_GENERICUNMOUNT 9 /* Generic (SCSI or ACS) mount request */
+
+			/* SCSI media changer server reply types */
+
+#define	MSG_ERR		1
+#define	MSG_DATA	2
+#define	RMC_RC		3
+
+                        /* SCSI media changer server messages */
+
+#define	RMC00	"RMC00 - SCSI media changer server not available on %s\n"
+#define	RMC01	"RMC01 - robot parameter is mandatory\n"
+#define	RMC02	"RMC02 - %s error : %s\n"
+#define	RMC03	"RMC03 - illegal function %d\n"
+#define	RMC04	"RMC04 - error getting request, netread = %d\n"
+#define	RMC05	"RMC05 - cannot allocate enough memory\n"
+#define	RMC06	"RMC06 - invalid value for %s\n"
+#define	RMC09	"RMC09 - fatal configuration error: %s %s\n"
+#define	RMC46	"RMC46 - request too large (max. %d)\n"
+#define	RMC92	"RMC92 - %s request by %d,%d from %s\n"
+#define	RMC98	"RMC98 - %s\n"
+
diff --git a/XRootdSSiRmcd/rmc_send_scsi_cmd.cpp b/XRootdSSiRmcd/rmc_send_scsi_cmd.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1003b3f438f8486a1c1c78bc1c5a446619def5e1
--- /dev/null
+++ b/XRootdSSiRmcd/rmc_send_scsi_cmd.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 1996-2000 by CERN/IT/PDP/DM
+ * All rights reserved
+ */
+
+/*	rmc_send_scsi_cmd - Send a SCSI command to a device */
+/*	return	-5	if not supported on this platform (serrno = SEOPNOTSUP)
+ *		-4	if SCSI error (serrno = EIO)
+ *		-3	if CAM error (serrno = EIO)
+ *		-2	if ioctl fails with errno (serrno = errno)
+ *		-1	if open/stat fails with errno (message fully formatted)
+ *		 0	if successful with no data transfer
+ *		>0	number of bytes transferred
+ */
+
+#include <iostream>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <linux/version.h>
+#include <sys/param.h>
+/* Impossible unless very very old kernels: */
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+#include "/usr/include/scsi/sg.h"
+#include <sys/stat.h>
+#include "scsictl.h"
+#include "serrno.h"
+#include "rmc_send_scsi_cmd.h"
+static char rmc_err_msgbuf[132];
+static const char *sk_msg[] = {
+        "No sense",
+        "Recovered error",
+        "Not ready",
+        "Medium error",
+        "Hardware error",
+        "Illegal request",
+        "Unit attention",
+        "Data protect",
+        "Blank check",
+        "Vendor unique",
+        "Copy aborted",
+        "Aborted command",
+        "Equal",
+        "Volume overflow",
+        "Miscompare",
+        "Reserved",
+};
+
+static void find_sgpath(char *const sgpath, const int maj, const int min) {
+        
+        /*
+          Find the sg device for a pair of major and minor device IDs
+          of a tape device. The match is done by
+          
+          . identifying the tape's st device node
+          . getting the device's unique ID from sysfs
+          . searching the sg device with the same ID (in sysfs)
+          
+          If no match is found, the returned sg path will be an empty
+          string.
+        */
+
+        char systape[] = "/sys/class/scsi_tape";
+        char sysgen[]  = "/sys/class/scsi_generic";
+        char syspath[256];
+
+        char tlink[256];
+        char glink[256];
+
+        int match = 0;        
+        DIR *dir_tape, *dir_gen;
+        struct dirent *dirent;
+        char st_dev[64];
+
+        struct stat sbuf;
+
+        sgpath[0] = '\0';
+
+        /* find the st sysfs entry */
+        if (!(dir_tape = opendir(systape))) return;  
+        while ((dirent = readdir(dir_tape))) {
+                
+                if (0 == strcmp(".", dirent->d_name)) continue;
+                if (0 == strcmp("..", dirent->d_name)) continue;
+
+                sprintf(st_dev, "/dev/%s", dirent->d_name);                
+                stat(st_dev, &sbuf);
+                if (maj == (int)major(sbuf.st_rdev) && min == (int)minor(sbuf.st_rdev)) {
+                        sprintf(syspath, "%s/%s/device", systape, dirent->d_name);
+                        match = 1;
+                        break;
+                }
+        }
+        closedir(dir_tape);
+
+        if (0 == match) return;
+
+        memset(tlink, 0, 256);
+        readlink(syspath, tlink, 256);
+
+        /* find the corresponding sg sysfs entry */
+        if (!(dir_gen = opendir(sysgen))) return;
+        while ((dirent = readdir(dir_gen))) {
+                
+                if (0 == strcmp(".", dirent->d_name)) continue;
+                if (0 == strcmp("..", dirent->d_name)) continue;
+
+                sprintf(syspath, "%s/%s/device", sysgen, dirent->d_name);
+                
+                memset(glink, 0, 256);
+                readlink(syspath, glink, 256);
+                
+                if (0 == strcmp(glink, tlink)) {
+                        sprintf(sgpath, "/dev/%s", dirent->d_name);
+                        goto out;
+                }
+        }
+ out:
+        closedir(dir_gen);
+        return;
+}
+
+
+int rmc_send_scsi_cmd (
+	const int tapefd,
+	const char *const path,
+	const int do_not_open,
+	const unsigned char *const cdb,
+	const int cdblen,
+	unsigned char *const buffer,
+	const int buflen,
+	char *const sense,
+	const int senselen,
+	const int flags,
+	int *const nb_sense_ret,
+	const char **const msgaddr)
+{
+	/* The timeout used when sending SCSI commands through the sg driver is in */
+	/* milliseconds and should equal that used by the st driver which on the   */
+	/* 28/01/2014 is 900 seconds and therefore 900000 milliseconds             */
+	const int timeout = 900000; /* milliseconds */
+	int fd;
+	FILE *fopen();
+	int n;
+	int resid = 0;
+	struct stat sbuf;
+	struct stat sbufa;
+	static char *sg_buffer;
+	static int sg_bufsiz = 0;
+	struct sg_header *sg_hd;
+	char sgpath[80];
+	int timeout_in_jiffies = 0;
+	int sg_big_buff_val =  SG_BIG_BUFF;
+	int procfd, nbread;
+	char procbuf[80];
+
+        (void)senselen;
+	/* First the value in /proc of the max buffer size for the sg driver */
+	procfd = open("/proc/scsi/sg/def_reserved_size", O_RDONLY);
+	if (procfd >= 0) {
+	  memset(procbuf, 0, sizeof(procbuf));
+	  nbread = read(procfd, procbuf, sizeof(procbuf) - 1);
+	  if (nbread > 0) {
+	    long int tmp;
+	    char *endptr = NULL;
+	    tmp = strtol(procbuf, &endptr, 10);
+	    if (endptr == NULL || *endptr == '\n') {
+	      sg_big_buff_val = (int) tmp;
+	    }
+	  }
+	  close(procfd);
+	}
+
+	if ((int)sizeof(struct sg_header) + cdblen + buflen > sg_big_buff_val) {
+		sprintf (rmc_err_msgbuf, "blocksize too large (max %zd)\n",
+		    sg_big_buff_val - sizeof(struct sg_header) - cdblen);
+		*msgaddr = rmc_err_msgbuf;
+		serrno = EINVAL;
+		return (-1);
+	}
+	if ((int)sizeof(struct sg_header)+cdblen+buflen > sg_bufsiz) {
+		if (sg_bufsiz > 0) free (sg_buffer);
+		if ((sg_buffer = (char *)malloc (sizeof(struct sg_header)+cdblen+buflen)) == NULL) {
+			serrno = errno;
+			sprintf (rmc_err_msgbuf, "cannot get memory");
+			*msgaddr = rmc_err_msgbuf;
+			return (-1);
+		}
+		sg_bufsiz = sizeof(struct sg_header) + cdblen + buflen;
+	}
+	if (do_not_open) {
+		fd = tapefd;
+		strcpy (sgpath, path);
+	} else {
+		if (stat (path, &sbuf) < 0) {
+			serrno = errno;
+        		snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "%s : stat error : %s\n", path, strerror(errno));
+			rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0';
+        		*msgaddr = rmc_err_msgbuf;
+			return (-1);
+		}
+
+                /* get the major device ID of the sg devices ... */
+		if (stat ("/dev/sg0", &sbufa) < 0) {
+			serrno = errno;
+			snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "/dev/sg0 : stat error : %s\n", strerror(errno));
+			rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0';
+			*msgaddr = rmc_err_msgbuf;
+			return (-1);
+		}
+                /* ... to detect links and use the path directly! */
+		if (major(sbuf.st_rdev) == major(sbufa.st_rdev)) {
+			strcpy (sgpath, path);
+		} else {
+                        find_sgpath(sgpath, major(sbuf.st_rdev), minor(sbuf.st_rdev));  
+		}
+
+		if ((fd = open (sgpath, O_RDWR)) < 0) {
+			serrno = errno;
+			snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "%s : open error : %s\n", sgpath, strerror(errno));
+			rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0';
+			*msgaddr = rmc_err_msgbuf;
+			return (-1);
+		}
+	}
+
+        /* set the sg timeout (in jiffies) */
+        timeout_in_jiffies = timeout * HZ / 1000;
+        ioctl (fd, SG_SET_TIMEOUT, &timeout_in_jiffies);
+
+	memset (sg_buffer, 0, sizeof(struct sg_header));
+	sg_hd = (struct sg_header *) sg_buffer;
+	sg_hd->reply_len = sizeof(struct sg_header) + ((flags & SCSI_IN) ? buflen : 0);
+	sg_hd->twelve_byte = cdblen == 12;
+	memcpy (sg_buffer+sizeof(struct sg_header), cdb, cdblen);
+	n = sizeof(struct sg_header) + cdblen;
+	if (buflen && (flags & SCSI_OUT)) {
+		memcpy (sg_buffer+n, buffer, buflen);
+		n+= buflen;
+	}
+	if (write (fd, sg_buffer, n) < 0) {
+		*msgaddr = (char *) strerror(errno);
+		serrno = errno;
+		snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "%s : write error : %s\n", sgpath, *msgaddr);
+		rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0';
+		*msgaddr = rmc_err_msgbuf;
+		if (! do_not_open) close (fd);
+		return (-2);
+	}
+	if ((n = read (fd, sg_buffer, sizeof(struct sg_header) +
+	    ((flags & SCSI_IN) ? buflen : 0))) < 0) {
+		*msgaddr = (char *) strerror(errno);
+		serrno = errno;
+		snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "%s : read error : %s\n", sgpath, *msgaddr);
+		rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0';
+		*msgaddr = rmc_err_msgbuf;
+		if (! do_not_open) close (fd);
+		return (-2);
+	}
+	if (! do_not_open) close (fd);
+	if (sg_hd->sense_buffer[0]) {
+		memcpy (sense, sg_hd->sense_buffer, sizeof(sg_hd->sense_buffer));
+		*nb_sense_ret = sizeof(sg_hd->sense_buffer);
+	}
+	if (sg_hd->sense_buffer[0] & 0x80) {	/* valid */
+		resid = sg_hd->sense_buffer[3] << 24 | sg_hd->sense_buffer[4] << 16 |
+		    sg_hd->sense_buffer[5] << 8 | sg_hd->sense_buffer[6];
+	}
+	if ((sg_hd->sense_buffer[0] & 0x70) &&
+	    ((sg_hd->sense_buffer[2] & 0xE0) == 0 ||
+	    (sg_hd->sense_buffer[2] & 0xF) != 0)) {
+		char tmp_msgbuf[132];
+		snprintf (tmp_msgbuf, sizeof(tmp_msgbuf), "%s ASC=%X ASCQ=%X",
+		    sk_msg[*(sense+2) & 0xF], *(sense+12), *(sense+13));
+		tmp_msgbuf[sizeof(tmp_msgbuf) - 1] = '\0';
+		serrno = EIO;
+		snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "%s : scsi error : %s\n", sgpath, tmp_msgbuf);
+		rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0';
+		*msgaddr = rmc_err_msgbuf;
+		return (-4);
+	} else if (sg_hd->result) {
+		*msgaddr = (char *) strerror(sg_hd->result);
+		serrno = sg_hd->result;
+		snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "%s : read error : %s\n", sgpath, *msgaddr);
+		rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0';
+		*msgaddr = rmc_err_msgbuf;
+		return (-2);
+	}
+	if (n)
+		n -= sizeof(struct sg_header) + resid;
+	if (n && (flags & SCSI_IN))
+		memcpy (buffer, sg_buffer+sizeof(struct sg_header), n);
+	return ((flags & SCSI_IN) ? n : buflen - resid);
+}
diff --git a/XRootdSSiRmcd/rmc_send_scsi_cmd.h b/XRootdSSiRmcd/rmc_send_scsi_cmd.h
new file mode 100644
index 0000000000000000000000000000000000000000..0ea32e0692f6d8857446d6bf5f1b763ca8ac568d
--- /dev/null
+++ b/XRootdSSiRmcd/rmc_send_scsi_cmd.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ * 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
+
+  int rmc_send_scsi_cmd (
+  const int tapefd,
+  const char *const path,
+  const int do_not_open,
+  const unsigned char *const cdb,
+  const int cdblen,
+  unsigned char *const buffer,
+  const int buflen,
+  char *const sense,
+  const int senselen,
+  const int flags,
+  int *const nb_sense_ret,
+  const char **const msgaddr);
+
diff --git a/XRootdSSiRmcd/rmc_sendrep.h b/XRootdSSiRmcd/rmc_sendrep.h
new file mode 100644
index 0000000000000000000000000000000000000000..04af53cf91044dfa0ec2519c150fc5cf5a7e04a1
--- /dev/null
+++ b/XRootdSSiRmcd/rmc_sendrep.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 1998-2002 by CERN/IT/PDP/DM
+ * All rights reserved
+ */
+
+#pragma once
+
+//#include "osdep.h"
+
+//EXTERN_C int rmc_sendrep(const int rpfd, const int rep_type, ...);
+int rmc_sendrep(const int rpfd, const int rep_type, ...);
+
diff --git a/XRootdSSiRmcd/rmc_smcsubr.cpp b/XRootdSSiRmcd/rmc_smcsubr.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..512e44585bce2a870ef724ffe64e7418ca460c8e
--- /dev/null
+++ b/XRootdSSiRmcd/rmc_smcsubr.cpp
@@ -0,0 +1,848 @@
+/*
+ * Copyright (C) 1998-2003 by CERN/IT/PDP/DM
+ * All rights reserved
+ */
+ 
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+#include <algorithm>
+
+#include <iostream>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "rbtsubr_constants.h"
+#include "rmc_constants.h"
+#include "rmc_send_scsi_cmd.h"
+#include "rmc_smcsubr.h"
+#include "rmc_smcsubr2.h"
+#include "scsictl.h"
+#include "serrno.h"
+#include "smc_constants.h"
+
+#define	RBT_XTRA_PROC 10
+
+
+int rmc_logit(const char *const func, const char *const msg, ...)
+{
+   return 0;
+}
+
+char *getconfent_fromfile(const char *filename,
+                          const char *category,
+                          const char *name,
+                          int flags)
+{
+   throw std::runtime_error("Not impemented");
+}
+
+static struct smc_status smc_status;
+static const char *smc_msgaddr;
+
+static void save_error(
+	const int rc,
+	const int nb_sense,
+	const char *const sense,
+	const char *const msgaddr)
+{
+	smc_msgaddr = msgaddr;
+	smc_status.rc = rc;
+	smc_status.skvalid = 0;
+	smc_status.save_errno = serrno;
+	if (rc == -4 && nb_sense >= 14) {
+		smc_status.asc = sense[12];
+		smc_status.ascq = sense[13];
+		smc_status.sensekey = sense[2] &0xF;
+		smc_status.skvalid = 1;
+	} else {
+		smc_status.asc = 0;
+		smc_status.ascq = 0;
+		smc_status.sensekey = 0;
+	}
+}
+
+static int vmatch (const char *const pattern, const char *const vid)
+{
+	const char *p;
+	const char *v;
+
+	for (p = pattern, v = vid; *p; p++, v++) {
+		if (*v == 0 && *p != '*')
+			return (1);
+		switch (*p) {
+		case '?':	/* match any single character */
+			continue;
+		case '*':
+			if (*(++p) == 0)
+				return (0); /* trailing * matches the rest */
+			while (vmatch (p, v)) {
+				if (*(++v) == 0)
+					return (1);
+			}
+			return (0);
+		default:
+			if (*p != *v)
+				return (1);
+		}
+	}
+	return (*v != 0);
+}
+
+static int get_element_size(
+	const int fd,
+	const char *const rbtdev,
+	const int type)
+{
+	unsigned char buf[128];
+	unsigned char cdb[12];
+	const char *msgaddr;
+	int nb_sense_ret;
+	int rc;
+	char sense[MAXSENSE];
+	int voltag = 0x10;
+        int pause_mode = 1;
+        int nretries = 0;
+
+ 	memset (cdb, 0, sizeof(cdb));
+ 	cdb[0] = 0xB8;		/* read element status */
+ 	cdb[1] = voltag + type; /* we request volume tag info and this type */
+ 	cdb[5] = 1;             /* we only need one element */
+ 	cdb[9] = 128;           /* limit for the report */
+
+        /* IBM library in pause mode  */ 
+        while (pause_mode && nretries <= 900) {
+ 	     rc = rmc_send_scsi_cmd (fd, rbtdev, 0, cdb, 12, buf, 128,
+ 		  sense, 38, SCSI_IN, &nb_sense_ret, &msgaddr);
+             if (rc < 0) {
+                if (rc == -4 && nb_sense_ret >= 14 && (sense[12] == 0x04)  && (sense[13] == -0X7B )) {
+                   sleep(60);
+                   pause_mode = 1;
+                } else  {
+                   pause_mode = 0; 
+                }
+             } else {
+                pause_mode = 0;
+             }
+             nretries++;
+        }
+
+ 	if (rc < 0) {
+ 		save_error (rc, nb_sense_ret, sense, msgaddr);
+ 		return (-1);
+ 	}
+	return (buf[10] * 256 + buf[11]);
+}
+
+static int get_element_info(
+	const char opcode,
+	const int fd,
+	const char *const rbtdev,
+	const int type,
+	const int start,
+	const int nbelem,
+	struct smc_element_info element_info[])
+{
+	int avail_elem;
+	unsigned char cdb[12];
+	unsigned char *data;
+	int edl;
+	int element_size;
+	char func[16];
+	int i;
+	int len;
+	const char *msgaddr;
+	int nb_sense_ret;
+	unsigned char *p;
+	unsigned char *page_end, *page_start;
+	unsigned char *q;
+	int rc;
+	char sense[MAXSENSE];
+        int pause_mode = 1;
+        int nretries = 0;
+	int nbReportBytesRemaining = 0;
+	int nbElementsInReport = 0;
+
+	strncpy (func, "get_elem_info", sizeof(func));
+	func[sizeof(func) - 1] = '\0';
+	if (type) {
+		element_size = get_element_size (fd, rbtdev, type);
+		if (element_size < 0) return (-1);
+	} else {
+		element_size = get_element_size (fd, rbtdev, 1); /* transport */
+		if (element_size < 0) return (-1);
+		i = get_element_size (fd, rbtdev, 2);	/* slot */
+		if (i < 0) return (-1);
+		if (i > element_size) element_size = i;
+		i = get_element_size (fd, rbtdev, 3);	/* port */
+		if (i < 0) return (-1);
+		if (i > element_size) element_size = i;
+		i = get_element_size (fd, rbtdev, 4);	/* device */
+		if (i < 0) return (-1);
+		if (i > element_size) element_size = i;
+	}
+	len = nbelem * element_size + 8;
+	if (type != 0 || nbelem == 1)
+		len += 8;	/* one element header */
+	else
+		len += 32;	/* possibly four element headers */
+	data = (unsigned char *)malloc (len);
+	memset (cdb, 0, sizeof(cdb));
+	cdb[0] = opcode;	/* read element status or request volume element address */
+	cdb[1] = 0x10 + type;
+	cdb[2] = start >> 8;
+	cdb[3] = start & 0xFF;
+	cdb[4] = nbelem >> 8;
+	cdb[5] = nbelem & 0xFF;
+	cdb[7] = len >> 16;
+	cdb[8] = (len >> 8) & 0xFF;
+	cdb[9] = len & 0xFF;
+
+        /* IBM library in pause mode  */ 
+        while (pause_mode && nretries <= 900) {
+	     rc = rmc_send_scsi_cmd (fd, rbtdev, 0, cdb, 12, data, len,
+		  sense, 38, SCSI_IN, &nb_sense_ret, &msgaddr);
+             if (rc < 0) {
+               if (rc == -4 && nb_sense_ret >= 14 && (sense[12] == 0x04)  && (sense[13] == -0X7B )) {
+                 sleep(60);
+                 pause_mode = 1;
+               } else  {
+                 pause_mode = 0;
+               }
+             } else {
+                pause_mode = 0;
+             }
+             nretries++;
+        }
+
+	if (rc < 0) {
+		save_error (rc, nb_sense_ret, sense, msgaddr);
+		free (data);
+		return (-1);
+	}
+	avail_elem = *(data+2) * 256 + *(data+3);
+	nbReportBytesRemaining = *(data+5) * 256 * 256 + *(data+6) * 256 + *(data+7);
+	i = 0;
+	p = data + 8;			/* point after data header */
+	while (i < avail_elem && 0 < nbReportBytesRemaining) {
+		nbReportBytesRemaining -= 8;
+		edl = *(p+2) * 256 + *(p+3);
+		page_start = p + 8;	/* point after page header */
+		page_end = page_start +
+			(((*(p+5) * 256 + *(p+6)) * 256) + *(p+7));
+		if (page_end > (data + len)) page_end = data + len;
+		for (p = page_start; p < page_end && i < avail_elem; p += edl, i++) {
+			nbElementsInReport++;
+			nbReportBytesRemaining -= edl;
+			element_info[i].element_address = *p * 256 + *(p+1);
+			element_info[i].element_type = *(page_start-8);
+			element_info[i].state = *(p+2);
+			element_info[i].asc = *(p+4);
+			element_info[i].ascq = *(p+5);
+			element_info[i].flags = *(p+9);
+			element_info[i].source_address = *(p+10) * 256 + *(p+11);
+			if ((*(page_start-7) & 0x80) == 0 ||
+			    (*(p+12) == '\0') || (*(p+12) == ' '))
+				element_info[i].name[0] = '\0';
+			else {
+				q = (unsigned char *) strchr ((char *)p+12, ' ');
+				if (q) {
+					strncpy (element_info[i].name, (char *)p+12, q-p-12);
+					element_info[i].name[q-p-12] = '\0';
+				} else
+					strcpy (element_info[i].name, (char *)p+12);
+				if (strlen (element_info[i].name) > CA_MAXVIDLEN)
+					element_info[i].name[CA_MAXVIDLEN] = '\0';
+			}
+		}
+	}
+	free (data);
+	return (nbElementsInReport);
+}
+
+int smc_get_geometry(
+	const int fd,
+	const char *const rbtdev,
+        struct robot_info *const robot_info)
+{
+	unsigned char buf[36];
+	unsigned char cdb[6];
+	char func[16];
+	const char *msgaddr;
+	int nb_sense_ret;
+	int rc;
+	char sense[MAXSENSE];
+        int pause_mode = 1;        
+        int nretries = 0;     
+
+
+	strncpy(func, "get_geometry", sizeof(func));
+	func[sizeof(func) - 1] = '\0';
+
+	memset (cdb, 0, sizeof(cdb));
+	cdb[0] = 0x12;		/* inquiry */
+	cdb[4] = 36;
+
+        /* IBM library in pause mode  */ 
+        while (pause_mode && nretries <= 900) { 
+	    rc = rmc_send_scsi_cmd (fd, rbtdev, 0, cdb, 6, buf, 36,
+		sense, 38, SCSI_IN, &nb_sense_ret, &msgaddr);
+            if (rc < 0) {
+              if (rc == -4 && nb_sense_ret >= 14 && (sense[12] == 0x04)  && (sense[13] == -0X7B )) {
+                 sleep(60);
+                 pause_mode = 1;
+              } else  {
+                 pause_mode = 0;
+              }
+            } else {
+                 pause_mode = 0;
+            }
+            nretries++;
+        }
+
+	if (rc < 0) {
+		save_error (rc, nb_sense_ret, sense, msgaddr);
+		return (-1);
+	}
+	memcpy (robot_info->inquiry, buf+8, 28);
+	robot_info->inquiry[28] = '\0';
+	memset (cdb, 0, sizeof(cdb));
+	cdb[0] = 0x1A;		/* mode sense */
+        cdb[1] = 0x08;          /* DBD bit - Disable block descriptors */
+	cdb[2] = 0x1D;		/* element address assignment page */
+	cdb[4] = 24;
+        pause_mode = 1;
+        nretries = 0;
+
+        /* IBM library in pause mode  */ 
+        while (pause_mode && nretries<=900) { 
+	     rc = rmc_send_scsi_cmd (fd, rbtdev, 0, cdb, 6, buf, 24,
+		 sense, 38, SCSI_IN, &nb_sense_ret, &msgaddr);
+             if (rc < 0) {
+               if (rc == -4 && nb_sense_ret >= 14 && (sense[12] == 0x04)  && (sense[13] == -0X7B )) {
+                 sleep(60);
+                 pause_mode = 1;
+               } else  {
+                 pause_mode = 0;
+               }
+             } else {
+                 pause_mode = 0;
+             }
+             nretries++;
+        }
+
+	if (rc < 0) {
+		save_error (rc, nb_sense_ret, sense, msgaddr);
+		return (-1);
+	}
+	robot_info->transport_start = buf[6] * 256 + buf[7];
+	robot_info->transport_count = buf[8] * 256 + buf[9];
+	robot_info->slot_start = buf[10] * 256 + buf[11];
+	robot_info->slot_count = buf[12] * 256 + buf[13];
+	robot_info->port_start = buf[14] * 256 + buf[15];
+	robot_info->port_count = buf[16] * 256 + buf[17];
+	robot_info->device_start = buf[18] * 256 + buf[19];
+	robot_info->device_count = buf[20] * 256 + buf[21];
+
+	return (0);
+}
+
+int smc_read_elem_status(
+	const int fd,
+	const char *const rbtdev,
+	const int type,
+	const int start,
+	const int nbelem,
+	struct smc_element_info element_info[])
+{
+	char func[16];
+
+	strncpy(func, "read_elem_statu", sizeof(func));
+	func[sizeof(func) - 1] = '\0';
+
+	return get_element_info ('\xB8', fd, rbtdev, type, start, nbelem, element_info);
+}
+
+int smc_find_cartridgeWithoutSendVolumeTag (
+	const int fd,
+	const char *const rbtdev,
+	const char *const find_template,
+	const int type,
+	const int start,
+	const int nbelem,
+	struct smc_element_info element_info[])
+{
+	static char err_msgbuf[132];
+	int nbFound = 0;
+	char func[16];
+	int i;
+	struct smc_element_info *inventory_info; 
+	char *msgaddr;
+	const int patternMatching = strchr (find_template, '*') || strchr (find_template, '?');
+	struct robot_info robot_info;
+	int tot_nbelem = 0;
+	int nbElementsInReport = 0;
+
+	strncpy(func, "findWithoutVT", sizeof(func));
+	func[sizeof(func) - 1] = '\0';
+
+	{
+		const int smc_get_geometry_rc = smc_get_geometry (fd, rbtdev, &robot_info);
+		if(smc_get_geometry_rc) {
+			return smc_get_geometry_rc;
+		}
+	}
+
+	tot_nbelem = robot_info.transport_count + robot_info.slot_count +
+		robot_info.port_count + robot_info.device_count;
+
+	if ((inventory_info = (struct smc_element_info *)malloc (tot_nbelem * sizeof(struct smc_element_info))) == NULL) {
+		serrno = errno;
+		sprintf (err_msgbuf, "malloc error: %s", strerror(errno));
+		msgaddr = err_msgbuf;
+		save_error (-1, 0, NULL, msgaddr);
+		return (-1);
+	}
+
+	nbElementsInReport = smc_read_elem_status (fd, rbtdev, type, start, tot_nbelem, inventory_info);
+	if(0 > nbElementsInReport) {
+		free (inventory_info);
+		return (nbElementsInReport);
+	}
+	for (i = 0 ; i < nbElementsInReport && nbFound < nbelem; i++) {
+		if (inventory_info[i].state & 0x1) {
+			if (patternMatching) {
+				if (vmatch (find_template, inventory_info[i].name) == 0) {
+					memcpy (&element_info[nbFound], &inventory_info[i],
+						sizeof(struct smc_element_info));
+					nbFound++;
+				}
+			} else {
+				if (strcmp (find_template, inventory_info[i].name) == 0) {
+					memcpy (element_info, &inventory_info[i],
+						sizeof(struct smc_element_info));
+					nbFound = 1;
+					break;
+				}
+			}
+		}
+	}
+	free (inventory_info);
+	return (nbFound);
+}
+
+
+int smc_find_cartridge(
+	const int fd,
+	const char *const rbtdev,
+	const char *const find_template,
+	const int type,
+	const int start,
+	const int nbelem,
+	struct smc_element_info element_info[],
+	const bool sendVolumeTag)
+{
+	unsigned char cdb[12];
+	char func[16];
+	const char *msgaddr;
+	int nb_sense_ret;
+	char plist[40];
+	int rc;
+	char sense[MAXSENSE];
+        int pause_mode = 1;
+        int nretries = 0;
+
+	strncpy(func, "findWithVT", sizeof(func));
+	func[sizeof(func) - 1] = '\0';
+        
+	if(!sendVolumeTag) {
+        	/* Skip the 0xB6 cdb command if the tape library is Spectra like */
+          	rc = smc_find_cartridgeWithoutSendVolumeTag (fd, rbtdev, find_template, type, start, nbelem,
+                                    element_info);
+          	if (rc >= 0)
+            		return (rc);
+          	return (-1);  
+        }
+
+	memset (cdb, 0, sizeof(cdb));
+	cdb[0] = 0xB6;		/* send volume tag */
+	cdb[1] = type;
+	cdb[2] = start >> 8;
+	cdb[3] = start & 0xFF;
+	cdb[5] = 5;
+	cdb[9] = 40;
+	memset (plist, 0, sizeof(plist));
+	strcpy (plist, find_template);
+   
+       /* IBM library in pause mode  */ 
+        while (pause_mode && nretries <= 900) {
+           
+           rc = rmc_send_scsi_cmd (fd, rbtdev, 0, cdb, 12, (unsigned char*)plist, 40,
+                           sense, 38, SCSI_OUT, &nb_sense_ret, &msgaddr);
+           if (rc < 0) {
+              if (rc == -4 && nb_sense_ret >= 14 && (sense[12] == 0x04)  && (sense[13] == -0X7B )) {
+                 sleep(60);
+                 pause_mode = 1;
+              } else  {
+                 pause_mode = 0; 
+              }
+           } else {
+              pause_mode = 0;
+           }
+           nretries++;
+        }
+
+	if (rc < 0) {
+           save_error (rc, nb_sense_ret, sense, msgaddr);
+	      if (rc == -4 && nb_sense_ret >= 14 && (sense[2] & 0xF) == 5) {
+	         rc = smc_find_cartridgeWithoutSendVolumeTag (fd, rbtdev, find_template, type,
+			    start, nbelem, element_info);
+			if (rc >= 0)
+				return (rc);
+		}
+		return (-1);
+	}
+	return get_element_info ('\xB5', fd, rbtdev, type, start, nbelem, element_info);
+}
+
+
+/* SCSI 3 additional sense code and additional sense qualifier */
+struct scsierr_codact {
+	unsigned char sensekey;
+	unsigned char asc;
+	unsigned char ascq;
+	short action;
+	const char *txt;
+};
+static struct scsierr_codact scsierr_acttbl[] = {
+    {0x02, 0x04, 0x00, RBT_FAST_RETRY, "Logical Unit Not Ready, Cause Not Reportable"},
+    {0x02, 0x04, 0x01, RBT_FAST_RETRY, "Logical Unit Is In Process of Becoming Ready"},
+    {0x02, 0x04, 0x02, RBT_NORETRY, "Logical Unit Not Ready, initialization required"},
+    {0x02, 0x04, 0x03, RBT_NORETRY, "Logical Unit Not Ready, Manual Intervention Required"},
+    {0x0B, 0x08, 0x00, RBT_NORETRY, "Logical Unit Communication Failure"},
+    {0x0B, 0x08, 0x01, RBT_NORETRY, "Logical Unit Communication Time-out"},
+    {0x05, 0x1A, 0x00, RBT_NORETRY, "Parameter List Length Error"},
+    {0x05, 0x20, 0x00, RBT_NORETRY, "Invalid Command Operation Code"},
+    {0x05, 0x21, 0x01, RBT_NORETRY, "Invalid Element Address"},
+    {0x05, 0x24, 0x00, RBT_NORETRY, "Invalid field in CDB"},
+    {0x05, 0x25, 0x00, RBT_NORETRY, "Logical Unit Not Supported"},
+    {0x05, 0x26, 0x00, RBT_NORETRY, "Invalid field in Parameter List"},
+    {0x05, 0x26, 0x01, RBT_NORETRY, "Parameter Not Supported"},
+    {0x05, 0x26, 0x02, RBT_NORETRY, "Parameter Value Invalid"},
+    {0x06, 0x28, 0x00, RBT_FAST_RETRY, "Not Ready to Ready Transition"},
+    {0x06, 0x28, 0x01, RBT_FAST_RETRY, "Import or Export Element Accessed"},
+    {0x06, 0x29, 0x00, RBT_FAST_RETRY, "Power On, Reset, or Bus Device Reset Occurred"},
+    {0x06, 0x2A, 0x01, RBT_FAST_RETRY, "Mode Parameters Changed"},
+    {0x05, 0x30, 0x00, RBT_NORETRY, "Incompatible Medium Installed"},
+    {0x00, 0x30, 0x03, RBT_FAST_RETRY, "Cleaning Cartridge Installed"},
+    {0x05, 0x39, 0x00, RBT_NORETRY, "Saving Parameters Not Supported"},
+    {0x05, 0x3A, 0x00, RBT_XTRA_PROC, "Medium Not Present"},
+    {0x05, 0x3B, 0x0D, RBT_XTRA_PROC, "Medium Destination Element Full"},
+    {0x05, 0x3B, 0x0E, RBT_XTRA_PROC, "Medium Source Element Empty"},
+    {0x04, 0x40, 0x01, RBT_NORETRY, "Hardware Error, General"},
+    {0x04, 0x40, 0x02, RBT_NORETRY, "Hardware Error, Tape Transport"},
+    {0x04, 0x40, 0x03, RBT_NORETRY, "Hardware Error, CAP"},
+    {0x0B, 0x43, 0x00, RBT_NORETRY, "Message Error"},
+    {0x02, 0x44, 0x00, RBT_NORETRY, "Internal Target Failure"},
+    {0x0B, 0x45, 0x00, RBT_NORETRY, "Select or Reselect Failure"},
+    {0x0B, 0x47, 0x00, RBT_NORETRY, "SCSI Parity Error"},
+    {0x0B, 0x48, 0x00, RBT_NORETRY, "Initiator Detected Error"},
+    {0x02, 0x4C, 0x00, RBT_NORETRY, "Logical Unit Failed Self-Configuration"},
+    {0x05, 0x4E, 0x00, RBT_NORETRY, "Overlapped Commands Attempted"},
+    {0x05, 0x53, 0x02, RBT_NORETRY, "Medium Removal Prevented"},
+    {0x06, 0x54, 0x00, RBT_NORETRY, "SCSI To Host System Interface Failure"},
+    {0x02, 0x5A, 0x01, RBT_NORETRY, "Operator Medium Removal Request"}
+};
+
+static const char* action_to_str(const short action) {
+	switch(action) {
+	case RBT_FAST_RETRY: return "RBT_FAST_RETRY";
+	case RBT_NORETRY   : return "RBT_NORETRY";
+	case RBT_XTRA_PROC : return "RBT_XTRA_PROC";
+	default            : return "UNKNOWN";
+	}
+}
+
+int smc_lasterror(
+	struct smc_status *const smc_stat,
+	const char **const msgaddr)
+{
+	unsigned int i;
+	char func[16];
+
+	strncpy (func, "lasterror", sizeof(func));
+	func[sizeof(func) - 1] = '\0';
+
+	rmc_logit(func, "Function entered:"
+		" asc=%d ascq=%d save_errno=%d rc=%d sensekey=%d skvalid=%d\n",
+		smc_status.asc, smc_status.ascq, smc_status.save_errno,
+		smc_status.rc, smc_status.sensekey, smc_status.skvalid);
+
+	smc_stat->rc = smc_status.rc;
+	smc_stat->skvalid = smc_status.skvalid;
+	*msgaddr = smc_msgaddr;
+	if ((smc_status.rc == -1 || smc_status.rc == -2) &&
+	    smc_status.save_errno == EBUSY)
+		return (EBUSY);
+	if (! smc_status.skvalid)
+		return (RBT_NORETRY);
+	smc_stat->sensekey = smc_status.sensekey;
+	smc_stat->asc = smc_status.asc;
+	smc_stat->ascq = smc_status.ascq;
+	for (i = 0; i < sizeof(scsierr_acttbl)/sizeof(struct scsierr_codact); i++) {
+		if (smc_status.asc == scsierr_acttbl[i].asc &&
+		    smc_status.ascq == scsierr_acttbl[i].ascq &&
+		    smc_status.sensekey == scsierr_acttbl[i].sensekey) {
+			const char *const action_str =
+				action_to_str(scsierr_acttbl[i].action);
+			*msgaddr = scsierr_acttbl[i].txt;
+
+			rmc_logit(func, "Entry found in scsierr_acttbl:"
+				" action_str=%s\n", action_str);
+
+			return (scsierr_acttbl[i].action);
+		}
+	}
+
+	rmc_logit(func, "No matching entry in scsierr_acttbl\n");
+
+	return (RBT_NORETRY);
+}
+
+int smc_move_medium(
+	const int fd,
+	const char *const rbtdev,
+	const int from,
+	const int to,
+	const int invert)
+{
+	unsigned char cdb[12];
+	char func[16];
+	const char *msgaddr;
+	int nb_sense_ret;
+	int rc;
+	char sense[MAXSENSE];
+        int pause_mode = 1;
+        int nretries = 0;         
+
+	strncpy(func, "move_medium", sizeof(func));
+	func[sizeof(func) - 1] = '\0';
+
+	memset (cdb, 0, sizeof(cdb));
+	cdb[0] = 0xA5;		/* move medium */
+	cdb[4] = from >> 8;
+	cdb[5] = from & 0xFF;
+	cdb[6] = to >> 8;
+	cdb[7] = to & 0xFF;
+	cdb[10] = invert;
+        
+        while (pause_mode) {
+	     rc = rmc_send_scsi_cmd (fd, rbtdev, 0, cdb, 12, NULL, 0,
+		sense, 38, SCSI_NONE, &nb_sense_ret, &msgaddr);
+            if (rc < 0) {
+              if (rc == -4 && nb_sense_ret >= 14 && (sense[12] == 0x04)  && (sense[13] == -0X7B )) {
+                 sleep(60);
+                 pause_mode = 1;
+              } else  {
+                 pause_mode = 0;
+              }
+            } else {
+                 pause_mode = 0;
+            }
+            nretries++;
+        }
+
+	if (rc < 0) {
+		save_error (rc, nb_sense_ret, sense, msgaddr);
+		return (-1);
+	}
+	return (0);
+}
+
+static int rmc_usrmsg(
+	const int rpfd,
+	const char *func,
+	const char *const msg,
+	...)
+{
+	va_list args;
+	char prtbuf[RMC_PRTBUFSZ];
+	const int save_errno = errno;
+
+	va_start (args, msg);
+	snprintf (prtbuf, sizeof(prtbuf), "%s: ", func);
+	prtbuf[sizeof(prtbuf) - 1] = '\0';
+	{
+		const size_t nbBytesUsed = strlen (prtbuf);
+
+		/* If there is still space in the print buffer */
+		if(nbBytesUsed < (sizeof(prtbuf))) {
+			const size_t nbBytesRemaining = sizeof(prtbuf) -
+				nbBytesUsed;
+			char *const p = prtbuf + nbBytesUsed;
+			vsnprintf (p, nbBytesRemaining, msg, args);
+			prtbuf[sizeof(prtbuf) - 1] = '\0';
+		}
+	}
+//	rmc_sendrep (rpfd, MSG_ERR, "%s", prtbuf);
+	va_end (args);
+	errno = save_errno;
+	return (0);
+}
+
+int smc_mount (
+	const int rpfd,
+	const int fd,
+	const char *const loader,
+	const struct robot_info *const robot_info,
+	const int drvord,
+	const char *const vid,
+	const int invert)
+{
+        int c;
+        const bool sendVolumeTag = true;
+        struct smc_element_info element_info;
+	char func[16];
+	const char *msgaddr;
+	struct smc_status smc_status;
+ 
+	strncpy (func, "smc_mount", sizeof(func));
+	func[sizeof(func) - 1] = '\0';
+
+	if ((c = smc_find_cartridge (fd, loader, vid, 0, 0, 1, &element_info, sendVolumeTag)) < 0) {
+		c = smc_lasterror (&smc_status, &msgaddr);
+		rmc_usrmsg ( rpfd, func, SR017, "find_cartridge", vid, msgaddr);
+		return (c);
+	}
+	if (c == 0) {
+		rmc_usrmsg ( rpfd, func, SR018, "mount", vid, drvord, "volume not in library");
+		return (RBT_NORETRY);
+	}
+	if (element_info.element_type != 2) {
+
+                /* compare requested and replied vid   */
+                rmc_usrmsg ( rpfd, func, "Asked for %s, got reply for %s\n", 
+                        vid, element_info.name );
+
+                /* detail on a tape's current location */
+                switch (element_info.element_type) {
+
+                case 1:
+                        rmc_usrmsg ( rpfd, func, "Location: medium transport element (0x%x)\n", 
+                                element_info.element_type );
+                        break;
+                case 2:                        
+                        /* normal case: in its home slot, not possible inside the if */
+                        break;
+                case 3:
+                        rmc_usrmsg ( rpfd, func, "Location: import/export element (0x%x)\n", 
+                                element_info.element_type );
+                        break;
+                case 4:
+                        rmc_usrmsg ( rpfd, func, "Location: data transfer element (0x%x)\n", 
+                                element_info.element_type );
+                        break;
+                default:
+                        rmc_usrmsg ( rpfd, func, "Location: unknown (0x%x)\n", 
+                                element_info.element_type );
+                }
+
+                rmc_usrmsg ( rpfd, func, SR018, "mount", vid, drvord, "volume in use");
+		return (RBT_SLOW_RETRY);
+	}
+	if ((c = smc_move_medium (fd, loader, element_info.element_address,
+	    robot_info->device_start+drvord, invert)) < 0) {
+		c = smc_lasterror (&smc_status, &msgaddr);
+		rmc_usrmsg ( rpfd, func, SR018, "mount", vid, drvord, msgaddr);
+		return (c);
+	}
+	return (0);
+}
+
+int smc_dismount (
+	const int rpfd,
+	const int fd,
+	const char *const loader,
+	struct robot_info *const robot_info,
+	const int drvord,
+	const char *const vid)
+{
+        const bool sendVolumeTag = true;
+	const unsigned int max_element_status_reads = 20;
+	const unsigned int dismount_status_read_delay = 1; // In seconds 
+	unsigned int nb_element_status_reads = 0;
+	int drive_not_unloaded = 1;
+	struct smc_element_info drive_element_info;
+	char func[16];
+	const char *msgaddr = 0;
+	struct smc_status smc_status;
+ 
+	strncpy (func, "smc_dismount", sizeof(func));
+	func[sizeof(func) - 1] = '\0';
+
+	memset(&smc_status, '\0', sizeof(smc_status));  
+
+	/* IBM libraries sometimes disagree with the eject of their drives. */
+	/* Sometimes the access bit of the result of Read Element Status    */
+	/* (XB8) indicates the gripper cannot access the tape even though   */
+	/* the eject was successful.  Reading the element status at a later */
+	/* point in time eventually indicates the tape is accessible.       */
+	while(drive_not_unloaded && nb_element_status_reads < max_element_status_reads) {
+		if (0 > smc_read_elem_status (fd, loader, 4, robot_info->device_start+drvord,
+		    	1, &drive_element_info)) {
+			const int smc_error = smc_lasterror (&smc_status, &msgaddr);
+			rmc_usrmsg ( rpfd, func, SR020, "read_elem_status", msgaddr);
+			return (smc_error);
+		}
+		if (0 == (drive_element_info.state & 0x1)) {
+			rmc_usrmsg ( rpfd, func, SR018, "demount", vid, drvord, "Medium Not Present");
+			return (RBT_OK);
+		}
+
+		drive_not_unloaded = (0 == (drive_element_info.state & 0x8));
+		if (drive_not_unloaded) {
+			rmc_usrmsg ( rpfd, func, "read_elem_status of %s on drive %d detected Drive Not Unloaded\n", vid, drvord);
+		}
+
+		nb_element_status_reads++;
+
+		if(nb_element_status_reads < max_element_status_reads) {
+			sleep(dismount_status_read_delay);
+		}
+	}
+	if(drive_not_unloaded) {
+		rmc_usrmsg ( rpfd, func, SR018, "demount", vid, drvord, "Drive Not Unloaded");
+		return (RBT_UNLD_DMNT);
+	}
+
+	if (*vid && strcmp (drive_element_info.name, vid)) {
+		rmc_usrmsg ( rpfd, func, SR009, vid, drive_element_info.name);
+		return (RBT_NORETRY);
+	}
+	if (0 > smc_move_medium (fd, loader, robot_info->device_start+drvord,
+	    drive_element_info.source_address, (drive_element_info.flags & 0x40) ? 1 : 0)) {
+		const int smc_error = smc_lasterror (&smc_status, &msgaddr);
+		rmc_usrmsg ( rpfd, func, SR018, "demount", vid, drvord, msgaddr);
+		return (smc_error);
+	}
+        // check that the vid is in a slot before returning 
+        while (1) {   
+          struct smc_element_info vol_element_info;
+          if (0 > smc_find_cartridge (fd, loader, drive_element_info.name, 0, 0, 1, &vol_element_info, sendVolumeTag )) {
+              const int smc_error = smc_lasterror (&smc_status, &msgaddr);
+              rmc_usrmsg ( rpfd, func, SR017, "find_cartridge", drive_element_info.name, msgaddr);
+              return (smc_error);
+          }
+         
+          // vid is in a storage slot 
+          if (vol_element_info.element_type == 2) break; 
+          // give time for the tape enter the slot 
+          sleep (2);
+    }
+
+	return (0);
+}
diff --git a/XRootdSSiRmcd/rmc_smcsubr.h b/XRootdSSiRmcd/rmc_smcsubr.h
new file mode 100644
index 0000000000000000000000000000000000000000..3e2bd2eec9e3e616779f812f9cc74329173946c7
--- /dev/null
+++ b/XRootdSSiRmcd/rmc_smcsubr.h
@@ -0,0 +1,70 @@
+/******************************************************************************
+ *
+ * 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 "smc_struct.h"
+
+int smc_get_geometry(
+  const int fd,
+  const char *const rbtdev,
+  struct robot_info *const robot_info);
+
+int smc_read_elem_status(
+  const int fd,
+  const char *const rbtdev,
+  const int type,
+  const int start,
+  const int nbelem,
+  struct smc_element_info element_info[]);
+
+int smc_find_cartridgeWithoutSendVolumeTag (
+  const int fd,
+  const char *const rbtdev,
+  const char *const find_template,
+  const int type,
+  const int start,
+  const int nbelem,
+  struct smc_element_info element_info[]);
+
+int smc_find_cartridge(
+  const int fd,
+  const char *const rbtdev,
+  const char *const find_template,
+  const int type,
+  const int start,
+  const int nbelem,
+  struct smc_element_info element_info[],
+  const bool sendVolumeTag);
+
+int smc_lasterror(
+  struct smc_status *const smc_stat,
+  const char **const msgaddr);
+
+int smc_move_medium(
+  const int fd,
+  const char *const rbtdev,
+  const int from,
+  const int to,
+  const int invert);
+
diff --git a/XRootdSSiRmcd/rmc_smcsubr2.h b/XRootdSSiRmcd/rmc_smcsubr2.h
new file mode 100644
index 0000000000000000000000000000000000000000..f67f4c9b440fe567b2b000bedd270a4da396aa41
--- /dev/null
+++ b/XRootdSSiRmcd/rmc_smcsubr2.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1998-2002 by CERN/IT/PDP/DM
+ * All rights reserved
+ */
+
+#pragma once
+
+#include "smc_struct.h"
+
+int smc_dismount (
+  const int rpfd,
+  const int fd,
+  const char *const loader,
+  struct robot_info *const robot_info,
+  const int drvord,
+  const char *const vid);
+
+int smc_export (
+  const int rpfd,
+  const int fd,
+  const char *const loader,
+  struct robot_info *const robot_info,
+  const char *const vid);
+
+int smc_import (
+  const int rpfd,
+  const int fd,
+  const char *const loader,
+  struct robot_info *const robot_info,
+  const char *const vid);
+
+int smc_mount (
+  const int rpfd,
+  const int fd,
+  const char *const loader,
+  const struct robot_info *const robot_info,
+  const int drvord,
+  const char *const vid,
+  const int invert);
+
diff --git a/XRootdSSiRmcd/scsictl.h b/XRootdSSiRmcd/scsictl.h
new file mode 100644
index 0000000000000000000000000000000000000000..e5e15e1e3741ca5ff58bfa9ca191cb6050738b2f
--- /dev/null
+++ b/XRootdSSiRmcd/scsictl.h
@@ -0,0 +1,77 @@
+/*
+ * $Id: scsictl.h,v 1.2 1999/12/09 13:46:22 jdurand Exp $
+ */
+
+/*
+ * Copyright (C) 1995-1996 by CERN/CN/SW/SC
+ * All rights reserved
+ */
+
+/*
+ * @(#)scsictl.h	1.1 12/10/96 CERN CN-SW/SC   Fabien Collin
+ */
+
+#pragma once
+
+#define MAXSENSE 255
+
+/* Values of the 'flags' field for function send_cmd */
+#define SCSI_IN            1
+#define SCSI_OUT           2
+#define SCSI_IN_OUT        4
+#define SCSI_NONE          8
+#define SCSI_SEL_WITH_ATN 16 
+#define SCSI_SYNC         32
+#define SCSI_WIDE         64
+
+/* SCSI status values */
+#define SCSI_STATUS_GOOD                       0x00
+#define SCSI_STATUS_CHECK_CONDITION            0x02
+#define SCSI_STATUS_CONDITION_MET_GOOD         0x04
+#define SCSI_STATUS_BUSY                       0x08
+#define SCSI_STATUS_INTERMEDIATE_GOOD          0x10
+#define SCSI_STATUS_INTERMEDIATE_CONDITION_MET 0x14
+#define SCSI_STATUS_RESERVATION_CONFLICT       0x18
+#define SCSI_STATUS_COMMAND_TERMINATED         0x22
+#define SCSI_STATUS_QUEUE_FULL                 0x28
+
+/* Generic SCSI driver status */
+#define CAM_OK       0 /* No error at the CAM level */
+#define CAM_TIMEOUT  1 /* Command timeout */
+#define CAM_ERROR    2 /* Error at the CAM level */
+#define CAM_NODEVICE 3 /* Device doesn't respond (inexistant device) */
+
+/* SCSI 3 Sense key */
+#define SCSI_SENSEKEY_NO_SENSE         0
+#define SCSI_SENSEKEY_RECOVERED_ERROR  1
+#define SCSI_SENSEKEY_NOT_READY        2
+#define SCSI_SENSEKEY_MEDIUM_ERROR     3
+#define SCSI_SENSEKEY_HARDWARE_ERROR   4
+#define SCSI_SENSEKEY_ILLEGAL_REQUEST  5
+#define SCSI_SENSEKEY_UNIT_ATTENTION   6
+#define SCSI_SENSEKEY_DATA_PROTECT     7
+#define SCSI_SENSEKEY_BLANK_CHECK      8
+#define SCSI_SENSEKEY_VENDOR_SPECIFIC  9
+#define SCSI_SENSEKEY_COPY_ABORTED    10
+#define SCSI_SENSEKEY_ABORTED_COMMAND 11
+#define SCSI_SENSEKEY_EQUAL           12
+#define SCSI_SENSEKEY_VOLUME_OVERFLOW 13
+#define SCSI_SENSEKEY_MISCOMPARE      14
+#define SCSI_SENSEKEY_RESERVED        15
+
+/* SCSI 3 Peripheric device types */
+#define SCSI_PERIPH_DIRECT_ACCESS     0
+#define SCSI_PERIPH_SEQUENTIAL_ACCESS 1
+#define SCSI_PERIPH_PRINTER           2
+#define SCSI_PERIPH_PROCESSOR         3
+#define SCSI_PERIPH_WORM              4
+#define SCSI_PERIPH_CDROM             5
+#define SCSI_PERIPH_SCANNER           6
+#define SCSI_PERIPH_OPTICAL           7
+#define SCSI_PERIPH_AUTOCHANGER       8
+#define SCSI_PERIPH_COMMUNICATION     9
+#define SCSI_PERIPH_ASC1             10
+#define SCSI_PERIPH_ASC2             11
+#define SCSI_PERIPH_RAID             12
+#define SCSI_PERIPH_UNKNOWN          31
+
diff --git a/XRootdSSiRmcd/serrno.cpp b/XRootdSSiRmcd/serrno.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7f4408cfba8c68e7b152fbc4a939974fa22988b7
--- /dev/null
+++ b/XRootdSSiRmcd/serrno.cpp
@@ -0,0 +1 @@
+int serrno = 0;
diff --git a/XRootdSSiRmcd/serrno.h b/XRootdSSiRmcd/serrno.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b0be7cdb077ed8fa8987b83ffa3bd2aca4a1be6
--- /dev/null
+++ b/XRootdSSiRmcd/serrno.h
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 1990-2002 by CERN/IT/PDP/DM
+ * All rights reserved
+ */
+
+/*
+ * serrno.h,v 1.65 2002/11/27 14:45:53
+ */
+
+/* serrno.h     Special error numbers - not in errno.h                  */
+
+#pragma once
+
+#include <sys/types.h>                  /* For size_t                   */
+#include <stddef.h>                     /* For size_t on _WIN32         */
+
+#define SEBASEOFF       1000            /* Base offset for special err. */
+#define EDBBASEOFF      1200            /* CDB error base offset        */
+#define EMSBASEOFF      1300            /* MSG error base offset        */
+#define ENSBASEOFF      1400            /* NS error base offset         */
+#define ERFBASEOFF      1500            /* RFIO error base offset       */
+#define ERTBASEOFF      1600            /* RTCOPY error base offset     */
+#define ESTBASEOFF      1700            /* STAGE error base offset      */
+#define ESQBASEOFF      1800            /* SYSREQ error base offset     */
+#define ETBASEOFF       1900            /* TAPE error base offset       */
+#define EVMBASEOFF      2000            /* VMGR error base offset       */
+#define EVQBASEOFF      2100            /* VDQM error base offset       */
+#define ERMBASEOFF      2200            /* RMC error base offset        */
+#define EMONBASEOFF     2300            /* Monitoring Error base offset */
+#define EUPBASEOFF      2400            /* UPV error base offset        */
+#define ESECBASEOFF     2700            /* Security error base offset   */
+#define EDNSBASEOFF     3000            /* DNS error base offset        */
+
+#define SENOERR         SEBASEOFF       /* No error                     */
+#define SENOSHOST       SEBASEOFF+1     /* Host not known               */
+#define SENOSSERV       SEBASEOFF+2     /* Service unknown              */
+#define SENOTRFILE      SEBASEOFF+3     /* Not a remote file            */
+#define SETIMEDOUT      SEBASEOFF+4     /* Has timed out                */
+#define SEBADFFORM      SEBASEOFF+5     /* Bad fortran format specifier */
+#define SEBADFOPT       SEBASEOFF+6     /* Bad fortran option specifier */
+#define SEINCFOPT       SEBASEOFF+7     /* Incompatible fortran options */
+#define SENAMETOOLONG   SEBASEOFF+8     /* File name too long           */
+#define SENOCONFIG      SEBASEOFF+9     /* Can't open configuration file*/
+#define SEBADVERSION    SEBASEOFF+10    /* Version ID mismatch          */
+#define SEUBUF2SMALL    SEBASEOFF+11    /* User buffer too small        */
+#define SEMSGINVRNO     SEBASEOFF+12    /* Invalid reply number         */
+#define SEUMSG2LONG     SEBASEOFF+13    /* User message too long        */
+#define SEENTRYNFND     SEBASEOFF+14    /* Entry not found              */
+#define SEINTERNAL      SEBASEOFF+15    /* Internal error               */
+#define SECONNDROP      SEBASEOFF+16    /* Connection closed by rem. end*/
+#define SEBADIFNAM      SEBASEOFF+17    /* Can't get interface name     */
+#define SECOMERR        SEBASEOFF+18    /* Communication error          */
+#define SENOMAPDB       SEBASEOFF+19    /* Can't open mapping database  */
+#define SENOMAPFND      SEBASEOFF+20    /* No user mapping              */
+#define SERTYEXHAUST    SEBASEOFF+21    /* Retry count exhausted        */
+#define SEOPNOTSUP      SEBASEOFF+22    /* Operation not supported      */
+#define SEWOULDBLOCK    SEBASEOFF+23    /* Resource temporarily unavailable */
+#define SEINPROGRESS    SEBASEOFF+24    /* Operation now in progress    */
+#define SECTHREADINIT   SEBASEOFF+25    /* Cthread initialization error */
+#define SECTHREADERR    SEBASEOFF+26    /* Thread interface call error  */
+#define SESYSERR        SEBASEOFF+27    /* System error                 */
+#define SENOTADMIN      SEBASEOFF+32    /* requestor is not administrator */
+#define SEUSERUNKN      SEBASEOFF+33    /* User unknown                 */
+#define SEDUPKEY        SEBASEOFF+34    /* Duplicate key value          */
+#define SEENTRYEXISTS   SEBASEOFF+35    /* Entry already exists         */
+#define SEGROUPUNKN     SEBASEOFF+36    /* Group Unknown                */
+#define SECHECKSUM      SEBASEOFF+37    /* Bad checksum                 */
+#define SESVCCLASSNFND  SEBASEOFF+38    /* This service class is not available for this host */
+#define SESQLERR        SEBASEOFF+39    /* Got SQL exception from database */
+#define SELOOP          SEBASEOFF+40    /* Too many symbolic links      */
+#define SENOPORTINRANGE SEBASEOFF+41    /* No port in range             */
+#define SENOVALUE       SEBASEOFF+42    /* No value                     */
+#define SEINVALIDCONFIG SEBASEOFF+43    /* Invalid configuration        */
+#define SEPYTHONEXEC    SEBASEOFF+44    /* Failed to execute Python     */
+#define SEMISSINGOPER   SEBASEOFF+45    /* Missing operand              */
+#define SEMISMATCH      SEBASEOFF+46    /* Mismatch                     */
+#define SEREQUESTFAILED SEBASEOFF+47    /* Request failed               */
+#define SEINVALIDNBARGS SEBASEOFF+48    /* Invalid number of arguments  */
+#define SEALREADYINIT   SEBASEOFF+49    /* Already initialized          */
+#define SECMDLNNOTPRSD  SEBASEOFF+50    /* Command line not parsed      */
+#define SEACCPTCONNINTR SEBASEOFF+51    /* Accept connection was interrupted */
+#define SEBADALLOC      SEBASEOFF+52    /* Failed to allocate memory    */
+#define SENOTANOWNER    SEBASEOFF+53    /* Not an owner                 */
+
+#define SEMAXERR        SEBASEOFF+53    /* Maximum error number         */
+
+#define SERRNO  (serrno - SEBASEOFF)    /* User convenience             */
+/*
+ * Backward compatibility
+ */
+#define SEFNAM2LONG     SENAMETOOLONG
+
+/*
+ * Package specific error messages (don't forget to update commmon/serror.c)
+ */
+
+/*
+ *------------------------------------------------------------------------
+ * DB errors
+ *------------------------------------------------------------------------
+ */
+#define EDB_A_ESESSION EDBBASEOFF+1    /* Cdb api           : invalid session    */
+#define EDB_A_EDB      EDBBASEOFF+2    /* Cdb api           : invalid db         */
+#define EDB_A_EINVAL   EDBBASEOFF+3    /* Cdb api           : invalid value      */
+#define EDB_A_RESHOST  EDBBASEOFF+4    /* Cdb api           : host res error     */
+#define EDB_A_TOOMUCH  EDBBASEOFF+5    /* Cdb api           : data size rejected */
+#define EDB_AS_SOCKET  EDBBASEOFF+6    /* Cdb api    system : socket() error     */
+#define EDB_AS_SOCKOPT EDBBASEOFF+7    /* Cdb api    system : [set/get]sockopt() error */
+#define EDB_AS_MALLOC  EDBBASEOFF+8    /* Cdb api    system : malloc() error     */
+#define EDB_A_NOERROR  EDBBASEOFF+9    /* Cdb api           : no last error      */
+#define EDB_A_IEINVAL  EDBBASEOFF+10   /* Cdb api           : interface invalid value */
+#define EDB_AS_BIND    EDBBASEOFF+11   /* Cdb api           : bind() error       */
+#define EDB_AS_LISTEN  EDBBASEOFF+12   /* Cdb api           : listen() error     */
+#define EDB_AS_GETSOCKNAME EDBBASEOFF+13 /* Cdb api         : getsockname() error */
+#define EDB_AS_ACCEPT  EDBBASEOFF+14   /* Cdb api           : accept() error     */
+#define EDB_AS_GETPEERNAME  EDBBASEOFF+15 /* Cdb api        : getpeername() error */
+#define EDB_A_WHOISIT  EDBBASEOFF+16 /* Cdb api        : Connection from bad host */
+
+#define EDB_D_EINVAL   EDBBASEOFF+20   /* Cdb daemon        : invalid value      */
+#define EDB_D_EAGAIN   EDBBASEOFF+21   /* Cdb daemon        : yet done           */
+#define EDB_D_AUTH     EDBBASEOFF+22   /* Cdb daemon        : unauthorized       */
+#define EDB_D_LOGIN    EDBBASEOFF+23   /* Cdb daemon        : login refused      */
+#define EDB_D_PWDCORR  EDBBASEOFF+24   /* Cdb daemon        : pwd file corrupted */
+#define EDB_D_ANA      EDBBASEOFF+25   /* Cdb daemon        : db analysis error  */
+#define EDB_D_HASHSIZE EDBBASEOFF+26   /* Cdb daemon        : bad hash size      */
+#define EDB_D_UNKNOWN  EDBBASEOFF+27   /* Cdb daemon        : unkn. db/table/key */
+#define EDB_D_NOLOCK   EDBBASEOFF+28   /* Cdb daemon        : lock is required   */
+#define EDB_D_CORRUPT  EDBBASEOFF+29   /* Cdb daemon        : probably corrupted */
+#define EDB_D_TOOMUCH  EDBBASEOFF+30   /* Cdb daemon        : data size rejected */
+#define EDB_D_ENOENT   EDBBASEOFF+31   /* Cdb daemon        : no entry           */
+#define EDB_D_ETYPE    EDBBASEOFF+32   /* Cdb daemon        : unknown member type*/
+#define EDB_D_EVALUE   EDBBASEOFF+33   /* Cdb daemon        : unknown member val */
+#define EDB_D_NULLVALUE EDBBASEOFF+34  /* Cdb daemon        : null member value  */
+#define EDB_D_LOCK     EDBBASEOFF+35   /* Cdb daemon        : cannot gain lock   */
+#define EDB_D_FREE     EDBBASEOFF+36   /* Cdb daemon        : unsafe free attempt*/
+#define EDB_D_SHUTDOWN EDBBASEOFF+37   /* Cdb daemon        : shutdown in progress */
+#define EDB_D_DEADLOCK EDBBASEOFF+38   /* Cdb daemon        : deadlock detected  */
+#define EDB_D_EXIST    EDBBASEOFF+39   /* Cdb daemon        : yet exists         */
+#define EDB_D_NOSPC    EDBBASEOFF+40   /* Cdb daemon        : no more space      */
+#define EDB_D_DUMPEND  EDBBASEOFF+41   /* Cdb daemon        : end of dump        */
+#define EDB_D_UNIQUE   EDBBASEOFF+42   /* Cdb daemon        : uniqued key yet exist */
+#define EDB_D_LISTEND  EDBBASEOFF+43   /* Cdb daemon        : end of list        */
+#define EDB_D_NOTDUMP  EDBBASEOFF+44   /* Cdb daemon        : not in dump mode   */
+#define EDB_D_DNSCHECK EDBBASEOFF+45   /* Cdb daemon        : double DNS check error */
+#define EDB_D_REJECTED EDBBASEOFF+46   /* Cdb daemon        : Connection rejected (not authorised) */
+#define EDB_D_INIT     EDBBASEOFF+47   /* Cdb daemon        : init in progress */
+#define EDB_D_INCONST  EDBBASEOFF+48   /* Cdb daemon        : inconsistent request (unstop and no previous stop, unfreeze and no previous freeze) */
+#define EDB_D_FREEHASHSIZE EDBBASEOFF+49 /* Cdb daemon      : bad free hash size      */
+
+#define EDB_DS_MALLOC  EDBBASEOFF+50   /* Cdb daemon system : malloc() error     */
+#define EDB_DS_CALLOC  EDBBASEOFF+51   /* Cdb daemon system : calloc() error     */
+#define EDB_DS_REALLOC EDBBASEOFF+52   /* Cdb daemon system : realloc() error    */
+#define EDB_DS_OPEN    EDBBASEOFF+53   /* Cdb daemon system : open() error       */
+#define EDB_DS_FSTAT   EDBBASEOFF+54   /* Cdb daemon system : fstat() error      */
+#define EDB_DS_LSEEK   EDBBASEOFF+55   /* Cdb daemon system : lseek() error      */
+#define EDB_DS_READ    EDBBASEOFF+56   /* Cdb daemon system : read() error       */
+#define EDB_DS_WRITE   EDBBASEOFF+57   /* Cdb daemon system : write() error      */
+#define EDB_DS_RENAME  EDBBASEOFF+58   /* Cdb daemon system : rename() error     */
+#define EDB_DS_FTRUNC  EDBBASEOFF+59   /* Cdb daemon system : ftruncate() error  */
+#define EDB_DS_TMPNAM  EDBBASEOFF+60   /* Cdb daemon system : tmpnam() error     */
+#define EDB_DS_FCNTL   EDBBASEOFF+61   /* Cdb daemon system : fcntl() error      */
+#define EDB_DS_MKDIR   EDBBASEOFF+62   /* Cdb daemon system : mkdir() error      */
+#define EDB_DS_TIMES   EDBBASEOFF+63   /* Cdb daemon system : times() error      */
+#define EDB_DS_SYSCONF EDBBASEOFF+64   /* Cdb daemon system : sysconf() err/unav */
+#define EDB_DS_GETHOSTNAME EDBBASEOFF+65 /* Cdb daemon system : gethostname() error*/
+#define EDB_DS_GETPEERNAME EDBBASEOFF+66 /* Cdb daemon system : getpeername() error*/
+#define EDB_DS_INET_NTOA EDBBASEOFF+67 /* Cdb daemon system : getpeername() error*/
+#define EDB_DS_REMOVE  EDBBASEOFF+68   /* Cdb daemon system : remove() error */
+#define EDB_DS_SIGACTION  EDBBASEOFF+69   /* Cdb daemon system : sigaction() error */
+#define EDB_DS_GETSOCKNAME EDBBASEOFF+70 /* Cdb daemon system : getsockname() error*/
+#define EDB_DS_BIND    EDBBASEOFF+71 /* Cdb daemon system : bind() error*/
+#define EDB_DS_LISTEN    EDBBASEOFF+72 /* Cdb daemon system : listen() error*/
+#define EDB_DS_CONNECT   EDBBASEOFF+73 /* Cdb daemon system : connect() error*/
+#define EDB_DS_SOCKET   EDBBASEOFF+74 /* Cdb daemon system : socket() error*/
+#define EDB_DS_SOCKOPT  EDBBASEOFF+75 /* Cdb daemon system : [set/get]sockopt() error*/
+#define EDB_D_RESHOST   EDBBASEOFF+76 /* Cdb daemon     : host res error     */
+#define EDB_D_REQSIZE   EDBBASEOFF+77 /* Cdb daemon     : request too big    */
+
+#define EDB_C_EINVAL     EDBBASEOFF+80 /* Cdb config        : invalid value      */
+#define EDB_C_ENOENT     EDBBASEOFF+81  /* Cdb config        : configuration error*/
+#define EDB_C_TOOMUCH  EDBBASEOFF+82   /* Cdb config        : conf. size rejected */
+#define EDB_CS_GETHOSTNAME EDBBASEOFF+83 /* Cdb config system : gethostname() error*/
+
+#define EDB_NOMOREDB   EDBBASEOFF+90 /* Cdb : nomoredb */
+
+#define EDBMAXERR      EDBBASEOFF+90
+
+/*
+ *------------------------------------------------------------------------
+ * MSG daemon errors
+ *------------------------------------------------------------------------
+ */
+#define EMSMSGU2REP     EMSBASEOFF+1    /* msg daemon unable to reply   */
+#define EMSMSGSYERR     EMSBASEOFF+2    /* msg daemon system error      */
+#define EMSNOPERM       EMSBASEOFF+3    /* Permission denied            */
+#define EMSMAXERR       EMSBASEOFF+3    /* Maximum error number of MSG  */
+/*
+ * Backward compatibility
+ */
+#define SEMSGU2REP      EMSMSGU2REP
+#define SEMSGSYERR      EMSMSGSYERR
+#define SENOPERM        EMSNOPERM
+
+/*
+ *------------------------------------------------------------------------
+ * NS (Name Server) errors
+ *------------------------------------------------------------------------
+ */
+#define	ENSNACT        ENSBASEOFF+1	/* Name server not active */
+#define	ENSFILECHG     ENSBASEOFF+2	/* File has been overwritten, request ignored */
+#define ENSNOSEG       ENSBASEOFF+3	/* Segment had been deleted */
+#define ENSISLINK      ENSBASEOFF+4	/* Is a link */
+#define ENSCLASSNOSEGS ENSBASEOFF+5	/* File class does not allow a copy on tape */
+#define ENSTOOMANYSEGS ENSBASEOFF+6	/* Too many copies on tape */
+#define ENSOVERWHENREP ENSBASEOFF+7	/* Cannot overwrite valid segment when replacing */
+#define ENHOSTNOTSET   ENSBASEOFF+8	/* CNS HOST not set */
+#define ENSMAXERR      ENSBASEOFF+8
+
+/*
+ *------------------------------------------------------------------------
+ * RFIO errors
+ *------------------------------------------------------------------------
+ */
+#define ERFNORCODE      ERFBASEOFF+1    /* RFIO communication error     */
+#define ERFHOSTREFUSED  ERFBASEOFF+2    /* RFIO rejected connect attempt*/
+#define ERFXHOST        ERFBASEOFF+3    /* Cross-host link (rename())   */
+#define ERFPROTONOTSUP  ERFBASEOFF+4    /* RFIO protocol not supported  */
+#define ERFMAXERR       ERFBASEOFF+4    /* Maximum error number of RFIO */
+/*
+ * Backward compatibility
+ */
+#define SENORCODE       ERFNORCODE
+#define SEHOSTREFUSED   ERFHOSTREFUSED
+#define SEXHOST         ERFXHOST
+#define SEPROTONOTSUP   ERFPROTONOTSUP
+
+/*
+ *------------------------------------------------------------------------
+ * RTCOPY errors
+ *------------------------------------------------------------------------
+ */
+#define ERTTMSERR       ERTBASEOFF+1    /* TMS call failed */
+#define ERTBLKSKPD      ERTBASEOFF+2    /* Blocks were skipped in file  */
+#define ERTTPE_LSZ      ERTBASEOFF+3    /* Blocks skipped and file truncated */
+#define ERTMNYPARY      ERTBASEOFF+4    /* Too many skipped blocks      */
+#define ERTLIMBYSZ      ERTBASEOFF+5    /* File limited by size         */
+#define ERTUSINTR       ERTBASEOFF+6    /* Request interrupted by user  */
+#define ERTOPINTR       ERTBASEOFF+7    /* Request interrupted by operator */
+#define ERTNOTCLIST     ERTBASEOFF+8    /* Request list is not circular */
+#define ERTBADREQ       ERTBASEOFF+9    /* Bad request structure */
+#define ERTMORETODO	ERTBASEOFF+10	/* Request partially processed */
+#define ERTDBERR        ERTBASEOFF+11   /* Catalogue DB error */
+#define ERTZEROSIZE     ERTBASEOFF+12   /* Zero sized file */
+#define ERTWRONGSIZE    ERTBASEOFF+13   /* Recalled file size incorrect */
+#define ERTWRONGFSEQ    ERTBASEOFF+14   /* Inconsistent FSEQ in VMGR and Cns */
+#define ERTMAXERR       ERTBASEOFF+14
+
+/*
+ *------------------------------------------------------------------------
+ * STAGE errors
+ *------------------------------------------------------------------------
+ */
+#define ESTCLEARED      ESTBASEOFF+1	/* aborted */
+#define ESTENOUGHF      ESTBASEOFF+2	/* enough free space */
+#define ESTLNKNCR       ESTBASEOFF+3	/* symbolic link not created */
+#define ESTLNKNSUP      ESTBASEOFF+4	/* symbolic link not supported */
+#define ESTNACT         ESTBASEOFF+5	/* Stager not active */
+#define ESTGROUP        ESTBASEOFF+6	/* Your group is invalid */
+#define ESTGRPUSER      ESTBASEOFF+7	/* No GRPUSER in configuration */
+#define ESTUSER         ESTBASEOFF+8	/* Invalid user */
+#define ESTHSMHOST      ESTBASEOFF+9	/* HSM HOST not specified */
+#define ESTTMSCHECK     ESTBASEOFF+10	/* tmscheck error */
+#define ESTLINKNAME     ESTBASEOFF+11	/* User link name processing error */
+#define ESTWRITABLE     ESTBASEOFF+12	/* User path in a non-writable directory */
+#define ESTKILLED       ESTBASEOFF+13	/* aborted by kill */
+#define ESTMEM          ESTBASEOFF+14	/* request too long (api) */
+#define ESTCONF         ESTBASEOFF+15	/* Stage configuration error */
+#define ESTSEGNOACC     ESTBASEOFF+16	/* Unreadable file on tape (segments not all accessible) */
+#define ESTREPLFAILED   ESTBASEOFF+17	/* File replication failed */
+#define ESTNOTAVAIL     ESTBASEOFF+18	/* File is currently not available */
+#define ESTJOBKILLED    ESTBASEOFF+19   /* Job killed by service administrator */
+#define ESTJOBTIMEDOUT	ESTBASEOFF+20	/* Job timed out while waiting to be scheduled */
+#define ESTSCHEDERR     ESTBASEOFF+21   /* Scheduler error */
+#define ESTSVCCLASSNOFS ESTBASEOFF+22   /* No filesystems available in service class */
+#define ESTNOSEGFOUND   ESTBASEOFF+23   /* File has no copy on tape and no diskcopies are accessible */
+#define ESTTAPEOFFLINE  ESTBASEOFF+24   /* File is on an offline tape */
+#define ESTREQCANCELED  ESTBASEOFF+25   /* Request canceled while queuing */
+#define ESTTCNOTFOUND   ESTBASEOFF+26   /* Tape-copy not found */
+#define ESTNOTAPEROUTE  ESTBASEOFF+27   /* The file cannot be routed to tape */
+#define ESTMAXERR       ESTBASEOFF+27
+
+/*
+ *------------------------------------------------------------------------
+ * SYSREQ errors
+ *------------------------------------------------------------------------
+ */
+#define ESQTMSNOTACT    ESQBASEOFF+1    /* TMS not active                 */
+#define ESQMAXERR       ESQBASEOFF+1    /* Maximum error number of SYSREQ */
+/*
+ * Backward compatibility
+ */
+#define SETMSNOTACT     ESQTMSNOTACT
+
+/*
+ *------------------------------------------------------------------------
+ * TAPE errors
+ *------------------------------------------------------------------------
+ */
+#define ETDNP		ETBASEOFF+1	/* daemon not available */
+#define ETSYS		ETBASEOFF+2	/* system error */
+#define	ETPRM		ETBASEOFF+3	/* bad parameter */
+#define	ETRSV		ETBASEOFF+4	/* reserv already issued */
+#define	ETNDV		ETBASEOFF+5	/* too many drives requested */
+#define	ETIDG		ETBASEOFF+6	/* invalid device group name */
+#define	ETNRS		ETBASEOFF+7	/* reserv not done */
+#define	ETIDN		ETBASEOFF+8	/* no drive with requested characteristics */
+#define	ETLBL		ETBASEOFF+9	/* bad label structure */
+#define	ETFSQ		ETBASEOFF+10	/* bad file sequence number */
+#define	ETINTR		ETBASEOFF+11	/* interrupted by user */
+#define ETEOV		ETBASEOFF+12	/* EOV found in multivolume set */
+#define ETRLSP		ETBASEOFF+13	/* release pending */
+#define ETBLANK		ETBASEOFF+14	/* blank tape */
+#define ETCOMPA		ETBASEOFF+15	/* compatibility problem */
+#define ETHWERR		ETBASEOFF+16	/* device malfunction */
+#define ETPARIT		ETBASEOFF+17	/* parity error */
+#define ETUNREC		ETBASEOFF+18	/* unrecoverable media error */
+#define ETNOSNS		ETBASEOFF+19	/* no sense */
+#define	ETRSLT		ETBASEOFF+20	/* reselect server */
+#define	ETVBSY		ETBASEOFF+21	/* volume busy or inaccessible */
+#define	ETDCA		ETBASEOFF+22	/* drive currently assigned */
+#define	ETNRDY		ETBASEOFF+23	/* drive not ready */
+#define	ETABSENT	ETBASEOFF+24	/* volume absent */
+#define	ETARCH		ETBASEOFF+25	/* volume archived */
+#define	ETHELD		ETBASEOFF+26	/* volume held or disabled */
+#define	ETNXPD		ETBASEOFF+27	/* file not expired */
+#define	ETOPAB		ETBASEOFF+28	/* operator cancel */
+#define	ETVUNKN		ETBASEOFF+29	/* volume unknown */
+#define	ETWLBL		ETBASEOFF+30	/* wrong label type */
+#define	ETWPROT		ETBASEOFF+31	/* cartridge write protected */
+#define	ETWVSN		ETBASEOFF+32	/* wrong vsn */
+#define ETBADMIR	ETBASEOFF+33    /* Tape has a bad MIR */
+#define ETNETACCEPTINTR ETBASEOFF+34    /* castor::tape::net::acceptConnection interrupted */
+#define ETNOLBLINFO	ETBASEOFF+35    /* Label information not found in memory */
+#define ETMLTDRVRSV	ETBASEOFF+36    /* Multi-drive reservations are not supported */
+#define ETNOLBLINFOMEM	ETBASEOFF+37    /* No memory available for label information */
+#define ETSESSIONERROR	ETBASEOFF+38    /* Tape-session error */
+#define ETINVALIDTFSEQ	ETBASEOFF+39    /* Invalid tape-file sequence-number */
+#define ETINVALIDTFSIZE	ETBASEOFF+40    /* Invalid tape-file file-size */
+#define ETMOUNTFAILED	ETBASEOFF+41    /* Failed to mount volume */
+#define ETDISMOUNTFAILED ETBASEOFF+42   /* Failed to dismount volume */
+#define ETQUERYVOLFAILED ETBASEOFF+43   /* Failed to query volume */
+#define ETFDISMOUNTFAILED ETBASEOFF+44  /* Failed to force dismount volume */
+#define ETDRVNOTREADYFORMNT ETBASEOFF+45 /* Drive not ready for mount */
+#define ETMAXERR        ETBASEOFF+45
+
+/*
+ *------------------------------------------------------------------------
+ * VMGR (Volume Manager) errors
+ *------------------------------------------------------------------------
+ */
+#define	EVMGRNACT	EVMBASEOFF+1	/* volume manager not active or service being drained */
+#define EVMGRNOHOST	EVMBASEOFF+2	/* VMGR HOST not set */
+#define EVMMAXERR       EVMBASEOFF+2
+
+/*
+ *------------------------------------------------------------------------
+ * UPV (User Privilege Validator) errors
+ *------------------------------------------------------------------------
+ */
+#define	ECUPVNACT	EUPBASEOFF+1	/* User Privilege Validator not active or service being drained */
+#define EUPMAXERR       EUPBASEOFF+1
+
+/*
+ *------------------------------------------------------------------------
+ * DNS errors - See netdb.h for details
+ *------------------------------------------------------------------------
+ */
+#define EDNSHOSTNOTFOUND EDNSBASEOFF+1  /* Authoritative Answer Host not found. */
+#define EDNSTRYAGAIN    EDNSBASEOFF+2   /* Non-Authoritative Host not found, or SERVERFAIL */
+#define EDNSNORECOVERY  EDNSBASEOFF+3   /* Non recoverable errors, FORMERR, REFUSED, NOTIMP. */
+#define EDNSNODATA      EDNSBASEOFF+4   /* Valid name, no data record of requested type. */
+#define EDNSNOADDRESS   EDNSBASEOFF+5   /* No address, look for MX record. */
+#define EDNSMAXERR      EDNSBASEOFF+6
+
+/*
+ *------------------------------------------------------------------------
+ * VDQM (Volume & Drive Queue Manager) errors
+ *------------------------------------------------------------------------
+ */
+#define EVQSYERR        EVQBASEOFF+1    /* Failed system call */
+#define EVQINCONSIST    EVQBASEOFF+2    /* Internal DB inconsistency */
+#define EVQREPLICA      EVQBASEOFF+3    /* DB replication failed */
+#define EVQNOVOL        EVQBASEOFF+4    /* No volume request queued */
+#define EVQNODRV        EVQBASEOFF+5    /* No free drive available */
+#define EVQNOSVOL       EVQBASEOFF+6    /* Specified vol. req. not found */
+#define EVQNOSDRV       EVQBASEOFF+7    /* Specified drv. req. not found */
+#define EVQALREADY      EVQBASEOFF+8    /* Specified vol. req. already exists */
+#define EVQUNNOTUP      EVQBASEOFF+9    /* Unit not up */
+#define EVQBADSTAT      EVQBASEOFF+10   /* Bad unit status request */
+#define EVQBADID        EVQBASEOFF+11   /* Incorrect vol.req or job ID */
+#define EVQBADJOBID     EVQBASEOFF+12   /* Incorrect job ID */
+#define EVQNOTASS       EVQBASEOFF+13   /* Unit not assigned */
+#define EVQBADVOLID     EVQBASEOFF+14   /* Attempt to mount with wrong VOLID */
+#define EVQREQASS       EVQBASEOFF+15   /* Attempt to delete an assigned req */
+#define EVQDGNINVL      EVQBASEOFF+16   /* Vol. req. for non-existing DGN */
+#define EVQPIPEFULL     EVQBASEOFF+17   /* Replication pipe is full */
+#define EVQHOLD         EVQBASEOFF+18   /* Server is held */
+#define EVQEOQREACHED   EVQBASEOFF+19   /* End of query reached */
+
+#define EVQMAXERR       EVQBASEOFF+19
+
+/*
+ *------------------------------------------------------------------------
+ * RMC (Remote SCSI media changer server) errors
+ *------------------------------------------------------------------------
+ */
+#define	ERMCNACT	ERMBASEOFF+1	/* Remote SCSI media changer server not active or service being drained */
+#define	ERMCRBTERR	(ERMBASEOFF+2)	/* Remote SCSI media changer error */
+#define	ERMCUNREC	ERMCRBTERR+1	/* Remote SCSI media changer unrec. error */
+#define	ERMCSLOWR	ERMCRBTERR+2	/* Remote SCSI media changer error (slow retry) */
+#define	ERMCFASTR	ERMCRBTERR+3	/* Remote SCSI media changer error (fast retry) */
+#define	ERMCDFORCE	ERMCRBTERR+4	/* Remote SCSI media changer error (demount force) */
+#define	ERMCDDOWN	ERMCRBTERR+5	/* Remote SCSI media changer error (drive down) */
+#define	ERMCOMSGN	ERMCRBTERR+6	/* Remote SCSI media changer error (ops message) */
+#define	ERMCOMSGS	ERMCRBTERR+7	/* Remote SCSI media changer error (ops message + retry) */
+#define	ERMCOMSGR	ERMCRBTERR+8	/* Remote SCSI media changer error (ops message + wait) */
+#define	ERMCUNLOAD	ERMCRBTERR+9	/* Remote SCSI media changer error (unload + demount) */
+#define ERMMAXERR       ERMBASEOFF+11
+
+/*
+ *------------------------------------------------------------------------
+ * MONITORING ERRORS
+ *------------------------------------------------------------------------
+ */
+
+#define EMON_SYSTEM     EMONBASEOFF+1  /* When a system error causes the monitoring to stop */
+#define EMON_NO_HOST    EMONBASEOFF+2  /* No monitoring host defined in the configuration */
+#define EMON_NO_PORT    EMONBASEOFF+3  /* No monitoring port defined in the configuration */
+#define EMON_NO_CLIENTPORT    EMONBASEOFF+4  /* No port for client requests defined in the configuration */
+
+#define EMONMAXERR     EMONBASEOFF+4
+
+/*
+ *------------------------------------------------------------------------
+ * SECURITY ERRORS
+ *------------------------------------------------------------------------
+ */
+#define ESEC_SYSTEM    ESECBASEOFF + 1 /* System error in the security package */
+#define ESEC_BAD_CREDENTIALS ESECBASEOFF + 2 /* Bad credentials */
+#define ESEC_NO_CONTEXT ESECBASEOFF + 3 /* Could not establish context */
+#define ESEC_BAD_MAGIC ESECBASEOFF + 4 /* Bad magic number */
+#define ESEC_NO_USER   ESECBASEOFF + 5 /* Could not map username to uid/gid */
+#define ESEC_NO_PRINC   ESECBASEOFF + 6 /* Could not map principal to username */
+#define ESEC_NO_SECMECH   ESECBASEOFF + 7 /* Could not load security mechanism */
+#define ESEC_CTX_NOT_INITIALIZED   ESECBASEOFF + 8 /* Context not initialized */
+#define ESEC_PROTNOTSUPP   ESECBASEOFF + 9 /* Security protocol not supported */
+#define ESEC_NO_SVC_NAME   ESECBASEOFF + 10 /* Service name not set */
+#define ESEC_NO_SVC_TYPE   ESECBASEOFF + 11 /* Service type not set */
+#define ESEC_NO_SECPROT   ESECBASEOFF + 12 /* Could not lookup security protocol */
+#define ESEC_BAD_CSEC_VERSION ESECBASEOFF + 13 /* Csec incompatability */
+#define ESEC_BAD_PEER_RESP ESECBASEOFF + 14 /* Unexpected response from peer */
+#define ESECMAXERR     ESECBASEOFF + 14
+
+extern int serrno;
diff --git a/XRootdSSiRmcd/smc_constants.h b/XRootdSSiRmcd/smc_constants.h
new file mode 100644
index 0000000000000000000000000000000000000000..86cdf71600c28269ad465867a4d3adbd5b914a0f
--- /dev/null
+++ b/XRootdSSiRmcd/smc_constants.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 1998-2002 by CERN/IT/PDP/DM
+ * All rights reserved
+ */
+
+#pragma once
+
+			/* error messages */
+
+#define	SR001	"SR001 - drive ordinal must be a non negative integer\n"
+#define	SR002	"SR002 - option -%c and -%c are mutually exclusive\n"
+#define	SR003	"SR003 - invalid query type %c\n"
+#define	SR004	"SR004 - vid %s must be at most 6 characters long\n"
+#define	SR005	"SR005 - loader must be specified\n"
+#define	SR006	"SR006 - drive ordinal is mandatory for demount operations\n"
+#define	SR007	"SR007 - drive ordinal and vid are mandatory for mount operations\n"
+#define	SR008	"SR008 - invalid device ordinal (must be < %d)\n"
+#define	SR009	"SR009 - vid mismatch: %s on request, %s on drive\n"
+#define	SR010	"SR010 - number of elements must be a positive integer\n"
+#define	SR011	"SR011 - vid is mandatory for export operations\n"
+#define	SR012	"SR012 - cannot allocate enough memory\n"
+#define	SR013	"SR013 - export slots are full\n"
+#define	SR014	"SR014 - slot ordinal must be a non negative integer\n"
+#define	SR015	"SR015 - storage cells are full\n"
+#define	SR016	"SR016 - invalid slot address (must be < %d)\n"
+#define	SR017	"SR017 - %s %s failed : %s\n"
+#define	SR018	"SR018 - %s of %s on drive %d failed : %s\n"
+#define	SR019	"SR019 - %s : %s error : %s\n"
+#define	SR020	"SR020 - %s failed : %s\n"
+#define	SR021	"SR021 - specify source slot and target slot\n"
+
diff --git a/XRootdSSiRmcd/smc_struct.h b/XRootdSSiRmcd/smc_struct.h
new file mode 100644
index 0000000000000000000000000000000000000000..4d518908a0734e2a175a2a827fd2e92742e25117
--- /dev/null
+++ b/XRootdSSiRmcd/smc_struct.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 1998-2002 by CERN/IT/PDP/DM
+ * All rights reserved
+ */
+
+#pragma once
+
+#include "Castor_limits.h"
+
+struct robot_info {
+  char inquiry[32];
+  int transport_start;
+  int transport_count;
+  int slot_start;
+  int slot_count;
+  int port_start;
+  int port_count;
+  int device_start;
+  int device_count;
+};
+
+struct extended_robot_info {
+  int     smc_fd;
+  char    smc_ldr[CA_MAXRBTNAMELEN+1];
+  struct robot_info robot_info;
+};
+
+struct smc_element_info {
+  int element_address;
+  int element_type;
+  int state;
+  unsigned char asc;
+  unsigned char ascq;
+  int flags;
+  int source_address;
+  char name[9];
+};
+
+struct smc_status {
+  unsigned char asc;
+  unsigned char ascq;
+  int save_errno;
+  int rc;		/* return code from send_scsi_cmd */
+  unsigned char sensekey;
+  int skvalid;	/* sense key is valid */
+};
+
diff --git a/cta.spec.in b/cta.spec.in
index efddfa5141a22c4a8febca2a2a8b44dab7cbd1f2..c6c39d360e2f0dc846fa95c3930be1ed8c261ee7 100644
--- a/cta.spec.in
+++ b/cta.spec.in
@@ -131,6 +131,51 @@ The tape server daemon
 %systemd_postun cta-taped.service
 %systemdDaemonReload
 
+%package -n cta-xrmcd
+Summary: CERN Tape Archive: Xrootd plugin
+Group: Application/CTA
+Requires: logrotate
+Requires: cta-common = %{version}-%{release}
+Requires: cta-lib = %{version}-%{release}
+Requires: xrootd-server
+%description -n cta-xrmcd
+CERN Tape Archive:
+The xroot plugin
+%files -n cta-xrmcd
+%defattr(0755,root,root)
+%{_libdir}/libXrdSsiRmcd.so*
+%attr(0644,root,root) %config(noreplace) /etc/logrotate.d/cta-xrmcd
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/cta/cta-xrmcd.conf
+%attr(0644,cta,tape) /etc/systemd/system/cta-xrmcd.service
+%attr(0644,root,root) %config(noreplace) /etc/sysconfig/cta-xrmcd
+
+#xrmcd installs libraries so we need ldconfig.
+%post -n cta-xrmcd
+/sbin/ldconfig
+%systemd_post cta-xrmcd.service
+%systemdDaemonReload
+
+%preun -n cta-xrmcd
+%systemd_preun cta-xrmcd.service
+
+%postun -n cta-xrmcd
+/sbin/ldconfig
+%systemd_post cta-xrmcd.service
+%systemdDaemonReload
+
+%package -n cta-xsmc
+Summary: CERN Tape Archive: command line interface
+Group: Application/CTA
+Requires: cta-lib = %{version}-%{release}
+%description -n cta-xsmc
+CERN Tape Archive:
+The xroot plugin
+%files -n cta-xsmc
+%defattr(-,root,root)
+%attr(0755,root,root) %{_bindir}/cta-xsmc
+%attr(0644,root,root) %doc /usr/share/man/man1/cta-xsmc-mount.1cta.gz
+%attr(0644,root,root) %doc /usr/share/man/man1/cta-xsmc-dismount.1cta.gz
+
 %package -n cta-frontend
 Summary: CERN Tape Archive: Xrootd plugin
 Group: Application/CTA