mh virtual tape & library system.


Instructions assume reader is familiar with the kernel build process.

There are two sections of code to build.
- The kernel module
- The user-space daemons.

Kernel module mhvtl:
==================
1) Make sure the kernel-devel package to match your running kernel is installed.
e.g.
RedHat AS 4 & 5:

	sh> rpm -qa|grep kernel
	kernel-2.6.9-34.0.1.EL
	kernel-devel-2.6.9-34.0.1.EL
	kernel-2.6.9-5.EL
	kernel-devel-2.6.9-5.EL
	kernel-utils-2.4-13.1.80

SLES 9 & 10:

	sh> rpm -qa|grep kernel


2) Extract the mhvtl source code.

	sh> tar xvfz mhvtl-2012-06-15.tgz

3) Change directory into the kernel driver source.

	sh> cd mhvtl-1.3/kernel/
	sh> make
	sh> sudo make install

Secure Boot:
============
With UEFI Secure Boot enabled the kernel loads only signed modules, and an
unsigned mhvtl.ko fails with "Key was rejected by service".

Recent DKMS releases sign the modules they build, unless signing is turned
off (try_sign_modules=false) or the build runs in a chroot. The key is the
one configured as mok_signing_key / mok_certificate in
/etc/dkms/framework.conf (or framework.conf.d); by default DKMS creates
/var/lib/dkms/mok.key and /var/lib/dkms/mok.pub on first use. Ubuntu uses
/var/lib/shim-signed/mok/MOK.der instead and offers to enrol it itself.

That certificate has to be enrolled once, as a machine owner key (MOK):

	sh> sudo mokutil --import /var/lib/dkms/mok.pub
	(choose a one-time password)
	sh> sudo reboot

At the next boot the firmware's MOK manager asks to enrol it, typically
"Enroll MOK", "Continue", "Yes", then the password. As long as DKMS keeps
signing with that key, modules it builds later, for new kernels too, load
without further steps. To check:

	sh> mokutil --test-key /var/lib/dkms/mok.pub
	sh> modinfo -F signer mhvtl
	sh> modinfo -F sig_key mhvtl

Enrolling a key does not change a module that is already built. If mhvtl.ko
is unsigned or signed with another key, rebuild it once DKMS signs with the
enrolled key:

	sh> sudo dkms build -m mhvtl -v <version> --force
	sh> sudo dkms install -m mhvtl -v <version> --force

On openSUSE, the prebuilt mhvtl-kmp packages are signed by their build
service instead; enrol the project's certificate for those. If you use
mhvtl-dkms there, recent openSUSE kernels also require the signing key to
carry the codeSigning extended key usage, or they reject the module
("key is not CodeSigning" in dmesg). DKMS adds it to the keys it generates
from release 3.1.7 on, but keeps using a key an older release generated: in
that case delete /var/lib/dkms/mok.key and mok.pub, rebuild the module as
above and enrol the new key (https://bugzilla.suse.com/show_bug.cgi?id=1242820).

A module built with plain "make install" is not signed: sign it with the
kernel's scripts/sign-file and a key the kernel trusts, or use mhvtl-dkms.

User space daemons:
===================
Pre-req for a running mhvtl
- sg3_utils (http://sg.danny.cz/sg/sg3_utils.html)

Pre-req to build/compile userspace:
- zlib-devel
- lzo-devel

* To build an RPM
  ===============

	sh> sudo cp mhvtl-YYYY-MM-DD.tar.gz /usr/src/packages/SOURCE/
	sh> cd /usr/src/packages/SOURCE
	sh> sudo rpmbuild -tb mhvtl-YYYY-MM-DD.tar.gz
	...  <wait for rpm build to complete>
	sh> sudo rpm -Uvh /usr/src/packages/RPMS/<cpu type>/mhvtl-1.3-z.<cpu type>.rpm
	...

- Note: For RedHat, replace 'packages' with 'redhat'

* To build from tar archive (Debian / Ubuntu):
  ============================================
 apt-get install lsscsi
 apt-get install sg3-utils

Note: we used to create a user and group called "vtl" to try to limit
the possible system hazards of having root access. But we now feel
that normal Linux permissions and security controls are sufficient.

Also note: The package sg3-utils has a different name based on the distribution
used. Most distributions (Red Hat/Suse/Centos) use an underscore (sg3_utils).
Debian based distributions (Debian/Ubuntu/Mint use a hyphen (sg3-utils).

Now build user space daemons:
From the parent directory where you extracted the source.

	sh> cd mhvtl-1.3

Build the binaries

	sh> make

Install the systemd scripts and binaries and tell systemd:

	sh> sudo make install
	sh> sudo systemctl daemon-reload

Enable and start the mhvtl target service:

	sh> sudo systemctl enable mhvtl.target
	sh> sudo systemctl start mhvtl.target

And make sure it worked:

	sh> sudo systemctl status mhvtl.target

You can test that your vtl* daemons are running with:

	sh> ps -ax | fgrep vtl

Starting a library also creates any virtual media its library_contents
lists that does not exist yet under MHVTL_HOME_PATH (default /var/lib/mhvtl):
mhvtl-media.service runs make_vtl_media before the library daemons start.
When not using systemd, create it before using mtx to load tapes:

	sh> sudo make_vtl_media

Without media files, mtx load will fail with a hardware error sense.

TCMU backend (experimental):
============================
Instead of the mhvtl kernel module, the daemons can present their devices
through the kernel's LIO target (target_core_user), using the handler daemon
mhvtl_tcmu_handler. No out-of-tree module is needed, and mhvtl-fabrics can
export the devices to other hosts over iSCSI.

Kernel modules (part of the distribution kernel):
- target_core_user, tcm_loop and, for iSCSI, iscsi_target_mod
  - EL8/EL9: in the kernel-modules package, not in kernel-core.
  - openSUSE: use the full kernel-default, not kernel-default-base.

From packages:
--------------
Install mhvtl-tcmu next to the main package (mhvtl-utils as an RPM, mhvtl
as a .deb). It satisfies the main package's kernel module dependency, so
mhvtl-dkms and its compiler and kernel headers are not needed.

On EL, which ships no libtcmu, the package carries its own copy, linked
into the handler.

From source:
------------
The handler needs libtcmu from tcmu-runner
(https://github.com/open-iscsi/tcmu-runner). Its headers are taken from
libtcmu-devel when installed, else from the copy in include/libtcmu
(tcmu-runner 1.5.4, which also builds against libtcmu 1.6.x).

- Fedora: install libtcmu-devel.
- Debian, Ubuntu, openSUSE: install libtcmu2 (library only; Leap 16's
  libtcmu-devel adds just the libtcmu.so link).
- EL: no packages. Build libtcmu from source, as
  install_libtcmu_from_source() in vagrant/install.sh does (needs
  glib2-devel and libnl3-devel), or link it statically as mhvtl-utils.spec
  does.

	sh> make TCMU=1
	sh> sudo make TCMU=1 install

TCMU_SRC=<absolute path to a tcmu-runner tree> uses that tree's headers
instead of the bundled copy (installed libtcmu-devel headers still come
first). TCMU_LIBS overrides how libtcmu is linked.
Without the library, "make TCMU=1" stops at once and says what is missing.

Using it:
---------
Set the backend in /etc/mhvtl/mhvtl.conf and restart:

	MHVTL_BACKEND=tcmu

	sh> sudo systemctl restart mhvtl.target

From a source tree, scripts/switch_backend.sh tcmu does the same (and
"mhvtl" switches back). The devices appear on this host through tcm_loop;
MHVTL_TCMU_LOOPBACK=no in mhvtl.conf skips that on a host that only
exports them.

Export over iSCSI:
------------------
Copy /usr/share/mhvtl/fabrics.conf.sample to /etc/mhvtl/fabrics.conf, set
the base name, the portal and the initiators allowed to log in (see
fabrics.conf(5)), then restart mhvtl.target. mhvtl-fabrics.service creates
one target per library (the changer is LUN 0, each drive the LUN of its
slot in device.conf) and one per standalone drive (LUN 0). Check the result with:

	sh> sudo mhvtl-fabrics status

Allow the portal port (3260/tcp by default) through the firewall. Do not
save these targets with "targetcli saveconfig": target.service would
restore them at boot, before the handler has created the backstores.

On the initiator (open-iscsi), a tape job fails on any transport error,
since the position after a lost command is unknown. open-iscsi ends a
session after 5 + 5 seconds without a NOP-Out answer; to ride out longer
network stalls, raise node.conn[0].timeo.noop_out_interval and
noop_out_timeout for this target (mhvtl-fabrics sets the target side's
Data-Out timeout to 30 s).

Test:
Note: Make sure the 'mtx' & 'lsscsi' utilities are installed
The virtual devices are attached to HBA #5 in this example.
e.g.
# lsscsi -g
[0:0:0:0]    disk    ATA      WDC WD1200BEVS-0 02.0  /dev/sda  /dev/sg0
[3:0:0:0]    cd/dvd  Optiarc  DVD RW AD-7910A  1.D1  /dev/sr0  /dev/sg1
[5:0:0:0]    mediumx SPECTRA  PYTHON           5500  /dev/sch0  /dev/sg6
[5:0:1:0]    tape    QUANTUM  SDLT600          5500  /dev/st0  /dev/sg2
[5:0:2:0]    tape    QUANTUM  SDLT600          5500  /dev/st1  /dev/sg3
[5:0:3:0]    tape    IBM      ULT3580-TD4      5500  /dev/st2  /dev/sg4
[5:0:4:0]    tape    IBM      ULT3580-TD4      5500  /dev/st3  /dev/sg5


# mtx -f /dev/sg6 status
  Storage Changer /dev/sg6:4 Drives, 37 Slots ( 4 Import/Export )
Data Transfer Element 0:Empty
Data Transfer Element 1:Empty
Data Transfer Element 2:Empty
Data Transfer Element 3:Empty
      Storage Element 1:Full :VolumeTag=SDLT01S3
      Storage Element 2:Full :VolumeTag=SDLT02S3
      Storage Element 3:Full :VolumeTag=SDLT03S3
      Storage Element 4:Full :VolumeTag=SDLT04S3
      Storage Element 5:Full :VolumeTag=SDLT05S3
      Storage Element 6:Full :VolumeTag=SDLT06S3
      Storage Element 7:Full :VolumeTag=SDLT07S3
      Storage Element 8:Full :VolumeTag=SDLT08S3
      Storage Element 9:Full :VolumeTag=SDLT09S3
      Storage Element 10:Empty
      Storage Element 11:Full :VolumeTag=ULT001L1
      Storage Element 12:Full :VolumeTag=ULT002L2
      Storage Element 13:Full :VolumeTag=ULT003L3
      Storage Element 14:Full :VolumeTag=ULT004L4
      Storage Element 15:Full :VolumeTag=ULT005L1
      Storage Element 16:Full :VolumeTag=ULT006L2
      Storage Element 17:Full :VolumeTag=ULT007L3
      Storage Element 18:Full :VolumeTag=ULT008L4
      Storage Element 19:Full :VolumeTag=ULT009L1
      Storage Element 20:Empty
      Storage Element 21:Full :VolumeTag=8MM001X4
      Storage Element 22:Full :VolumeTag=8MM002X4
      Storage Element 23:Full :VolumeTag=8MM003X4
      Storage Element 24:Full :VolumeTag=8MM004X4
      Storage Element 25:Empty
      Storage Element 26:Empty
      Storage Element 27:Empty
      Storage Element 28:Empty
      Storage Element 29:Empty
      Storage Element 30:Empty
      Storage Element 31:Full :VolumeTag=CLN001L1
      Storage Element 32:Full :VolumeTag=CLN002L1
      Storage Element 33:Full :VolumeTag=CLN003L1
      Storage Element 34 IMPORT/EXPORT:Empty
      Storage Element 35 IMPORT/EXPORT:Empty
      Storage Element 36 IMPORT/EXPORT:Empty
      Storage Element 37 IMPORT/EXPORT:Empty


Enjoy.

Please feel free in letting me know if this works for you.

Bug fixes and suggestions always welcome.

markh794@gmail.com
