diff --git a/mediachanger/castorrmc/rmc/rmc_send_scsi_cmd.c b/mediachanger/castorrmc/rmc/rmc_send_scsi_cmd.c
new file mode 100644
index 0000000000000000000000000000000000000000..c4803e8b618ba468d8453b412c266118ed7f2c0b
--- /dev/null
+++ b/mediachanger/castorrmc/rmc/rmc_send_scsi_cmd.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 1996-2000 by CERN/IT/PDP/DM
+ * All rights reserved
+ */
+
+/*	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 <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 "Ctape.h"
+static char tp_err_msgbuf[132];
+static 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",
+};
+struct scsi_info {
+        int status;
+        char *text;
+};
+struct scsi_info scsi_codmsg[] = {
+	{ SCSI_STATUS_CHECK_CONDITION,	    "Check condition"      },
+	{ SCSI_STATUS_BUSY,		    "Target busy"          },
+	{ SCSI_STATUS_RESERVATION_CONFLICT, "Reservation conflict" },
+	{ 0xFF,				    NULL }
+};
+#define PROCBUFSZ 80
+
+static void find_sgpath(char *sgpath, int maj, 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 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 timeout,   /* in milliseconds */
+	const int flags,
+	int *const nb_sense_ret,
+	char **const msgaddr)
+{
+	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[PROCBUFSZ];
+
+  (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, PROCBUFSZ);
+	  nbread = read(procfd, procbuf, PROCBUFSZ -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 (tp_err_msgbuf, "blocksize too large (max %zd)\n",
+		    sg_big_buff_val - sizeof(struct sg_header) - cdblen);
+		*msgaddr = tp_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 = malloc (sizeof(struct sg_header)+cdblen+buflen)) == NULL) {
+			serrno = errno;
+			sprintf (tp_err_msgbuf, TP005);
+			*msgaddr = tp_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 (tp_err_msgbuf, sizeof(tp_err_msgbuf), TP042, path, "stat", strerror(errno));
+			tp_err_msgbuf[sizeof(tp_err_msgbuf) - 1] = '\0';
+        		*msgaddr = tp_err_msgbuf;
+			return (-1);
+		}
+
+                /* get the major device ID of the sg devices ... */
+		if (stat ("/dev/sg0", &sbufa) < 0) {
+			serrno = errno;
+			snprintf (tp_err_msgbuf, sizeof(tp_err_msgbuf), TP042, "/dev/sg0", "stat", strerror(errno));
+			tp_err_msgbuf[sizeof(tp_err_msgbuf) - 1] = '\0';
+			*msgaddr = tp_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 (tp_err_msgbuf, sizeof(tp_err_msgbuf), TP042, sgpath, "open", strerror(errno));
+			tp_err_msgbuf[sizeof(tp_err_msgbuf) - 1] = '\0';
+			*msgaddr = tp_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 (tp_err_msgbuf, sizeof(tp_err_msgbuf), TP042, sgpath, "write", *msgaddr);
+		tp_err_msgbuf[sizeof(tp_err_msgbuf) - 1] = '\0';
+		*msgaddr = tp_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 (tp_err_msgbuf, sizeof(tp_err_msgbuf), TP042, sgpath, "read", *msgaddr);
+		tp_err_msgbuf[sizeof(tp_err_msgbuf) - 1] = '\0';
+		*msgaddr = tp_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 (tp_err_msgbuf, sizeof(tp_err_msgbuf), TP042, sgpath, "scsi", tmp_msgbuf);
+		tp_err_msgbuf[sizeof(tp_err_msgbuf) - 1] = '\0';
+		*msgaddr = tp_err_msgbuf;
+		return (-4);
+	} else if (sg_hd->result) {
+		*msgaddr = (char *) strerror(sg_hd->result);
+		serrno = sg_hd->result;
+		snprintf (tp_err_msgbuf, sizeof(tp_err_msgbuf), TP042, sgpath, "read", *msgaddr);
+		tp_err_msgbuf[sizeof(tp_err_msgbuf) - 1] = '\0';
+		*msgaddr = tp_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);
+}