├── .github └── workflows │ └── codeql.yml ├── .gitignore ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile ├── README ├── ccan └── ccan │ └── crc32c │ ├── _info │ ├── benchmark │ ├── Makefile │ └── bench.c │ ├── crc32c.c │ ├── crc32c.h │ └── test │ ├── api-crc32c.c │ └── run-crc32c.c ├── config.mk ├── doc ├── 4_library_example │ ├── device.conf │ ├── library_contents.10 │ ├── library_contents.20 │ ├── library_contents.30 │ ├── library_contents.40 │ └── mhvtl.conf └── index.html ├── etc ├── .gitignore ├── Makefile ├── generate_device_conf.in ├── generate_library_contents.in ├── library_contents.sample ├── mhvtl-load-modules.service.in ├── mhvtl.conf.in ├── mhvtl.target ├── vtllibrary@.service.in └── vtltape@.service.in ├── include └── vtl_u.h ├── kernel ├── .gitignore ├── Makefile ├── backport.h ├── config.sh ├── fetch.c ├── fetch24.c ├── fetch26.c ├── fetch27.c ├── fetch50.c ├── mhvtl.c └── vtl_common.h ├── man ├── Makefile ├── device.conf.5.in ├── dump_tape.1.in ├── edit_tape.1.in ├── generate_device_conf.1.in ├── generate_library_contents.1.in ├── library_contents.5.in ├── make_vtl_media.1.in ├── mhvtl.conf.5.in ├── mhvtl_kernel_mod_build.1.in ├── mktape.1.in ├── preload_tape.1.in ├── tapeexerciser.1.in ├── update_device.conf.1.in ├── vtlcmd.1.in ├── vtllibrary.1.in └── vtltape.1.in ├── mhvtl-utils.spec ├── scripts ├── 70-persistent-generic.rules ├── 70-persistent-tape.rules ├── Makefile ├── NetBackup │ ├── drive_stats.pl │ └── vlt_endeject_notify.pl ├── build-persistent-tape-rules.sh ├── centos_configure.sh ├── checkarch.sh ├── checkpatch.pl ├── lio_target_passthru.sh ├── mhvtl-1.4.ebuild ├── rescan-scsi-bus.sh ├── start-mhvtl-scst.sh ├── stgt-target-setup.conf ├── test_lbp.sh └── update_device.conf.in ├── tcopy ├── Makefile ├── pathnames.h ├── tcopy.1 └── tcopy.c ├── todo ├── usr ├── .gitignore ├── Makefile ├── README.LZO ├── ait_pm.c ├── be_byteshift.h ├── crc32c.c ├── default_smc_pm.c ├── default_ssc_pm.c ├── dump_messageQ.c ├── edit_tape.c ├── hp_smc_pm.c ├── hp_ultrium_pm.c ├── ibm_03592_pm.c ├── ibm_smc_pm.c ├── log.c ├── logging.h ├── lzoconf.h ├── lzodefs.h ├── make_scsi_dev ├── make_vtl_media.in ├── mhvtl-device-conf-generator.c ├── mhvtl_io.c ├── mhvtl_kernel_mod_build.in ├── mhvtl_list.h ├── mhvtl_log.h ├── mhvtl_scsi.h ├── minilzo.c ├── minilzo.h ├── mktape.c ├── mode.c ├── mode.h ├── overland_pm.c ├── q.c ├── q.h ├── quantum_dlt_pm.c ├── reed-solomon.c ├── scalar_pm.c ├── security_protocol.h ├── smc.c ├── smc.h ├── spc.c ├── spc.h ├── spectra_pm.c ├── ssc.c ├── ssc.h ├── stk9x40_pm.c ├── stklxx_pm.c ├── subprocess.c ├── subprocess.h ├── t10000_pm.c ├── tape_util.c ├── tapeexerciser.c ├── ult3580_pm.c ├── validate_crc.c ├── vtl_cart_type.c ├── vtlcart.c ├── vtlcart_v1.c ├── vtlcart_v1_mtr.c ├── vtlcmd.c ├── vtllib.c ├── vtllib.h ├── vtllibrary.c ├── vtltape.c ├── vtltape.h └── vtltape_pem.h ├── vagrant ├── README.MD ├── Vagrantfile └── install.sh └── webgui └── index.php /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '43 6 * * 5' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'cpp' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v2 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v1 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v1 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v1 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.ko 2 | *.o 3 | *~ 4 | /cscope.* 5 | /kernel/.*.ko.cmd 6 | /kernel/.*.o.cmd 7 | /kernel/.tmp_versions/ 8 | /kernel/mhvtl.mod.c 9 | /kernel/Module.symvers 10 | /kernel/modules.order 11 | /kernel/config.h 12 | /scripts/update_device.conf 13 | /man/*.1 14 | /man/*.5 15 | /tcopy/tcopy 16 | local.mk 17 | mhvtl_kernel.tgz 18 | /usr/mhvtl_kernel_mod_build 19 | 20 | # Vagrant specific files 21 | /vagrant/.vagrant 22 | /vagrant/*.log 23 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | mh virtual tape & library system. 2 | 3 | 4 | Instructions assume reader is familiar with the kernel build process. 5 | 6 | There are two sections of code to build. 7 | - The kernel module 8 | - The user-space daemons. 9 | 10 | Kernel module mhvtl: 11 | ================== 12 | 1) Make sure the kernel-devel package to match your running kernel is installed. 13 | e.g. 14 | RedHat AS 4 & 5: 15 | 16 | sh> rpm -qa|grep kernel 17 | kernel-2.6.9-34.0.1.EL 18 | kernel-devel-2.6.9-34.0.1.EL 19 | kernel-2.6.9-5.EL 20 | kernel-devel-2.6.9-5.EL 21 | kernel-utils-2.4-13.1.80 22 | 23 | SLES 9 & 10: 24 | 25 | sh> rpm -qa|grep kernel 26 | 27 | 28 | 2) Extract the mhvtl source code. 29 | 30 | sh> tar xvfz mhvtl-2012-06-15.tgz 31 | 32 | 3) Change directory into the kernel driver source. 33 | 34 | sh> cd mhvtl-1.3/kernel/ 35 | sh> make 36 | sh> sudo make install 37 | 38 | 39 | User space daemons: 40 | =================== 41 | Pre-req for a running mhvtl 42 | - sg3_utils (http://sg.danny.cz/sg/sg3_utils.html) 43 | 44 | Pre-req to build/compile userspace: 45 | - zlib-devel 46 | - lzo-devel 47 | 48 | * To build an RPM 49 | =============== 50 | 51 | sh> sudo cp mhvtl-YYYY-MM-DD.tar.gz /usr/src/packages/SOURCE/ 52 | sh> cd /usr/src/packages/SOURCE 53 | sh> sudo rpmbuild -tb mhvtl-YYYY-MM-DD.tar.gz 54 | ... 55 | sh> sudo rpm -Uvh /usr/src/packages/RPMS//mhvtl-1.3-z..rpm 56 | ... 57 | 58 | - Note: For RedHat, replace 'packages' with 'redhat' 59 | 60 | * To build from tar archive (Debian / Ubuntu): 61 | ============================================ 62 | apt-get install lsscsi 63 | apt-get install sg3-utils 64 | 65 | Note: we used to create a user and group called "vtl" to try to limit 66 | the possible system hazards of having root access. But we now feel 67 | that normal Linux permissions and security controls are sufficient. 68 | 69 | Also note: The package sg3-utils has a different name based on the distribution 70 | used. Most distributions (Red Hat/Suse/Centos) use an underscore (sg3_utils). 71 | Debian based distributions (Debian/Ubuntu/Mint use a hyphen (sg3-utils). 72 | 73 | Now build user space daemons: 74 | From the parent directory where you extracted the source. 75 | 76 | sh> cd mhvtl-1.3 77 | 78 | Build the binaries 79 | 80 | sh> make 81 | 82 | Install the systemd scripts and binaries and tell systemd: 83 | 84 | sh> sudo make install 85 | sh> sudo systemctl daemon-reload 86 | 87 | Enable and start the mhvtl target service: 88 | 89 | sh> sudo systemctl enable mhvtl.target 90 | sh> sudo systemctl start mhvtl.target 91 | 92 | And make sure it worked: 93 | 94 | sh> sudo systemctl status mhvtl.target 95 | 96 | You can test that your vtl* daemons are running with: 97 | 98 | sh> ps -ax | fgrep vtl 99 | 100 | Test: 101 | Note: Make sure the 'mtx' & 'lsscsi' utilities are installed 102 | The virtual devices are attached to HBA #5 in this example. 103 | e.g. 104 | # lsscsi -g 105 | [0:0:0:0] disk ATA WDC WD1200BEVS-0 02.0 /dev/sda /dev/sg0 106 | [3:0:0:0] cd/dvd Optiarc DVD RW AD-7910A 1.D1 /dev/sr0 /dev/sg1 107 | [5:0:0:0] mediumx SPECTRA PYTHON 5500 /dev/sch0 /dev/sg6 108 | [5:0:1:0] tape QUANTUM SDLT600 5500 /dev/st0 /dev/sg2 109 | [5:0:2:0] tape QUANTUM SDLT600 5500 /dev/st1 /dev/sg3 110 | [5:0:3:0] tape IBM ULT3580-TD4 5500 /dev/st2 /dev/sg4 111 | [5:0:4:0] tape IBM ULT3580-TD4 5500 /dev/st3 /dev/sg5 112 | 113 | 114 | # mtx -f /dev/sg6 status 115 | Storage Changer /dev/sg6:4 Drives, 37 Slots ( 4 Import/Export ) 116 | Data Transfer Element 0:Empty 117 | Data Transfer Element 1:Empty 118 | Data Transfer Element 2:Empty 119 | Data Transfer Element 3:Empty 120 | Storage Element 1:Full :VolumeTag=SDLT01S3 121 | Storage Element 2:Full :VolumeTag=SDLT02S3 122 | Storage Element 3:Full :VolumeTag=SDLT03S3 123 | Storage Element 4:Full :VolumeTag=SDLT04S3 124 | Storage Element 5:Full :VolumeTag=SDLT05S3 125 | Storage Element 6:Full :VolumeTag=SDLT06S3 126 | Storage Element 7:Full :VolumeTag=SDLT07S3 127 | Storage Element 8:Full :VolumeTag=SDLT08S3 128 | Storage Element 9:Full :VolumeTag=SDLT09S3 129 | Storage Element 10:Empty 130 | Storage Element 11:Full :VolumeTag=ULT001L1 131 | Storage Element 12:Full :VolumeTag=ULT002L2 132 | Storage Element 13:Full :VolumeTag=ULT003L3 133 | Storage Element 14:Full :VolumeTag=ULT004L4 134 | Storage Element 15:Full :VolumeTag=ULT005L1 135 | Storage Element 16:Full :VolumeTag=ULT006L2 136 | Storage Element 17:Full :VolumeTag=ULT007L3 137 | Storage Element 18:Full :VolumeTag=ULT008L4 138 | Storage Element 19:Full :VolumeTag=ULT009L1 139 | Storage Element 20:Empty 140 | Storage Element 21:Full :VolumeTag=8MM001X4 141 | Storage Element 22:Full :VolumeTag=8MM002X4 142 | Storage Element 23:Full :VolumeTag=8MM003X4 143 | Storage Element 24:Full :VolumeTag=8MM004X4 144 | Storage Element 25:Empty 145 | Storage Element 26:Empty 146 | Storage Element 27:Empty 147 | Storage Element 28:Empty 148 | Storage Element 29:Empty 149 | Storage Element 30:Empty 150 | Storage Element 31:Full :VolumeTag=CLN001L1 151 | Storage Element 32:Full :VolumeTag=CLN002L1 152 | Storage Element 33:Full :VolumeTag=CLN003L1 153 | Storage Element 34 IMPORT/EXPORT:Empty 154 | Storage Element 35 IMPORT/EXPORT:Empty 155 | Storage Element 36 IMPORT/EXPORT:Empty 156 | Storage Element 37 IMPORT/EXPORT:Empty 157 | 158 | 159 | Enjoy. 160 | 161 | Please feel free in letting me know if this works for you. 162 | 163 | Bug fixes and suggestions always welcome. 164 | 165 | markh794@gmail.com 166 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This makefile needs to be invoked as follows: 3 | # 4 | #make 5 | # 6 | # Here, options include: 7 | # 8 | # all to build all utilities 9 | # clean to clean up all intermediate files 10 | # kernel to build kernel module 11 | # 12 | 13 | include config.mk 14 | 15 | PARENTDIR = mhvtl-$(VER) 16 | CHECK_CC = cgcc 17 | CHECK_CC_FLAGS = '$(CHECK_CC) -Wbitwise -Wno-return-void -no-compile $(ARCH)' 18 | 19 | TAR_FILE := mhvtl-$(shell date +%F)-$(VERSION).$(EXTRAVERSION).tgz 20 | 21 | MAKE_VTL_MEDIA = usr/make_vtl_media 22 | 23 | export PREFIX DESTDIR TOPDIR 24 | 25 | CFLAGS=-Wall -g -O2 -D_LARGEFILE64_SOURCE $(RPM_OPT_FLAGS) 26 | CLFLAGS=-shared 27 | 28 | all: usr etc scripts 29 | 30 | scripts: patch 31 | $(MAKE) -C scripts 32 | 33 | etc: patch 34 | $(MAKE) -C etc 35 | 36 | usr: patch 37 | $(MAKE) -C usr 38 | 39 | kernel: patch 40 | $(MAKE) -C kernel 41 | 42 | .PHONY:check 43 | check: ARCH=$(shell sh scripts/checkarch.sh) 44 | check: 45 | CC=$(CHECK_CC_FLAGS) $(MAKE) all 46 | 47 | tags: 48 | $(MAKE) -C usr tags 49 | $(MAKE) -C kernel tags 50 | 51 | patch: 52 | 53 | clean: 54 | $(MAKE) -C usr clean 55 | $(MAKE) -C etc clean 56 | $(MAKE) -C scripts clean 57 | $(MAKE) -C man clean 58 | $(MAKE) -C kernel clean 59 | $(RM) -f mhvtl_kernel.tgz 60 | 61 | .PHONY: distclean 62 | distclean: 63 | $(MAKE) -C usr distclean 64 | $(MAKE) -C etc distclean 65 | $(MAKE) -C scripts distclean 66 | $(MAKE) -C kernel distclean 67 | $(MAKE) -C man clean 68 | $(RM) -f mhvtl_kernel.tgz 69 | $(RM) ../$(TAR_FILE) 70 | 71 | install: all 72 | $(MAKE) -C usr install 73 | $(MAKE) -C scripts install 74 | $(MAKE) -i -C etc install 75 | $(MAKE) -C man man 76 | $(MAKE) -C man install 77 | [ -d $(DESTDIR)$(MHVTL_HOME_PATH) ] || mkdir -p $(DESTDIR)$(MHVTL_HOME_PATH) 78 | (cd kernel; tar --sort=name --mtime=@1 --format=gnu -czf ../mhvtl_kernel.tgz *) 79 | [ -d $(DESTDIR)$(FIRMWAREDIR)/mhvtl ] || mkdir -p $(DESTDIR)$(FIRMWAREDIR)/mhvtl 80 | install -m 755 mhvtl_kernel.tgz $(DESTDIR)$(FIRMWAREDIR)/mhvtl/ 81 | ifeq ($(ROOTUID),YES) 82 | ldconfig 83 | systemctl daemon-reload 84 | endif 85 | # now ensure VTL media is setup 86 | env LD_LIBRARY_PATH=$(DESTDIR)$(LIBDIR) \ 87 | $(MAKE_VTL_MEDIA) \ 88 | --config-dir=$(DESTDIR)$(MHVTL_CONFIG_PATH) \ 89 | --home-dir=$(DESTDIR)$(MHVTL_HOME_PATH) \ 90 | --mktape-path=usr 91 | 92 | tar: distclean 93 | test -d ../$(PARENTDIR) || ln -s $(TOPDIR) ../$(PARENTDIR) 94 | (cd kernel; tar cfz ../mhvtl_kernel.tgz *) 95 | (cd ..; tar cvzf $(TAR_FILE) --exclude='.git*' \ 96 | $(PARENTDIR)/man \ 97 | $(PARENTDIR)/doc \ 98 | $(PARENTDIR)/kernel \ 99 | $(PARENTDIR)/usr \ 100 | $(PARENTDIR)/etc/ \ 101 | $(PARENTDIR)/scripts/ \ 102 | $(PARENTDIR)/ccan/ \ 103 | $(PARENTDIR)/tcopy/ \ 104 | $(PARENTDIR)/include \ 105 | $(PARENTDIR)/Makefile \ 106 | $(PARENTDIR)/config.mk \ 107 | $(PARENTDIR)/README \ 108 | $(PARENTDIR)/INSTALL \ 109 | $(PARENTDIR)/ChangeLog \ 110 | $(PARENTDIR)/mhvtl_kernel.tgz \ 111 | $(PARENTDIR)/mhvtl-utils.spec) 112 | $(RM) ../$(PARENTDIR) 113 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | mhvtl: A Virtual Tape & Library system. 3 | 4 | This package is composed of a kernel module (mhvtl) which is a pseudo HBA 5 | 6 | The vtl is basically a stripped down scsi_debug kernel module + a char dev 7 | 'back end' to pass the SCSI commands thru to user space daemons. It is the 8 | user space daemons responsibility to respond and process the SCSI commands. 9 | 10 | See the INSTALL file for compile and install instructions. 11 | 12 | This has been my first attempt at kernel level programming. Suggestions and 13 | comments always welcome. It has also been many years since I have done any c 14 | programming. Please be gentle.. 15 | 16 | Mark Harvey 17 | markh794@gmail.com 18 | -------------------------------------------------------------------------------- /ccan/ccan/crc32c/_info: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | #include 4 | 5 | /** 6 | * crc32c - routine for Castagnoli CRC (crc32c) of bytes 7 | * 8 | * Cyclic Redundancy Check routine, optimized for x86-64. Reasonably fast 9 | * checksum routines, but not suitable for cryptographic use. 10 | * 11 | * They are useful for simple error detection, eg. a 32-bit CRC will 12 | * detect a single error burst of up to 32 bits. 13 | * 14 | * Example: 15 | * #include 16 | * #include 17 | * #include 18 | * 19 | * // Given "123456789" outputs 0xe3069283 20 | * int main(int argc, char *argv[]) 21 | * { 22 | * if (argc != 2) { 23 | * fprintf(stderr, "Usage: %s \n" 24 | * "Prints 32 bit CRC of the string\n", argv[0]); 25 | * exit(1); 26 | * } 27 | * printf("0x%08x\n", crc32c(0, argv[1], strlen(argv[1]))); 28 | * exit(0); 29 | * } 30 | * 31 | * License: MIT 32 | * Author: Mark Adler 33 | * Maintainer: Rusty Russell 34 | */ 35 | int main(int argc, char *argv[]) 36 | { 37 | if (argc != 2) 38 | return 1; 39 | 40 | if (strcmp(argv[1], "depends") == 0) { 41 | printf("ccan/compiler\n"); 42 | return 0; 43 | } 44 | 45 | return 1; 46 | } 47 | -------------------------------------------------------------------------------- /ccan/ccan/crc32c/benchmark/Makefile: -------------------------------------------------------------------------------- 1 | CCANDIR=../../.. 2 | CFLAGS=-Wall -Werror -O3 -I$(CCANDIR) -flto 3 | #CFLAGS=-Wall -Werror -g3 -I$(CCANDIR) 4 | LDFLAGS := -flto -O3 5 | 6 | all: bench 7 | 8 | CCAN_OBJS:=ccan-tal.o ccan-tal-grab_file.o ccan-noerr.o ccan-take.o ccan-time.o 9 | 10 | bench: bench.o $(CCAN_OBJS) 11 | 12 | clean: 13 | rm -f bench *.o 14 | 15 | ccan-time.o: $(CCANDIR)/ccan/time/time.c 16 | $(CC) $(CFLAGS) -c -o $@ $< 17 | ccan-tal.o: $(CCANDIR)/ccan/tal/tal.c 18 | $(CC) $(CFLAGS) -c -o $@ $< 19 | ccan-take.o: $(CCANDIR)/ccan/take/take.c 20 | $(CC) $(CFLAGS) -c -o $@ $< 21 | ccan-noerr.o: $(CCANDIR)/ccan/noerr/noerr.c 22 | $(CC) $(CFLAGS) -c -o $@ $< 23 | ccan-tal-grab_file.o: $(CCANDIR)/ccan/tal/grab_file/grab_file.c 24 | $(CC) $(CFLAGS) -c -o $@ $< 25 | -------------------------------------------------------------------------------- /ccan/ccan/crc32c/benchmark/bench.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define RUNS 65536 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | void *p; 13 | struct timeabs start, end; 14 | size_t len, runs; 15 | uint64_t sums = 0; 16 | bool sw = false, hw = false; 17 | 18 | if (argv[1]) { 19 | if (streq(argv[1], "--software")) { 20 | sw = true; 21 | argv++; 22 | argc--; 23 | 24 | } else if (streq(argv[1], "--hardware")) { 25 | hw = true; 26 | argv++; 27 | argc--; 28 | } 29 | } 30 | 31 | if (argc < 2 || (runs = atol(argv[1])) == 0) 32 | errx(1, "Usage: bench []"); 33 | 34 | p = grab_file(NULL, argv[2]); 35 | if (!p) 36 | err(1, "Reading %s", argv[2] ? argv[2] : ""); 37 | len = tal_count(p) - 1; 38 | start = time_now(); 39 | if (sw) { 40 | for (size_t i = 0; i < runs; i++) 41 | sums += crc32c_sw(0, p, len); 42 | } else if (hw) { 43 | for (size_t i = 0; i < runs; i++) 44 | sums += crc32c_hw(0, p, len); 45 | } else { 46 | for (size_t i = 0; i < runs; i++) 47 | sums += crc32c(0, p, len); 48 | } 49 | end = time_now(); 50 | 51 | assert(sums % runs == 0); 52 | printf("%u usec for %zu bytes, sum=%08x\n", 53 | (int)time_to_usec(time_divide(time_between(end, start), runs)), 54 | len, 55 | (unsigned int)(sums / runs)); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /ccan/ccan/crc32c/crc32c.h: -------------------------------------------------------------------------------- 1 | /* Licensed under MIT - see LICENSE file for details */ 2 | #ifndef CCAN_CRC32C_H 3 | #define CCAN_CRC32C_H 4 | #include 5 | #include 6 | 7 | /** 8 | * crc32c - Castagnoli 32 bit crc of string of bytes 9 | * @start_crc: the initial crc (usually 0) 10 | * @buf: pointer to bytes 11 | * @size: length of buffer 12 | * 13 | * If you don't know what crc32 to use, use this one: it's the best. 14 | * 15 | * @Article{castagnoli-crc, 16 | * author = { Guy Castagnoli and Stefan Braeuer and Martin Herrman}, 17 | * title = {{Optimization of Cyclic Redundancy-Check Codes with 24 18 | * and 32 Parity Bits}}, 19 | * journal = IEEE Transactions on Communication, 20 | * year = {1993}, 21 | * volume = {41}, 22 | * number = {6}, 23 | * pages = {}, 24 | * month = {June}, 25 | *} 26 | * 32 bit CRC checksum using polynomial 27 | * X^32+X^28+X^27+X^26+X^25+X^23+X^22+X^20+X^19+X^18+X^14+X^13+X^11+X^10+X^9+X^8+X^6+X^0. 28 | * 29 | * You can calculate the CRC of non-contiguous arrays by passing @start_crc 30 | * as 0 the first time, and the current crc result from then on. 31 | * 32 | * Example: 33 | * #include 34 | * ... 35 | * // Check that iovec has the crc we expect (Castagnoli version) 36 | * static bool check_crc(uint32_t expected, const struct iovec *iov, int l) 37 | * { 38 | * uint32_t crc = 0; 39 | * while (l >= 0) { 40 | * crc = crc32c(crc, iov->iov_base, iov->iov_len); 41 | * iov++; 42 | * } 43 | * return crc == expected; 44 | * } 45 | */ 46 | uint32_t crc32c(uint32_t start_crc, const void *buf, size_t size); 47 | 48 | #endif /* CCAN_CRC32C_H */ 49 | -------------------------------------------------------------------------------- /ccan/ccan/crc32c/test/api-crc32c.c: -------------------------------------------------------------------------------- 1 | /* Test vectors from https://tools.ietf.org/html/rfc3720#appendix-B.4 */ 2 | #include 3 | #include 4 | #include 5 | 6 | #define BSWAP_32(val) \ 7 | ((((uint32_t)(val) & 0x000000ff) << 24) \ 8 | | (((uint32_t)(val) & 0x0000ff00) << 8) \ 9 | | (((uint32_t)(val) & 0x00ff0000) >> 8) \ 10 | | (((uint32_t)(val) & 0xff000000) >> 24)) 11 | 12 | #if HAVE_LITTLE_ENDIAN 13 | #define BE32_TO_CPU(le_val) BSWAP_32((uint32_t)le_val) 14 | #else 15 | #define BE32_TO_CPU(le_val) ((uint32_t)(le_val)) 16 | #endif 17 | 18 | int main(void) 19 | { 20 | unsigned char m[48]; 21 | 22 | plan_tests(5); 23 | 24 | /* 32 bytes of zeroes: 25 | 26 | Byte: 0 1 2 3 27 | 28 | 0: 00 00 00 00 29 | ... 30 | 28: 00 00 00 00 31 | 32 | CRC: aa 36 91 8a 33 | */ 34 | 35 | memset(m, 0, 32); 36 | ok1(crc32c(0, m, 32) == BE32_TO_CPU(0xaa36918a)); 37 | 38 | /* 32 bytes of ones: 39 | 40 | Byte: 0 1 2 3 41 | 42 | 0: ff ff ff ff 43 | ... 44 | 28: ff ff ff ff 45 | 46 | CRC: 43 ab a8 62 47 | */ 48 | memset(m, 0xff, 32); 49 | ok1(crc32c(0, m, 32) == BE32_TO_CPU(0x43aba862)); 50 | 51 | /* 32 bytes of incrementing 00..1f: 52 | 53 | Byte: 0 1 2 3 54 | 55 | 0: 00 01 02 03 56 | ... 57 | 28: 1c 1d 1e 1f 58 | 59 | CRC: 4e 79 dd 46 60 | */ 61 | for (size_t i = 0; i < 32; i++) 62 | m[i] = i; 63 | ok1(crc32c(0, m, 32) == BE32_TO_CPU(0x4e79dd46)); 64 | 65 | /* 32 bytes of decrementing 1f..00: 66 | 67 | Byte: 0 1 2 3 68 | 69 | 0: 1f 1e 1d 1c 70 | ... 71 | 28: 03 02 01 00 72 | 73 | CRC: 5c db 3f 11 74 | */ 75 | for (size_t i = 0; i < 32; i++) 76 | m[i] = 31 - i; 77 | ok1(crc32c(0, m, 32) == BE32_TO_CPU(0x5cdb3f11)); 78 | 79 | /* An iSCSI - SCSI Read (10) Command PDU 80 | Byte: 0 1 2 3 81 | 82 | 0: 01 c0 00 00 83 | 4: 00 00 00 00 84 | 8: 00 00 00 00 85 | 12: 00 00 00 00 86 | 16: 14 00 00 00 87 | 20: 00 00 04 00 88 | 24: 00 00 00 14 89 | 28: 00 00 00 18 90 | 32: 28 00 00 00 91 | 36: 00 00 00 00 92 | 40: 02 00 00 00 93 | 44: 00 00 00 00 94 | 95 | CRC: 56 3a 96 d9 96 | */ 97 | memset(m, 0, sizeof(m)); 98 | m[0] = 0x01; 99 | m[1] = 0xc0; 100 | m[16] = 0x14; 101 | m[22] = 0x04; 102 | m[27] = 0x14; 103 | m[31] = 0x18; 104 | m[32] = 0x28; 105 | m[40] = 0x02; 106 | ok1(crc32c(0, m, sizeof(m)) == BE32_TO_CPU(0x563a96d9)); 107 | 108 | return exit_status(); 109 | } 110 | -------------------------------------------------------------------------------- /ccan/ccan/crc32c/test/run-crc32c.c: -------------------------------------------------------------------------------- 1 | /* Test vectors from https://tools.ietf.org/html/rfc3720#appendix-B.4 */ 2 | 3 | /* Get access to sw version explicitly */ 4 | #include 5 | #include 6 | #include 7 | 8 | #define BSWAP_32(val) \ 9 | ((((uint32_t)(val) & 0x000000ff) << 24) \ 10 | | (((uint32_t)(val) & 0x0000ff00) << 8) \ 11 | | (((uint32_t)(val) & 0x00ff0000) >> 8) \ 12 | | (((uint32_t)(val) & 0xff000000) >> 24)) 13 | 14 | #if HAVE_LITTLE_ENDIAN 15 | #define BE32_TO_CPU(le_val) BSWAP_32((uint32_t)le_val) 16 | #else 17 | #define BE32_TO_CPU(le_val) ((uint32_t)(le_val)) 18 | #endif 19 | 20 | int main(void) 21 | { 22 | unsigned char m[48]; 23 | 24 | plan_tests(5); 25 | 26 | /* 32 bytes of zeroes: 27 | 28 | Byte: 0 1 2 3 29 | 30 | 0: 00 00 00 00 31 | ... 32 | 28: 00 00 00 00 33 | 34 | CRC: aa 36 91 8a 35 | */ 36 | 37 | memset(m, 0, 32); 38 | ok1(crc32c_sw(0, m, 32) == BE32_TO_CPU(0xaa36918a)); 39 | 40 | /* 32 bytes of ones: 41 | 42 | Byte: 0 1 2 3 43 | 44 | 0: ff ff ff ff 45 | ... 46 | 28: ff ff ff ff 47 | 48 | CRC: 43 ab a8 62 49 | */ 50 | memset(m, 0xff, 32); 51 | ok1(crc32c_sw(0, m, 32) == BE32_TO_CPU(0x43aba862)); 52 | 53 | /* 32 bytes of incrementing 00..1f: 54 | 55 | Byte: 0 1 2 3 56 | 57 | 0: 00 01 02 03 58 | ... 59 | 28: 1c 1d 1e 1f 60 | 61 | CRC: 4e 79 dd 46 62 | */ 63 | for (size_t i = 0; i < 32; i++) 64 | m[i] = i; 65 | ok1(crc32c_sw(0, m, 32) == BE32_TO_CPU(0x4e79dd46)); 66 | 67 | /* 32 bytes of decrementing 1f..00: 68 | 69 | Byte: 0 1 2 3 70 | 71 | 0: 1f 1e 1d 1c 72 | ... 73 | 28: 03 02 01 00 74 | 75 | CRC: 5c db 3f 11 76 | */ 77 | for (size_t i = 0; i < 32; i++) 78 | m[i] = 31 - i; 79 | ok1(crc32c_sw(0, m, 32) == BE32_TO_CPU(0x5cdb3f11)); 80 | 81 | /* An iSCSI - SCSI Read (10) Command PDU 82 | Byte: 0 1 2 3 83 | 84 | 0: 01 c0 00 00 85 | 4: 00 00 00 00 86 | 8: 00 00 00 00 87 | 12: 00 00 00 00 88 | 16: 14 00 00 00 89 | 20: 00 00 04 00 90 | 24: 00 00 00 14 91 | 28: 00 00 00 18 92 | 32: 28 00 00 00 93 | 36: 00 00 00 00 94 | 40: 02 00 00 00 95 | 44: 00 00 00 00 96 | 97 | CRC: 56 3a 96 d9 98 | */ 99 | memset(m, 0, sizeof(m)); 100 | m[0] = 0x01; 101 | m[1] = 0xc0; 102 | m[16] = 0x14; 103 | m[22] = 0x04; 104 | m[27] = 0x14; 105 | m[31] = 0x18; 106 | m[32] = 0x28; 107 | m[40] = 0x02; 108 | ok1(crc32c_sw(0, m, sizeof(m)) == BE32_TO_CPU(0x563a96d9)); 109 | 110 | return exit_status(); 111 | } 112 | -------------------------------------------------------------------------------- /config.mk: -------------------------------------------------------------------------------- 1 | TOPDIR ?= $(CURDIR) 2 | 3 | VER ?= $(shell awk '/Version/ {print $$2}' $(TOPDIR)/mhvtl-utils.spec) 4 | REL ?= $(shell awk -F'[ %]' '/Release/ {print $$2}' $(TOPDIR)/mhvtl-utils.spec) 5 | EXTRAVERSION ?= $(shell awk '/define minor/ {print $$3}' $(TOPDIR)/mhvtl-utils.spec) 6 | 7 | FIRMWAREDIR ?= $(shell awk '/^%.*_firmwarepath/ {print $$3}' $(TOPDIR)/mhvtl-utils.spec) 8 | 9 | GITHASH ?= $(if $(shell test -d $(TOPDIR)/.git && echo 1),commit:\ $(shell git show -s --format=%h)) 10 | GITDATE ?= $(if $(shell test -d $(TOPDIR)/.git && echo 1),$(shell git show -s --format=%aI)) 11 | 12 | VERSION ?= $(VER) 13 | 14 | PREFIX ?= /usr 15 | MANDIR ?= /share/man 16 | 17 | MHVTL_HOME_PATH ?= /opt/mhvtl 18 | MHVTL_CONFIG_PATH ?= /etc/mhvtl 19 | SYSTEMD_GENERATOR_DIR ?= /lib/systemd/system-generators 20 | SYSTEMD_SERVICE_DIR ?= /lib/systemd/system 21 | 22 | ifeq ($(shell whoami),root) 23 | ROOTUID = YES 24 | endif 25 | 26 | ifeq ($(shell grep lib64$ /etc/ld.so.conf /etc/ld.so.conf.d/* | wc -l),0) 27 | LIBDIR ?= $(PREFIX)/lib 28 | else 29 | LIBDIR ?= $(PREFIX)/lib64 30 | endif 31 | 32 | -include $(TOPDIR)/local.mk 33 | 34 | HOME_PATH = $(subst /,\/,$(MHVTL_HOME_PATH)) 35 | CONFIG_PATH = $(subst /,\/,$(MHVTL_CONFIG_PATH)) 36 | -------------------------------------------------------------------------------- /doc/4_library_example/library_contents.10: -------------------------------------------------------------------------------- 1 | VERSION: 2 2 | 3 | Drive 1: 4 | Drive 2: 5 | Drive 3: 6 | Drive 4: 7 | Drive 5: 8 | Drive 6: 9 | Drive 7: 10 | Drive 8: 11 | Drive 9: 12 | 13 | Picker 1: 14 | 15 | MAP 1: 16 | MAP 2: 17 | MAP 3: 18 | MAP 4: 19 | 20 | # Slot 1 - ?, no gaps 21 | # Slot N: [barcode] 22 | # [barcode] 23 | # a barcode is comprised of three fields: [Leading] [identifier] [Trailing] 24 | # Leading "CLN" -- cleaning tape 25 | # Leading "W" -- WORM tape 26 | # Leading "NOBAR" -- will appear to have no barcode 27 | # If the barcode is at least 8 character long, then the last two characters are 28 | Trailing 29 | # Trailing "S3" - SDLT600 30 | # Trailing "X4" - AIT-4 31 | # Trailing "L1" - LTO 1 32 | # Trailing "TA" - T10000+ 33 | # Trailing "JA" - 3592+ 34 | # Trailing "JB" - 3592E05+ 35 | # Trailing "JW" - WORM 3592+ 36 | # Trailing "JX" - WORM 3592E05+ 37 | # 38 | Slot 01: L10001S3 39 | Slot 02: L10002S3 40 | Slot 03: L10003S3 41 | Slot 04: L10004S3 42 | Slot 05: L10005S3 43 | Slot 06: L10006S3 44 | Slot 07: L10007S3 45 | Slot 08: L10008S3 46 | Slot 09: L10009S3 47 | Slot 10: L10010S3 48 | Slot 11: L10011S3 49 | Slot 12: L10012S3 50 | Slot 13: L10013S3 51 | Slot 14: L10014S3 52 | Slot 15: L10015S3 53 | Slot 16: L10016S3 54 | Slot 17: L10017S3 55 | Slot 18: L10018S3 56 | Slot 19: L10019S3 57 | Slot 20: L10020S3 58 | Slot 21: L10021S3 59 | Slot 22: L10022S3 60 | Slot 23: L10023S3 61 | Slot 24: L10024S3 62 | Slot 25: L10025S3 63 | Slot 26: L10026S3 64 | Slot 27: L10027S3 65 | Slot 28: L10028S3 66 | Slot 29: L10029S3 67 | Slot 30: L10030S3 68 | Slot 31: L10031S3 69 | Slot 32: L10032S3 70 | Slot 33: L10033S3 71 | Slot 34: L10034S3 72 | Slot 35: L10035S3 73 | Slot 36: L10036S3 74 | Slot 37: L10037S3 75 | Slot 38: L10038S3 76 | Slot 39: L10039S3 77 | Slot 40: L10040S3 78 | Slot 41: L10041S3 79 | Slot 42: L10042S3 80 | Slot 43: L10043S3 81 | Slot 44: L10044S3 82 | Slot 45: L10045S3 83 | Slot 46: L10046S3 84 | Slot 47: L10047S3 85 | Slot 48: L10048S3 86 | Slot 49: L10049S3 87 | Slot 50: L10050S3 88 | -------------------------------------------------------------------------------- /doc/4_library_example/library_contents.20: -------------------------------------------------------------------------------- 1 | VERSION: 2 2 | 3 | Drive 1: 4 | Drive 2: 5 | Drive 3: 6 | Drive 4: 7 | Drive 5: 8 | Drive 6: 9 | Drive 7: 10 | Drive 8: 11 | Drive 9: 12 | 13 | Picker 1: 14 | 15 | MAP 1: 16 | MAP 2: 17 | MAP 3: 18 | MAP 4: 19 | 20 | # Slot 1 - ?, no gaps 21 | # Slot N: [barcode] 22 | # [barcode] 23 | # a barcode is comprised of three fields: [Leading] [identifier] [Trailing] 24 | # Leading "CLN" -- cleaning tape 25 | # Leading "W" -- WORM tape 26 | # Leading "NOBAR" -- will appear to have no barcode 27 | # If the barcode is at least 8 character long, then the last two characters are 28 | Trailing 29 | # Trailing "S3" - SDLT600 30 | # Trailing "X4" - AIT-4 31 | # Trailing "L1" - LTO 1 32 | # Trailing "TA" - T10000+ 33 | # Trailing "JA" - 3592+ 34 | # Trailing "JB" - 3592E05+ 35 | # Trailing "JW" - WORM 3592+ 36 | # Trailing "JX" - WORM 3592E05+ 37 | # 38 | Slot 01: L20001S3 39 | Slot 02: L20002S3 40 | Slot 03: L20003S3 41 | Slot 04: L20004S3 42 | Slot 05: L20005S3 43 | Slot 06: L20006S3 44 | Slot 07: L20007S3 45 | Slot 08: L20008S3 46 | Slot 09: L20009S3 47 | Slot 10: L20010S3 48 | Slot 11: L20011S3 49 | Slot 12: L20012S3 50 | Slot 13: L20013S3 51 | Slot 14: L20014S3 52 | Slot 15: L20015S3 53 | Slot 16: L20016S3 54 | Slot 17: L20017S3 55 | Slot 18: L20018S3 56 | Slot 19: L20019S3 57 | Slot 20: L20020S3 58 | Slot 21: L20021S3 59 | Slot 22: L20022S3 60 | Slot 23: L20023S3 61 | Slot 24: L20024S3 62 | Slot 25: L20025S3 63 | Slot 26: L20026S3 64 | Slot 27: L20027S3 65 | Slot 28: L20028S3 66 | Slot 29: L20029S3 67 | Slot 30: L20030S3 68 | Slot 31: L20031S3 69 | Slot 32: L20032S3 70 | Slot 33: L20033S3 71 | Slot 34: L20034S3 72 | Slot 35: L20035S3 73 | Slot 36: L20036S3 74 | Slot 37: L20037S3 75 | Slot 38: L20038S3 76 | Slot 39: L20039S3 77 | Slot 40: L20040S3 78 | Slot 41: L20041S3 79 | Slot 42: L20042S3 80 | Slot 43: L20043S3 81 | Slot 44: L20044S3 82 | Slot 45: L20045S3 83 | Slot 46: L20046S3 84 | Slot 47: L20047S3 85 | Slot 48: L20048S3 86 | Slot 49: L20049S3 87 | Slot 50: L20050S3 88 | -------------------------------------------------------------------------------- /doc/4_library_example/library_contents.30: -------------------------------------------------------------------------------- 1 | VERSION: 2 2 | 3 | Drive 1: 4 | Drive 2: 5 | Drive 3: 6 | Drive 4: 7 | Drive 5: 8 | Drive 6: 9 | Drive 7: 10 | Drive 8: 11 | Drive 9: 12 | 13 | Picker 1: 14 | 15 | MAP 1: 16 | MAP 2: 17 | MAP 3: 18 | MAP 4: 19 | 20 | # Slot 1 - ?, no gaps 21 | # Slot N: [barcode] 22 | # [barcode] 23 | # a barcode is comprised of three fields: [Leading] [identifier] [Trailing] 24 | # Leading "CLN" -- cleaning tape 25 | # Leading "W" -- WORM tape 26 | # Leading "NOBAR" -- will appear to have no barcode 27 | # If the barcode is at least 8 character long, then the last two characters are 28 | Trailing 29 | # Trailing "S3" - SDLT600 30 | # Trailing "X4" - AIT-4 31 | # Trailing "L1" - LTO 1 32 | # Trailing "TA" - T10000+ 33 | # Trailing "JA" - 3592+ 34 | # Trailing "JB" - 3592E05+ 35 | # Trailing "JW" - WORM 3592+ 36 | # Trailing "JX" - WORM 3592E05+ 37 | # 38 | Slot 01: L30001S3 39 | Slot 02: L30002S3 40 | Slot 03: L30003S3 41 | Slot 04: L30004S3 42 | Slot 05: L30005S3 43 | Slot 06: L30006S3 44 | Slot 07: L30007S3 45 | Slot 08: L30008S3 46 | Slot 09: L30009S3 47 | Slot 10: L30010S3 48 | Slot 11: L30011S3 49 | Slot 12: L30012S3 50 | Slot 13: L30013S3 51 | Slot 14: L30014S3 52 | Slot 15: L30015S3 53 | Slot 16: L30016S3 54 | Slot 17: L30017S3 55 | Slot 18: L30018S3 56 | Slot 19: L30019S3 57 | Slot 20: L30020S3 58 | Slot 21: L30021S3 59 | Slot 22: L30022S3 60 | Slot 23: L30023S3 61 | Slot 24: L30024S3 62 | Slot 25: L30025S3 63 | Slot 26: L30026S3 64 | Slot 27: L30027S3 65 | Slot 28: L30028S3 66 | Slot 29: L30029S3 67 | Slot 30: L30030S3 68 | Slot 31: L30031S3 69 | Slot 32: L30032S3 70 | Slot 33: L30033S3 71 | Slot 34: L30034S3 72 | Slot 35: L30035S3 73 | Slot 36: L30036S3 74 | Slot 37: L30037S3 75 | Slot 38: L30038S3 76 | Slot 39: L30039S3 77 | Slot 40: L30040S3 78 | Slot 41: L30041S3 79 | Slot 42: L30042S3 80 | Slot 43: L30043S3 81 | Slot 44: L30044S3 82 | Slot 45: L30045S3 83 | Slot 46: L30046S3 84 | Slot 47: L30047S3 85 | Slot 48: L30048S3 86 | Slot 49: L30049S3 87 | Slot 50: L30050S3 88 | -------------------------------------------------------------------------------- /doc/4_library_example/library_contents.40: -------------------------------------------------------------------------------- 1 | VERSION: 2 2 | 3 | Drive 1: 4 | Drive 2: 5 | Drive 3: 6 | Drive 4: 7 | Drive 5: 8 | Drive 6: 9 | Drive 7: 10 | Drive 8: 11 | Drive 9: 12 | 13 | Picker 1: 14 | 15 | MAP 1: 16 | MAP 2: 17 | MAP 3: 18 | MAP 4: 19 | 20 | # Slot 1 - ?, no gaps 21 | # Slot N: [barcode] 22 | # [barcode] 23 | # a barcode is comprised of three fields: [Leading] [identifier] [Trailing] 24 | # Leading "CLN" -- cleaning tape 25 | # Leading "W" -- WORM tape 26 | # Leading "NOBAR" -- will appear to have no barcode 27 | # If the barcode is at least 8 character long, then the last two characters are 28 | Trailing 29 | # Trailing "S3" - SDLT600 30 | # Trailing "X4" - AIT-4 31 | # Trailing "L1" - LTO 1 32 | # Trailing "TA" - T10000+ 33 | # Trailing "JA" - 3592+ 34 | # Trailing "JB" - 3592E05+ 35 | # Trailing "JW" - WORM 3592+ 36 | # Trailing "JX" - WORM 3592E05+ 37 | # 38 | Slot 01: L40001S3 39 | Slot 02: L40002S3 40 | Slot 03: L40003S3 41 | Slot 04: L40004S3 42 | Slot 05: L40005S3 43 | Slot 06: L40006S3 44 | Slot 07: L40007S3 45 | Slot 08: L40008S3 46 | Slot 09: L40009S3 47 | Slot 10: L40010S3 48 | Slot 11: L40011S3 49 | Slot 12: L40012S3 50 | Slot 13: L40013S3 51 | Slot 14: L40014S3 52 | Slot 15: L40015S3 53 | Slot 16: L40016S3 54 | Slot 17: L40017S3 55 | Slot 18: L40018S3 56 | Slot 19: L40019S3 57 | Slot 20: L40020S3 58 | Slot 21: L40021S3 59 | Slot 22: L40022S3 60 | Slot 23: L40023S3 61 | Slot 24: L40024S3 62 | Slot 25: L40025S3 63 | Slot 26: L40026S3 64 | Slot 27: L40027S3 65 | Slot 28: L40028S3 66 | Slot 29: L40029S3 67 | Slot 30: L40030S3 68 | Slot 31: L40031S3 69 | Slot 32: L40032S3 70 | Slot 33: L40033S3 71 | Slot 34: L40034S3 72 | Slot 35: L40035S3 73 | Slot 36: L40036S3 74 | Slot 37: L40037S3 75 | Slot 38: L40038S3 76 | Slot 39: L40039S3 77 | Slot 40: L40040S3 78 | Slot 41: L40041S3 79 | Slot 42: L40042S3 80 | Slot 43: L40043S3 81 | Slot 44: L40044S3 82 | Slot 45: L40045S3 83 | Slot 46: L40046S3 84 | Slot 47: L40047S3 85 | Slot 48: L40048S3 86 | Slot 49: L40049S3 87 | Slot 50: L40050S3 88 | -------------------------------------------------------------------------------- /doc/4_library_example/mhvtl.conf: -------------------------------------------------------------------------------- 1 | 2 | # Home directory for config file(s) 3 | MHVTL_CONFIG_PATH=/etc/mhvtl 4 | 5 | # Default media capacity (5 G) 6 | CAPACITY=5000 7 | 8 | # Set default verbosity [0|1] 9 | VERBOSE=0 10 | 11 | # Set kernel module debugging [0|1] 12 | VTL_DEBUG=0 13 | -------------------------------------------------------------------------------- /etc/.gitignore: -------------------------------------------------------------------------------- 1 | mhvtl.conf 2 | device.conf 3 | library_contents.10 4 | library_contents.30 5 | vtllibrary@.service 6 | vtltape@.service 7 | mhvtl-load-modules.service 8 | generate_device_conf 9 | generate_library_contents 10 | -------------------------------------------------------------------------------- /etc/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # etc/Makefile 3 | # 4 | 5 | CURDIR = "../" 6 | include ../config.mk 7 | 8 | TAPE_SERVICE_FILE = vtltape@.service 9 | LIB_SERVICE_FILE = vtllibrary@.service 10 | MHVTL_TARGET_FILE = mhvtl.target 11 | MHVTL_LOAD_MODULES_SERVICE_FILE = mhvtl-load-modules.service 12 | MHVTL_CONF_FILE = mhvtl.conf 13 | DEVICE_CONF_FILE = device.conf 14 | LIB_CONTENTS_FILES = library_contents.10 library_contents.30 15 | 16 | GENERATE_DEVICE_CONF = generate_device_conf 17 | GENERATE_LIB_CONTENTS = generate_library_contents 18 | 19 | # files that need to be generated 20 | GENERATOR_FILES=$(MHVTL_CONF_FILE).in \ 21 | $(TAPE_SERVICE_FILE).in \ 22 | $(LIB_SERVICE_FILE).in \ 23 | $(MHVTL_LOAD_MODULES_SERVICE_FILE).in \ 24 | $(GENERATE_DEVICE_CONF).in \ 25 | $(GENERATE_LIB_CONTENTS).in 26 | GENERATED_FILES=$(GENERATOR_FILES:.in=) 27 | 28 | ALL_FILES = $(GENERATED_FILES) $(DEVICE_CONF_FILE) $(LIB_CONTENTS_FILES) 29 | 30 | all: $(ALL_FILES) 31 | 32 | %: %.in 33 | sed -e s'/@CONF_PATH@/$(CONFIG_PATH)/' \ 34 | -e s'/@HOME_PATH@/$(HOME_PATH)/' $< > $@ 35 | 36 | $(GENERATE_DEVICE_CONF): $(GENERATE_DEVICE_CONF).in 37 | sed -e s'/@CONF_PATH@/$(CONFIG_PATH)/' \ 38 | -e s'/@HOME_PATH@/$(HOME_PATH)/' $< > $@ 39 | chmod 755 $@ 40 | 41 | $(GENERATE_LIB_CONTENTS): $(GENERATE_LIB_CONTENTS).in 42 | sed -e s'/@CONF_PATH@/$(CONFIG_PATH)/' \ 43 | -e s'/@HOME_PATH@/$(HOME_PATH)/' $< > $@ 44 | chmod 755 $@ 45 | 46 | $(DEVICE_CONF_FILE): $(GENERATE_DEVICE_CONF) 47 | bash ./$(GENERATE_DEVICE_CONF) --force --home-dir=$(MHVTL_HOME_PATH) --override-home 48 | 49 | $(LIB_CONTENTS_FILES): $(GENERATE_LIB_CONTENTS) $(DEVICE_CONF_FILE) 50 | bash ./$(GENERATE_LIB_CONTENTS) --force --config=. 51 | 52 | .PHONY: distclean 53 | distclean: clean 54 | 55 | .PHONY: clean 56 | clean: 57 | $(RM) $(GENERATED_FILES) 58 | $(RM) $(DEVICE_CONF_FILE) $(LIB_CONTENTS_FILES) 59 | 60 | .PHONY: install 61 | install: all 62 | [ -d $(DESTDIR)$(SYSTEMD_SERVICE_DIR) ] || install -d -m 755 $(DESTDIR)$(SYSTEMD_SERVICE_DIR) 63 | install -m 644 $(LIB_SERVICE_FILE) $(DESTDIR)$(SYSTEMD_SERVICE_DIR) 64 | semanage fcontext -a -t systemd_unit_file_t \'$(DESTDIR)$(SYSTEMD_SERVICE_DIR)/$(LIB_SERVICE_FILE)\' 65 | install -m 644 $(TAPE_SERVICE_FILE) $(DESTDIR)$(SYSTEMD_SERVICE_DIR) 66 | semanage fcontext -a -t systemd_unit_file_t \'$(DESTDIR)$(SYSTEMD_SERVICE_DIR)/$(TAPE_SERVICE_FILE)\' 67 | install -m 644 $(MHVTL_TARGET_FILE) $(DESTDIR)$(SYSTEMD_SERVICE_DIR) 68 | semanage fcontext -a -t systemd_unit_file_t \'$(DESTDIR)$(SYSTEMD_SERVICE_DIR)/$(MHVTL_TARGET_FILE)\' 69 | install -m 644 $(MHVTL_LOAD_MODULES_SERVICE_FILE) $(DESTDIR)$(SYSTEMD_SERVICE_DIR) 70 | semanage fcontext -a -t systemd_unit_file_t \'$(DESTDIR)$(SYSTEMD_SERVICE_DIR)/$(MHVTL_LOAD_MODULES_SERVICE_FILE)\' 71 | restorecon -R -v $(DESTDIR)$(SYSTEMD_SERVICE_DIR) 72 | [ -d $(DESTDIR)$(MHVTL_CONFIG_PATH) ] || install -d -m 755 $(DESTDIR)$(MHVTL_CONFIG_PATH) 73 | install -m 755 $(GENERATE_DEVICE_CONF) $(DESTDIR)/usr/bin 74 | install -m 755 $(GENERATE_LIB_CONTENTS) $(DESTDIR)/usr/bin 75 | # save backup copies of config files 76 | install -m 644 -b -S .orig $(MHVTL_CONF_FILE) $(DESTDIR)$(MHVTL_CONFIG_PATH) 77 | install -m 644 -b -S .orig $(DEVICE_CONF_FILE) $(DESTDIR)$(MHVTL_CONFIG_PATH) 78 | install -m 644 -b -S .orig $(LIB_CONTENTS_FILES) $(DESTDIR)$(MHVTL_CONFIG_PATH) 79 | -------------------------------------------------------------------------------- /etc/generate_library_contents.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # generate_library_contents -- generate library_contents.* files 4 | # 5 | # This script generates the library_contents. (where 6 | # number defaults to 10 and 30) files in our configuration 7 | # directory. This is normally only done at installation time, 8 | # but having this script makes it possible for administrators/ 9 | # users to customize the configuration if desired. 10 | # 11 | 12 | DEVICE_CONF='device.conf' 13 | PROG_NAME="$0" 14 | FORCE='' 15 | MHVTL_CONFIG_PATH='@CONF_PATH@' 16 | DEST_DIR='.' 17 | 18 | usage() 19 | { 20 | echo "Usage: $PROG_NAME: [OPTIONS] -- generate" 'library_contents.*' "files from $DEVICE_CONF" 21 | echo "where OPTIONS are from:" 22 | echo " [-h|--help] -- print this message and exit" 23 | echo " [-C|--config-dir CONFIG_DIR] -- specificy config dir [default $MHVTL_CONFIG_PATH]" 24 | echo " [-D|--dest-dir DIRECTORY] -- specificy destination dir [default $DEST_DIR]" 25 | echo " [-f|--force] -- overwrite files if present" 26 | } 27 | 28 | create_library_file() 29 | { 30 | if (( $# != 1 )) ; then 31 | echo "create_library_file internal error: expected 1 argument, got $#" 1>&2 32 | exit 1 33 | fi 34 | 35 | LIBID=$1 36 | 37 | echo "VERSION: 2" 38 | echo "" 39 | 40 | # Count number of drives in this library 41 | DRV_COUNT=$(grep -c "Library ID: $LIBID" $MHVTL_CONFIG_PATH/$DEVICE_CONF) 42 | 43 | # Add a 'Drive X:' for each drive 44 | for a in $(seq 1 $DRV_COUNT) ; do 45 | printf "Drive %d:\n" $a 46 | done 47 | 48 | # create the static (non-changing, comment) part of the file 49 | cat <&2 160 | exit 1 161 | esac 162 | done 163 | 164 | # should be no more arguments 165 | if [[ $# -gt 0 ]] ; then 166 | echo "error: too many arguments" 1>&2 167 | usage 168 | exit 1 169 | fi 170 | 171 | if [[ ! -d $MHVTL_CONFIG_PATH ]] ; then 172 | echo "error: mhvtl config path not present: $MHVTL_CONFIG_PATH" 1>&2 173 | usage 174 | exit 1 175 | fi 176 | if [[ ! -r $MHVTL_CONFIG_PATH/$DEVICE_CONF ]] ; then 177 | echo "error: need device config file: $MHVTL_CONFIG_PATH/$DEVICE_CONF" 1>&2 178 | usage 179 | exit 1 180 | fi 181 | 182 | # get a list of our libraries 183 | LIB_ID_LIST=$(awk '/^Library:/ {print $2}' $MHVTL_CONFIG_PATH/$DEVICE_CONF) 184 | 185 | for id in $LIB_ID_LIST ; do 186 | ID_FILE="$DEST_DIR/library_contents.$id" 187 | 188 | if [[ -r $ID_FILE ]] ; then 189 | if [[ -z "$FORCE" ]] ; then 190 | echo "error: already exists: $ID_FILE" 1>&2 191 | exit 1 192 | fi 193 | fi 194 | echo '===>' "Generating: $ID_FILE ..." 195 | create_library_file $id > $ID_FILE 196 | done 197 | 198 | exit 0 199 | -------------------------------------------------------------------------------- /etc/library_contents.sample: -------------------------------------------------------------------------------- 1 | # Define how many tape drives you want in the vtl.. 2 | 3 | Drive 1: 4 | Drive 2: 5 | Drive 3: 6 | Drive 4: 7 | Drive 5: 8 | Drive 6: 9 | Drive 7: 10 | Drive 8: 11 | 12 | # Place holder for the robotic arm. Not really used. 13 | Picker 1: 14 | 15 | # Media Access Port 16 | # (mailslots, Cartridge Access Port, ) 17 | # Again, define how many MAPs this vtl will contain. 18 | MAP 1: 19 | MAP 2: 20 | MAP 3: 21 | MAP 4: 22 | 23 | # And the 'big' on, define your media and in which slot contains media. 24 | # When the rc script is started, all media listed here will be created 25 | # using the default media capacity. 26 | Slot 1: ULT001L1 27 | Slot 2: ULT002L1 28 | Slot 3: ULT003L1 29 | Slot 4: ULT004L1 30 | Slot 5: ULT005L1 31 | Slot 6: ULT006L1 32 | Slot 7: ULT007L1 33 | Slot 8: ULT008L1 34 | Slot 9: ULT009L1 35 | Slot 10: ULT010L1 36 | Slot 11: SDLT01L1 37 | Slot 12: SDLT02L1 38 | Slot 13: SDLT03L1 39 | Slot 14: SDLT04L1 40 | Slot 15: SDLT05L1 41 | Slot 16: SDLT06L1 42 | Slot 17: SDLT07L1 43 | Slot 18: SDLT08L1 44 | Slot 19: SDLT09L1 45 | Slot 20: SDLT10L1 46 | Slot 21: 47 | Slot 22: 48 | Slot 23: 49 | Slot 24: 50 | Slot 25: 51 | Slot 26: 52 | Slot 27: 53 | Slot 28: 54 | Slot 29: 55 | Slot 30: 56 | Slot 31: CLN001L1 57 | Slot 32: CLN002L1 58 | -------------------------------------------------------------------------------- /etc/mhvtl-load-modules.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Load mhvtl modules 3 | Documentation=man:man:vtltape(1) man:man:vtllibrary(1) 4 | Before=mhvtl.target 5 | PartOf=mhvtl.target 6 | Conflicts=shutdown.target 7 | Before=shutdown.target 8 | 9 | [Service] 10 | Type=oneshot 11 | RemainAfterExit=yes 12 | Environment=VTL_DEBUG="0" 13 | EnvironmentFile=-@CONF_PATH@/mhvtl.conf 14 | ExecStart=/sbin/modprobe mhvtl opts=${VTL_DEBUG} 15 | ExecStart=/sbin/modprobe sg 16 | 17 | [Install] 18 | WantedBy=mhvtl.target 19 | -------------------------------------------------------------------------------- /etc/mhvtl.conf.in: -------------------------------------------------------------------------------- 1 | # 2 | # mhvtl.conf 3 | # 4 | 5 | # Home directory for tape emulation files 6 | MHVTL_HOME_PATH=@HOME_PATH@ 7 | 8 | # Default media capacity (500 M) 9 | CAPACITY=500 10 | 11 | # Set default verbosity [0|1|2|3] 12 | VERBOSE=1 13 | 14 | # Set kernel module debugging [0|1] 15 | VTL_DEBUG=0 16 | 17 | # vtltape and vtllibrary debugging [Blank or -d] 18 | #DAEMON_DEBUG=-d 19 | -------------------------------------------------------------------------------- /etc/mhvtl.target: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=mhvtl service allowing to start/stop all vtltape@.service and vtllibrary@.service instances at once 3 | Documentation=man:man:vtltape(1) man:man:vtllibrary(1) 4 | 5 | [Install] 6 | WantedBy=multi-user.target 7 | -------------------------------------------------------------------------------- /etc/vtllibrary@.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Documentation=man:vtllibrary(1) man:vtlcmd(1) 3 | Description=Robot Library Daemon for Virtual Tape & Robot Library 4 | Before=mhvtl.target 5 | Requires=mhvtl-load-modules.service 6 | After=mhvtl-load-modules.service 7 | PartOf=mhvtl.target 8 | 9 | [Service] 10 | Type=simple 11 | Environment=VERBOSE=0 12 | Environment=DAEMON_DEBUG= 13 | EnvironmentFile=-@CONF_PATH@/mhvtl.conf 14 | ExecStart=/usr/bin/vtllibrary -F -q%i -v${VERBOSE} ${DAEMON_DEBUG} 15 | ExecStop=/usr/bin/vtlcmd %i exit 16 | KillMode=none 17 | ExecReload=/usr/bin/kill -HUP $MAINPID 18 | 19 | [Install] 20 | WantedBy=mhvtl.target 21 | -------------------------------------------------------------------------------- /etc/vtltape@.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Documentation=man:vtltape(1) man:vtlcmd(1) 3 | Description=Tape Daemon for Virtual Tape & Robot Library 4 | Before=mhvtl.target 5 | Requires=mhvtl-load-modules.service 6 | After=mhvtl-load-modules.service 7 | PartOf=mhvtl.target 8 | 9 | [Service] 10 | Type=simple 11 | Environment=VERBOSE=0 12 | Environment=DAEMON_DEBUG= 13 | EnvironmentFile=-@CONF_PATH@/mhvtl.conf 14 | ExecStart=/usr/bin/vtltape -F -q%i -v${VERBOSE} ${DAEMON_DEBUG} 15 | ExecStop=/usr/bin/vtlcmd %i exit 16 | KillMode=none 17 | 18 | [Install] 19 | WantedBy=mhvtl.target 20 | -------------------------------------------------------------------------------- /include/vtl_u.h: -------------------------------------------------------------------------------- 1 | /* 2 | * vtl_u.h 3 | */ 4 | #define NETLINK_VTL 22 5 | 6 | struct mhvtl_event { 7 | u32 tid; 8 | aligned_u64 sid; 9 | aligned_u64 serial_no; 10 | u32 cid; 11 | u32 state; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /kernel/.gitignore: -------------------------------------------------------------------------------- 1 | TAGS 2 | -------------------------------------------------------------------------------- /kernel/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # $Id: Makefile,v 1.2.2.3 2006-08-30 06:35:14 markh Exp $ 3 | # 4 | 5 | # CC=/usr/bin/gcc 6 | # 7 | EXTRA_CFLAGS += -I$(SRC)/../include 8 | EXTRA_CFLAGS += -DMHVTL_DEBUG 9 | 10 | obj-m := mhvtl.o 11 | vtl-objs := mhvtl.o 12 | 13 | V ?= $(shell uname -r) 14 | 15 | ifeq ($(KDIR),) 16 | ifneq ($(wildcard /lib/modules/$(V)/build),) 17 | KDIR := /lib/modules/$(V)/build 18 | else 19 | ifneq ($(wildcard /usr/src/linux-headers-$(V)),) 20 | KDIR := /usr/src/linux-headers-$(V) 21 | endif 22 | endif 23 | endif 24 | 25 | export KDIR 26 | 27 | PWD := $(shell pwd) 28 | 29 | default: config.h 30 | $(MAKE) -C $(KDIR) M=$(PWD) modules 31 | 32 | config.h: config.sh 33 | ./config.sh 34 | 35 | clean: 36 | $(RM) mhvtl.ko 37 | $(RM) *.o 38 | $(RM) TAGS 39 | $(RM) config.h 40 | 41 | distclean: clean 42 | $(RM) .*.o.d \ 43 | mhvtl.mod.c \ 44 | Modules.symvers \ 45 | Module.symvers \ 46 | .mhvtl.ko.cmd \ 47 | .mhvtl.o.cmd \ 48 | .mhvtl.mod.o.cmd \ 49 | .event.o.cmd \ 50 | .event.o.d \ 51 | .Module.symvers.cmd \ 52 | .mhvtl.mod.cmd \ 53 | .modules.order.cmd \ 54 | mhvtl.mod \ 55 | Module.markers \ 56 | modules.order \ 57 | mhvtl.ko.unsigned \ 58 | .mhvtl.ko.unsigned.cmd \ 59 | config.h 60 | $(RM) -r .tmp_versions 61 | 62 | install: 63 | install -o root -g root -m 644 mhvtl.ko /lib/modules/$(V)/kernel/drivers/scsi/; \ 64 | depmod -a; \ 65 | if [ -f "/etc/modprobe.d/unsupported-modules" ]; then \ 66 | sed -i 's/^allow_unsupported_modules 0/allow_unsupported_modules 1/' /etc/modprobe.d/unsupported-modules; \ 67 | fi 68 | 69 | install-bkup: 70 | cp mhvtl.ko ~/mhvtl-$(V)_`uname -m`.ko 71 | 72 | tags: 73 | ctags -R * 74 | -------------------------------------------------------------------------------- /kernel/backport.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Include wrappers for older kernels as interfaces change 3 | */ 4 | 5 | #include "config.h" 6 | 7 | #ifndef SG_SEGMENT_SZ 8 | #define SG_SEGMENT_SZ 65536 9 | #endif 10 | 11 | #ifndef slab_flags_t 12 | typedef unsigned __bitwise slab_flags_t; 13 | #endif 14 | 15 | /* 16 | * Copied kmem_cache_create_usercopy() from scst project 17 | */ 18 | #if !defined(HAVE_KMEM_CACHE_CREATE_USERCOPY) 19 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) 20 | static inline struct kmem_cache *kmem_cache_create_usercopy(const char *name, 21 | unsigned int size, unsigned int align, 22 | slab_flags_t flags, 23 | unsigned int useroffset, unsigned int usersize, 24 | void (*ctor)(void *)) 25 | { 26 | return kmem_cache_create(name, size, align, flags, ctor, NULL); 27 | } 28 | #elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0) 29 | static inline struct kmem_cache *kmem_cache_create_usercopy(const char *name, 30 | unsigned int size, unsigned int align, 31 | slab_flags_t flags, 32 | unsigned int useroffset, unsigned int usersize, 33 | void (*ctor)(void *)) 34 | { 35 | return kmem_cache_create(name, size, align, flags, ctor); 36 | } 37 | #endif 38 | #endif 39 | 40 | #if !defined(HAVE_FILE_INODE) 41 | /* 42 | * See also patch "new helper: file_inode(file)" (commit ID 43 | * 496ad9aa8ef448058e36ca7a787c61f2e63f0f54). 44 | */ 45 | static inline struct inode *file_inode(struct file *f) 46 | { 47 | return f->f_path.dentry->d_inode; 48 | } 49 | #endif 50 | 51 | #if !defined(HAVE_SYSFS_EMIT) 52 | /* https://patches.linaro.org/project/stable/patch/20210305120853.392925382@linuxfoundation.org/ */ 53 | /** 54 | * sysfs_emit - scnprintf equivalent, aware of PAGE_SIZE buffer. 55 | * @buf: start of PAGE_SIZE buffer. 56 | * @fmt: format 57 | * @...: optional arguments to @format 58 | * 59 | * 60 | * Returns number of characters written to @buf. 61 | */ 62 | static int sysfs_emit(char *buf, const char *fmt, ...) 63 | { 64 | va_list args; 65 | int len; 66 | 67 | if (WARN(!buf || offset_in_page(buf), 68 | "invalid sysfs_emit: buf:%p\n", buf)) 69 | return 0; 70 | 71 | va_start(args, fmt); 72 | len = vscnprintf(buf, PAGE_SIZE, fmt, args); 73 | va_end(args); 74 | 75 | return len; 76 | } 77 | #endif 78 | -------------------------------------------------------------------------------- /kernel/config.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # vim: tabstop=4 shiftwidth=4 expandtab colorcolumn=80 foldmethod=marker : 3 | 4 | # uncomment the next line to enable script debugging 5 | # set -x 6 | 7 | # make sure we have the kernel directory defined 8 | if [ -z "${KDIR}" ] ; then 9 | echo "error: you must supply environment variable KDIR" 1>&2 10 | echo " or you do not have the kernel-devel installed" 1>&2 11 | exit 1 12 | fi 13 | 14 | # 15 | # "syms" is an associative array, where the "key" 16 | # is a symbol that we try to find (using grep) in 17 | # the "value", i.e. we try to find the string 18 | # "sysfs_emit" in the include file sysfs.h. Based 19 | # on that, we create a cpp #define or #undef. 20 | # 21 | declare -A syms 22 | syms[kmem_cache_create_usercopy]='slab.h' 23 | syms[file_inode]='fs.h' 24 | syms[sysfs_emit]='sysfs.h' 25 | 26 | output='config.h' 27 | kparent="${KDIR%/*}" 28 | 29 | # 30 | # use the "fs.h" to determine where the kernel headers are located 31 | # 32 | if [ -e "${KDIR}/include/linux/fs.h" ] 33 | then 34 | hdrs="${KDIR}/include" 35 | elif [ -e "${kparent}/source/include/linux/fs.h" ] 36 | then 37 | hdrs="${kparent}/source/include" 38 | else 39 | echo "Cannot infer kernel headers location" 1>&2 40 | exit 1 41 | fi 42 | 43 | rm -f "${output}" 44 | 45 | cat <"${output}" 46 | /* Autogenerated by kernel/config.sh - do not edit 47 | */ 48 | 49 | #ifndef _MHVTL_KERNEL_CONFIG_H 50 | #define _MHVTL_KERNEL_CONFIG_H 51 | 52 | 53 | EOF 54 | 55 | # 56 | # start checking for compatability issues 57 | # 58 | 59 | # 60 | # first, check the symbols in our associative array 61 | # 62 | for sym in ${!syms[@]} 63 | do 64 | grep -q "${sym}" "${hdrs}/linux/${syms[$sym]}" 65 | if [ $? -eq 0 ] 66 | then 67 | printf '#define HAVE_%s\n' \ 68 | "$( echo "${sym}" | tr [:lower:] [:upper:] )" >> "${output}" 69 | else 70 | printf '#undef HAVE_%s\n' \ 71 | "$( echo "${sym}" | tr [:lower:] [:upper:] )" >> "${output}" 72 | fi 73 | done 74 | 75 | # 76 | # do we have a "genhd.h" present? 77 | # 78 | if [ -e "${hdrs}/linux/genhd.h" ]; then 79 | echo "#define HAVE_GENHD" 80 | else 81 | echo "#undef HAVE_GENHD" 82 | fi >> "${output}" 83 | 84 | # 85 | # see if "struct file_operations" has member "unlocked_ioctl" 86 | # (otherwise, just "ioctl") 87 | # 88 | syms[file_operations]='fs.h' 89 | if grep -q unlocked_ioctl "${hdrs}/linux/fs.h"; then 90 | echo "#ifndef HAVE_UNLOCKED_IOCTL" 91 | echo "#define HAVE_UNLOCKED_IOCTL" 92 | echo "#endif" 93 | else 94 | echo "#undef HAVE_UNLOCKED_IOCTL" 95 | fi >> "${output}" 96 | 97 | # 98 | # check for the scsi queue command taking one or two args 99 | # 100 | str=$( grep 'rc = func_name##_lck' ${hdrs}/scsi/scsi_host.h ) 101 | if [[ "$str" == *,* ]] ; then 102 | echo "#undef QUEUECOMMAND_LCK_ONE_ARG" 103 | else 104 | echo "#ifndef QUEUECOMMAND_LCK_ONE_ARG" 105 | echo "#define QUEUECOMMAND_LCK_ONE_ARG" 106 | echo "#endif" 107 | fi >> "${output}" 108 | 109 | # 110 | # check for DEFINE_SEMAPHORE() taking an argument or not 111 | # 112 | if grep -q 'DEFINE_SEMAPHORE(_name, _n)' "${hdrs}/linux/semaphore.h"; then 113 | echo "#ifndef DEFINE_SEMAPHORE_HAS_NUMERIC_ARG" 114 | echo "#define DEFINE_SEMAPHORE_HAS_NUMERIC_ARG" 115 | echo "#endif" 116 | else 117 | echo "#undef DEFINE_SEMAPHORE_HAS_NUMERIC_ARG" 118 | fi >> "${output}" 119 | 120 | # 121 | # check if scsi_host_template argument to scsi_host_alloc 122 | # is const 123 | # 124 | if grep -F -q 'extern struct Scsi_Host *scsi_host_alloc(const' \ 125 | "${hdrs}/scsi/scsi_host.h"; then 126 | # the first argument to scsi_host_alloc needs to be a "const" 127 | echo "#ifndef DEFINE_CONST_STRUCT_SCSI_HOST_TEMPLATE" 128 | echo "#define DEFINE_CONST_STRUCT_SCSI_HOST_TEMPLATE" 129 | echo "#endif" 130 | else 131 | echo "#undef DEFINE_CONST_STRUCT_SCSI_HOST_TEMPLATE" 132 | fi >> "${output}" 133 | 134 | # 135 | # We need to find the definition for "struct bus_type", so that we 136 | # can if the "match" member of this struct, which points to a function, 137 | # has a 2nd argument that is const or not. 138 | # 139 | 140 | # The pattern to find (if "const" is needed) 141 | pat='int (*match)(struct device *dev, const struct device_driver *drv);' 142 | 143 | # First, find the file 144 | bus_type_def_file=$(grep -rl 'struct bus_type {' ${hdrs}) 145 | : {bus_type_def_file:="not-found"} 146 | 147 | # Now check for the 2nd argument needs a "const" 148 | if [ -r "$bus_type_def_file" ] && 149 | grep -F -q "$pat" "$bus_type_def_file"; then 150 | # the second argument needs a "const" definition 151 | echo "#ifndef DEFINE_CONST_STRUCT_DEVICE_DRIVER" 152 | echo "#define DEFINE_CONST_STRUCT_DEVICE_DRIVER" 153 | echo "#endif" 154 | else 155 | echo "#undef DEFINE_CONST_STRUCT_DEVICE_DRIVER" 156 | fi >> "${output}" 157 | 158 | # 159 | # check if slave_configure has been renamed to sdev_configure 160 | # 161 | pat='int (* sdev_configure)(struct scsi_device *, struct queue_limits *lim);' 162 | if grep -F -q "$pat" "${hdrs}/scsi/scsi_host.h"; then 163 | echo "#ifndef DEFINE_QUEUE_LIMITS_SCSI_DEV_CONFIGURE" 164 | echo "#define DEFINE_QUEUE_LIMITS_SCSI_DEV_CONFIGURE" 165 | echo "#endif" 166 | else 167 | echo "#undef DEFINE_QUEUE_LIMITS_SCSI_DEV_CONFIGURE" 168 | fi >> "${output}" 169 | 170 | # 171 | # check if del_timer_sync() has been renamed to timer_delete() 172 | # 173 | if grep -F -q 'int timer_delete_sync(' "${hdrs}/linux/timer.h"; then 174 | echo "#ifndef USE_TIMER_DELETE_NOT_DEL_TIMER" 175 | echo "#define USE_TIMER_DELETE_NOT_DEL_TIMER" 176 | echo "#endif" 177 | else 178 | echo "#undef USE_TIMER_DELETE_NOT_DEL_TIMER" 179 | fi >> "${output}" 180 | 181 | printf '\n\n#endif /* _MHVTL_KERNEL_CONFIG_H */\n' >> "${output}" 182 | -------------------------------------------------------------------------------- /kernel/fetch.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copy data from SCSI command buffer to device buffer 4 | * (SCSI command buffer -> user space) 5 | * 6 | * Returns number of bytes fetched into 'arr'/FIFO or -1 if error. 7 | */ 8 | static int mhvtl_fetch_to_dev_buffer(struct scsi_cmnd *scp, char __user *arr, 9 | int max_arr_len) 10 | { 11 | int k, req_len, act_len, len, active; 12 | int retval; 13 | void *kaddr; 14 | void *kaddr_off; 15 | struct scatterlist *sg; 16 | 17 | if (0 == scp->request_bufflen) 18 | return 0; 19 | if (NULL == scp->request_buffer) 20 | return -1; 21 | if (NULL == arr) { 22 | pr_crit("%s, userspace pointer is NULL\n", __func__); 23 | WARN_ON(1); 24 | } 25 | 26 | if (!((scp->sc_data_direction == DMA_BIDIRECTIONAL) || 27 | (scp->sc_data_direction == DMA_TO_DEVICE))) 28 | return -1; 29 | if (0 == scp->use_sg) { 30 | req_len = scp->request_bufflen; 31 | act_len = (req_len < max_arr_len) ? req_len : max_arr_len; 32 | if (copy_to_user(arr, scp->request_buffer, act_len)) 33 | return -1; 34 | return act_len; 35 | } 36 | sg = (struct scatterlist *)scp->request_buffer; 37 | for (k = 0, req_len = 0, active = 0; k < scp->use_sg; ++k, ++sg) { 38 | kaddr = (unsigned char *)kmap(sg->page); 39 | if (NULL == kaddr) 40 | return -1; 41 | kaddr_off = (unsigned char *)kaddr + sg->offset; 42 | len = sg->length; 43 | if ((req_len + len) > max_arr_len) { 44 | len = max_arr_len - req_len; 45 | active = 1; 46 | } 47 | retval = copy_to_user(arr + req_len, kaddr_off, len); 48 | kunmap(sg->page); 49 | if (retval) { 50 | pr_err("mhvtl: %s[%d] failed to copy_to_user()\n", 51 | __func__, __LINE__); 52 | return -1; 53 | } 54 | if (active) 55 | return req_len + len; 56 | req_len += sg->length; 57 | } 58 | return req_len; 59 | } 60 | 61 | /* 62 | * fill_from_user_buffer : Retrieves data from user-space into SCSI 63 | * buffer(s) 64 | 65 | Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . 66 | */ 67 | static int mhvtl_fill_from_user_buffer(struct scsi_cmnd *scp, char __user *arr, 68 | int arr_len) 69 | { 70 | int k, req_len, act_len, len, active; 71 | int retval; 72 | void *kaddr; 73 | void *kaddr_off; 74 | struct scatterlist *sg; 75 | 76 | if (0 == scp->request_bufflen) 77 | return 0; 78 | if (NULL == scp->request_buffer) 79 | return DID_ERROR << 16; 80 | if (!((scp->sc_data_direction == DMA_BIDIRECTIONAL) || 81 | (scp->sc_data_direction == DMA_FROM_DEVICE))) 82 | return DID_ERROR << 16; 83 | if (0 == scp->use_sg) { 84 | req_len = scp->request_bufflen; 85 | act_len = (req_len < arr_len) ? req_len : arr_len; 86 | if (copy_from_user(scp->request_buffer, arr, act_len)) 87 | pr_err("%s[%d]: failed to copy_from_user()\n", 88 | __func__, __LINE__); 89 | 90 | scp->resid = req_len - act_len; 91 | return 0; 92 | } 93 | active = 1; 94 | sg = (struct scatterlist *)scp->request_buffer; 95 | for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sg) { 96 | if (active) { 97 | kaddr = (unsigned char *)kmap(sg->page); 98 | if (NULL == kaddr) 99 | return DID_ERROR << 16; 100 | kaddr_off = (unsigned char *)kaddr + sg->offset; 101 | len = sg->length; 102 | if ((req_len + len) > arr_len) { 103 | active = 0; 104 | len = arr_len - req_len; 105 | } 106 | retval = copy_from_user(kaddr_off, arr + req_len, len); 107 | kunmap(sg->page); 108 | if (retval) { 109 | pr_err("mhvtl: %s[%d] failed to copy_from_user()\n", 110 | __func__, __LINE__); 111 | return -1; 112 | } 113 | act_len += len; 114 | } 115 | req_len += sg->length; 116 | } 117 | scp->resid = req_len - act_len; 118 | 119 | return 0; 120 | } 121 | 122 | /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 123 | static int mhvtl_fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 124 | int arr_len) 125 | { 126 | int k, req_len, act_len, len, active; 127 | void *kaddr; 128 | void *kaddr_off; 129 | struct scatterlist *sg; 130 | 131 | if (0 == scp->request_bufflen) 132 | return 0; 133 | if (NULL == scp->request_buffer) 134 | return DID_ERROR << 16; 135 | if (!((scp->sc_data_direction == DMA_BIDIRECTIONAL) || 136 | (scp->sc_data_direction == DMA_FROM_DEVICE))) 137 | return DID_ERROR << 16; 138 | if (0 == scp->use_sg) { 139 | req_len = scp->request_bufflen; 140 | act_len = (req_len < arr_len) ? req_len : arr_len; 141 | memcpy(scp->request_buffer, arr, act_len); 142 | scp->resid = req_len - act_len; 143 | return 0; 144 | } 145 | active = 1; 146 | sg = (struct scatterlist *)scp->request_buffer; 147 | for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sg) { 148 | if (active) { 149 | kaddr = (unsigned char *) 150 | kmap_atomic(sg->page, KM_USER0); 151 | if (NULL == kaddr) 152 | return DID_ERROR << 16; 153 | kaddr_off = (unsigned char *)kaddr + sg->offset; 154 | len = sg->length; 155 | if ((req_len + len) > arr_len) { 156 | active = 0; 157 | len = arr_len - req_len; 158 | } 159 | memcpy(kaddr_off, arr + req_len, len); 160 | kunmap_atomic(kaddr, KM_USER0); 161 | act_len += len; 162 | } 163 | req_len += sg->length; 164 | } 165 | scp->resid = req_len - act_len; 166 | 167 | return 0; 168 | } 169 | 170 | -------------------------------------------------------------------------------- /kernel/fetch24.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copy data from SCSI command buffer to device buffer 4 | * (SCSI command buffer -> user space) 5 | * 6 | * Returns number of bytes fetched into 'arr'/FIFO or -1 if error. 7 | */ 8 | static int mhvtl_fetch_to_dev_buffer(struct scsi_cmnd *scp, char __user *arr, 9 | int max_arr_len) 10 | { 11 | int k, req_len, act_len, len, active; 12 | int retval; 13 | void *kaddr; 14 | void *kaddr_off; 15 | struct scatterlist *sg; 16 | 17 | if (0 == scp->request_bufflen) 18 | return 0; 19 | if (NULL == scp->request_buffer) 20 | return -1; 21 | if (NULL == arr) { 22 | pr_err("%s, userspace pointer is NULL\n", __func__); 23 | WARN_ON(1); 24 | } 25 | 26 | if (!((scp->sc_data_direction == DMA_BIDIRECTIONAL) || 27 | (scp->sc_data_direction == DMA_TO_DEVICE))) 28 | return -1; 29 | if (0 == scp->use_sg) { 30 | req_len = scp->request_bufflen; 31 | act_len = (req_len < max_arr_len) ? req_len : max_arr_len; 32 | if (copy_to_user(arr, scp->request_buffer, act_len)) 33 | return -1; 34 | return act_len; 35 | } 36 | active = 1; 37 | req_len = 0; 38 | act_len = 0; 39 | scsi_for_each_sg(scp, sg, scp->use_sg, k) { 40 | if (active) { 41 | kaddr = (unsigned char *)kmap(sg_page(sg)); 42 | if (NULL == kaddr) 43 | return DID_ERROR << 16; 44 | kaddr_off = (unsigned char *)kaddr + sg->offset; 45 | len = sg->length; 46 | if ((req_len + len) > max_arr_len) { 47 | active = 0; 48 | len = max_arr_len - req_len; 49 | } 50 | retval = copy_to_user(arr + act_len, kaddr_off, len); 51 | kunmap(sg_page(sg)); 52 | if (retval) { 53 | pr_err("mhvtl: %s[%d] failed to " 54 | "copy_to_user()\n", 55 | __func__, __LINE__); 56 | return -1; 57 | } 58 | act_len += len; 59 | } 60 | req_len += sg->length; 61 | } 62 | if (scp->resid) 63 | scp->resid -= act_len; 64 | else 65 | scp->resid = req_len - act_len; 66 | return 0; 67 | } 68 | 69 | /* 70 | * fill_from_user_buffer : Retrieves data from user-space into SCSI 71 | * buffer(s) 72 | 73 | Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . 74 | */ 75 | static int mhvtl_fill_from_user_buffer(struct scsi_cmnd *scp, char __user *arr, 76 | int arr_len) 77 | { 78 | int k, req_len, act_len, len, active; 79 | int retval; 80 | void *kaddr; 81 | void *kaddr_off; 82 | struct scatterlist *sg; 83 | 84 | if (0 == scp->request_bufflen) 85 | return 0; 86 | if (NULL == scp->request_buffer) 87 | return DID_ERROR << 16; 88 | if (!((scp->sc_data_direction == DMA_BIDIRECTIONAL) || 89 | (scp->sc_data_direction == DMA_FROM_DEVICE))) 90 | return DID_ERROR << 16; 91 | if (0 == scp->use_sg) { 92 | req_len = scp->request_bufflen; 93 | act_len = (req_len < arr_len) ? req_len : arr_len; 94 | if (copy_from_user(scp->request_buffer, arr, act_len)) 95 | pr_err("%s[%d]: failed to copy_from_user()\n", 96 | __func__, __LINE__); 97 | 98 | scp->resid = req_len - act_len; 99 | return 0; 100 | } 101 | active = 1; 102 | req_len = 0; 103 | act_len = 0; 104 | scsi_for_each_sg(scp, sg, scp->use_sg, k) { 105 | if (active) { 106 | kaddr = (unsigned char *)kmap(sg_page(sg)); 107 | if (NULL == kaddr) 108 | return DID_ERROR << 16; 109 | kaddr_off = (unsigned char *)kaddr + sg->offset; 110 | len = sg->length; 111 | if ((req_len + len) > arr_len) { 112 | active = 0; 113 | len = arr_len - req_len; 114 | } 115 | retval = copy_from_user(kaddr_off, arr + req_len, len); 116 | kunmap(sg_page(sg)); 117 | if (retval) { 118 | pr_err("mhvtl: %s[%d] failed to copy_from_user()\n", 119 | __func__, __LINE__); 120 | return -1; 121 | } 122 | act_len += len; 123 | } 124 | req_len += sg->length; 125 | } 126 | if (scp->resid) 127 | scp->resid -= act_len; 128 | else 129 | scp->resid = req_len - act_len; 130 | 131 | return 0; 132 | } 133 | 134 | /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 135 | static int mhvtl_fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 136 | int arr_len) 137 | { 138 | int k, req_len, act_len, len, active; 139 | void *kaddr; 140 | void *kaddr_off; 141 | struct scatterlist *sg; 142 | 143 | if (0 == scp->request_bufflen) 144 | return 0; 145 | if (NULL == scp->request_buffer) 146 | return DID_ERROR << 16; 147 | if (!((scp->sc_data_direction == DMA_BIDIRECTIONAL) || 148 | (scp->sc_data_direction == DMA_FROM_DEVICE))) 149 | return DID_ERROR << 16; 150 | if (0 == scp->use_sg) { 151 | req_len = scp->request_bufflen; 152 | act_len = (req_len < arr_len) ? req_len : arr_len; 153 | memcpy(scp->request_buffer, arr, act_len); 154 | scp->resid = req_len - act_len; 155 | return 0; 156 | } 157 | active = 1; 158 | req_len = act_len = 0; 159 | scsi_for_each_sg(scp, sg, scp->use_sg, k) { 160 | if (active) { 161 | kaddr = (unsigned char *) 162 | kmap_atomic(sg_page(sg), KM_USER0); 163 | if (NULL == kaddr) 164 | return DID_ERROR << 16; 165 | kaddr_off = (unsigned char *)kaddr + sg->offset; 166 | len = sg->length; 167 | if ((req_len + len) > arr_len) { 168 | active = 0; 169 | len = arr_len - req_len; 170 | } 171 | memcpy(kaddr_off, arr + req_len, len); 172 | kunmap_atomic(kaddr, KM_USER0); 173 | act_len += len; 174 | } 175 | req_len += sg->length; 176 | } 177 | if (scp->resid) 178 | scp->resid -= act_len; 179 | else 180 | scp->resid = req_len - act_len; 181 | 182 | return 0; 183 | } 184 | 185 | -------------------------------------------------------------------------------- /kernel/fetch26.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Routines based on linux/lib/scatterlist.c 4 | */ 5 | 6 | /** 7 | * sg_copy_buffer - Copy data between a linear buffer and an SG list 8 | * @sgl: The SG list 9 | * @nents: Number of SG entries 10 | * @buf: Where to copy from 11 | * @buflen: The number of bytes to copy 12 | * @to_buffer: transfer direction (non zero == from an sg list to a 13 | * buffer, 0 == from a buffer to an sg list 14 | * 15 | * Returns the number of copied bytes. 16 | * 17 | **/ 18 | static size_t mhvtl_sg_copy_user(struct scatterlist *sgl, unsigned int nents, 19 | __user void *buf, size_t buflen, int to_buffer) 20 | { 21 | struct scatterlist *sg; 22 | size_t buf_off = 0; 23 | int i; 24 | int ret; 25 | 26 | for_each_sg(sgl, sg, nents, i) { 27 | struct page *page; 28 | int n = 0; 29 | unsigned int sg_off = sg->offset; 30 | unsigned int sg_copy = sg->length; 31 | 32 | if (sg_copy > buflen) 33 | sg_copy = buflen; 34 | buflen -= sg_copy; 35 | 36 | while (sg_copy > 0) { 37 | unsigned int page_copy; 38 | void *p; 39 | 40 | page_copy = PAGE_SIZE - sg_off; 41 | if (page_copy > sg_copy) 42 | page_copy = sg_copy; 43 | 44 | page = nth_page(sg_page(sg), n); 45 | p = kmap_atomic(page, KM_BIO_SRC_IRQ); 46 | 47 | if (to_buffer) 48 | ret = copy_to_user(buf + buf_off, p + sg_off, page_copy); 49 | else { 50 | ret = copy_from_user(p + sg_off, buf + buf_off, page_copy); 51 | flush_kernel_dcache_page(page); 52 | } 53 | 54 | kunmap_atomic(p, KM_BIO_SRC_IRQ); 55 | 56 | buf_off += page_copy; 57 | sg_off += page_copy; 58 | if (sg_off == PAGE_SIZE) { 59 | sg_off = 0; 60 | n++; 61 | } 62 | sg_copy -= page_copy; 63 | } 64 | 65 | if (!buflen) 66 | break; 67 | } 68 | 69 | return buf_off; 70 | } 71 | 72 | size_t mhvtl_copy_from_user(struct scatterlist *sgl, unsigned int nents, 73 | char __user *buf, size_t buflen) 74 | { 75 | return mhvtl_sg_copy_user(sgl, nents, buf, buflen, 0); 76 | } 77 | 78 | size_t mhvtl_copy_to_user(struct scatterlist *sgl, unsigned int nents, 79 | char __user *buf, size_t buflen) 80 | { 81 | return mhvtl_sg_copy_user(sgl, nents, buf, buflen, 1); 82 | } 83 | 84 | /* 85 | * Copy data from SCSI command buffer to device buffer 86 | * (SCSI command buffer -> user space) 87 | * 88 | * Returns number of bytes fetched into 'arr' or -1 if error. 89 | */ 90 | static int mhvtl_fetch_to_dev_buffer(struct scsi_cmnd *scp, char __user *arr, int len) 91 | { 92 | struct scsi_data_buffer *sdb = scsi_out(scp); 93 | 94 | if (!scsi_bufflen(scp)) 95 | return 0; 96 | if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 97 | return -1; 98 | 99 | return mhvtl_copy_to_user(sdb->table.sgl, sdb->table.nents, arr, len); 100 | } 101 | 102 | /* 103 | * fill_from_user_buffer : Retrieves data from user-space into SCSI 104 | * buffer(s) 105 | 106 | Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . 107 | */ 108 | static int mhvtl_fill_from_user_buffer(struct scsi_cmnd *scp, char __user *arr, 109 | int arr_len) 110 | { 111 | int act_len; 112 | struct scsi_data_buffer *sdb = scsi_in(scp); 113 | 114 | if (!sdb->length) 115 | return 0; 116 | if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 117 | return DID_ERROR << 16; 118 | 119 | act_len = mhvtl_copy_from_user(sdb->table.sgl, sdb->table.nents, 120 | arr, arr_len); 121 | if (sdb->resid) 122 | sdb->resid -= act_len; 123 | else 124 | sdb->resid = scsi_bufflen(scp) - act_len; 125 | 126 | return 0; 127 | 128 | } 129 | 130 | /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 131 | static int mhvtl_fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 132 | int arr_len) 133 | { 134 | int act_len; 135 | struct scsi_data_buffer *sdb = scsi_in(scp); 136 | 137 | if (!sdb->length) 138 | return 0; 139 | if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 140 | return DID_ERROR << 16; 141 | 142 | act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 143 | arr, arr_len); 144 | if (sdb->resid) 145 | sdb->resid -= act_len; 146 | else 147 | sdb->resid = scsi_bufflen(scp) - act_len; 148 | 149 | return 0; 150 | } 151 | 152 | -------------------------------------------------------------------------------- /kernel/fetch27.c: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * mhvtl_sg_copy_user - Copy data between user-space linear buffer and an SG list 4 | * @sgl: The SG list 5 | * @nents: Number of SG entries 6 | * @buf: Where to copy from 7 | * @buflen: The number of bytes to copy 8 | * @to_buffer: Transfer direction (non zero == from an sg list to a buffer, 9 | * 0 == from a buffer to an sg list 10 | * 11 | * Returns number of copied bytes 12 | * 13 | * Taken in whole from scatterlist.c 14 | */ 15 | 16 | static size_t mhvtl_sg_copy_user(struct scatterlist *sgl, unsigned int nents, 17 | __user void *buf, size_t buflen, int to_buffer) 18 | { 19 | unsigned int offset = 0; 20 | struct sg_mapping_iter miter; 21 | /* Do not use SG_MITER_ATOMIC flag on the sg_miter_start() call */ 22 | unsigned int sg_flags = 0; 23 | unsigned int rem; 24 | void *kmem_user; 25 | 26 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30) 27 | if (to_buffer) 28 | sg_flags |= SG_MITER_FROM_SG; 29 | else 30 | sg_flags |= SG_MITER_TO_SG; 31 | #endif 32 | 33 | kmem_user = kmem_cache_alloc(sgp, 0); 34 | if (!kmem_user) 35 | return offset; 36 | 37 | sg_miter_start(&miter, sgl, nents, sg_flags); 38 | 39 | while (sg_miter_next(&miter) && offset < buflen) { 40 | unsigned int len; 41 | 42 | len = min(miter.length, buflen - offset); 43 | if (len > SG_SEGMENT_SZ) { 44 | pr_warn("scatter-gather segment size larger than SG_SEGMENT_SZ (%d > %d)", 45 | len, SG_SEGMENT_SZ); 46 | goto abort_early; 47 | } 48 | 49 | if (to_buffer) { 50 | memcpy(kmem_user, miter.addr, len); 51 | rem = copy_to_user(buf + offset, kmem_user, len); 52 | } else { 53 | rem = copy_from_user(kmem_user, buf + offset, len); 54 | memcpy(miter.addr, kmem_user, len); 55 | flush_kernel_dcache_page(miter.page); 56 | } 57 | if (rem) 58 | pr_debug("mhvtl: %s(): " 59 | "copy_%s_user() failed, rem %ld, buf 0x%llx, " 60 | "miter.addr 0x%llx, len %d\n", 61 | __func__, (to_buffer) ? "to" : "from", 62 | (long)rem, 63 | (unsigned long long)(buf + offset), 64 | (unsigned long long)miter.addr, len); 65 | 66 | offset += len; 67 | } 68 | 69 | abort_early: 70 | sg_miter_stop(&miter); 71 | kmem_cache_free(sgp, kmem_user); 72 | 73 | return offset; 74 | } 75 | 76 | static size_t mhvtl_copy_from_user(struct scatterlist *sgl, unsigned int nents, 77 | char __user *buf, size_t buflen) 78 | { 79 | return mhvtl_sg_copy_user(sgl, nents, buf, buflen, 0); 80 | } 81 | 82 | static size_t mhvtl_copy_to_user(struct scatterlist *sgl, unsigned int nents, 83 | char __user *buf, size_t buflen) 84 | { 85 | return mhvtl_sg_copy_user(sgl, nents, buf, buflen, 1); 86 | } 87 | 88 | /* 89 | * Copy data from SCSI command buffer to device buffer 90 | * (SCSI command buffer -> user space) 91 | * 92 | * Returns number of bytes fetched into 'arr' or -1 if error. 93 | */ 94 | static int mhvtl_fetch_to_dev_buffer(struct scsi_cmnd *scp, char __user *arr, int len) 95 | { 96 | struct scsi_data_buffer *sdb = scsi_out(scp); 97 | 98 | if (!scsi_bufflen(scp)) 99 | return 0; 100 | if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 101 | return -1; 102 | 103 | return mhvtl_copy_to_user(sdb->table.sgl, sdb->table.nents, arr, len); 104 | } 105 | 106 | /* 107 | * fill_from_user_buffer : Retrieves data from user-space into SCSI 108 | * buffer(s) 109 | 110 | Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . 111 | */ 112 | static int mhvtl_fill_from_user_buffer(struct scsi_cmnd *scp, char __user *arr, 113 | int arr_len) 114 | { 115 | int act_len; 116 | struct scsi_data_buffer *sdb = scsi_in(scp); 117 | 118 | if (!sdb->length) 119 | return 0; 120 | if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 121 | return DID_ERROR << 16; 122 | 123 | act_len = mhvtl_copy_from_user(sdb->table.sgl, sdb->table.nents, 124 | arr, arr_len); 125 | if (sdb->resid) 126 | sdb->resid -= act_len; 127 | else 128 | sdb->resid = scsi_bufflen(scp) - act_len; 129 | 130 | return 0; 131 | 132 | } 133 | 134 | /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 135 | static int mhvtl_fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 136 | int arr_len) 137 | { 138 | int act_len; 139 | struct scsi_data_buffer *sdb = scsi_in(scp); 140 | 141 | if (!sdb->length) 142 | return 0; 143 | if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 144 | return DID_ERROR << 16; 145 | 146 | act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 147 | arr, arr_len); 148 | if (sdb->resid) 149 | sdb->resid -= act_len; 150 | else 151 | sdb->resid = scsi_bufflen(scp) - act_len; 152 | 153 | return 0; 154 | } 155 | 156 | -------------------------------------------------------------------------------- /kernel/fetch50.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * mhvtl_sg_copy_user - Copy data between user-space linear buffer and an SG list 5 | * @sgl: The SG list 6 | * @nents: Number of SG entries 7 | * @buf: Where to copy from 8 | * @buflen: The number of bytes to copy 9 | * @to_buffer: Transfer direction (non zero == from an sg list to a buffer, 10 | * 0 == from a buffer to an sg list 11 | * 12 | * Returns number of copied bytes 13 | * 14 | * Taken in whole from scatterlist.c 15 | */ 16 | 17 | static size_t mhvtl_sg_copy_user(struct scatterlist *sgl, unsigned int nents, 18 | __user void *buf, size_t buflen, int to_buffer) 19 | { 20 | unsigned int offset = 0; 21 | struct sg_mapping_iter miter; 22 | /* Do not use SG_MITER_ATOMIC flag on the sg_miter_start() call */ 23 | unsigned int sg_flags = 0; 24 | unsigned int rem; 25 | void *kmem_user; 26 | 27 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30) 28 | if (to_buffer) 29 | sg_flags |= SG_MITER_FROM_SG; 30 | else 31 | sg_flags |= SG_MITER_TO_SG; 32 | #endif 33 | 34 | kmem_user = kmem_cache_alloc(sgp, 0); 35 | if (!kmem_user) 36 | return offset; 37 | 38 | sg_miter_start(&miter, sgl, nents, sg_flags); 39 | 40 | while (sg_miter_next(&miter) && offset < buflen) { 41 | unsigned int len; 42 | 43 | len = min(miter.length, buflen - offset); 44 | if (unlikely(len > SG_SEGMENT_SZ)) { 45 | pr_warn("scatter-gather segment size larger than SG_SEGMENT_SZ (%d > %d)", 46 | len, SG_SEGMENT_SZ); 47 | goto abort_early; 48 | } 49 | 50 | /* Since user copy 'white list' - need to copy into 'kmem_buffer' first */ 51 | if (to_buffer) { 52 | memcpy(kmem_user, miter.addr, len); 53 | rem = copy_to_user(buf + offset, kmem_user, len); 54 | } else { 55 | rem = copy_from_user(kmem_user, buf + offset, len); 56 | memcpy(miter.addr, kmem_user, len); 57 | flush_dcache_page(miter.page); 58 | } 59 | if (rem) 60 | pr_warn("mhvtl: %s(): " 61 | "copy_%s_user() failed, rem %ld, buf 0x%pS, " 62 | "miter.addr 0x%pS, len %d\n", 63 | __func__, (to_buffer) ? "to" : "from", 64 | (long)rem, 65 | (buf + offset), 66 | miter.addr, 67 | len); 68 | 69 | offset += len; 70 | } 71 | 72 | abort_early: 73 | sg_miter_stop(&miter); 74 | kmem_cache_free(sgp, kmem_user); 75 | 76 | return offset; 77 | } 78 | 79 | static size_t mhvtl_copy_from_user(struct scatterlist *sgl, unsigned int nents, 80 | char __user *buf, size_t buflen) 81 | { 82 | return mhvtl_sg_copy_user(sgl, nents, buf, buflen, 0); 83 | } 84 | 85 | static size_t mhvtl_copy_to_user(struct scatterlist *sgl, unsigned int nents, 86 | char __user *buf, size_t buflen) 87 | { 88 | return mhvtl_sg_copy_user(sgl, nents, buf, buflen, 1); 89 | } 90 | 91 | /* 92 | * Copy data from SCSI command buffer to device buffer 93 | * (SCSI command buffer -> user space) 94 | * 95 | * Returns number of bytes fetched into 'arr' or -1 if error. 96 | */ 97 | static int mhvtl_fetch_to_dev_buffer(struct scsi_cmnd *scp, char __user *arr, int len) 98 | { 99 | if (!scsi_bufflen(scp)) 100 | return 0; 101 | if (scp->sc_data_direction != DMA_TO_DEVICE) 102 | return -1; 103 | 104 | return mhvtl_copy_to_user(scsi_sglist(scp), scsi_sg_count(scp), arr, len); 105 | } 106 | 107 | /* 108 | * fill_from_user_buffer : Retrieves data from user-space into SCSI 109 | * buffer(s) 110 | 111 | Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . 112 | */ 113 | static int mhvtl_fill_from_user_buffer(struct scsi_cmnd *scp, char __user *arr, 114 | int arr_len) 115 | { 116 | int act_len; 117 | struct scsi_data_buffer *sdb = &scp->sdb; 118 | 119 | if (!sdb->length) 120 | return 0; 121 | if (scp->sc_data_direction != DMA_FROM_DEVICE) 122 | return DID_ERROR << 16; 123 | 124 | act_len = mhvtl_copy_from_user(sdb->table.sgl, sdb->table.nents, 125 | arr, arr_len); 126 | scsi_set_resid(scp, scsi_bufflen(scp) - act_len); 127 | 128 | return 0; 129 | } 130 | 131 | /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */ 132 | static int mhvtl_fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 133 | int arr_len) 134 | { 135 | int act_len; 136 | struct scsi_data_buffer *sdb = &scp->sdb; 137 | 138 | if (!sdb->length) 139 | return 0; 140 | if (scp->sc_data_direction != DMA_FROM_DEVICE) 141 | return DID_ERROR << 16; 142 | 143 | act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 144 | arr, arr_len); 145 | scsi_set_resid(scp, scsi_bufflen(scp) - act_len); 146 | 147 | return 0; 148 | } 149 | 150 | -------------------------------------------------------------------------------- /kernel/vtl_common.h: -------------------------------------------------------------------------------- 1 | /* Common stuff for kernel and usr programs */ 2 | #ifndef VTL_COMMON_H 3 | #define VTL_COMMON_H 4 | 5 | #define SENSE_BUF_SIZE 96 6 | /* Max cdb size */ 7 | #define MAX_COMMAND_SIZE 16 8 | 9 | #define VTL_IDLE 0x00 10 | #define VTL_QUEUE_CMD 0xfe 11 | 12 | /* ioctl defines */ 13 | #define VX_TAPE_ONLINE 0x80 14 | #define VTL_POLL_AND_GET_HEADER 0x200 15 | #define VTL_GET_DATA 0x201 16 | #define VTL_PUT_DATA 0x203 17 | #define VTL_REMOVE_LU 0x205 18 | 19 | #define VENDOR_ID_LEN 8 20 | #define PRODUCT_ID_LEN 16 21 | #define PRODUCT_REV_LEN 4 22 | 23 | struct mhvtl_header { 24 | unsigned long long serialNo; 25 | unsigned char cdb[MAX_COMMAND_SIZE]; 26 | unsigned char *buf; 27 | }; 28 | 29 | struct mhvtl_ds { 30 | void *data; 31 | unsigned int sz; 32 | unsigned long long serialNo; 33 | void *sense_buf; 34 | unsigned char sam_stat; 35 | }; 36 | 37 | struct mhvtl_ctl { 38 | unsigned int channel; 39 | unsigned int id; 40 | unsigned int lun; 41 | }; 42 | 43 | #if !defined(FALSE) 44 | #define FALSE 0 45 | #endif 46 | 47 | #if !defined(TRUE) 48 | #define TRUE 1 49 | #endif 50 | 51 | #endif /* VTL_COMMON_H */ 52 | 53 | -------------------------------------------------------------------------------- /man/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This makefile needs to be invoked as follows: 3 | # 4 | #make 5 | # 6 | # Here, options include: 7 | # 8 | # all to build all utilities 9 | # clean to clean up all intermediate files 10 | # 11 | # 12 | # Makefile magic 13 | # $@ is a variable that expands to the name of the file being built 14 | # $< is a variable that expands to the naem of the source file 15 | # @ at the beginning of the first line tell make not to echo the commands as it run it. 16 | # 17 | 18 | CURDIR = "../" 19 | 20 | include ../config.mk 21 | 22 | MONTH = $(shell date -r ../ChangeLog +%B) 23 | YEAR = $(shell date -r ../ChangeLog +%Y) 24 | 25 | objects = $(patsubst %.in,%,$(wildcard *.in)) 26 | 27 | man: $(objects) 28 | 29 | all: $(objects) 30 | 31 | %: %.in 32 | sed -e s'/@VERSION@/$(VERSION)/' \ 33 | -e s'/@MONTH@/$(MONTH)/' \ 34 | -e s'/@YEAR@/$(YEAR)/' \ 35 | -e s'/@CONFIG_PATH@/$(CONFIG_PATH)/' \ 36 | -e s'/@HOME_PATH@/$(HOME_PATH)/' $< > $@ 37 | 38 | install: 39 | install -d -m 755 $(DESTDIR)$(PREFIX)$(MANDIR)/man1 40 | install -d -m 755 $(DESTDIR)$(PREFIX)$(MANDIR)/man5 41 | install mktape.1 $(DESTDIR)$(PREFIX)$(MANDIR)/man1/ 42 | install vtlcmd.1 $(DESTDIR)$(PREFIX)$(MANDIR)/man1/ 43 | install vtltape.1 $(DESTDIR)$(PREFIX)$(MANDIR)/man1/ 44 | install edit_tape.1 $(DESTDIR)$(PREFIX)$(MANDIR)/man1/ 45 | install vtllibrary.1 $(DESTDIR)$(PREFIX)$(MANDIR)/man1/ 46 | install make_vtl_media.1 $(DESTDIR)$(PREFIX)$(MANDIR)/man1/ 47 | install mhvtl_kernel_mod_build.1 $(DESTDIR)$(PREFIX)$(MANDIR)/man1/ 48 | install dump_tape.1 $(DESTDIR)$(PREFIX)$(MANDIR)/man1/ 49 | install preload_tape.1 $(DESTDIR)$(PREFIX)$(MANDIR)/man1/ 50 | install tapeexerciser.1 $(DESTDIR)$(PREFIX)$(MANDIR)/man1/ 51 | install update_device.conf.1 $(DESTDIR)$(PREFIX)$(MANDIR)/man1/ 52 | install generate_device_conf.1 $(DESTDIR)$(PREFIX)$(MANDIR)/man1/ 53 | install generate_library_contents.1 $(DESTDIR)$(PREFIX)$(MANDIR)/man1/ 54 | install mhvtl.conf.5 $(DESTDIR)$(PREFIX)$(MANDIR)/man5/ 55 | install device.conf.5 $(DESTDIR)$(PREFIX)$(MANDIR)/man5/ 56 | install library_contents.5 $(DESTDIR)$(PREFIX)$(MANDIR)/man5/ 57 | 58 | clean: 59 | rm -f *.1 *.5 60 | -------------------------------------------------------------------------------- /man/device.conf.5.in: -------------------------------------------------------------------------------- 1 | .TH device.conf "5" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | device.conf \- Configuration file for 4 | .BR vtllibrary(1) 5 | and 6 | .BR vtltape(1) 7 | .SH DESCRIPTION 8 | .\" Add any additional description here 9 | .PP 10 | Each configured device contains a unique entry in device.conf 11 | 12 | Each section starts at column 1 and is terminated by a blank line. 13 | .IP e.g. 14 | Library: 10 CHANNEL: 00 TARGET: 00 LUN: 00 15 | Vendor identification: SPECTRA 16 | Product identification: PYTHON 17 | Product revision level: 550V 18 | Unit serial number: XYZZY_A 19 | NAA: 10:22:33:44:ab:00:00:00 20 | Home directory: @HOME_PATH@/Spectra 21 | fifo: /var/tmp/mhvtl 22 | PERSIST: True 23 | .PP 24 | Where descriptor 25 | .B Library: 26 | or 27 | .B Drive: 28 | starts each section The descriptor is followed by a unique ID (a decimal number) 29 | 30 | On the same line following the descriptor is the SCSI corrordinates for the 31 | device described. 32 | 33 | .B Vendor identification, 34 | .B Product identification, 35 | .B Product revision level 36 | and 37 | .B Unit serial number 38 | are common fields across all device types. 39 | 40 | .B NAA 41 | field is used by some backup software (e.g. Legato) as means to uniquely identify devices. It is used by INQUIRY VPD page 0x83. Most software uses the 42 | .B Unit serial number 43 | as the unique identifier. 44 | 45 | .B Compression: 46 | factor 47 | .B X 48 | enabled 49 | .B Y 50 | 51 | Where 52 | .PP 53 | .B X 54 | is 1 through 9. 55 | .IP 56 | 1 is fastest compression, 9 is best compression. 57 | .PP 58 | .B Y 59 | .IP 60 | 1: compression is enabled, 0: compression is disabled. 61 | 62 | .PP 63 | .B Compression type: 64 | zlib or lzo 65 | 66 | .PP 67 | .B Backoff: 68 | Value between 10 and 10000. Default is 1000. 69 | This value is added to existing 'usleep' time in between ioctl polls. If there is work to do, the usleep time is reset to 10. 70 | 71 | .PP 72 | .B Home directory: 73 | /some/where/with/space 74 | .PP 75 | Specify a parent directory for the virtual media associated with this library. 76 | Only in valid ^Library: entries (not for ^Tape: entries) 77 | 78 | .PP 79 | .B fifo: 80 | /some/where/for/named/pipe 81 | .PP 82 | If fifo: is defined, (near) real time state information will be available 83 | for external applications by reading from this named pipe. 84 | .PP 85 | Note: the '-f fifo' switch on daemon startup has higher precedence 86 | 87 | .PP 88 | .B PERSIST: 89 | True | False 90 | If PERSIST is set to 'Yes' or 'True' - enable saving state on shutdown. 91 | A file 'library_contents.XX.persist' will be created on shutdown to save 92 | persistent state. On startup - Default to read the 93 | library_contents.XX.persist if the file exists. Fall back to 94 | library_contents.XX if no .persist file exists. 95 | 96 | .SH AUTHOR 97 | Written by Mark Harvey 98 | .SH BUGS 99 | .RS 100 | This man page. 101 | .RE 102 | .RS 103 | No version information. 104 | .RE 105 | .RS 106 | Config file not xml. 107 | .RE 108 | .RS 109 | .BR vtllibrary(1) 110 | and 111 | .BR vtltape(1) 112 | needs to be restarted to read any changes made. 113 | .RE 114 | .SH "REPORTING BUGS" 115 | Report bugs to 116 | .SH COPYRIGHT 117 | Copyright \(co 2005 Free Software Foundation, Inc. 118 | .br 119 | This is free software; see the source for copying conditions. There is NO 120 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 121 | .SH "SEE ALSO" 122 | .BR library_contents(5) 123 | .BR make_vtl_media(1), 124 | .BR mktape(1), 125 | .BR vtlcmd(1), 126 | .BR vtllibrary(1), 127 | .BR vtltape(1) 128 | -------------------------------------------------------------------------------- /man/dump_tape.1.in: -------------------------------------------------------------------------------- 1 | .TH dump_tape "1" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | dump_tape \- Utility to dump tape contents for virtual media in VTL. 4 | .SH SYNOPSIS 5 | .B dump_tape 6 | .B [ \-h ] 7 | .br 8 | .B dump_tape 9 | .B [ \fIOPTIONS\fR] 10 | .SH DESCRIPTION 11 | .\" Add any additional description here 12 | .PP 13 | Dump the contents of the specified PCL. If a library is specified, look 14 | there, else look through all of the libraries. 15 | .SH OPTIONS 16 | .TP 17 | .B \-h 18 | display usage information and exit 19 | .TP 20 | .B \-v 21 | be verbose 22 | .TP 23 | .B \-d 24 | print debugging information 25 | .TP 26 | .BR \-l lib_no 27 | \fB\-l n\fR 28 | Where lib_no is the library index number (default library index numbers 10 & 30). 29 | .TP 30 | \fB\-m PCL\fR 31 | where PCL is the Physical Cartridge Label (barcode). This is required. 32 | .TP 33 | .B \-D 34 | dump data 35 | .SH AUTHOR 36 | Written by Mark Harvey 37 | .SH BUGS 38 | Needs to be made user friendly. 39 | .SH "REPORTING BUGS" 40 | Report bugs to 41 | .SH COPYRIGHT 42 | Copyright \(co 2005 Free Software Foundation, Inc. 43 | .br 44 | This is free software; see the source for copying conditions. There is NO 45 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 46 | .SH "SEE ALSO" 47 | .BR make_vtl_media(1), 48 | .BR library_contents(5), 49 | .BR vtlcmd(1), 50 | .BR vtllibrary(1), 51 | .BR vtltape(1), 52 | .BR edit_tape(1), 53 | .BR preload_tape(1) 54 | -------------------------------------------------------------------------------- /man/edit_tape.1.in: -------------------------------------------------------------------------------- 1 | .TH edit_tape "1" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | edit_tape \- Utility to update meta data virtual media for the VTL. 4 | .SH SYNOPSIS 5 | .B edit_tape 6 | .B [ \-h ] 7 | .B [ \fIoptions \fR] 8 | .B ... 9 | .SH DESCRIPTION 10 | .\" Add any additional description here 11 | .PP 12 | Create and initialise new media for the Virtual Tape Library. Media is created in the 13 | /opt/vtl/ directory. This path is hard coded. 14 | .SH OPTIONS 15 | .TP 16 | \fB\-h\fR 17 | display this help and exit 18 | .TP 19 | \fB\-m PCL\fR 20 | where PCL is the Physical Cartridge Label (barcode). 21 | .TP 22 | \fB\-w on|off\fR 23 | Turn on|off media write-protect flag 24 | .TP 25 | \fB\-s size\fR 26 | where size is the capacity of the virtual media - Size is defined in 'megabytes'. 27 | .TP 28 | \fB\-t type\fR 29 | The media 'type' which can be: "data" , "WORM" (Write Once Read Many) or 30 | "clean" (cleaning cartridge) 31 | .TP 32 | \fB\-d density\fR 33 | Media density. Can be one of LTO1, LTO2, LTO3, LTO4, LTO5, LTO6, LTO7, LTO8, LTO9, SDLT1, SDLT2, SDLT3, SDLT4, AIT1, AIT2, AIT3, 34 | AIT4, T10KA, T10KB, T10KC, 9840A, 9840B, 9840C, 9840D, 9940A, 9940B, J1A, E05 and E06 35 | 36 | The 'J1A, E05 and E06' media densities refer to the IBM 03592 media types. 37 | 38 | .SH AUTHOR 39 | Written by Mark Harvey 40 | .SH BUGS 41 | Needs to be made user friendly. 42 | .SH "REPORTING BUGS" 43 | Report bugs to 44 | .SH COPYRIGHT 45 | Copyright \(co 2005 Free Software Foundation, Inc. 46 | .br 47 | This is free software; see the source for copying conditions. There is NO 48 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 49 | .SH "SEE ALSO" 50 | .BR make_vtl_media(1), 51 | .BR library_contents(5), 52 | .BR vtlcmd(1), 53 | .BR vtllibrary(1), 54 | .BR vtltape(1) 55 | .BR mktape(1) 56 | -------------------------------------------------------------------------------- /man/generate_device_conf.1.in: -------------------------------------------------------------------------------- 1 | .TH generate_device_conf "1" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | generate_device_conf \- Utility to generate the device.conf file 4 | .SH SYNOPSIS 5 | .B generate_device_conf -h|--help -- print help message and exit 6 | .br 7 | .BI generate_device_conf OPTIONS 8 | .SH DESCRIPTION 9 | .PP 10 | This script creates the device.conf file, from scratch. Edit this 11 | script and run it to generate a non-default configuration. 12 | .PP 13 | This script is normally run at software installation time, but can be 14 | edited then run again to regenerate the 15 | .B device.conf 16 | file again. 17 | .PP 18 | .I OPTIONS 19 | are from: 20 | .TP 21 | \fB\-H\fR, \fB\-\-home-dir\fR \fIHOME_DIR\fR 22 | Set the 23 | .I mhvtl 24 | home directory [default 25 | .BR @HOME_PATH@ . 26 | .TP 27 | \fB\-D\fR, \fB\-\-dest-dir\fR \fIDIR\fR 28 | Set the destination directory [default 29 | .BR . ] 30 | .TP 31 | \fB\-f\fR, \fB\-\-force\fR 32 | Overwrite existing 33 | .B device.conf 34 | if needed. 35 | .TP 36 | \fB\-o\fR, \fB\-\-override-home\fR 37 | Allow script to continue even if home directory is not present. 38 | .SH AUTHOR 39 | Written by Mark Harvey. 40 | .SH BUGS 41 | Needs to be made user friendly and more verbose. 42 | And it would be nice to be able to change the device configuration 43 | file without editing this script. 44 | .SH "REPORTING BUGS" 45 | Report bugs to 46 | .SH COPYRIGHT 47 | Copyright \(co 2018 Free Software Foundation, Inc. 48 | .br 49 | This is free software; see the source for copying conditions. There is NO 50 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 51 | .SH "SEE ALSO" 52 | .BR device.conf(5) , 53 | .BR make_vtl_media(1) , 54 | .BR library_contents(5) , 55 | .BR vtlcmd(1) , 56 | .BR vtllibrary(1) , 57 | .BR vtltape(1) , 58 | .BR edit_tape(1) , 59 | .BR generate_library_contents(1) 60 | -------------------------------------------------------------------------------- /man/generate_library_contents.1.in: -------------------------------------------------------------------------------- 1 | .TH generate_library_contents "1" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | generate_library_contents \- Utility to generate the lib_contents.* files from device.conf 4 | .SH SYNOPSIS 5 | \fBgenerate_library_contents -h|--help\fR -- print help usage and exit, or 6 | .br 7 | .B generate_library_contents 8 | .I [OPTIONS] 9 | .SH DESCRIPTION 10 | Where 11 | .I OPTIONS 12 | are from: 13 | .TP 14 | \fB\-C\fR, \fB\-\-config-dir\fR=\fIDIR\fR 15 | Set config directory [defaults to 16 | .BR @CONF_PATH@ ] 17 | .TP 18 | \fB\-D\fR, \fB\-\-dest-dir\fR=\fIDIR\fR 19 | Set the destination directory [defaults to 20 | .BR . ] 21 | .TP 22 | \fB\-f\fR, \fB\-\-force\fR 23 | Write over existing library_contents.* files, if needed. 24 | .PP 25 | This script creates the library_contents.* files from the 26 | .B device.conf 27 | file. 28 | It is normally run at system installation time, but can be called to regenerate 29 | these files if 30 | .B device.conf 31 | has changed. 32 | .PP 33 | .SH AUTHOR 34 | Written by Mark Harvey. 35 | Updated by Lee Duncan. 36 | .SH BUGS 37 | Needs to be made user friendly and more verbose. 38 | And perhaps this should be integrated with 39 | .BR generate_device_conf(1) . 40 | .SH "REPORTING BUGS" 41 | Report bugs to 42 | .SH COPYRIGHT 43 | Copyright \(co 2018 Free Software Foundation, Inc. 44 | .br 45 | This is free software; see the source for copying conditions. There is NO 46 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 47 | .SH "SEE ALSO" 48 | .BR device.conf(5) , 49 | .BR make_vtl_media(1) , 50 | .BR library_contents(5) , 51 | .BR vtlcmd(1) , 52 | .BR vtllibrary(1) , 53 | .BR vtltape(1) , 54 | .BR edit_tape(1) , 55 | .BR generate_device_conf(1) 56 | -------------------------------------------------------------------------------- /man/library_contents.5.in: -------------------------------------------------------------------------------- 1 | .TH library_contents "5" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | library_contents \- Configuration file for 4 | .BR vtllibrary(1) 5 | .SH DESCRIPTION 6 | .\" Add any additional description here 7 | .PP 8 | Configuration file for vtllibrary daemon (part of Virtual Tape Library) 9 | One line per entry. 10 | Contains the following sections, Only the 'Slot' section should be populated 11 | with additional information (barcodes). 12 | The other sections are used as place holders. e.g. If the number of MAP 13 | slots are to be changed within the VTL, change the number of entries in 14 | this configuration file. 15 | .IP "Drive #: " 16 | Note: Set the serial number of the drive in device.conf 17 | .IP "Picker #:" 18 | .IP "MAP #:" 19 | .IP "Slot #: [Barcode]" 20 | Where [Barcode] can be any ASCII string from 1 to 12 chars in length. If there is no Barcode 21 | defined for the Slot number, the slot is taken to be empty. 22 | .SH AUTHOR 23 | Written by Mark Harvey 24 | .SH BUGS 25 | .RS 26 | This man page. 27 | .RE 28 | .RS 29 | No version information. 30 | .RE 31 | .RS 32 | Config file not xml. 33 | .RE 34 | .RS 35 | .BR vtllibrary(1) 36 | needs to be restarted to read any changes made. 37 | .RE 38 | .SH "REPORTING BUGS" 39 | Report bugs to 40 | .SH COPYRIGHT 41 | Copyright \(co 2005 Free Software Foundation, Inc. 42 | .br 43 | This is free software; see the source for copying conditions. There is NO 44 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 45 | .SH "SEE ALSO" 46 | .BR make_vtl_media(1), 47 | .BR mktape(1), 48 | .BR vtlcmd(1), 49 | .BR vtllibrary(1), 50 | .BR vtltape(1) 51 | .BR device.conf(5) 52 | -------------------------------------------------------------------------------- /man/make_vtl_media.1.in: -------------------------------------------------------------------------------- 1 | .TH make_vtl_media "1" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | make_vtl_media \- create the library database from lib_contents.* file(s) 4 | .SH SYNOPSIS 5 | \fBmake_vtl_media \-h|\-\-help\fR -- print help message and exit, or 6 | .br 7 | .B make_vtl_media 8 | .I [OPTIONS] 9 | .SH DESCRIPTION 10 | .PP 11 | Where 12 | .I OPTIONS 13 | are from: 14 | .TP 15 | \fB\-H\fR, \fB\-\-home-dir\fR=\fIDIR\fR 16 | Set the 17 | .I mhvtl 18 | home directory [default 19 | .BR @HOME_PATH@ ] 20 | .TP 21 | \fB\-C\fR, \fB\-\-config-dir\fR=\fIDIR\fR 22 | Set the config directory [default 23 | .BR @CONFIG_PATH@ ] 24 | .TP 25 | \fB\-f\fR, \fB\-\-force\fR 26 | Overwrite existing database files, if needed. 27 | .TP 28 | \fB\-c\fR, \fB\-\-create-dir\fR 29 | Create the home directory, if needed. 30 | .PP 31 | This program is invoked initialy when the software is installed, but 32 | can also be ran later to recreate the tape libraray database. It does so by reading 33 | the 34 | .I device.conf 35 | and 36 | .I library_contents.* 37 | files in our configuration directory, and finding the 38 | .B Slot 39 | entries in those files, extracting the 40 | .I barcode 41 | found for each slot. 42 | .PP 43 | .IP "If \fIbarcode\fR starts with W" 44 | Create as Write Once Read Many (WORM) media type. 45 | .IP "If \fIbarcode\fR starts with CLN" 46 | Create media type as cleaning cartridge. 47 | .IP "Otherwise" 48 | Create the media as a data cartridge. 49 | .IP 50 | Attempts to use the chars 7 and 8 to work out the media type (LTO1/2/3/4/5/6/7, 51 | T10K, AIT etc) See 52 | .B mktape(1) 53 | for more details on media density. 54 | .IP 55 | Feel free to replace this script with one that better suits your needs. 56 | .PP 57 | If the configuration is regenerated then the 58 | .B mhvtl.target 59 | service should be restarted. 60 | .SH AUTHOR 61 | Written by Mark Harvey 62 | .SH BUGS 63 | Not documented. 64 | .SH "REPORTING BUGS" 65 | Report bugs to 66 | .SH COPYRIGHT 67 | Copyright \(co 2019 Free Software Foundation, Inc. 68 | .P 69 | This is free software; see the source for copying conditions. There is NO 70 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 71 | .SH "SEE ALSO" 72 | .BR library_contents(5) , 73 | .BR mktape(1) , 74 | .BR vtlcmd(1) , 75 | .BR vtllibrary(1) , 76 | .BR vtltape(1) , 77 | .BR generate_device_conf(1) , 78 | .BR generate_library_contents(1) 79 | -------------------------------------------------------------------------------- /man/mhvtl.conf.5.in: -------------------------------------------------------------------------------- 1 | .TH mhvtl.conf "5" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | mhvtl.conf \- Configuration file for 4 | .B vtllibrary(1) 5 | and 6 | .B vtltape(1) 7 | .SH DESCRIPTION 8 | .\" Add any additional description here 9 | .PP 10 | Configuration file to define startup behaviour of the virtual tape library. 11 | .TP 12 | MHVTL_HOME_PATH=@HOME_PATH@ 13 | The location where 14 | .I mhvtl 15 | stores its tape 16 | .IR database . 17 | .TP 18 | CAPACITY=500 19 | Defines default capacity any new media will be created (in Megabytes). 20 | .B make_vtl_media(1) 21 | uses this value and passes to 22 | .IR mktape . 23 | .TP 24 | VERBOSE=1 25 | Set verbosity to level [0|1|2|3] for daemon logging level at startup. 26 | Refer to 27 | .B vtlcmd(1) 28 | to adjust logging level at runtime. 29 | .TP 30 | VTL_DEBUG=0 31 | Set to [0|1]. to disable/enable kernel module logging. Can be enabled/disabled 32 | at runtime via: 33 | .IP 34 | "echo 0 > /sys/bus/pseduo/drivers/mhvtl/opts" to disable, or 35 | .IP 36 | "echo 1 > /sys/bus/pseudo/drivers/mhvtl/opts" to enable logging. 37 | .TP 38 | DAEMON_DEBUG='' 39 | Set to 40 | .I '' 41 | to disable daemon debugging, or 42 | .I '-d' 43 | to enable it. 44 | .SH AUTHOR 45 | Written by Mark Harvey 46 | .SH BUGS 47 | This man page. 48 | .PP 49 | Config file not xml. 50 | .PP 51 | .B vtllibrary(1) 52 | needs to be restarted to read any changes made. (By design). 53 | .SH "REPORTING BUGS" 54 | Report bugs to 55 | .SH COPYRIGHT 56 | Copyright \(co 2019 Free Software Foundation, Inc. 57 | .br 58 | This is free software; see the source for copying conditions. There is NO 59 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 60 | .SH "SEE ALSO" 61 | .BR mktape(1) , 62 | .BR vtlcmd(1) , 63 | .BR vtllibrary(1) , 64 | .BR vtltape(1) 65 | -------------------------------------------------------------------------------- /man/mhvtl_kernel_mod_build.1.in: -------------------------------------------------------------------------------- 1 | .TH mhvtl_kernel_mod_build "1" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | mhvtl_kernel_mod_build \- Simple wrapper script to extract mhvtl.ko source and compile 4 | .SH SYNOPSIS 5 | \fBmhvtl_kernel_mod_build 6 | .br 7 | .SH DESCRIPTION 8 | .br 9 | This bash script simply extracts /usr/lib/firmware/mhvtl/mhvtl_kernel.tgz and compiles (make && sudo make install) 10 | .br 11 | The mhvtl.ko source is extracted into a unique tmp directory using 'mktemp()' 12 | .SH AUTHOR 13 | Written by Mark Harvey 14 | .SH BUGS 15 | Assumes the kernel-devel and gcc plus supporting packages are already installed. 16 | .SH "REPORTING BUGS" 17 | Report bugs to or log an issue at https://github.com/markh794/mhvtl.git 18 | .br 19 | Better yet, I'm happy to accept patches which fix bugs :) 20 | .SH COPYRIGHT 21 | Copyright \(co 2019 Free Software Foundation, Inc. 22 | .P 23 | This is free software; see the source for copying conditions. There is NO 24 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 25 | .SH "SEE ALSO" 26 | .BR library_contents(5) , 27 | .BR mktape(1) , 28 | .BR vtlcmd(1) , 29 | .BR vtllibrary(1) , 30 | .BR vtltape(1) , 31 | .BR generate_device_conf(1) , 32 | .BR generate_library_contents(1) 33 | -------------------------------------------------------------------------------- /man/mktape.1.in: -------------------------------------------------------------------------------- 1 | .TH mktape "1" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | mktape \- Utility to create new/blank virtual media for the VTL. 4 | .SH SYNOPSIS 5 | .B mktape \-h 6 | .br 7 | .B mktape REQUIRED_PARAMS 8 | .BI [ OPTIONS ] 9 | .B ... 10 | .SH DESCRIPTION 11 | .PP 12 | Create and initialise new media for the Virtual Tape Library. Media is 13 | created in the 14 | .B @HOME_PATH@ 15 | directory by default. This can be over-ridden 16 | using the 'Home directory:' setting in 17 | .BR device.conf . 18 | .SH OPTIONS 19 | Options are from: 20 | .TP 21 | .B \-h 22 | display this help and exit 23 | .TP 24 | .B \-V 25 | Print version information and exit 26 | .TP 27 | .B \-v 28 | Be verbose 29 | .TP 30 | .B \-D 31 | Enter debugging mode (much each output) 32 | .TP 33 | \fB\-C\fR \fIconfig-dir\fR 34 | Use 35 | .I config-dir 36 | instead of the default of 37 | .BR @CONFIG_PATH@ . 38 | .PP 39 | Required options are: 40 | .TP 41 | \fB\-l\fR \fIn\fR 42 | Where 43 | .I n 44 | is the library index number (default library index numbers 10 & 30). 45 | The 'Home directory:' entry for the library specified is used as parent 46 | directory for media created. 47 | If the library index number does not exist, then a subdir under 48 | @HOME_PATH@/ 49 | is created and virtual media created in this directory. 50 | For example "mktape -l 20 -m ABC123 -s 1024 -t data -d LTO3" will create a virtual 51 | media 52 | .I ABC123 53 | in @HOME_PATH@/20/ 54 | if no library index 20 defined in 55 | .BR device.conf . 56 | .TP 57 | \fB\-m\fR \fIPCL\fR 58 | where 59 | .I PCL 60 | is the Physical Cartridge Label (barcode). 61 | .TP 62 | \fB\-s\fR \fIsize\fR 63 | where 64 | .I size 65 | is the capacity of the virtual media - Size is defined in 'megabytes'. 66 | .TP 67 | \fB\-t\fR \fItype\fR 68 | The media 69 | .I type 70 | which can be: 71 | .BR data , 72 | .B WORM 73 | (Write Once Read Many), 74 | .B clean 75 | (cleaning cartridge) or 76 | .B NULL 77 | for media which does not save data. 78 | .PP 79 | The 80 | .B NULL 81 | is a special media type used primarily to test performance with disk 82 | writes kept to a minimum. Note: Metadata (512bytes per data block) is still 83 | written. 84 | .TP 85 | \fB\-d\fR \fIdensity\fR 86 | Media 87 | .IR density . 88 | Can be one of 89 | .BR LTO1 , 90 | .BR LTO2 , 91 | .BR LTO3 , 92 | .BR LTO4 , 93 | .BR LTO5 , 94 | .BR LTO6 , 95 | .BR LTO7 , 96 | .BR LTO8 , 97 | .BR LTO9 , 98 | .BR SDLT1 , 99 | .BR SDLT2 , 100 | .BR SDLT3 , 101 | .BR SDLT4 , 102 | .BR AIT1 , 103 | .BR AIT2 , 104 | .BR AIT3 , 105 | .BR AIT4 , 106 | .BR T10KA , 107 | .BR T10KB , 108 | .BR T10KC , 109 | .BR 9840A , 110 | .BR 9840B , 111 | .BR 9840C , 112 | .BR 9840D , 113 | .BR 9940A , 114 | .BR 9940B , 115 | .BR J1A , 116 | .BR E05 117 | and 118 | .BR E06 . 119 | .PP 120 | The 121 | .BR J1A , 122 | .B E05 123 | and 124 | .B E06 125 | media densities refer to the IBM 03592 media types. 126 | .SH AUTHOR 127 | Written by Mark Harvey 128 | .SH BUGS 129 | Needs to be made user friendly. 130 | .SH "REPORTING BUGS" 131 | Report bugs to 132 | .SH COPYRIGHT 133 | Copyright \(co 2018 Free Software Foundation, Inc. 134 | .br 135 | This is free software; see the source for copying conditions. There is NO 136 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 137 | .SH "SEE ALSO" 138 | .BR make_vtl_media(1) , 139 | .BR library_contents(5) , 140 | .BR vtlcmd(1) , 141 | .BR vtllibrary(1) , 142 | .BR vtltape(1) , 143 | .BR edit_tape(1) , 144 | .BR generate_device_conf(1) , 145 | .BR generate_library_contents(1) 146 | -------------------------------------------------------------------------------- /man/preload_tape.1.in: -------------------------------------------------------------------------------- 1 | .TH preload_tape "1" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | preload_tape \- Utility to write a file directly to virtual media. 4 | .SH SYNOPSIS 5 | .B preload_tape 6 | .B [ \-h ] 7 | .br 8 | .B preload_tape 9 | .B [ \fIOPTIONS\fR] 10 | .SH DESCRIPTION 11 | .\" Add any additional description here 12 | .PP 13 | Dump the contents of the specified PCL. If a library is specified, look 14 | there, else look through all of the libraries. 15 | .SH OPTIONS 16 | .TP 17 | .B \-h 18 | display usage information and exit 19 | .TP 20 | .B \-v 21 | be verbose 22 | .TP 23 | .B \-d 24 | print debugging information 25 | .TP 26 | .BR \-l lib_no 27 | \fB\-l n\fR 28 | Where lib_no is the library index number (default library index numbers 10 & 30). 29 | .TP 30 | \fB\-m PCL\fR 31 | where PCL is the Physical Cartridge Label (barcode). This is required. 32 | .TP 33 | \fB\-F \fR 34 | where is the source of the data to write 'in' virtual media format. 35 | .TP 36 | \fB\-b block_size\fR 37 | where block_size is the size of the 'tape block' - e.g. -b 65535 will write in 64k blocks 38 | .TP 39 | \fB\-c LZO|ZLIB|NONE\fR 40 | Compress data before writing in virtual media format. 41 | .TP 42 | .B 43 | .SH AUTHOR 44 | Written by Mark Harvey 45 | .SH BUGS 46 | Needs to be made user friendly. 47 | .SH "REPORTING BUGS" 48 | Report bugs to 49 | .SH COPYRIGHT 50 | Copyright \(co 2005 Free Software Foundation, Inc. 51 | .br 52 | This is free software; see the source for copying conditions. There is NO 53 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 54 | .SH "SEE ALSO" 55 | .BR make_vtl_media(1), 56 | .BR library_contents(5), 57 | .BR vtlcmd(1), 58 | .BR dump_tape(1), 59 | .BR vtllibrary(1), 60 | .BR vtltape(1), 61 | .BR edit_tape(1) 62 | -------------------------------------------------------------------------------- /man/tapeexerciser.1.in: -------------------------------------------------------------------------------- 1 | .TH tapeexerciser "1" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | tapeexerciser \- Utility to exercise virtual media for the VTL. 4 | .SH SYNOPSIS 5 | .B tapeexerciser 6 | .BR \-f tape_device 7 | .SH DESCRIPTION 8 | .\" Add any additional description here 9 | .PP 10 | Exercise the specified tape drive path and exercise the tape found 11 | there. 12 | .PP 13 | .B NOTE: 14 | This will overwrite the contents of the tape media on the specified drive. 15 | .SH AUTHOR 16 | Written by Mark Harvey 17 | .SH BUGS 18 | Needs to be made user friendly. 19 | .SH "REPORTING BUGS" 20 | Report bugs to 21 | .SH COPYRIGHT 22 | Copyright \(co 2005 Free Software Foundation, Inc. 23 | .br 24 | This is free software; see the source for copying conditions. There is NO 25 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 26 | .SH "SEE ALSO" 27 | .BR make_vtl_media(1), 28 | .BR library_contents(5), 29 | .BR vtlcmd(1), 30 | .BR vtllibrary(1), 31 | .BR vtltape(1) 32 | .BR edit_tape(1) 33 | -------------------------------------------------------------------------------- /man/update_device.conf.1.in: -------------------------------------------------------------------------------- 1 | .TH update_device.conf "1" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | update_device.conf \- Utility to update device.conf to version 4 4 | .SH SYNOPSIS 5 | .B update_device.conf 6 | .SH DESCRIPTION 7 | .\" Add any additional description here 8 | .PP 9 | This script updates the device.conf file to version 4, and sets 10 | the library index to one more than the number of drives found. 11 | .SH AUTHOR 12 | Written by Mark Harvey 13 | .SH BUGS 14 | Needs to be made user friendly and more verbose. 15 | .SH "REPORTING BUGS" 16 | Report bugs to 17 | .SH COPYRIGHT 18 | Copyright \(co 2005 Free Software Foundation, Inc. 19 | .br 20 | This is free software; see the source for copying conditions. There is NO 21 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 22 | .SH "SEE ALSO" 23 | .BR device.conf(5) 24 | .BR make_vtl_media(1), 25 | .BR library_contents(5), 26 | .BR vtlcmd(1), 27 | .BR vtllibrary(1), 28 | .BR vtltape(1) 29 | .BR edit_tape(1) 30 | -------------------------------------------------------------------------------- /man/vtlcmd.1.in: -------------------------------------------------------------------------------- 1 | .TH vtlcmd "1" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | vtlcmd \- user space utility to send commands to 4 | .BR vtltape(1), 5 | .BR vtllibrary(1), 6 | daemons. 7 | .SH SYNOPSIS 8 | .B vtlcmd 'Q number' 9 | .B [ \-h ] 10 | .B [ \fIcommand \fR] 11 | .B ... 12 | .SH DESCRIPTION 13 | .\" Add any additional description here 14 | .PP 15 | Where 'Q number' is the message queue number for the drive (see 16 | .BR vtltape(1) 17 | ) 18 | 19 | .TP 20 | \fB\-h\fR 21 | display this help and exit 22 | .SH COMMAND 23 | .IP verbose 24 | Toggle verbose flag. This will cycle verbose flag thru verbose settings 3 2 1 off 25 | .IP "load " 26 | Load media ID (barcode) - Used for stand-alone tape drive daemon. 27 | .IP "unload " 28 | Unload media ID (barcode) 29 | .IP "compression " 30 | Changes compression libraries used to compress each block of data. Valid for 31 | .B tape 32 | only. 33 | .IP "delay load x" 34 | Sets a delay for loading media to 35 | .B x 36 | seconds. Valid values 0 - 20. ssc target returns <02/04/01> 'NOT READY/BECOMMING READY' status in response to any 'Test Unit Ready' requested until timer expires. 37 | Valid for 38 | .B tape 39 | only. 40 | .IP "delay unload x" 41 | Sets a delay for unloading media to 42 | .B x 43 | seconds. Valid values 0 - 20. Valid for 44 | .B tape 45 | only. 46 | .IP "delay rewind x" 47 | Sets a delay for rewinding media to 48 | .B x 49 | seconds. Valid values 0 - 30. Valid for 50 | .B tape 51 | only. 52 | .IP "delay position x" 53 | Sets a delay for positioning media to 54 | .B x 55 | seconds. Valid values 0 - 20. Valid for 56 | .B tape 57 | only. 58 | .IP "delay thread x" 59 | Sets a delay for \'threading\' media to 60 | .B x 61 | seconds. Valid values 0 - 20. Valid for 62 | .B tape 63 | only. 64 | 65 | .IP "TapeAlert " 66 | Send a 64bit hex number, each bit corresponds to one TapeAlert flag as defined by t10.org. Where bit 0 is TapeAlert flag 1, and bit 63 is TapeAlert flag 64. 67 | .IP exit 68 | Send a terminate message to daemon. 69 | .IP online 70 | Valid for 71 | .B library 72 | only. 73 | Place library in 'online' mode. 74 | .IP offline 75 | Valid for 76 | .B library 77 | only. 78 | Take library 'offline'. 79 | .IP "add slot" 80 | Valid for 81 | .B library 82 | only. 83 | This will dynamically add an additional storage slot to the library. This is not persistent. 84 | .IP "list map" 85 | Valid for 86 | .B library 87 | only. 88 | Returns a list of media IDs in Media Access Port (MAP). 89 | .IP "open map" 90 | Valid for 91 | .B library 92 | only. 93 | Logically 'opens' the Media Access Port (MAP). 94 | .IP "close map" 95 | Valid for 96 | .B library 97 | only. 98 | Logically 'closes' the Media Access Port (MAP). MAP needs to be 'closed' 99 | before the Medium Transport Element can move media to/from MAP. 100 | .IP "empty map" 101 | Valid for 102 | .B library 103 | only. 104 | Clears media from Media Access Port (MAP). Only valid when MAP is 105 | in 'open' state 106 | .IP "load map " 107 | Valid for 108 | .B library 109 | only. 110 | Places logically into the Media Access Port (MAP). Note: needs 111 | to exist first, otherwise the command fails with suggestion to create media 112 | first. see 113 | .BR mktape(1) 114 | for creating media. 115 | .SH AUTHOR 116 | Written by Mark Harvey 117 | .SH BUGS 118 | Needs to be made user friendly. 119 | .SH "REPORTING BUGS" 120 | Report bugs to 121 | .SH COPYRIGHT 122 | Copyright \(co 2005 Free Software Foundation, Inc. 123 | .br 124 | This is free software; see the source for copying conditions. There is NO 125 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 126 | .SH "SEE ALSO" 127 | .BR library_contents(5), 128 | .BR mktape(1), 129 | .BR vtllibrary(1), 130 | .BR vtltape(1) 131 | -------------------------------------------------------------------------------- /man/vtllibrary.1.in: -------------------------------------------------------------------------------- 1 | .TH vtllibrary "1" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | vtllibrary \- user space daemon to handle SCSI SMC commands for Virtual Tape Library. 4 | .SH SYNOPSIS 5 | \fBvtllibrary \-h\fR -- print a help message and exit, or 6 | .br 7 | .B vtllibrary 8 | .I [OPTIONS] 9 | \fB\-q\fR \fIQUEUE_ID\fR -- Emulate a tape library for queue \fIQUEUE_ID\fR. 10 | .SH DESCRIPTION 11 | .\" Add any additional description here 12 | This command emulates a tape library device, using queue 13 | .IR QUEUE_ID , 14 | which represent the message queue number used for this daemon. 15 | This number is derived from the 16 | .I device.conf 17 | where it must be unique. Media files can be created using 18 | .I OPTIONS 19 | are from: 20 | .TP 21 | .B \-d 22 | Enable debug logging (to stdout). Do not background the process, 23 | and set verbosity to level 9. 24 | .TP 25 | .BI \-v[ N ] 26 | Enable verbose logging (to syslog) at level \fIN\fR (default 1). 27 | .TP 28 | .B -F 29 | Run in the foreground, not as a daemon. 30 | .TP 31 | .BI \-f FIFO 32 | Near real time device state information will be available for external utilities by reading from this fifo. This switch has a higher precedence than the 'fifo:' entry in 33 | .BR device.conf . 34 | .PP 35 | The 36 | .B vtllibrary 37 | daemon simulates a tape library device, and is started by 38 | .BR systemd(1) , 39 | as needed, one invocation per Tape Library being simulated. The 40 | .B vtllibrary 41 | daemon registers each 42 | .B vtltape(1) 43 | via message queue. The 44 | .B vtllibrary 45 | reads @CONFIG_PATH@/library_contents.* 46 | and dynamically builds an internal structure of Storage slots and Media Access slots. 47 | All media movement is performed on internal structures only. The configuration file 48 | is never changed, i.e. a re-start of the daemon will result in the loss of any 49 | previous media movements. 50 | .P 51 | When media is moved to/from a "Data transfer element" (tape drive), a (un)load message is sent 52 | via the drive 'slot number' message Q number to load/unload the barcode. 53 | .SH FILES 54 | @CONFIG_PATH@/device.conf -- to find which \fIlibrary_contents.*\fR files to examine 55 | .br 56 | @CONFIG_PATH@/library_contents.* 57 | .SH AUTHOR 58 | Written by Mark Harvey 59 | .SH BUGS 60 | Does not implement the complete SCSI SMC-2/SMC-3 command set. 61 | .SH "REPORTING BUGS" 62 | Report bugs to 63 | .SH COPYRIGHT 64 | Copyright \(co 2019 Free Software Foundation, Inc. 65 | .br 66 | This is free software; see the source for copying conditions. There is NO 67 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 68 | .SH "SEE ALSO" 69 | .BR library_contents(5) , 70 | .BR mktape(1) , 71 | .BR make_vtl_media(1) , 72 | .BR vtlcmd(1) , 73 | .BR vtltape(1) 74 | -------------------------------------------------------------------------------- /man/vtltape.1.in: -------------------------------------------------------------------------------- 1 | .TH vtltape "1" "@MONTH@ @YEAR@" "mhvtl @VERSION@" "User Commands" 2 | .SH NAME 3 | vtltape \- user space daemon to handle SCSI SSC commands for Virtual Tape Library. 4 | .SH SYNOPSIS 5 | \fBvtltape -h\fR -- print a help message and exit, or 6 | .br 7 | .B vtltape 8 | .I [OPTIONS] 9 | \fB-q\fR \fIQUEUE_ID\fR -- Emulate a tape drive for queue \fIQUEUE_ID\fR. 10 | .SH DESCRIPTION 11 | .\" Add any additional description here 12 | This command emulates a tape device, using queue 13 | .IR QUEUE_ID , 14 | which represent the message queue number used for this daemon. 15 | This number is derived from the 16 | .I device.conf 17 | where it must be unique. Media files can be created using 18 | .BR mktape(1) . 19 | .P 20 | .I OPTIONS 21 | are from: 22 | .TP 23 | .B \-d 24 | Enable debug logging (to stdout). Do not background the process, 25 | and set verbosity to level 9. 26 | .TP 27 | .BI \-v[ N ] 28 | Enable verbose logging (to syslog) at level \fIN\fR (default 1). 29 | .TP 30 | .BI \-f FIFO 31 | Near real time device state information will be available for external utilities by reading from this fifo. 32 | This switch has a higher precedence than the 'fifo:' entry in 33 | .BR 34 | device.conf . 35 | .SH AUTHOR 36 | Written by Mark Harvey 37 | .SH BUGS 38 | Does not implement the complete SCSI SSC-3 command set. 39 | .SH "REPORTING BUGS" 40 | Report bugs to 41 | .SH COPYRIGHT 42 | Copyright \(co 2019 Free Software Foundation, Inc. 43 | .br 44 | This is free software; see the source for copying conditions. There is NO 45 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 46 | .SH "SEE ALSO" 47 | .BR library_contents(5) , 48 | .BR make_vtl_media(1) , 49 | .BR mktape(1) , 50 | .BR vtlcmd(1) , 51 | .BR vtllibrary(1) 52 | -------------------------------------------------------------------------------- /scripts/70-persistent-generic.rules: -------------------------------------------------------------------------------- 1 | 2 | # Media changer 3 | ACTION=="add|change", KERNEL=="sg[0-9]*", SUBSYSTEM=="scsi_generic", PROGRAM=="/lib/udev/scsi_id --page=0x83 --whitelisted -u --device=$tempnode", RESULT=="?IBM_03584L32_XYZZY_A00*", NAME="sg9" 4 | 5 | # Persistent name starting from 'sg6' 6 | ACTION=="add|change", KERNEL=="sg[0-9]*", SUBSYSTEM=="scsi_generic", PROGRAM=="/lib/udev/scsi_id --page=0x83 --whitelisted --device=$tempnode", RESULT=="350223344ff000100", NAME="sg6" 7 | ACTION=="add|change", KERNEL=="sg[0-9]*", SUBSYSTEM=="scsi_generic", PROGRAM=="/lib/udev/scsi_id --page=0x83 --whitelisted --device=$tempnode", RESULT=="350223344ff000200", NAME="sg7" 8 | ACTION=="add|change", KERNEL=="sg[0-9]*", SUBSYSTEM=="scsi_generic", PROGRAM=="/lib/udev/scsi_id --page=0x83 --whitelisted --device=$tempnode", RESULT=="350223344ff000300", NAME="sg8" 9 | -------------------------------------------------------------------------------- /scripts/70-persistent-tape.rules: -------------------------------------------------------------------------------- 1 | ACTION=="add|change", KERNEL=="st[0-9]*", SUBSYSTEM=="scsi_tape", ENV{ID_SERIAL}=="350223344ff000100", NAME="st0" 2 | ACTION=="add|change", KERNEL=="nst[0-9]*", SUBSYSTEM=="scsi_tape", ENV{ID_SERIAL}=="350223344ff000100", NAME="nst0" 3 | # 4 | ACTION=="add|change", KERNEL=="st[0-9]*", SUBSYSTEM=="scsi_tape", ENV{ID_SERIAL}=="350223344ff000200", NAME="st1" 5 | ACTION=="add|change", KERNEL=="nst[0-9]*", SUBSYSTEM=="scsi_tape", ENV{ID_SERIAL}=="350223344ff000200", NAME="nst1" 6 | # 7 | ACTION=="add|change", KERNEL=="st[0-9]*", SUBSYSTEM=="scsi_tape", ENV{ID_SERIAL}=="350223344ff000300", NAME="st2" 8 | ACTION=="add|change", KERNEL=="nst[0-9]*", SUBSYSTEM=="scsi_tape", ENV{ID_SERIAL}=="350223344ff000300", NAME="nst2" 9 | -------------------------------------------------------------------------------- /scripts/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CURDIR = "../" 3 | include ../config.mk 4 | 5 | RCFILE = update_device.conf 6 | 7 | $(RCFILE): $(RCFILE).in 8 | sed -e s'/@CONF_PATH@/$(CONFIG_PATH)/' $< > $@ 9 | 10 | .PHONY: rcfile 11 | rcfile: $(RCFILE) 12 | 13 | .PHONY: distclean 14 | distclean: 15 | rm -f $(RCFILE) 16 | 17 | .PHONY: clean 18 | clean: 19 | rm -f $(RCFILE) 20 | 21 | .PHONY: install 22 | install: 23 | install -m 700 $(RCFILE) $(DESTDIR)$(PREFIX)/bin/ 24 | 25 | -------------------------------------------------------------------------------- /scripts/NetBackup/drive_stats.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # 3 | # To be called from NetBackup volmgr/bin/drive_unmount_notify 4 | # Parses output of "scsi_command -log_dump" 5 | # 6 | # To collect hard & soft errors from drive(s) along with informaiton 7 | # about bytes sent/received by initiator & bytes written/read to/from media 8 | # 9 | # Released under GPL2 license 10 | 11 | ############################################################################## 12 | ## Modules 13 | ############################################################################### 14 | 15 | use strict; 16 | use POSIX qw(locale_h); 17 | 18 | ############################################################################# 19 | ## Variables 20 | ############################################################################# 21 | my $locale = setlocale(LC_CTYPE); 22 | my $line; 23 | my $tape_usage = 0; 24 | my $read_errors = 0; 25 | my $write_errors = 0; 26 | my $last_drive = 0; 27 | my $last_drive_value = 0; 28 | 29 | my $write_bytes_initiator; 30 | my $write_bytes_media; 31 | my $read_bytes_initiator; 32 | my $read_bytes_media; 33 | 34 | my $total_corrective_read_errors; 35 | my $total_read_retries; 36 | 37 | my $total_corrective_write_errors; 38 | my $total_write_retries; 39 | 40 | print "\n ===============\n"; 41 | while($line = <>) { 42 | $line =~ s/^M//g; # Strip any cr/lf to lf 43 | chomp($line); 44 | # Print header information 45 | if ($line =~ /^Inquiry/) { 46 | print $line . "\n"; 47 | } 48 | if ($line =~ /path/) { 49 | print $line . "\n"; 50 | } 51 | if ($line =~ /Serial_Number/) { 52 | print $line . "\n\n"; 53 | } 54 | 55 | # Search for Write Error log page (0x02) 56 | if ($line =~ /^\*\*\*Write\s+Error\s+Log\s+Page/) { 57 | $tape_usage = 0; 58 | $write_errors = 1; 59 | $read_errors = 0; 60 | } 61 | # Search for Read Error log page (0x03) 62 | if ($line =~ /^\*\*\*Read\s+Error\s+Log\s+Page/) { 63 | $tape_usage = 0; 64 | $write_errors = 0; 65 | $read_errors = 1; 66 | } 67 | # Search for Tape Usage log page (0x0C) 68 | if ($line =~ /^\*\*\*Log\s+page\s+\((.*)\)/) { 69 | if ($1 =~ /0x0c/) { # Found Tape Usage log page 70 | $tape_usage = 1; 71 | $write_errors = 0; 72 | $read_errors = 0; 73 | } else { # Not a log page we're interested in - reset all 74 | $tape_usage = 0; 75 | $write_errors = 0; 76 | $read_errors = 0; 77 | } 78 | } 79 | # last loop matched key.. This time around is the value 80 | if ($last_drive) { 81 | $last_drive_value = 1; 82 | } 83 | if ($line =~ /attribute\s0x020[abcd]/) { # Key match 84 | $last_drive = 1; 85 | $last_drive_value = 0; 86 | } 87 | 88 | if ($tape_usage) { 89 | if ($line =~ /parameter\s+code:\s+0x0000,\s+value:\s+(.*)/) { 90 | $write_bytes_initiator = hex("$1"); 91 | print "Bytes written by initiator : $write_bytes_initiator\n"; 92 | } 93 | if ($line =~ /parameter\s+code:\s+0x0001,\s+value:\s+(.*)/) { 94 | $write_bytes_media = hex("$1"); 95 | print "Bytes written to media : $write_bytes_media\n"; 96 | } 97 | if ($line =~ /parameter\s+code:\s+0x0002,\s+value:\s+(.*)/) { 98 | $read_bytes_media = hex("$1"); 99 | print "Bytes read from media : $read_bytes_media\n"; 100 | } 101 | if ($line =~ /parameter\s+code:\s+0x0003,\s+value:\s+(.*)/) { 102 | $read_bytes_initiator = hex("$1"); 103 | print "Bytes read by initiator : $read_bytes_initiator\n"; 104 | } 105 | } 106 | if ($read_errors) { 107 | if ($line =~ /parameter\s+code:\s+0x0003,\s+value:\s+(.*)/) { 108 | $total_corrective_read_errors = hex("$1"); 109 | print "Total Corrective read errors : $total_corrective_read_errors\n"; 110 | } 111 | if ($line =~ /parameter\s+code:\s+0x0004,\s+value:\s+(.*)/) { 112 | $total_read_retries = hex("$1"); 113 | print "Total read retries : $total_read_retries\n"; 114 | } 115 | } 116 | if ($write_errors) { 117 | if ($line =~ /parameter\s+code:\s+0x0003,\s+value:\s+(.*)/) { 118 | $total_corrective_write_errors = hex("$1"); 119 | print "Total Corrective write errors : $total_corrective_write_errors\n"; 120 | } 121 | if ($line =~ /parameter\s+code:\s+0x0004,\s+value:\s+(.*)/) { 122 | $total_write_retries = hex("$1"); 123 | print "Total write retries : $total_write_retries\n"; 124 | } 125 | } 126 | if ($last_drive_value) { 127 | print "Media previously mounted in : $line\n"; 128 | $last_drive_value = 0; 129 | $last_drive = 0; 130 | } 131 | } 132 | 133 | -------------------------------------------------------------------------------- /scripts/NetBackup/vlt_endeject_notify.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # vlt_endeject_notify 3 | # 4 | # This script is called after the vault job completes the eject processing for 5 | # the media to be vaulted. 6 | # 7 | # This script will empty the MAP after a vault eject and insert any tapes 8 | # "returning" from the vault into 9 | # 10 | # Netbackup provides 4 parameters to the script when executed from 11 | # a vault profile: 12 | # 1 = $robot_number - robot number 13 | # 2 = $vault_name - logical vault name 14 | # 3 = $vault_profile - profile name 15 | # 4 = $vault_session_id - vault session id 16 | 17 | # This script: 18 | # must be executable by the root user 19 | # must exit with 0 upon successful completion 20 | # must exit with a non zero error code upon failure 21 | # 22 | # CAUTION: writing anything to stdout or stderr will cause problems in the 23 | # calling program. 24 | # 25 | # This script closes STDOUT and STDERR and opens them as a pipe to the 26 | # mail command. 27 | # Any errors encountered will be in the output that is emailed. 28 | use strict; 29 | use warnings; 30 | 31 | my ($robot_number, $vault_name, $vault_profile, $vault_session_id) = @ARGV; 32 | 33 | my $mail_to = join ",", qw( 34 | admin1@example.com 35 | admin2@example.com 36 | ); 37 | 38 | my $vtlcmd_binary = "/usr/bin/vtlcmd"; 39 | my $vmquery_binary = "/usr/openv/volmgr/bin/vmquery"; 40 | my $vmupdate_binary = "/usr/openv/volmgr/bin/vmupdate"; 41 | my $robot_type = "tld"; # Netbackup robot type 42 | my $mhvtl_robot_number = 50; 43 | my $mail_subject = "Vault Eject for $vault_name"; 44 | my $mail_binary = find_mail_binary(); 45 | my $scratch_pool = "Scratch"; 46 | 47 | # Open STDOUT and STDERR as pipes to the mail command only if not running in an 48 | # interactive terminal 49 | if (not -t STDIN and not -t STDOUT) { 50 | close(STDOUT); 51 | close(STDERR); 52 | open(STDOUT, "|-", qq{$mail_binary -s "$mail_subject" "$mail_to"} ); 53 | open(STDERR, ">&", "STDOUT"); 54 | } 55 | 56 | list_map(); 57 | open_map(); 58 | empty_map(); 59 | insert_tapes(); 60 | close_map(); 61 | inventory_robot(); 62 | 63 | sub empty_map { 64 | print "Emptying MAP: "; 65 | system("$vtlcmd_binary $mhvtl_robot_number empty map"); 66 | if ($?) { 67 | die "Error emptying MAP: $!"; 68 | } 69 | } 70 | 71 | sub list_map { 72 | print "Current MAP "; 73 | system("$vtlcmd_binary $mhvtl_robot_number list map"); 74 | if ($?) { 75 | die "Error listing contents of MAP: $@"; 76 | } 77 | } 78 | 79 | sub open_map { 80 | print "Opening MAP: "; 81 | system("$vtlcmd_binary $mhvtl_robot_number open map"); 82 | if ($?) { 83 | die "Error opening MAP: $!"; 84 | } 85 | } 86 | 87 | sub close_map { 88 | print "Closing MAP: "; 89 | system("$vtlcmd_binary $mhvtl_robot_number close map"); 90 | if ($?) { 91 | die "Error closing MAP: $!"; 92 | } 93 | } 94 | 95 | sub inventory_robot { 96 | print "Inventorying robot:\n"; 97 | system("$vmupdate_binary -rt $robot_type -rn $robot_number -full -empty_map -use_barcode_rules"); 98 | if ($?) { 99 | die "Error inventorying robot: $!"; 100 | } 101 | } 102 | 103 | sub insert_tapes { 104 | # Get all tapes that are "outside" the library and have been returned to the 105 | # scratch volume pool 106 | my @returned_tapes = 107 | map { 108 | (split /\s+/, $_)[3] 109 | } 110 | grep { 111 | # This regex filters all lines that don't have the 12th field (Volume Pool) 112 | # as the Scratch Volume Pool 113 | /^(?:[^\s]+\s+){11}$scratch_pool/ 114 | } `$vmquery_binary -rt NONE -W`; 115 | 116 | if ($?) { 117 | die "Error running vmquery: $!"; 118 | } 119 | 120 | foreach my $tape_to_insert (@returned_tapes) { 121 | print "Loading Tape $tape_to_insert into MAP: "; 122 | system("$vtlcmd_binary $mhvtl_robot_number load map $tape_to_insert"); 123 | if ($?) { 124 | die "Error inserting tape into MAP: $!"; 125 | } 126 | } 127 | } 128 | 129 | # Taken from the sample netbackup vlt_endeject_notify script 130 | sub find_mail_binary { 131 | foreach my $mail_command ( qw( mailx Mail mail ) ) { 132 | foreach my $mail_dir ( qw( /usr/bin /usr/ucb /usr/sbin /bin /sbin ) ) { 133 | return "$mail_dir/$mail_command" if -e "$mail_dir/$mail_command"; 134 | } 135 | } 136 | 137 | die "No mail binary found!"; 138 | } 139 | -------------------------------------------------------------------------------- /scripts/build-persistent-tape-rules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # To 'view' what are valid fields we can use - Pick a tape drive you are interested in. using /dev/st0 here. 4 | 5 | # # udevadm info --name=/dev/st0 --query=all 6 | # P: /devices/pseudo_9/adapter0/host4/target4:0:1/4:0:1:0/scsi_tape/st0 7 | # N: st0 8 | # S: tape/by-id/scsi-350223344ab000100 9 | # E: DEVLINKS=/dev/tape/by-id/scsi-350223344ab000100 10 | # E: DEVNAME=/dev/st0 11 | # E: DEVPATH=/devices/pseudo_9/adapter0/host4/target4:0:1/4:0:1:0/scsi_tape/st0 12 | # E: ID_BUS=scsi 13 | # E: ID_MODEL=ULT3580-TD5 14 | # E: ID_MODEL_ENC=ULT3580-TD5\x20\x20\x20\x20\x20 15 | # E: ID_REVISION=0105 16 | # E: ID_SCSI=1 17 | # E: ID_SCSI_SERIAL=XYZZY_A1 18 | # E: ID_SERIAL=350223344ab000100 19 | # E: ID_SERIAL_SHORT=50223344ab000100 20 | # E: ID_TYPE=tape 21 | # E: ID_VENDOR=IBM 22 | # E: ID_VENDOR_ENC=IBM\x20\x20\x20\x20\x20 23 | # E: ID_WWN=0x50223344ab000100 24 | # E: ID_WWN_WITH_EXTENSION=0x50223344ab000100 25 | # E: MAJOR=9 26 | # E: MINOR=0 27 | # E: SUBSYSTEM=scsi_tape 28 | # E: USEC_INITIALIZED=421748 29 | # E: nodmraid=1 30 | # 31 | # Anything beginning with 'E' are environmental and can be used by/for 'ENV{}' 32 | 33 | for SN in `grep ^Drive -A6 /etc/mhvtl/device.conf | awk '/NAA:/ {print $2}' | sed -e "s/://g" -e "s/^[13]0/50/g"` 34 | do 35 | echo "ACTION==\"add|change\", KERNEL==\"nst*\", ENV{SUBSYSTEM}==\"scsi_tape\", ENV{ID_SERIAL_SHORT}==\"$SN\", SYMLINK+=\"tape/by-path/%E{ID_VENDOR}-%E{ID_MODEL}-%E{ID_SCSI_SERIAL}-nst\", MODE=\"0666\"" 36 | done 37 | -------------------------------------------------------------------------------- /scripts/centos_configure.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ### Install script for auto install mhvtl on CentOS Linux 6.2 i386/x86_64 4 | ### Version: 1.0.0 5 | ### made by patrick ru 6 | ### mail: patrick.ru@hotmail.com 7 | ### Date: 2012.Mar.18 8 | 9 | # prepair : pre-install centos linux 6.2 with minimal installation. 10 | 11 | # update the system 12 | yum update -y 13 | 14 | # close the selinux and the firewall 15 | chkconfig iptables off 16 | service iptables stop 17 | sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config 18 | /usr/sbin/setenforce 0 19 | 20 | # install Git 21 | yum install -y git 22 | 23 | # install supported Rpms 24 | yum install -y mc ntp gcc gcc-c++ make kernel-devel zlib-devel sg3_utils lsscsi mt-st mtx lzo lzo-devel perl-Config-General 25 | 26 | # Create required directories 27 | mkdir -p /opt/mhvtl 28 | mkdir -p /etc/mhvtl 29 | 30 | # install mhvtl 31 | mkdir -p /usr/src/mhvtl 32 | cd /usr/src/mhvtl 33 | git init 34 | git pull http://github.com/markh794/mhvtl.git 35 | make distclean 36 | cd kernel/ 37 | make && make install 38 | cd .. 39 | make && make install 40 | systemctl enable mhvtl 41 | systemctl start mhvtl 42 | 43 | # install tgt 44 | mkdir /etc/tgt 45 | mkdir /usr/src/tgt 46 | cd /usr/src/tgt 47 | git init 48 | git pull http://github.com/fujita/tgt.git 49 | make && make install 50 | /usr/sbin/tgtd -d 1 51 | 52 | # install mhvtl-gui 53 | yum install -y httpd php sudo sysstat 54 | cp /etc/sudoers /etc/sudoers.old 55 | sed -i '/Defaults requiretty/s/^/#/' /etc/sudoers 56 | echo "apache ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers 57 | chkconfig httpd on 58 | mkdir /var/www/html/mhvtl 59 | cd /var/www/html/mhvtl 60 | git init 61 | git pull http://github.com/niadev67/mhvtl-gui.git 62 | chown -R apache:apache ./ 63 | service httpd start 64 | touch /var/www/html/mhvtl/ENABLE_TGTD_SCSI_TARGET 65 | sh scripts/auto.iscsi.config.stgt.sh 66 | 67 | echo installation has finished! please use mhvtl-gui to install and config tgtd after config the mhvtl for running! 68 | -------------------------------------------------------------------------------- /scripts/checkarch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | arch=`gcc -dumpmachine` 3 | 4 | case $arch in 5 | `echo $arch | grep x86_64`) 6 | echo -m64 7 | ;; 8 | `echo $arch | grep "i[3-6]86"`) 9 | echo -m32 10 | ;; 11 | *) 12 | echo ' 13 | Failed to parse your architecture. 14 | Please run 15 | 16 | $ make check32 17 | 18 | or 19 | 20 | $ make check64 21 | 22 | manually. 23 | ' 24 | exit 1 25 | ;; 26 | esac 27 | -------------------------------------------------------------------------------- /scripts/lio_target_passthru.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "Usage: $0 initiator_iqn (to add to iSCSI ACL)" 5 | exit 6 | fi 7 | # Use $1 if defined, otherwise default to this IQN iniator addr 8 | INIT_IQN=${1:-iqn.1994-05.com.redhat:e284d58153b4} 9 | 10 | # Reference: 11 | # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=880576 12 | 13 | IQN="iqn.2019-03.com.mhvtl:target" 14 | 15 | HBA=`lsscsi -H | awk '/mhvtl/ {print $1}' | sed -e 's/\[//' -e 's/\]//'` 16 | 17 | # Extract SCSI h:b:t:l of each dev 18 | SCSI_ADDR=`lsscsi $HBA | awk '{print $1}'` 19 | 20 | targetcli /iscsi/ create $IQN 21 | 22 | # Setup LIO backing store - Walk each device, extract /dev/sg path 23 | for dev in $SCSI_ADDR 24 | do 25 | read -r hba channel id lun <<< `echo $dev | awk -F: '{print $1,$2,$3,$4}' | sed -e 's/\[//' -e 's/\]//g'` 26 | 27 | # Extract the SCSI Passthru device (/dev/sg) of this h:b:t:l 28 | PASSTHRU=`lsscsi -g $hba $channel $id $lun | awk '{print $7}'` 29 | 30 | echo "hba: $hba, Channel: $channel, SCSI ID: $id, SCSI LUN: $lun - scsi passthru path: $PASSTHRU" 31 | MHVTL=$(printf "h%db%dt%dl%d" $hba $channel $id $lun) 32 | 33 | TLD="/sys/kernel/config/target/core/pscsi_0/mhVTL${MHVTL}" 34 | mkdir -p $TLD 35 | uuidgen > $TLD/wwn/vpd_unit_serial 36 | echo scsi_host_id=$hba,scsi_channel_id=$channel,scsi_target_id=$id,scsi_lun_id=$lun > $TLD/control 37 | echo $PASSTHRU > $TLD/udev_path 38 | echo 1 > $TLD/enable 39 | 40 | # Map LIO backing store to mhVTL /dev/sgXX path 41 | targetcli /iscsi/$IQN/tpg1/luns/ create /backstores/pscsi/mhVTL${MHVTL} 42 | # targetcli ls 43 | # sleep 2 44 | done 45 | 46 | targetcli /iscsi/$IQN/tpg1/acls/ create $INIT_IQN 47 | 48 | targetcli ls 49 | 50 | # Open up TCP port 3260 through iptables 51 | # CentOS7 anyway.. 52 | firewall-cmd --add-port 3260/tcp 53 | 54 | -------------------------------------------------------------------------------- /scripts/mhvtl-1.4.ebuild: -------------------------------------------------------------------------------- 1 | # Copyright 1999-2010 Gentoo Foundation 2 | # Distributed under the terms of the GNU General Public License v2 3 | # $Header: 4 | 5 | EAPI="2" 6 | 7 | inherit linux-mod eutils 8 | 9 | MY_P="${PN}-2012-09-13" 10 | DESCRIPTION="mhvtl module provides Virtual (SCSI) Tape Library" 11 | HOMEPAGE="http://sites.google.com/site/linuxvtl2" 12 | SRC_URI="http://sites.google.com/site/linuxvtl2/${MY_P}.tgz" 13 | 14 | LICENSE="GPL-2" 15 | SLOT="0" 16 | KEYWORDS="~amd64 ~x86" 17 | IUSE="doc" 18 | 19 | DEPEND=">=virtual/linux-sources-2.6.19 20 | sys-fs/lsscsi 21 | sys-libs/zlib 22 | sys-libs/lzo 23 | sys-apps/sg3_utils" 24 | RDEPEND="" 25 | 26 | MODULE_NAMES="mhvtl(block:${S}/kernel:${S}/kernel)" 27 | BUILD_TARGETS="clean default" 28 | MHVTL_HOME_PATH=/var/spool/media/vtl 29 | 30 | pkg_setup() { 31 | CONFIG_CHECK="~BLK_DEV_SR ~CHR_DEV_SG" 32 | check_extra_config 33 | BUILD_PARAMS="KDIR=${KV_DIR}" 34 | linux-mod_pkg_setup 35 | } 36 | 37 | src_prepare() { 38 | epatch "${FILESDIR}/1.2-kerneldir.patch" 39 | epatch "${FILESDIR}/1.2-etc.patch" 40 | epatch "${FILESDIR}/1.2-make_vtl_media.patch" 41 | epatch "${FILESDIR}/1.2-mhvtl.patch" 42 | } 43 | 44 | src_compile() { 45 | emake clean || die 46 | linux-mod_src_compile || die "linux-mod_src_compile" 47 | emake MHVTL_HOME_PATH=${MHVTL_HOME_PATH} || die "emake failed" 48 | } 49 | 50 | src_install() { 51 | linux-mod_src_install || die "Error: installing module failed!" 52 | 53 | emake MHVTL_HOME_PATH=${MHVTL_HOME_PATH} DESTDIR=${D} install || die "emake failed" 54 | 55 | einfo "Generating udev rules ..." 56 | dodir /etc/udev/rules.d/ 57 | cat > "${D}"/etc/udev/rules.d/70-mhvtl.rules <<-EOF || die 58 | # do not edit this file, it will be overwritten on update 59 | # 60 | KERNEL=="mhvtl[0-9]*", MODE="0660", OWNER="root", GROUP="root" 61 | EOF 62 | 63 | newinitd "${FILESDIR}"/mhvtl.init.d mhvtl || die 64 | 65 | if use doc; then 66 | dohtml -r doc/* || die 67 | fi 68 | 69 | doman man/*.1 || die 70 | dodoc README INSTALL 71 | } 72 | 73 | pkg_postinst() { 74 | linux-mod_pkg_postinst 75 | } 76 | -------------------------------------------------------------------------------- /scripts/start-mhvtl-scst.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | modprobe mpt2sas 4 | modprobe pl2303 5 | 6 | modprobe scst 7 | modprobe scst-vdisk 8 | modprobe scst_tape 9 | modprobe scst_changer 10 | 11 | # for iSCSI 12 | modprobe scsi_transport_iscsi 13 | modprobe iscsi-scst 14 | iscsi-scstd 15 | iscsid 16 | 17 | # for FC 18 | modprobe qla2x00tgt 19 | 20 | modprobe scst_user 21 | modprobe scst_local 22 | 23 | /opt/fast/application/fileio/fileio_tgt_gpu -o -e 1 -b 4096 gpu01 gpu -- -o -s $((1000*1024*1024*1024)) $(/opt/fast/scripts/diskmapper.sh /opt/fast/scripts/disks_shelf_2.lst) & 24 | 25 | sleep 3 26 | 27 | echo "add gpu01 0" > /sys/kernel/scst_tgt/targets/scst_local/scst_local_tgt/luns/mgmt 28 | 29 | DEVICE=`lsscsi | grep gpu01 | awk '{print $6;}'` 30 | 31 | echo "Formatting GPU Device: $DEVICE" 32 | 33 | mkfs.ext4 $DEVICE 34 | 35 | mount $DEVICE /mnt 36 | 37 | mkdir -p /mnt/mhvtl-data 38 | chown vtl:vtl /mnt/mhvtl-data 39 | ln -s /mnt/mhvtl-data /opt/mhvtl 40 | make_vtl_media 41 | 42 | systemctl start mhvtl 43 | 44 | sleep 5 45 | 46 | # create SCST config 47 | 48 | ( 49 | cat << 'EOF' 50 | 51 | HANDLER dev_tape { 52 | DEVICE 7:0:1:0 53 | DEVICE 7:0:2:0 54 | } 55 | 56 | HANDLER dev_changer { 57 | DEVICE 7:0:0:0 58 | } 59 | 60 | TARGET_DRIVER qla2x00t { 61 | enabled 1 62 | 63 | TARGET 21:00:00:24:ff:05:7b:1a { 64 | LUN 1 7:0:0:0 65 | LUN 2 7:0:1:0 66 | LUN 3 7:0:2:0 67 | enabled 1 68 | } 69 | } 70 | 71 | EOF 72 | ) > /etc/scst.conf 73 | 74 | scstadmin -config 75 | -------------------------------------------------------------------------------- /scripts/stgt-target-setup.conf: -------------------------------------------------------------------------------- 1 | # This is a sample config file for tgt-admin. 2 | # By default, tgt-admin looks for its config file in /etc/tgt/targets.conf 3 | 4 | # Set the driver. If not specified, defaults to "iscsi". 5 | default-driver iscsi 6 | 7 | # Sample target with one LUN only. Defaults to allow access for all initiators: 8 | 9 | 10 | device-type pt 11 | bs-type sg 12 | backing-store /dev/sg2 13 | backing-store /dev/sg3 14 | allow-in-use yes 15 | 16 | 17 | -------------------------------------------------------------------------------- /scripts/test_lbp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #systemctl stop mhvtl 4 | #systemctl start mhvtl 5 | 6 | if [[ $EUID -ne 0 ]]; then 7 | echo "Sorry, this script needs to be run as root" 8 | exit 1 9 | fi 10 | 11 | # Library source slot to move tape to/from 12 | SOURCE_SLOT=1 13 | # Which drive are we testing - /etc/mhvtl/device.conf 14 | DRV_INDEX=18 15 | 16 | while [[ $# -gt 0 ]]; do 17 | case $1 in 18 | -i|--index) 19 | if [ -z "$2" ]; then # Check for missing arg 20 | echo "Usage: Need to specify drive index" 21 | echo "e.g. $0 -i 11" 22 | exit 1 23 | fi 24 | DRV_INDEX="$2" 25 | shift # past argument 26 | shift # past value 27 | ;; 28 | 29 | -s|--source) 30 | if [ -z "$2" ]; then # Check for missing arg 31 | echo "Usage: Need to specify source slot" 32 | echo "e.g. $0 -s 1" 33 | exit 1 34 | fi 35 | SOURCE_SLOT="$2" 36 | shift # past argument 37 | shift # past value 38 | ;; 39 | 40 | *) 41 | shift # past argument 42 | ;; 43 | esac 44 | done 45 | 46 | 47 | i=`grep -A6 "^Drive: ${DRV_INDEX} " /etc/mhvtl/device.conf | awk '/Library/ {print $5}'` 48 | # Convert into hex - leading '0' typically means it's an octal value 49 | TARGET_DRIVE=$((16#${i}-1)) 50 | if [ ${TARGET_DRIVE} -lt 0 ]; then 51 | echo "Unable to find drive at index ${DRV_INDEX}... Exiting" 52 | echo "Perhaps provide drive index using \"-i \"" 53 | echo "e.g. $0 -i 11" 54 | exit 55 | fi 56 | 57 | read -r channel id lun <<< `grep "^Drive: ${DRV_INDEX} " /etc/mhvtl/device.conf | awk '{print $4,$6,$8}'` 58 | #echo "Channel: $channel, id: $id, lun: $lun" 59 | 60 | HBA=`lsscsi -H | awk '/mhvtl/ {print $1}' | sed -e 's/\[//g' -e 's/\]//g'` 61 | SG=`lsscsi -g ${HBA} ${channel} ${id} ${lun} | awk '{print $7}'` 62 | ST=`lsscsi -g ${HBA} ${channel} ${id} ${lun} | awk '{print $6}'` 63 | 64 | MTX=`lsscsi -g ${HBA} 0 0 0 | awk '{print $7}'` 65 | 66 | #echo "HBA: ${HBA}" 67 | #echo "st : ${ST}" 68 | #echo "sg : ${SG}" 69 | #echo "mtx : ${MTX}" 70 | 71 | echo "++ Moving tape slot: ${SOURCE_SLOT} to drive: ${TARGET_DRIVE}" 72 | mtx -f ${MTX} load ${SOURCE_SLOT} ${TARGET_DRIVE} 73 | vtlcmd ${DRV_INDEX} verbose 74 | vtlcmd ${DRV_INDEX} verbose 75 | 76 | echo 77 | 78 | echo "++ Checking status of ${ST}" 79 | mt -f ${ST} status 80 | 81 | echo 82 | 83 | CRC32C=2 84 | RSCRC=1 85 | LBP_W="40" 86 | LBP_R="80" 87 | LBP_RW="c0" 88 | ## Set LBP_W 89 | #sg_wr_mode -p 0x0a,0xf0 -d -c 0a,f0,00,1c,${CRC32C},4,${LBP_W},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ${SG} 90 | ## Set LBP_R 91 | #sg_wr_mode -p 0x0a,0xf0 -d -c 0a,f0,00,1c,${CRC32C},4,${LBP_R},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ${SG} 92 | 93 | # Set LBP_R & LBP_W 94 | echo -e "++ Enable LBP CRC32C RW\n" 95 | sg_wr_mode -p 0x0a,0xf0 -d -c 0a,f0,00,1c,${CRC32C},4,${LBP_RW},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ${SG} 96 | 97 | echo -e "++ Reading 64k + 4 to /tmp/CRC32c.out" 98 | dd if=${ST} of=/tmp/CRC32c.out bs=65540 count=1 99 | 100 | echo 101 | 102 | echo -e "++ Enable LBP Reed-Solomon CRC RW\n" 103 | sg_wr_mode -p 0x0a,0xf0 -d -c 0a,f0,00,1c,${RSCRC},4,${LBP_RW},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ${SG} 104 | 105 | echo "++ Reading 64k + 4 to /tmp/RS-CRC.out" 106 | dd if=${ST} of=/tmp/RS-CRC.out bs=65540 count=1 107 | 108 | echo 109 | 110 | # Turn off LBP 111 | echo -e "++ Turn off LBP\n" 112 | sg_wr_mode -p 0x0a,0xf0 -d -c 0a,f0,00,1c,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ${SG} 113 | 114 | echo "++ Reading 64k to /tmp/NO_LBP.out" 115 | dd if=${ST} of=/tmp/NO_LBP.out bs=65540 count=1 116 | 117 | echo 118 | 119 | echo "Offline drive" 120 | mt -f ${ST} offline 121 | 122 | echo "Moving tape from drive: ${TARGET_DRIVE} to slot: ${SOURCE_SLOT}" 123 | mtx -f ${MTX} unload ${SOURCE_SLOT} ${TARGET_DRIVE} 124 | -------------------------------------------------------------------------------- /scripts/update_device.conf.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # 3 | # Copyright (C) 2005 - 2025 Mark Harvey markh794@gmail.com 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; version 2 of the License. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | # 18 | 19 | use strict; 20 | 21 | my $if; 22 | my $lib; 23 | my $slt = 1; 24 | my $num_drives = 0; 25 | my $old_device_conf = "@CONF_PATH@/device.conf"; 26 | my $new_device_conf = "@CONF_PATH@/device.conf_$$"; 27 | 28 | if (! -e $old_device_conf ) { 29 | die "Can not find $old_device_conf"; 30 | } 31 | 32 | # Confirm device.conf not current version.. 33 | # Also count number of drives. 34 | open(IF, " < $old_device_conf") || die "Can't open $old_device_conf"; 35 | while($if = ) { 36 | if ($if =~ /VERSION:\s+(\d+)/) { 37 | if ($1 == 4) { 38 | print "Nothing to upgrade.. Exiting\n"; 39 | exit 0; 40 | } 41 | } 42 | if ($if =~ /Library\sID:.*Slot:/) { # Found V4 type entry.. Exit 43 | exit 0; 44 | } 45 | if ($if =~ /^Drive/) { 46 | $num_drives++; 47 | } 48 | } 49 | close IF; 50 | 51 | # Now create new temporary device.conf 52 | $lib = $num_drives + 1; 53 | open(IF, " < $old_device_conf") || die "Can't open $old_device_conf for reading"; 54 | open(OF, " > $new_device_conf") || die "Can't open $new_device_conf for writing"; 55 | while($if = ) { 56 | # Update library 'index' with max drives + 1 57 | $if =~ s/^Library:\s(\d+)/Library: $lib/g; 58 | if ($if =~ /VERSION:/) { 59 | print OF "VERSION: 4\n"; 60 | } else { 61 | print OF $if; 62 | } 63 | if ($if =~ /^Drive:\s(\d+)/) { 64 | print OF " Library ID: $lib Slot: $slt\n"; 65 | $slt++; 66 | } 67 | } 68 | close IF; 69 | close OF; 70 | 71 | # Now remove original config file and replace with new one 72 | unlink($old_device_conf); 73 | system("mv $new_device_conf $old_device_conf"); 74 | 75 | # Now 'move' library_contents to library_contents.$lib 76 | $new_device_conf = "@CONF_PATH@/library_contents.$lib"; 77 | $old_device_conf = "@CONF_PATH@/library_contents"; 78 | open(IF, " < $old_device_conf") || die "Can't open $old_device_conf for reading"; 79 | open(OF, " > $new_device_conf") || die "Can't open $new_device_conf for writing"; 80 | while($if = ) { 81 | print OF $if; 82 | } 83 | close IF; 84 | close OF; 85 | 86 | # Now remove original file(s) 87 | unlink($old_device_conf); 88 | 89 | exit 0; 90 | 91 | -------------------------------------------------------------------------------- /tcopy/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for linux port of Tcopy 2 | # By Nicholas Harbour, 2000 3 | 4 | CURDIR = "../" 5 | include ../config.mk 6 | 7 | BINARY=tcopy 8 | MANPAGE=tcopy.1 9 | BIN_PATH=$(PREFIX)/bin/ 10 | MAN_PATH=$(PREFIX)/$(MANDIR)/man1/ 11 | OBJS=tcopy.o 12 | CC=gcc 13 | OPTS=-Wall 14 | 15 | all: tcopy install 16 | 17 | tcopy: clean $(OBJS) 18 | $(CC) $(OPTS) -o $(BINARY) $(OBJS) 19 | 20 | install: tcopy 21 | cp $(BINARY) $(BIN_PATH) 22 | cp $(MANPAGE) $(MAN_PATH) 23 | 24 | clean: 25 | rm -f $(OBJS) tcopy 26 | 27 | -------------------------------------------------------------------------------- /tcopy/pathnames.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1989, 1993 3 | * The Regents of the University of California. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by the University of 16 | * California, Berkeley and its contributors. 17 | * 4. Neither the name of the University nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 | * SUCH DAMAGE. 32 | * 33 | * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 34 | */ 35 | 36 | #define _PATH_DEFTAPE "/dev/nst0" 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /tcopy/tcopy.1: -------------------------------------------------------------------------------- 1 | .\" Copyright (c) 1985, 1990, 1991, 1993 2 | .\" The Regents of the University of California. All rights reserved. 3 | .\" 4 | .\" Redistribution and use in source and binary forms, with or without 5 | .\" modification, are permitted provided that the following conditions 6 | .\" are met: 7 | .\" 1. Redistributions of source code must retain the above copyright 8 | .\" notice, this list of conditions and the following disclaimer. 9 | .\" 2. Redistributions in binary form must reproduce the above copyright 10 | .\" notice, this list of conditions and the following disclaimer in the 11 | .\" documentation and/or other materials provided with the distribution. 12 | .\" 3. All advertising materials mentioning features or use of this software 13 | .\" must display the following acknowledgement: 14 | .\" This product includes software developed by the University of 15 | .\" California, Berkeley and its contributors. 16 | .\" 4. Neither the name of the University nor the names of its contributors 17 | .\" may be used to endorse or promote products derived from this software 18 | .\" without specific prior written permission. 19 | .\" 20 | .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 | .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 | .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | .\" SUCH DAMAGE. 31 | .\" 32 | .\" @(#)tcopy.1 8.2 (Berkeley) 4/17/94 33 | .\" $FreeBSD: src/usr.bin/tcopy/tcopy.1,v 1.7 2000/03/01 12:20:12 sheldonh Exp $ 34 | .\" 35 | .Dd April 17, 1994 36 | .Dt TCOPY 1 37 | .Os BSD 4.3 38 | .Sh NAME 39 | .Nm tcopy 40 | .Nd copy and/or verify mag tapes 41 | .Sh SYNOPSIS 42 | .Nm 43 | .Op Fl cvx 44 | .Op Fl s Ar maxblk 45 | .Oo Ar src Op Ar dest 46 | .Oc 47 | .Sh DESCRIPTION 48 | .Nm Tcopy 49 | is designed to copy magnetic tapes. The only assumption made 50 | about the tape is that there are two tape marks at the end. 51 | .Nm Tcopy 52 | with only a source tape 53 | .Pf ( Ar /dev/nst0 54 | by default) specified will print 55 | information about the sizes of records and tape files. If a destination 56 | is specified a copy will be made of the source tape. The blocking on the 57 | destination tape will be identical to that used on the source tape. Copying 58 | a tape will yield the same output as if just printing the sizes. 59 | .Pp 60 | Options: 61 | .Bl -tag -width s_maxblk 62 | .It Fl c 63 | Copy 64 | .Ar src 65 | to 66 | .Ar dest 67 | and then verify that the two tapes are identical. 68 | .It Fl s Ar maxblk 69 | Specify a maximum block size, 70 | .Ar maxblk . 71 | .It Fl v 72 | Given the two tapes, 73 | .ar src 74 | and 75 | .Ar dest 76 | verify that they are identical. 77 | .It Fl x 78 | Output all informational messages to the standard error. 79 | This option is useful when 80 | .Ar dest 81 | is 82 | .Pa /dev/stdout . 83 | .El 84 | .Sh SEE ALSO 85 | .Xr mtio 4 86 | .Sh HISTORY 87 | The 88 | .Nm 89 | command appeared in 90 | .Bx 4.3 . 91 | .Sh BUGS 92 | Writting an image of a tape to a file does not preserve much more than 93 | the raw data. 94 | Block size(s) and tape EOF marks are lost which would 95 | otherwise be preserved in a tape-to-tape copy. 96 | 97 | EOD is determined by two sequential EOF marks with no data between. 98 | There are old systems which typically wrote three EOF's between tape 99 | files. 100 | .Xr tcopy 1 101 | will erroneously stop copying early in this case. 102 | 103 | When using the copy/verify option \-c 104 | .Xr tcopy 1 105 | does not rewind the tapes prior to start. 106 | A rewind is performed 107 | after writing prior to the verification stage. 108 | If one doesn't start 109 | at BOT then the comparison may not be of the intended data. 110 | -------------------------------------------------------------------------------- /todo: -------------------------------------------------------------------------------- 1 | - Review return values from functions and make consistent. 2 | Some functions return SAM_STAT_XXX, some return *sam_status 3 | 4 | - Major -> Add personality modules to library 5 | ================================ 6 | 7 | -------------------------------------------------------------------------------- /usr/.gitignore: -------------------------------------------------------------------------------- 1 | mhvtl-device-conf-generator 2 | dump_messageQ 3 | dump_tape 4 | edit_tape 5 | preload_tape 6 | libvtlcart.so 7 | libvtlscsi.so 8 | make_vtl_media 9 | mktape 10 | tapeexerciser 11 | vtlcmd 12 | vtllibrary 13 | vtltape 14 | TAGS 15 | -------------------------------------------------------------------------------- /usr/README.LZO: -------------------------------------------------------------------------------- 1 | 2 | ============================================================================ 3 | miniLZO -- mini subset of the LZO real-time data compression library 4 | ============================================================================ 5 | 6 | Author : Markus Franz Xaver Johannes Oberhumer 7 | 8 | http://www.oberhumer.com/opensource/lzo/ 9 | Version : 2.09 10 | Date : 04 Feb 2015 11 | 12 | I've created miniLZO for projects where it is inconvenient to 13 | include (or require) the full LZO source code just because you 14 | want to add a little bit of data compression to your application. 15 | 16 | miniLZO implements the LZO1X-1 compressor and both the standard and 17 | safe LZO1X decompressor. Apart from fast compression it also useful 18 | for situations where you want to use pre-compressed data files (which 19 | must have been compressed with LZO1X-999). 20 | 21 | miniLZO consists of one C source file and three header files: 22 | minilzo.c 23 | minilzo.h, lzoconf.h, lzodefs.h 24 | 25 | To use miniLZO just copy these files into your source directory, add 26 | minilzo.c to your Makefile and #include minilzo.h from your program. 27 | Note: you also must distribute this file ('README.LZO') with your project. 28 | 29 | minilzo.o compiles to about 6 KiB (using gcc or Visual C on an i386), and 30 | the sources are about 30 KiB when packed with zip - so there's no more 31 | excuse that your application doesn't support data compression :-) 32 | 33 | For more information, documentation, example programs and other support 34 | files (like Makefiles and build scripts) please download the full LZO 35 | package from 36 | http://www.oberhumer.com/opensource/lzo/ 37 | 38 | Have fun, 39 | Markus 40 | 41 | 42 | P.S. minilzo.c is generated automatically from the LZO sources and 43 | therefore functionality is completely identical 44 | 45 | 46 | Appendix A: building miniLZO 47 | ---------------------------- 48 | miniLZO is written such a way that it should compile and run 49 | out-of-the-box on most machines. 50 | 51 | If you are running on a very unusual architecture and lzo_init() fails then 52 | you should first recompile with '-DLZO_DEBUG' to see what causes the failure. 53 | The most probable case is something like 'sizeof(void *) != sizeof(size_t)'. 54 | After identifying the problem you can compile by adding some defines 55 | like '-DSIZEOF_VOID_P=8' to your Makefile. 56 | 57 | The best solution is (of course) using Autoconf - if your project uses 58 | Autoconf anyway just add '-DMINILZO_HAVE_CONFIG_H' to your compiler 59 | flags when compiling minilzo.c. See the LZO distribution for an example 60 | how to set up configure.ac. 61 | 62 | 63 | Appendix B: list of public functions available in miniLZO 64 | --------------------------------------------------------- 65 | Library initialization 66 | lzo_init() 67 | 68 | Compression 69 | lzo1x_1_compress() 70 | 71 | Decompression 72 | lzo1x_decompress() 73 | lzo1x_decompress_safe() 74 | 75 | Checksum functions 76 | lzo_adler32() 77 | 78 | Version functions 79 | lzo_version() 80 | lzo_version_string() 81 | lzo_version_date() 82 | 83 | Portable (but slow) string functions 84 | lzo_memcmp() 85 | lzo_memcpy() 86 | lzo_memmove() 87 | lzo_memset() 88 | 89 | 90 | Appendix C: suggested macros for 'configure.ac' when using Autoconf 91 | ------------------------------------------------------------------- 92 | Checks for typedefs and structures 93 | AC_CHECK_TYPE(ptrdiff_t,long) 94 | AC_TYPE_SIZE_T 95 | AC_CHECK_SIZEOF(short) 96 | AC_CHECK_SIZEOF(int) 97 | AC_CHECK_SIZEOF(long) 98 | AC_CHECK_SIZEOF(long long) 99 | AC_CHECK_SIZEOF(__int64) 100 | AC_CHECK_SIZEOF(void *) 101 | AC_CHECK_SIZEOF(size_t) 102 | AC_CHECK_SIZEOF(ptrdiff_t) 103 | 104 | Checks for compiler characteristics 105 | AC_C_CONST 106 | 107 | Checks for library functions 108 | AC_CHECK_FUNCS(memcmp memcpy memmove memset) 109 | 110 | 111 | Appendix D: Copyright 112 | --------------------- 113 | LZO and miniLZO are Copyright (C) 1996-2015 Markus Franz Xaver Oberhumer 114 | All Rights Reserved. 115 | 116 | LZO and miniLZO are distributed under the terms of the GNU General 117 | Public License (GPL). See the file COPYING. 118 | 119 | Special licenses for commercial and other applications which 120 | are not willing to accept the GNU General Public License 121 | are available by contacting the author. 122 | 123 | 124 | -------------------------------------------------------------------------------- /usr/be_byteshift.h: -------------------------------------------------------------------------------- 1 | #ifndef _LINUX_UNALIGNED_BE_BYTESHIFT_H 2 | #define _LINUX_UNALIGNED_BE_BYTESHIFT_H 3 | 4 | static inline uint16_t __get_unaligned_be16(const uint8_t *p) 5 | { 6 | return p[0] << 8 | p[1]; 7 | } 8 | 9 | static inline uint32_t __get_unaligned_be32(const uint8_t *p) 10 | { 11 | return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; 12 | } 13 | 14 | static inline uint64_t __get_unaligned_be64(const uint8_t *p) 15 | { 16 | return (uint64_t)__get_unaligned_be32(p) << 32 | 17 | __get_unaligned_be32(p + 4); 18 | } 19 | 20 | static inline void __put_unaligned_be16(uint16_t val, uint8_t *p) 21 | { 22 | *p++ = val >> 8; 23 | *p++ = val; 24 | } 25 | 26 | static inline void __put_unaligned_be32(uint32_t val, uint8_t *p) 27 | { 28 | __put_unaligned_be16(val >> 16, p); 29 | __put_unaligned_be16(val, p + 2); 30 | } 31 | 32 | static inline void __put_unaligned_be64(uint64_t val, uint8_t *p) 33 | { 34 | __put_unaligned_be32(val >> 32, p); 35 | __put_unaligned_be32(val, p + 4); 36 | } 37 | 38 | static inline uint16_t get_unaligned_be16(const void *p) 39 | { 40 | return __get_unaligned_be16((const uint8_t *)p); 41 | } 42 | 43 | static inline uint32_t get_unaligned_be24(const uint8_t *p) 44 | { 45 | return p[0] << 16 | p[1] << 8 | p[2]; 46 | } 47 | 48 | static inline uint32_t get_unaligned_be32(const void *p) 49 | { 50 | return __get_unaligned_be32((const uint8_t *)p); 51 | } 52 | 53 | static inline uint64_t get_unaligned_be48(const void *p) 54 | { 55 | return (uint64_t)__get_unaligned_be32(p) << 32 | 56 | __get_unaligned_be16(p + 4); 57 | } 58 | 59 | static inline uint64_t get_unaligned_be64(const void *p) 60 | { 61 | return __get_unaligned_be64((const uint8_t *)p); 62 | } 63 | 64 | static inline void put_unaligned_be16(uint16_t val, void *p) 65 | { 66 | __put_unaligned_be16(val, (uint8_t *)p); 67 | } 68 | 69 | static inline void put_unaligned_be24(uint32_t val, void *p) 70 | { 71 | ((uint8_t *)p)[0] = (val >> 16) & 0xff; 72 | ((uint8_t *)p)[1] = (val >> 8) & 0xff; 73 | ((uint8_t *)p)[2] = val & 0xff; 74 | } 75 | 76 | static inline void put_unaligned_be32(uint32_t val, void *p) 77 | { 78 | __put_unaligned_be32(val, (uint8_t *)p); 79 | } 80 | 81 | static inline void put_unaligned_be48(uint64_t val, void *p) 82 | { 83 | __put_unaligned_be32(val >> 32, (uint8_t *)p); 84 | __put_unaligned_be16(val, p + 4); 85 | } 86 | 87 | static inline void put_unaligned_be64(uint64_t val, void *p) 88 | { 89 | __put_unaligned_be64(val, (uint8_t *)p); 90 | } 91 | 92 | #endif /* _LINUX_UNALIGNED_BE_BYTESHIFT_H */ 93 | -------------------------------------------------------------------------------- /usr/default_smc_pm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Personality module for default emulation 3 | */ 4 | 5 | #include 6 | #include 7 | #include "mhvtl_list.h" 8 | #include "vtllib.h" 9 | #include "smc.h" 10 | #include "logging.h" 11 | #include "be_byteshift.h" 12 | #include "mhvtl_log.h" 13 | #include "mode.h" 14 | 15 | static struct smc_personality_template smc_pm = { 16 | .library_has_map = TRUE, 17 | .library_has_barcode_reader = TRUE, 18 | .library_has_playground = TRUE, 19 | 20 | .dvcid_len = 32, 21 | }; 22 | 23 | static void update_default_inquiry(struct lu_phy_attr *lu) 24 | { 25 | struct smc_priv *smc_p; 26 | 27 | smc_p = lu->lu_private; 28 | 29 | lu->inquiry[2] = 5; /* SNSI Approved Version */ 30 | lu->inquiry[3] = 2; /* Response data format */ 31 | lu->inquiry[4] = 0x43; /* Additional length */ 32 | 33 | memcpy(&lu->inquiry[38], &lu->lu_serial_no, 12); 34 | lu->inquiry[55] |= smc_p->pm->library_has_barcode_reader ? 1 : 0; 35 | put_unaligned_be16(0x005c, &lu->inquiry[58]); /* SAM-2 */ 36 | put_unaligned_be16(0x0b56, &lu->inquiry[60]); /* SPI-4 */ 37 | put_unaligned_be16(0x02fe, &lu->inquiry[62]); /* SMC-2 */ 38 | put_unaligned_be16(0x030f, &lu->inquiry[64]); /* SPC-3 */ 39 | 40 | /* Device Identification */ 41 | lu->lu_vpd[PCODE_OFFSET(0x83)] = alloc_vpd(VPD_83_SZ); 42 | if (lu->lu_vpd[PCODE_OFFSET(0x83)]) 43 | update_vpd_83(lu, NULL); 44 | 45 | } 46 | 47 | void init_default_smc(struct lu_phy_attr *lu) 48 | { 49 | smc_pm.name = "mhVTL - Default emulation"; 50 | smc_pm.library_has_map = TRUE; 51 | smc_pm.library_has_barcode_reader = TRUE; 52 | smc_pm.library_has_playground = TRUE; 53 | smc_pm.dvcid_serial_only = FALSE; 54 | 55 | smc_pm.start_drive = 0x001; 56 | smc_pm.start_picker = 0x2f0; 57 | smc_pm.start_map = 0x300; 58 | smc_pm.start_storage = 0x400; 59 | 60 | smc_pm.lu = lu; 61 | smc_personality_module_register(&smc_pm); 62 | 63 | init_slot_info(lu); 64 | update_default_inquiry(lu); 65 | 66 | init_smc_log_pages(lu); 67 | init_smc_mode_pages(lu); 68 | } 69 | -------------------------------------------------------------------------------- /usr/dump_messageQ.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dump_messageQ - A utility to empty & examine a message queue 3 | * 4 | * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | * 21 | * Modification History: 22 | * 2010-03-31 hstadler - source code revision, argument checking 23 | * 24 | * Dump any existing data in the messageQ. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include "q.h" 31 | 32 | long my_id; 33 | int verbose = 0; 34 | int debug = 0; 35 | char *mhvtl_driver_name = "dump_messageQ"; 36 | 37 | static void usage(char *prog) 38 | { 39 | fprintf(stdout, "Usage : %s [-h|-help]\n", prog); 40 | fprintf(stdout, "Version: %s\n\n", MHVTL_VERSION); 41 | fprintf(stdout, "Dumping message queue content of " 42 | "library/tape queue.\n"); 43 | fprintf(stdout, "Primarily used for debugging purposes.\n\n"); 44 | } 45 | 46 | int main(int argc, char **argv) 47 | { 48 | int r_qid; 49 | long mcounter = 0; 50 | int i; 51 | struct q_entry r_entry; 52 | 53 | my_id = 0; 54 | 55 | /* checking several positions of -h/-help */ 56 | for (i = 1; i < argc; i++) { 57 | if (!strcmp(argv[i], "-h")) { 58 | usage(argv[0]); 59 | exit(1); 60 | } 61 | if (!strcmp(argv[i], "-?")) { 62 | usage(argv[0]); 63 | exit(1); 64 | } 65 | if (!strcmp(argv[i], "/h")) { 66 | usage(argv[0]); 67 | exit(1); 68 | } 69 | if (!strcmp(argv[i], "/?")) { 70 | usage(argv[0]); 71 | exit(1); 72 | } 73 | if (!strcmp(argv[i], "-help")) { 74 | usage(argv[0]); 75 | exit(1); 76 | } 77 | } 78 | 79 | if (argc > 1) { 80 | printf("Invalid option: %s\n", argv[1]); 81 | printf("Try '%s -h' for more information\n", argv[0]); 82 | exit(1); 83 | } 84 | 85 | /* Initialize message queue as necessary */ 86 | r_qid = init_queue(); 87 | if (r_qid == -1) 88 | exit(1); 89 | 90 | while (msgrcv(r_qid, &r_entry, MAXOBN, 0, IPC_NOWAIT) > 0) { 91 | mcounter++; 92 | if (mcounter == 1) { 93 | printf("\nDump Message Queue Content\n\n"); 94 | printf("%6s %6s %6s %-55s\n", "MessNo", "RcvID", 95 | "SndID", "MessageText"); 96 | } 97 | printf("%6ld %6ld %6ld %-55s\n", mcounter, r_entry.rcv_id, 98 | r_entry.msg.snd_id, r_entry.msg.text); 99 | } 100 | if (mcounter == 0) 101 | printf("Message queue empty\n"); 102 | 103 | exit(0); 104 | } 105 | 106 | -------------------------------------------------------------------------------- /usr/hp_smc_pm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Personality module for HP E-Series 3 | */ 4 | 5 | #include 6 | #include 7 | #include "mhvtl_list.h" 8 | #include "vtllib.h" 9 | #include "smc.h" 10 | #include "logging.h" 11 | #include "be_byteshift.h" 12 | #include "mhvtl_log.h" 13 | #include "mode.h" 14 | 15 | static void update_eml_vpd_80(struct lu_phy_attr *lu) 16 | { 17 | struct vpd **lu_vpd = lu->lu_vpd; 18 | uint8_t *d; 19 | int pg; 20 | 21 | /* Unit Serial Number */ 22 | pg = PCODE_OFFSET(0x80); 23 | if (lu_vpd[pg]) /* Free any earlier allocation */ 24 | dealloc_vpd(lu_vpd[pg]); 25 | lu_vpd[pg] = alloc_vpd(0x12); 26 | if (lu_vpd[pg]) { 27 | d = lu_vpd[pg]->data; 28 | snprintf((char *)&d[0], 11, "%-10.10s", lu->lu_serial_no); 29 | /* Unique Logical Library Identifier */ 30 | } else { 31 | MHVTL_ERR("Could not malloc(0x12) bytes, line %d", __LINE__); 32 | } 33 | } 34 | 35 | static void update_eml_vpd_83(struct lu_phy_attr *lu) 36 | { 37 | struct vpd **lu_vpd = lu->lu_vpd; 38 | uint8_t *d; 39 | int num; 40 | char *ptr; 41 | int pg; 42 | int len, j; 43 | 44 | num = VENDOR_ID_LEN + PRODUCT_ID_LEN + 10; 45 | 46 | pg = PCODE_OFFSET(0x83); 47 | if (lu_vpd[pg]) /* Free any earlier allocation */ 48 | dealloc_vpd(lu_vpd[pg]); 49 | lu_vpd[pg] = alloc_vpd(num + 12); 50 | if (!lu_vpd[pg]) { 51 | MHVTL_ERR("Can't malloc() to setup for vpd_83"); 52 | return; 53 | } 54 | 55 | d = lu_vpd[pg]->data; 56 | 57 | d[0] = 2; 58 | d[1] = 1; 59 | d[2] = 0; 60 | d[3] = num; 61 | 62 | memcpy(&d[4], &lu->vendor_id, VENDOR_ID_LEN); 63 | memcpy(&d[12], &lu->product_id, PRODUCT_ID_LEN); 64 | memcpy(&d[28], &lu->lu_serial_no, 10); 65 | len = (int)strlen(lu->lu_serial_no); 66 | ptr = &lu->lu_serial_no[len]; 67 | 68 | num += 4; 69 | /* NAA IEEE registered identifier (faked) */ 70 | d[num] = 0x1; /* Binary */ 71 | d[num + 1] = 0x3; 72 | d[num + 2] = 0x0; 73 | d[num + 3] = 0x8; 74 | d[num + 4] = 0x51; 75 | d[num + 5] = 0x23; 76 | d[num + 6] = 0x45; 77 | d[num + 7] = 0x60; 78 | d[num + 8] = 0x3; 79 | d[num + 9] = 0x3; 80 | d[num + 10] = 0x3; 81 | d[num + 11] = 0x3; 82 | 83 | if (lu->naa) { /* If defined in config file */ 84 | sscanf((const char *)lu->naa, 85 | "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 86 | &d[num + 4], 87 | &d[num + 5], 88 | &d[num + 6], 89 | &d[num + 7], 90 | &d[num + 8], 91 | &d[num + 9], 92 | &d[num + 10], 93 | &d[num + 11]); 94 | } else { /* Else munge the serial number */ 95 | ptr--; 96 | for (j = 11; j > 3; ptr--, j--) 97 | d[num + j] = *ptr; 98 | } 99 | d[num + 4] &= 0x0f; 100 | d[num + 4] |= 0x50; 101 | } 102 | 103 | static struct smc_personality_template smc_pm = { 104 | .library_has_map = TRUE, 105 | .library_has_barcode_reader = TRUE, 106 | .library_has_playground = FALSE, 107 | .start_picker = 0x0001, 108 | .start_map = 0x000a, 109 | .start_drive = 0x01f4, 110 | .start_storage = 0x03e8, 111 | 112 | .dvcid_len = 34, 113 | }; 114 | 115 | void init_hp_eml_smc(struct lu_phy_attr *lu) 116 | { 117 | smc_pm.name = "mhVTL - HP EML E-Series emulation"; 118 | 119 | smc_pm.lu = lu; 120 | smc_personality_module_register(&smc_pm); 121 | 122 | init_slot_info(lu); 123 | 124 | update_eml_vpd_80(lu); 125 | update_eml_vpd_83(lu); 126 | init_smc_log_pages(lu); 127 | init_smc_mode_pages(lu); 128 | } 129 | 130 | void init_hp_msl_smc(struct lu_phy_attr *lu) 131 | { 132 | smc_pm.name = "mhVTL - HP MSL Series emulation"; 133 | 134 | smc_pm.lu = lu; 135 | smc_pm.start_picker = 0x0001; 136 | smc_pm.start_storage = 0x0020; 137 | smc_pm.start_drive = 0x01e0; 138 | smc_pm.start_map = 0x01c0; 139 | smc_pm.dvcid_len = 20, 140 | smc_pm.dvcid_serial_only = TRUE, 141 | smc_pm.no_dvcid_flag = TRUE, 142 | 143 | lu->inquiry[2] = 2; /* Set SCSI-2 Approved Version */ 144 | 145 | smc_personality_module_register(&smc_pm); 146 | 147 | init_slot_info(lu); 148 | 149 | update_eml_vpd_80(lu); 150 | update_eml_vpd_83(lu); 151 | init_smc_log_pages(lu); 152 | init_smc_mode_pages(lu); 153 | } 154 | -------------------------------------------------------------------------------- /usr/logging.h: -------------------------------------------------------------------------------- 1 | /* 2 | * logging macros 3 | * 4 | * Copyright (C) 2005-2025 Mark Harvey markh794@gmail.com 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | */ 11 | 12 | #ifndef _LOGGING_H_ 13 | #define _LOGGING_H_ 14 | 15 | #include 16 | 17 | #define MHVTL_OPT_NOISE 3 18 | 19 | #ifdef MHVTL_DEBUG 20 | extern char mhvtl_driver_name[]; 21 | extern int debug; 22 | extern int verbose; 23 | 24 | #define MHVTL_DBG_NO_FUNC(lvl, format, arg...) { \ 25 | if (debug) \ 26 | printf("%s: " format "\n", \ 27 | mhvtl_driver_name, ## arg); \ 28 | else if ((verbose & MHVTL_OPT_NOISE) >= (lvl)) \ 29 | syslog(LOG_DAEMON|LOG_INFO, format, ## arg); \ 30 | } 31 | 32 | #define MHVTL_ERR(format, arg...) { \ 33 | if (debug) { \ 34 | printf("%s: ERROR: %s(): " format "\n", \ 35 | mhvtl_driver_name, __func__, ## arg); \ 36 | fflush(NULL); \ 37 | } else { \ 38 | syslog(LOG_DAEMON|LOG_ERR, "ERROR: %s(): line: %d," format, \ 39 | __func__, __LINE__, ## arg); \ 40 | } \ 41 | } 42 | 43 | #define MHVTL_LOG(format, arg...) { \ 44 | if (debug) { \ 45 | printf("%s: %s(): " format "\n", \ 46 | mhvtl_driver_name, __func__, ## arg); \ 47 | fflush(NULL); \ 48 | } else { \ 49 | syslog(LOG_DAEMON|LOG_ERR, "%s(): " format, \ 50 | __func__, ## arg); \ 51 | } \ 52 | } 53 | 54 | #define MHVTL_DBG(lvl, format, arg...) { \ 55 | if (debug) \ 56 | printf("%s: %s(): " format "\n", \ 57 | mhvtl_driver_name, __func__, ## arg); \ 58 | else if ((verbose & MHVTL_OPT_NOISE) >= (lvl)) \ 59 | syslog(LOG_DAEMON|LOG_INFO, "%s(): " format, \ 60 | __func__, ## arg); \ 61 | } 62 | 63 | #define MHVTL_DBG_PRT_CDB(lvl, cmd) { \ 64 | if (debug) { \ 65 | mhvtl_prt_cdb((lvl), (cmd)); \ 66 | } else if ((verbose & MHVTL_OPT_NOISE) >= (lvl)) { \ 67 | mhvtl_prt_cdb((lvl), (cmd)); \ 68 | } \ 69 | } 70 | 71 | #else 72 | 73 | #define MHVTL_DBG(lvl, s...) 74 | #define MHVTL_DBG_NO_FUNC(lvl, s...) 75 | #define MHVTL_DBG_PRT_CDB(lvl, cmd) 76 | 77 | #define MHVTL_ERR(format, arg...) { \ 78 | syslog(LOG_DAEMON|LOG_ERR, "ERROR: %s(): " format, \ 79 | __func__, ## arg); \ 80 | } 81 | 82 | #define MHVTL_LOG(format, arg...) { \ 83 | syslog(LOG_DAEMON|LOG_ERR, "%s(): " format, \ 84 | __func__, ## arg); \ 85 | } 86 | 87 | #endif /* MHVTL_DEBUG */ 88 | #endif /* _LOGGING_H_ */ 89 | -------------------------------------------------------------------------------- /usr/make_scsi_dev: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # 3 | # * perl replacement for the VERITAS /usr/openv/volmgr/bin/make_scsi_dev 4 | # * 5 | # * Re-creates the /dev/sg/ & /dev/st/ symlinks back to the native linux 6 | # * device nodes. 7 | # * 8 | # * 9 | # * $Id: make_scsi_dev,v 1.2.2.1 2006-08-06 07:58:44 markh Exp $ 10 | # * 11 | # * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com 12 | # * 13 | # * This program is free software; you can redistribute it and/or modify 14 | # * it under the terms of the GNU General Public License as published by 15 | # * the Free Software Foundation; either version 2 of the License, or 16 | # * (at your option) any later version. 17 | # * 18 | # * This program is distributed in the hope that it will be useful, 19 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # * GNU General Public License for more details. 22 | # * 23 | # * You should have received a copy of the GNU General Public License 24 | # * along with this program; if not, write to the Free Software 25 | # * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 26 | # 27 | 28 | use strict; 29 | 30 | my $line; 31 | my $type; 32 | my $hba; 33 | my $bus; 34 | my $target; 35 | my $lun; 36 | my $path; 37 | my $st; 38 | my $sg; 39 | 40 | system("rm -f /dev/st/*"); 41 | system("rm -f /dev/sg/*"); 42 | 43 | open(D, "lsscsi -g|") || die "Could not execute \'lsscsi -g\'\n"; 44 | while($line = ) { 45 | chomp $line; 46 | next unless ($line =~ /tape|mediumx/); 47 | # print "$line\n"; 48 | ($hba,$bus,$target,$lun,$type) = ($line =~ /(\d+):(\d+):(\d+):(\d+)]\s+([a-z]*)/); 49 | # print "HBA: $hba, BUS: $bus, ID: $target, LUN: $lun\n"; 50 | $path = "h" . $hba . "c" . $bus . "t" . $target . "l" . $lun; 51 | ($st) = ($line =~ /\/dev\/(st\d+)/); 52 | ($sg) = ($line =~ /\/dev\/(sg\d+)/); 53 | if($type =~ /tape/) { 54 | system("ln -s /dev/$st /dev/st/$path"); 55 | system("ln -s /dev/n$st /dev/st/n$path"); 56 | } 57 | system("ln -s /dev/$sg /dev/sg/$path"); 58 | } 59 | close (D); 60 | 61 | -------------------------------------------------------------------------------- /usr/mhvtl_kernel_mod_build.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Used to automate the building of the mhvtl.ko module 4 | # on a running system - without requiring the whole source 5 | 6 | BUILD=$(mktemp -u -t tmp.XXXXXXXXXX) 7 | 8 | module_source=@FIRMWAREDIR@/mhvtl/mhvtl_kernel.tgz 9 | 10 | if [ ! -d ${BUILD} ]; then 11 | mkdir -p ${BUILD} 12 | fi 13 | 14 | cd ${BUILD} 15 | tar xfz ${module_source} 16 | 17 | make && sudo make install 18 | 19 | rm -r ${BUILD} 20 | -------------------------------------------------------------------------------- /usr/mhvtl_list.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIST_H__ 2 | #define __LIST_H__ 3 | 4 | /* taken from linux kernel */ 5 | 6 | #undef offsetof 7 | #ifdef __compiler_offsetof 8 | #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) 9 | #else 10 | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 11 | #endif 12 | 13 | #define container_of(ptr, type, member) ({ \ 14 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 15 | (type *)( (char *)__mptr - offsetof(type, member) );}) 16 | 17 | struct list_head { 18 | struct list_head *next, *prev; 19 | }; 20 | 21 | #define LIST_HEAD_INIT(name) { &(name), &(name) } 22 | 23 | #define LIST_HEAD(name) \ 24 | struct list_head name = LIST_HEAD_INIT(name) 25 | 26 | static inline void INIT_LIST_HEAD(struct list_head *list) 27 | { 28 | list->next = list; 29 | list->prev = list; 30 | } 31 | 32 | #define list_first_entry(ptr, type, member) \ 33 | list_entry((ptr)->next, type, member) 34 | 35 | static inline int list_empty(const struct list_head *head) 36 | { 37 | return head->next == head; 38 | } 39 | 40 | #define list_entry(ptr, type, member) \ 41 | container_of(ptr, type, member) 42 | 43 | #define list_for_each(pos, head) \ 44 | for (pos = (head)->next; pos != (head); pos = pos->next) 45 | 46 | #define list_for_each_entry(pos, head, member) \ 47 | for (pos = list_entry((head)->next, typeof(*pos), member); \ 48 | &pos->member != (head); \ 49 | pos = list_entry(pos->member.next, typeof(*pos), member)) 50 | 51 | #define list_for_each_entry_safe(pos, n, head, member) \ 52 | for (pos = list_entry((head)->next, typeof(*pos), member), \ 53 | n = list_entry(pos->member.next, typeof(*pos), member); \ 54 | &pos->member != (head); \ 55 | pos = n, n = list_entry(n->member.next, typeof(*n), member)) 56 | 57 | static inline void __list_add(struct list_head *newhead, 58 | struct list_head *prev, 59 | struct list_head *next) 60 | { 61 | next->prev = newhead; 62 | newhead->next = next; 63 | newhead->prev = prev; 64 | prev->next = newhead; 65 | } 66 | 67 | static inline void list_add(struct list_head *newhead, struct list_head *head) 68 | { 69 | __list_add(newhead, head, head->next); 70 | } 71 | 72 | static inline void list_add_tail(struct list_head *newhead, struct list_head *head) 73 | { 74 | __list_add(newhead, head->prev, head); 75 | } 76 | 77 | static inline void __list_del(struct list_head *prev, struct list_head *next) 78 | { 79 | next->prev = prev; 80 | prev->next = next; 81 | } 82 | 83 | static inline void list_del(struct list_head *entry) 84 | { 85 | __list_del(entry->prev, entry->next); 86 | entry->next = entry->prev = NULL; 87 | } 88 | 89 | static inline void list_del_init(struct list_head *entry) 90 | { 91 | __list_del(entry->prev, entry->next); 92 | INIT_LIST_HEAD(entry); 93 | } 94 | 95 | static inline void __list_splice(const struct list_head *list, 96 | struct list_head *prev, 97 | struct list_head *next) 98 | { 99 | struct list_head *first = list->next; 100 | struct list_head *last = list->prev; 101 | 102 | first->prev = prev; 103 | prev->next = first; 104 | 105 | last->next = next; 106 | next->prev = last; 107 | } 108 | 109 | static inline void list_splice_init(struct list_head *list, 110 | struct list_head *head) 111 | { 112 | if (!list_empty(list)) { 113 | __list_splice(list, head, head->next); 114 | INIT_LIST_HEAD(list); 115 | } 116 | } 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /usr/minilzo.h: -------------------------------------------------------------------------------- 1 | /* minilzo.h -- mini subset of the LZO real-time data compression library 2 | 3 | This file is part of the LZO real-time data compression library. 4 | 5 | Copyright (C) 1996-2015 Markus Franz Xaver Johannes Oberhumer 6 | All Rights Reserved. 7 | 8 | The LZO library is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License as 10 | published by the Free Software Foundation; either version 2 of 11 | the License, or (at your option) any later version. 12 | 13 | The LZO library is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with the LZO library; see the file COPYING. 20 | If not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 | 23 | Markus F.X.J. Oberhumer 24 | 25 | http://www.oberhumer.com/opensource/lzo/ 26 | */ 27 | 28 | /* 29 | * NOTE: 30 | * the full LZO package can be found at 31 | * http://www.oberhumer.com/opensource/lzo/ 32 | */ 33 | 34 | 35 | #ifndef __MINILZO_H_INCLUDED 36 | #define __MINILZO_H_INCLUDED 1 37 | 38 | #define MINILZO_VERSION 0x2090 39 | 40 | #if defined(__LZOCONF_H_INCLUDED) 41 | # error "you cannot use both LZO and miniLZO" 42 | #endif 43 | 44 | /* internal Autoconf configuration file - only used when building miniLZO */ 45 | #ifdef MINILZO_HAVE_CONFIG_H 46 | # include 47 | #endif 48 | #include 49 | #include 50 | 51 | #ifndef __LZODEFS_H_INCLUDED 52 | #include "lzodefs.h" 53 | #endif 54 | #undef LZO_HAVE_CONFIG_H 55 | #include "lzoconf.h" 56 | 57 | #if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION) 58 | # error "version mismatch in header files" 59 | #endif 60 | 61 | 62 | #ifdef __cplusplus 63 | extern "C" { 64 | #endif 65 | 66 | 67 | /*********************************************************************** 68 | // 69 | ************************************************************************/ 70 | 71 | /* Memory required for the wrkmem parameter. 72 | * When the required size is 0, you can also pass a NULL pointer. 73 | */ 74 | 75 | #define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS 76 | #define LZO1X_1_MEM_COMPRESS ((lzo_uint32_t) (16384L * lzo_sizeof_dict_t)) 77 | #define LZO1X_MEM_DECOMPRESS (0) 78 | 79 | 80 | /* compression */ 81 | LZO_EXTERN(int) 82 | lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len, 83 | lzo_bytep dst, lzo_uintp dst_len, 84 | lzo_voidp wrkmem ); 85 | 86 | /* decompression */ 87 | LZO_EXTERN(int) 88 | lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len, 89 | lzo_bytep dst, lzo_uintp dst_len, 90 | lzo_voidp wrkmem /* NOT USED */ ); 91 | 92 | /* safe decompression with overrun testing */ 93 | LZO_EXTERN(int) 94 | lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len, 95 | lzo_bytep dst, lzo_uintp dst_len, 96 | lzo_voidp wrkmem /* NOT USED */ ); 97 | 98 | 99 | #ifdef __cplusplus 100 | } /* extern "C" */ 101 | #endif 102 | 103 | #endif /* already included */ 104 | 105 | 106 | /* vim:set ts=4 sw=4 et: */ 107 | -------------------------------------------------------------------------------- /usr/mode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This handles any SCSI OP 'mode sense / mode select' 3 | * 4 | * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | * See comments in vtltape.c for a more complete version release... 21 | * 22 | */ 23 | 24 | int add_mode_page_rw_err_recovery(struct lu_phy_attr *lu); 25 | int add_mode_disconnect_reconnect(struct lu_phy_attr *lu); 26 | int add_mode_control(struct lu_phy_attr *lu); 27 | int add_mode_control_extension(struct lu_phy_attr *lu); 28 | int add_mode_control_data_protection(struct lu_phy_attr *lu); 29 | int add_mode_data_compression(struct lu_phy_attr *lu); 30 | int add_mode_device_configuration(struct lu_phy_attr *lu); 31 | int add_mode_device_configuration_extention(struct lu_phy_attr *lu); 32 | int add_mode_medium_partition(struct lu_phy_attr *lu); 33 | int add_mode_power_condition(struct lu_phy_attr *lu); 34 | int add_mode_information_exception(struct lu_phy_attr *lu); 35 | int add_mode_medium_configuration(struct lu_phy_attr *lu); 36 | int add_mode_ait_device_configuration(struct lu_phy_attr *lu); 37 | int add_mode_ult_encr_mode_pages(struct lu_phy_attr *lu); 38 | int add_mode_vendor_25h_mode_pages(struct lu_phy_attr *lu); 39 | int add_mode_encryption_mode_attribute(struct lu_phy_attr *lu); 40 | int add_mode_behavior_configuration(struct lu_phy_attr *lu); 41 | 42 | int add_mode_device_capabilities(struct lu_phy_attr *lu); 43 | int add_mode_transport_geometry(struct lu_phy_attr *lu); 44 | int add_mode_element_address_assignment(struct lu_phy_attr *lu); 45 | int update_prog_early_warning(struct lu_phy_attr *lu); 46 | int update_logical_block_protection(struct lu_phy_attr *lu, uint8_t *buf); 47 | void dealloc_all_mode_pages(struct lu_phy_attr *lu); 48 | int add_smc_mode_page_drive_configuration(struct lu_phy_attr *lu); 49 | -------------------------------------------------------------------------------- /usr/overland_pm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Personality module for OVERLAND 3 | */ 4 | 5 | #include 6 | #include 7 | #include "mhvtl_list.h" 8 | #include "vtllib.h" 9 | #include "smc.h" 10 | #include "logging.h" 11 | #include "be_byteshift.h" 12 | #include "mhvtl_log.h" 13 | #include "mode.h" 14 | 15 | static void update_eml_vpd_80(struct lu_phy_attr *lu) 16 | { 17 | struct vpd **lu_vpd = lu->lu_vpd; 18 | uint8_t *d; 19 | int pg; 20 | 21 | /* Unit Serial Number */ 22 | pg = PCODE_OFFSET(0x80); 23 | if (lu_vpd[pg]) /* Free any earlier allocation */ 24 | dealloc_vpd(lu_vpd[pg]); 25 | lu_vpd[pg] = alloc_vpd(0x12); 26 | if (lu_vpd[pg]) { 27 | d = lu_vpd[pg]->data; 28 | /* d[4 - 15] Serial number of device */ 29 | snprintf((char *)&d[0], 11, "%-10.10s", lu->lu_serial_no); 30 | /* Unique Logical Library Identifier */ 31 | } else { 32 | MHVTL_ERR("Could not malloc(0x12) bytes, line %d", __LINE__); 33 | } 34 | } 35 | 36 | static void update_eml_vpd_83(struct lu_phy_attr *lu) 37 | { 38 | struct vpd *vpd_pg = lu->lu_vpd[PCODE_OFFSET(0x83)]; 39 | uint8_t *d; 40 | int num; 41 | char *ptr; 42 | int len, j; 43 | 44 | d = vpd_pg->data; 45 | 46 | d[0] = 2; 47 | d[1] = 1; 48 | d[2] = 0; 49 | num = VENDOR_ID_LEN + PRODUCT_ID_LEN + 10; 50 | d[3] = num; 51 | 52 | memcpy(&d[4], &lu->vendor_id, VENDOR_ID_LEN); 53 | memcpy(&d[12], &lu->product_id, PRODUCT_ID_LEN); 54 | memcpy(&d[28], &lu->lu_serial_no, 10); 55 | len = (int)strlen(lu->lu_serial_no); 56 | ptr = &lu->lu_serial_no[len]; 57 | 58 | num += 4; 59 | /* NAA IEEE registered identifier (faked) */ 60 | d[num] = 0x1; /* Binary */ 61 | d[num + 1] = 0x3; 62 | d[num + 2] = 0x0; 63 | d[num + 3] = 0x8; 64 | d[num + 4] = 0x51; 65 | d[num + 5] = 0x23; 66 | d[num + 6] = 0x45; 67 | d[num + 7] = 0x60; 68 | d[num + 8] = 0x3; 69 | d[num + 9] = 0x3; 70 | d[num + 10] = 0x3; 71 | d[num + 11] = 0x3; 72 | 73 | if (lu->naa) { /* If defined in config file */ 74 | sscanf((const char *)lu->naa, 75 | "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 76 | &d[num + 4], 77 | &d[num + 5], 78 | &d[num + 6], 79 | &d[num + 7], 80 | &d[num + 8], 81 | &d[num + 9], 82 | &d[num + 10], 83 | &d[num + 11]); 84 | } else { /* Else munge the serial number */ 85 | ptr--; 86 | for (j = 11; j > 3; ptr--, j--) 87 | d[num + j] = *ptr; 88 | } 89 | d[num + 4] &= 0x0f; 90 | d[num + 4] |= 0x50; 91 | } 92 | 93 | static struct smc_personality_template smc_pm = { 94 | .library_has_map = TRUE, 95 | .library_has_barcode_reader = TRUE, 96 | .library_has_playground = FALSE, 97 | .start_map = 0x0000, 98 | .start_picker = 0x0001, 99 | .start_storage = 0x0002, 100 | .start_drive = 0x00ff, 101 | 102 | .dvcid_len = 34, 103 | }; 104 | 105 | void init_overland_smc(struct lu_phy_attr *lu) 106 | { 107 | smc_pm.name = "mhVTL - Overland Series emulation"; 108 | 109 | smc_pm.lu = lu; 110 | smc_personality_module_register(&smc_pm); 111 | 112 | init_slot_info(lu); 113 | 114 | update_eml_vpd_80(lu); 115 | update_eml_vpd_83(lu); 116 | init_smc_log_pages(lu); 117 | init_smc_mode_pages(lu); 118 | } 119 | -------------------------------------------------------------------------------- /usr/q.c: -------------------------------------------------------------------------------- 1 | /* 2 | * From Unix System Programming - 3 | * Starting from Pg 195 4 | * 5 | * Advanced inter-process communications 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "q.h" 12 | 13 | extern int debug; 14 | extern char *mhvtl_driver_name; 15 | 16 | #define MHVTL_ERR(format, arg...) { \ 17 | if (debug) \ 18 | printf("%s: ERROR %s: " format "\n", \ 19 | "mhvtl_driver_name", __func__, ## arg); \ 20 | else \ 21 | syslog(LOG_DAEMON|LOG_ERR, "ERROR %s: " format, \ 22 | __func__, ## arg); \ 23 | } 24 | 25 | static void warn(char *s) 26 | { 27 | fprintf(stderr, "Warning: %s\n", s); 28 | } 29 | 30 | int init_queue(void) 31 | { 32 | int queue_id; 33 | 34 | /* Attempt to create or open message queue */ 35 | queue_id = msgget(QKEY, IPC_CREAT | QPERM); 36 | if (queue_id == -1) { 37 | char s[245]; 38 | switch (errno) { 39 | case EACCES: 40 | strcpy(s, "Operation not permitted"); 41 | break; 42 | case EEXIST: 43 | strcpy(s, "Message Q already exists"); 44 | break; 45 | case ENOENT: 46 | strcpy(s, "Message Q does not exist"); 47 | break; 48 | case ENOSPC: 49 | strcpy(s, "Exceeded max num of message queues"); 50 | break; 51 | default: 52 | strcpy(s, "errno not valid"); 53 | break; 54 | } 55 | MHVTL_ERR("msgget(%d) failed %s, %s", 56 | QKEY, strerror(errno), s); 57 | } 58 | 59 | return queue_id; 60 | } 61 | 62 | int send_msg(char *cmd, long rcv_id) 63 | { 64 | int len, s_qid; 65 | struct q_entry s_entry; 66 | 67 | memset(&s_entry, 0, sizeof(struct q_entry)); 68 | 69 | s_qid = init_queue(); 70 | if (s_qid == -1) 71 | return -1; 72 | 73 | s_entry.rcv_id = rcv_id; 74 | s_entry.msg.snd_id = my_id; 75 | strcpy(s_entry.msg.text, cmd); 76 | len = strlen(s_entry.msg.text) + 1 + offsetof(struct q_entry, msg.text); 77 | 78 | if (msgsnd(s_qid, &s_entry, len, 0) == -1) { 79 | MHVTL_ERR("msgsnd failed: %s", strerror(errno)); 80 | return -1; 81 | } 82 | 83 | return 0; 84 | } 85 | 86 | static void proc_obj(struct q_entry *q_entry) 87 | { 88 | printf("rcv_id: %ld, snd_id: %ld, text: %s\n", 89 | q_entry->rcv_id, q_entry->msg.snd_id, q_entry->msg.text); 90 | } 91 | 92 | int enter(char *objname, long rcv_id) 93 | { 94 | int len, s_qid; 95 | struct q_entry s_entry; /* Structure to hold message */ 96 | 97 | /* Validate name length, rcv_id */ 98 | if (strlen(objname) > MAXTEXTLEN) { 99 | warn("Name too long"); 100 | return -1; 101 | } 102 | 103 | if (rcv_id > 32764 || rcv_id < 0) { 104 | warn("Invalid rcv_id"); 105 | return -1; 106 | } 107 | 108 | /* Initialize message queue as nessary */ 109 | s_qid = init_queue(); 110 | if (s_qid == -1) 111 | return -1; 112 | 113 | /* Initialize s_entry */ 114 | s_entry.rcv_id = rcv_id; 115 | s_entry.msg.snd_id = my_id; 116 | strcpy(s_entry.msg.text, objname); 117 | len = strlen(s_entry.msg.text) + 1 + offsetof(struct q_msg, text); 118 | 119 | /* Send message, waiting if nessary */ 120 | if (msgsnd(s_qid, &s_entry, len, 0) == -1) { 121 | MHVTL_ERR("msgsnd failed: %s", strerror(errno)); 122 | return -1; 123 | } 124 | 125 | return 0; 126 | } 127 | 128 | int serve(void) 129 | { 130 | int mlen, r_qid; 131 | struct q_entry r_entry; 132 | 133 | /* Initialise message queue as necessary */ 134 | r_qid = init_queue(); 135 | if (r_qid == -1) 136 | return -1; 137 | 138 | /* Get and process next message, waiting if necessary */ 139 | for (;;) { 140 | mlen = msgrcv(r_qid, &r_entry, MAXOBN, 141 | (-1 * MAXPRIOR), MSG_NOERROR); 142 | if (mlen == -1) { 143 | MHVTL_ERR("msgsnd failed: %s", strerror(errno)); 144 | return -1; 145 | } else { 146 | /* Process object name */ 147 | proc_obj(&r_entry); 148 | } 149 | } 150 | } 151 | 152 | -------------------------------------------------------------------------------- /usr/q.h: -------------------------------------------------------------------------------- 1 | /* 2 | * q.h -- Message queue for vtltape/vtllibrary 3 | * 4 | * Copyright (C) 2005 - 2025 Mark Harvey markh794 at gmail dot com 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | * Message key - My 2 seconds of fame :-) 21 | */ 22 | 23 | #ifndef _Q_H_ 24 | #define _Q_H_ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #define MAXTEXTLEN 1024 33 | 34 | struct q_msg { 35 | long snd_id; 36 | char text[MAXTEXTLEN+1]; 37 | }; 38 | 39 | #define QKEY (key_t)0x4d61726b /* Identifying key for queue */ 40 | #define QPERM 0660 /* Permissions for queue */ 41 | #define MAXOBN sizeof(struct q_msg) /* Maximum length of message for Q. */ 42 | #define MAXPRIOR 1024 /* max priority level */ 43 | #define VTLCMD_Q 32768 /* Priority for vtlcmd */ 44 | 45 | struct q_entry { 46 | long rcv_id; 47 | struct q_msg msg; 48 | }; 49 | 50 | 51 | int enter(char *, long rcv_id); 52 | int send_msg(char *cmd, long rcv_id); 53 | int serve(void); 54 | int init_queue(void); 55 | 56 | extern long my_id; 57 | 58 | /* Message strings passed between vtllibrary & vtltape */ 59 | #define msg_not_occupied "Not occupied" 60 | #define msg_occupied "occupied" 61 | #define msg_unload_ok "Unloaded OK" 62 | #define msg_load_failed "Load failed" 63 | #define msg_load_ok "Loaded OK" 64 | #define msg_mount_state "mount_state" 65 | #define msg_eject "eject" 66 | #define msg_set_empty "set_empty" 67 | 68 | #endif /* _Q_H_ */ 69 | -------------------------------------------------------------------------------- /usr/scalar_pm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Personality module for Scalar series of robots 3 | */ 4 | 5 | #include 6 | #include "mhvtl_list.h" 7 | #include "vtllib.h" 8 | #include "smc.h" 9 | #include "logging.h" 10 | #include "be_byteshift.h" 11 | #include "mhvtl_log.h" 12 | #include "mode.h" 13 | 14 | static struct smc_personality_template smc_pm = { 15 | .library_has_map = TRUE, 16 | .library_has_barcode_reader = TRUE, 17 | .library_has_playground = FALSE, 18 | 19 | .dvcid_len = 34, 20 | }; 21 | 22 | static void init_scalar_inquiry(struct lu_phy_attr *lu) 23 | { 24 | struct smc_priv *smc_p; 25 | smc_p = lu->lu_private; 26 | 27 | lu->inquiry[2] = 3; /* SNSI Approved Version */ 28 | lu->inquiry[3] = 2; /* Response data format */ 29 | lu->inquiry[4] = 0x1f; /* Additional length */ 30 | 31 | lu->inquiry[6] |= smc_p->pm->library_has_barcode_reader ? 0x20 : 0; 32 | lu->inquiry[55] |= smc_p->pm->library_has_barcode_reader ? 1 : 0; 33 | 34 | put_unaligned_be16(0x005c, &lu->inquiry[58]); /* SAM-2 */ 35 | put_unaligned_be16(0x008d, &lu->inquiry[60]); /* SAM-4 */ 36 | put_unaligned_be16(0x0120, &lu->inquiry[62]); /* SPC-3 */ 37 | put_unaligned_be16(0x02fe, &lu->inquiry[64]); /* SMC-2 */ 38 | } 39 | 40 | static void update_scalar_vpd_80(struct lu_phy_attr *lu) 41 | { 42 | struct vpd *lu_vpd; 43 | uint8_t *d; 44 | 45 | lu_vpd = lu->lu_vpd[PCODE_OFFSET(0x80)]; 46 | 47 | /* Unit Serial Number */ 48 | if (lu_vpd) /* Free any earlier allocation */ 49 | dealloc_vpd(lu_vpd); 50 | 51 | lu_vpd = alloc_vpd(24); 52 | if (lu_vpd) { 53 | d = lu_vpd->data; 54 | /* d[4 - 27] Serial number prefixed by Vendor ID */ 55 | snprintf((char *)&d[0], 26, "%-s%-17s", lu->vendor_id, lu->lu_serial_no); 56 | } else { 57 | MHVTL_ERR("Could not malloc(24) bytes, line %d", __LINE__); 58 | } 59 | } 60 | 61 | static void update_scalar_vpd_83(struct lu_phy_attr *lu) 62 | { 63 | struct vpd *lu_vpd; 64 | uint8_t *d; 65 | 66 | lu_vpd = lu->lu_vpd[PCODE_OFFSET(0x83)]; 67 | 68 | /* Unit Serial Number */ 69 | if (lu_vpd) /* Free any earlier allocation */ 70 | dealloc_vpd(lu_vpd); 71 | 72 | lu_vpd = alloc_vpd(36); 73 | if (lu_vpd) { 74 | d = lu_vpd->data; 75 | d[0] = 0xf2; 76 | d[1] = 0x01; 77 | d[3] = 0x20; 78 | snprintf((char *)&d[4], 9, "%-8s", lu->vendor_id); 79 | snprintf((char *)&d[12], 25, "%-24s", lu->lu_serial_no); 80 | 81 | } else { 82 | MHVTL_ERR("Could not malloc(36) bytes, line %d", __LINE__); 83 | } 84 | } 85 | 86 | void init_scalar_smc(struct lu_phy_attr *lu) 87 | { 88 | int h, m, sec; 89 | int day, month, year; 90 | 91 | smc_pm.name = "mhVTL - Scalar emulation"; 92 | smc_pm.library_has_map = TRUE; 93 | smc_pm.library_has_barcode_reader = TRUE; 94 | smc_pm.library_has_playground = FALSE; 95 | smc_pm.dvcid_serial_only = FALSE; 96 | 97 | smc_pm.start_picker = 0x0001; 98 | smc_pm.start_map = 0x0010; 99 | smc_pm.start_drive = 0x0100; 100 | smc_pm.start_storage = 0x1000; 101 | 102 | smc_pm.lu = lu; 103 | smc_personality_module_register(&smc_pm); 104 | 105 | init_slot_info(lu); 106 | 107 | /* Reference Quantum 6-00423013 SCSI Reference - Rev A */ 108 | ymd(&year, &month, &day, &h, &m, &sec); 109 | 110 | /* Controller firmware build date */ 111 | sprintf((char *)&lu->inquiry[36], "%04d-%02d-%02d %02d:%02d:%02d", 112 | year, month, day, h, m, sec); 113 | 114 | init_scalar_inquiry(lu); 115 | update_scalar_vpd_80(lu); 116 | update_scalar_vpd_83(lu); 117 | 118 | init_smc_log_pages(lu); 119 | init_smc_mode_pages(lu); 120 | } 121 | -------------------------------------------------------------------------------- /usr/security_protocol.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _SECURITY_PROTOCOL_H_ 3 | #define _SECURITY_PROTOCOL_H_ 4 | /* 5 | * Security Protocol IN/OUT 6 | * 7 | * Based on spc4r14 / ssc3r04a 8 | * 9 | */ 10 | 11 | /* 12 | * Security Algorithm Code 13 | */ 14 | #define HMAC_KDF_SHA1 0x0020002 15 | #define HMAC_KDF_SHA256 0x0020005 16 | #define HMAC_KDF_SHA384 0x0020006 17 | #define HMAC_KDF_SHA512 0x0020007 18 | #define KDF_AES_128_XCBC 0x0020004 19 | 20 | 21 | /* 22 | * Security Association 23 | * spc4r14 5.13.2 24 | */ 25 | struct sa { 26 | uint32_t ac_sai; 27 | uint32_t ds_sai; 28 | uint32_t timeout; 29 | 30 | uint64_t ac_sqn; 31 | uint64_t ds_sqn; 32 | 33 | uint8_t ac_nonce[64]; 34 | uint8_t ds_nonce[64]; 35 | 36 | uint8_t key_seed[64]; 37 | 38 | uint32_t kdf_id; 39 | 40 | uint8_t keymat[1024]; 41 | 42 | uint16_t usage_type; 43 | uint8_t usage_data[1024]; 44 | uint8_t mgmt_data[1024]; 45 | }; 46 | 47 | 48 | #endif /* _SECURITY_PROTOCOL_H_ */ 49 | -------------------------------------------------------------------------------- /usr/smc.h: -------------------------------------------------------------------------------- 1 | 2 | /* Element type codes */ 3 | #define ANY 0 4 | #define MEDIUM_TRANSPORT 1 5 | #define STORAGE_ELEMENT 2 6 | #define MAP_ELEMENT 3 7 | #define DATA_TRANSFER 4 8 | 9 | #define CAP_CLOSED 1 10 | #define CAP_OPEN 0 11 | #define OPERATOR 1 12 | #define ROBOT_ARM 0 13 | 14 | struct smc_personality_template { 15 | char *name; 16 | uint32_t library_has_map:1; 17 | uint32_t library_has_barcode_reader:1; 18 | uint32_t library_has_playground:1; 19 | uint32_t dvcid_serial_only:1; 20 | uint32_t no_dvcid_flag:1; 21 | 22 | uint32_t start_drive; 23 | uint32_t start_picker; 24 | uint32_t start_map; 25 | uint32_t start_storage; 26 | uint32_t dvcid_len; 27 | 28 | struct lu_phy_attr *lu; 29 | }; 30 | 31 | uint8_t smc_allow_removal(struct scsi_cmd *cmd); 32 | uint8_t smc_initialize_element_status(struct scsi_cmd *cmd); 33 | uint8_t smc_initialize_element_status_with_range(struct scsi_cmd *cmd); 34 | uint8_t smc_log_sense(struct scsi_cmd *cmd); 35 | uint8_t smc_move_medium(struct scsi_cmd *cmd); 36 | uint8_t smc_read_element_status(struct scsi_cmd *cmd); 37 | uint8_t smc_rezero(struct scsi_cmd *cmd); 38 | uint8_t smc_open_close_import_export_element(struct scsi_cmd *cmd); 39 | 40 | int get_cart_type(char *barcode); 41 | void update_home_dir(long my_id); /* for the 'get_cart_type()' function only */ 42 | 43 | int slotOccupied(struct s_info *s); 44 | void setImpExpStatus(struct s_info *s, int flg); 45 | void setSlotEmpty(struct s_info *s); 46 | void unload_drive_on_shutdown(struct s_info *src, struct s_info *dest); 47 | 48 | void init_slot_info(struct lu_phy_attr *lu); 49 | void init_stkl20(struct lu_phy_attr *lu); 50 | void init_stklxx(struct lu_phy_attr *lu); 51 | void init_stkslxx(struct lu_phy_attr *lu); 52 | void init_default_smc(struct lu_phy_attr *lu); 53 | void init_scalar_smc(struct lu_phy_attr *lu); 54 | void init_spectra_logic_smc(struct lu_phy_attr *lu); 55 | void init_spectra_215_smc(struct lu_phy_attr *lu); 56 | void init_spectra_gator_smc(struct lu_phy_attr *lu); 57 | void init_ibmts3100(struct lu_phy_attr *lu); 58 | void init_ibm3584(struct lu_phy_attr *lu); 59 | void init_hp_eml_smc(struct lu_phy_attr *lu); 60 | void init_hp_msl_smc(struct lu_phy_attr *lu); 61 | void init_overland_smc(struct lu_phy_attr *lu); 62 | void smc_personality_module_register(struct smc_personality_template *pm); 63 | void setAccessStatus(struct s_info *s, int flg); 64 | -------------------------------------------------------------------------------- /usr/spc.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef SPC_H 3 | #define SPC_H 4 | 5 | /* Variables for simple, single initiator, SCSI Reservation system */ 6 | 7 | extern uint64_t SPR_Reservation_Key; 8 | extern uint32_t SPR_Reservation_Generation; 9 | extern uint8_t SPR_Reservation_Type; 10 | 11 | 12 | uint8_t resp_spc_pro(uint8_t *cdb, struct mhvtl_ds *dbuf_p); 13 | uint8_t resp_spc_pri(uint8_t *cdb, struct mhvtl_ds *dbuf_p); 14 | 15 | uint8_t spc_illegal_op(struct scsi_cmd *cmd); 16 | uint8_t spc_inquiry(struct scsi_cmd *cmd); 17 | uint8_t spc_log_select(struct scsi_cmd *cmd); 18 | uint8_t spc_log_sense(struct scsi_cmd *cmd); 19 | uint8_t spc_mode_select(struct scsi_cmd *cmd); 20 | uint8_t spc_mode_sense(struct scsi_cmd *cmd); 21 | uint8_t spc_recv_diagnostics(struct scsi_cmd *cmd); 22 | uint8_t spc_release(struct scsi_cmd *cmd); 23 | uint8_t spc_request_sense(struct scsi_cmd *cmd); 24 | uint8_t spc_reserve(struct scsi_cmd *cmd); 25 | uint8_t spc_send_diagnostics(struct scsi_cmd *cmd); 26 | uint8_t spc_tur(struct scsi_cmd *cmd); 27 | 28 | #endif /* SPC_H */ 29 | -------------------------------------------------------------------------------- /usr/spectra_pm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Personality module for Spectra Logic 3 | */ 4 | 5 | #include 6 | #include "mhvtl_list.h" 7 | #include "vtllib.h" 8 | #include "smc.h" 9 | #include "logging.h" 10 | #include "be_byteshift.h" 11 | #include "mhvtl_log.h" 12 | #include "mode.h" 13 | #include "mhvtl_scsi.h" 14 | 15 | static void update_spectra_215_device_capabilities(struct lu_phy_attr *lu) 16 | { 17 | struct mode *mp; 18 | 19 | mp = lookup_pcode(&lu->mode_pg, MODE_DEVICE_CAPABILITIES, 0); 20 | if (!mp) { /* Can't find page ??? */ 21 | MHVTL_ERR("Can't find MODE_DEVICE_CAPABILITIES page"); 22 | return; 23 | } 24 | 25 | mp->pcodePointer[2] = 0x0b; 26 | mp->pcodePointer[3] = 0x00; 27 | mp->pcodePointer[4] = 0x0a; 28 | mp->pcodePointer[5] = 0x0b; 29 | mp->pcodePointer[6] = 0x00; 30 | mp->pcodePointer[7] = 0x0b; 31 | } 32 | 33 | static void update_spectra_gator_device_capabilities(struct lu_phy_attr *lu) 34 | { 35 | struct mode *mp; 36 | 37 | mp = lookup_pcode(&lu->mode_pg, MODE_DEVICE_CAPABILITIES, 0); 38 | if (!mp) { /* Can't find page ??? */ 39 | MHVTL_ERR("Can't find MODE_DEVICE_CAPABILITIES page"); 40 | return; 41 | } 42 | 43 | mp->pcodePointer[2] = 0x0e; 44 | mp->pcodePointer[3] = 0x00; 45 | mp->pcodePointer[4] = 0x0e; 46 | mp->pcodePointer[5] = 0x0e; 47 | mp->pcodePointer[6] = 0x0e; 48 | mp->pcodePointer[7] = 0x0e; 49 | } 50 | 51 | static void update_spectra_t_series_device_capabilities(struct lu_phy_attr *lu) 52 | { 53 | struct mode *mp; 54 | 55 | mp = lookup_pcode(&lu->mode_pg, MODE_DEVICE_CAPABILITIES, 0); 56 | if (!mp) { /* Can't find page ??? */ 57 | MHVTL_ERR("Can't find MODE_DEVICE_CAPABILITIES page"); 58 | return; 59 | } 60 | 61 | mp->pcodePointer[2] = 0x0e; 62 | mp->pcodePointer[3] = 0x00; 63 | mp->pcodePointer[4] = 0x0e; 64 | mp->pcodePointer[5] = 0x0e; 65 | mp->pcodePointer[6] = 0x0e; 66 | mp->pcodePointer[7] = 0x0e; 67 | } 68 | 69 | static struct smc_personality_template smc_pm = { 70 | .library_has_map = TRUE, 71 | .library_has_barcode_reader = TRUE, 72 | .library_has_playground = FALSE, 73 | 74 | /* Rev G of SpectraLogic Tseries states this is now 1Eh 75 | * Yet... 76 | * DVCID=1 'Identifier Length (1Eh) but goes on to describe 77 | * fields 52 through 83 are for the Device Identifier -> and that 78 | * adds up to 32 by my calculations. And in table 10-5 specifies 79 | * Identifier Length as 1Gh... (hmmm forgot to carry the one in 80 | * base 16 addition when they got to 1Fh) - which is of course 81 | * 20h (32 decimal). 82 | */ 83 | .dvcid_len = 0x20, 84 | }; 85 | 86 | void init_spectra_215_smc(struct lu_phy_attr *lu) 87 | { 88 | smc_pm.name = "mhVTL - Spectra Treefrog emulation"; 89 | smc_pm.library_has_map = FALSE; 90 | smc_pm.library_has_barcode_reader = TRUE; 91 | smc_pm.dvcid_serial_only = TRUE; 92 | smc_pm.no_dvcid_flag = TRUE; 93 | smc_pm.dvcid_len = 0; 94 | 95 | /* Extracted from Spectra Treefrog-Series SCSI Developers guide */ 96 | smc_pm.start_picker = 86; 97 | smc_pm.start_map = 99; /* fake */ 98 | smc_pm.start_drive = 31; 99 | smc_pm.start_storage = 1; 100 | 101 | smc_pm.lu = lu; 102 | smc_personality_module_register(&smc_pm); 103 | 104 | init_slot_info(lu); 105 | 106 | init_smc_log_pages(lu); 107 | init_smc_mode_pages(lu); 108 | /* Now that 'init_smc_mode_pages()' has allocated device capabilities 109 | * page, update to valid default values for Spectra-Logic treefrog 110 | */ 111 | update_spectra_215_device_capabilities(lu); 112 | } 113 | 114 | void init_spectra_gator_smc(struct lu_phy_attr *lu) 115 | { 116 | smc_pm.name = "mhVTL - Spectra Gator emulation"; 117 | smc_pm.library_has_map = TRUE; 118 | smc_pm.library_has_barcode_reader = TRUE; 119 | smc_pm.dvcid_serial_only = TRUE; 120 | smc_pm.dvcid_len = 10; 121 | 122 | /* Extracted from Spectra Gator SCSI Developers guide */ 123 | smc_pm.start_picker = 0x02c3; 124 | smc_pm.start_map = 0x0001; 125 | smc_pm.start_drive = 0x02a3; 126 | smc_pm.start_storage = 0x001e; 127 | 128 | smc_pm.lu = lu; 129 | smc_personality_module_register(&smc_pm); 130 | 131 | init_slot_info(lu); 132 | 133 | init_smc_log_pages(lu); 134 | init_smc_mode_pages(lu); 135 | /* Now that 'init_smc_mode_pages()' has allocated device capabilities 136 | * page, update to valid default values for Spectra-Logic Gator Series 137 | */ 138 | update_spectra_gator_device_capabilities(lu); 139 | } 140 | 141 | void init_spectra_logic_smc(struct lu_phy_attr *lu) 142 | { 143 | smc_pm.name = "mhVTL - Spectra T-Series emulation"; 144 | smc_pm.library_has_map = TRUE; 145 | smc_pm.library_has_barcode_reader = TRUE; 146 | smc_pm.dvcid_serial_only = TRUE; 147 | 148 | /* Extracted from Spectra T-Series SCSI Developers guide */ 149 | smc_pm.start_picker = 0x0001; 150 | smc_pm.start_map = 0x0010; 151 | smc_pm.start_drive = 0x0100; 152 | smc_pm.start_storage = 0x1000; 153 | 154 | smc_pm.lu = lu; 155 | smc_personality_module_register(&smc_pm); 156 | 157 | init_slot_info(lu); 158 | 159 | init_smc_log_pages(lu); 160 | init_smc_mode_pages(lu); 161 | /* Now that 'init_smc_mode_pages()' has allocated device capabilities 162 | * page, update to valid default values for Spectra-Logic T Series 163 | */ 164 | update_spectra_t_series_device_capabilities(lu); 165 | } 166 | -------------------------------------------------------------------------------- /usr/stklxx_pm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Personality module for STK L series of robots 3 | * e.g. L180, L700, L20/40/80 4 | */ 5 | 6 | #include 7 | #include 8 | #include "mhvtl_list.h" 9 | #include "vtllib.h" 10 | #include "smc.h" 11 | #include "logging.h" 12 | #include "be_byteshift.h" 13 | #include "mhvtl_log.h" 14 | #include "mode.h" 15 | 16 | static struct smc_personality_template smc_pm = { 17 | .library_has_map = TRUE, 18 | .library_has_barcode_reader = TRUE, 19 | .library_has_playground = TRUE, 20 | 21 | .dvcid_len = 34, 22 | }; 23 | 24 | static void update_stk_l_vpd_80(struct lu_phy_attr *lu) 25 | { 26 | struct vpd **lu_vpd; 27 | uint8_t *d; 28 | 29 | lu_vpd = &lu->lu_vpd[PCODE_OFFSET(0x80)]; 30 | 31 | /* Unit Serial Number */ 32 | if (*lu_vpd) { /* Free any earlier allocation */ 33 | dealloc_vpd(*lu_vpd); 34 | *lu_vpd = NULL; 35 | } 36 | 37 | *lu_vpd = alloc_vpd(0x12); 38 | if (*lu_vpd) { 39 | d = (*lu_vpd)->data; 40 | /* d[4 - 15] Serial number of device */ 41 | snprintf((char *)&d[0], 13, "%-12.12s", lu->lu_serial_no); 42 | /* Unique Logical Library Identifier */ 43 | } else { 44 | MHVTL_ERR("Could not malloc(0x12) bytes, line %d", __LINE__); 45 | } 46 | } 47 | 48 | static void update_stk_l_vpd_83(struct lu_phy_attr *lu) 49 | { 50 | struct vpd *lu_vpd; 51 | 52 | lu_vpd = lu->lu_vpd[PCODE_OFFSET(0x83)]; 53 | 54 | /* STK L series do not have this VPD page - remove */ 55 | if (lu_vpd) { /* Free any earlier allocation */ 56 | dealloc_vpd(lu_vpd); 57 | lu->lu_vpd[PCODE_OFFSET(0x83)] = NULL; 58 | } 59 | } 60 | 61 | void init_stkl20(struct lu_phy_attr *lu) 62 | { 63 | smc_pm.name = "mhVTL - STK L20/40/80 series emulation"; 64 | smc_pm.library_has_map = TRUE; 65 | smc_pm.library_has_barcode_reader = TRUE; 66 | smc_pm.library_has_playground = TRUE; 67 | 68 | /* Follow L20 SCSI Reference Manual */ 69 | smc_pm.start_picker = 0x0001; 70 | smc_pm.start_map = 0x000a; /* 10d - 55d */ 71 | smc_pm.start_drive = 0x01f4; /* 500d - 519d */ 72 | smc_pm.start_storage = 0x03e8; /* 1000d - 1677d */ 73 | 74 | smc_pm.lu = lu; 75 | smc_personality_module_register(&smc_pm); 76 | 77 | init_slot_info(lu); 78 | 79 | update_stk_l_vpd_80(lu); 80 | update_stk_l_vpd_83(lu); 81 | init_smc_log_pages(lu); 82 | init_smc_mode_pages(lu); 83 | /* FIXME: Need to add page 0x2d - Drive Configuration Page */ 84 | add_smc_mode_page_drive_configuration(lu); 85 | } 86 | 87 | void init_stklxx(struct lu_phy_attr *lu) 88 | { 89 | smc_pm.name = "mhVTL - STK L series emulation"; 90 | smc_pm.library_has_map = TRUE; 91 | smc_pm.library_has_barcode_reader = TRUE; 92 | smc_pm.library_has_playground = TRUE; 93 | 94 | /* Follow L700e/L180 SCSI Reference Manual - 8th Edition */ 95 | smc_pm.start_picker = 0x0001; 96 | smc_pm.start_map = 0x000a; /* 10d - 55d */ 97 | smc_pm.start_drive = 0x01f4; /* 500d - 519d */ 98 | smc_pm.start_storage = 0x03e8; /* 1000d - 1677d */ 99 | 100 | smc_pm.lu = lu; 101 | smc_personality_module_register(&smc_pm); 102 | 103 | init_slot_info(lu); 104 | 105 | update_stk_l_vpd_80(lu); 106 | update_stk_l_vpd_83(lu); 107 | init_smc_log_pages(lu); 108 | init_smc_mode_pages(lu); 109 | } 110 | 111 | void init_stkslxx(struct lu_phy_attr *lu) 112 | { 113 | smc_pm.name = "mhVTL - STK SL series emulation"; 114 | smc_pm.library_has_map = TRUE; 115 | smc_pm.library_has_barcode_reader = TRUE; 116 | smc_pm.library_has_playground = TRUE; 117 | 118 | /* Follow Streamline SL500 Interface Reference Manual - 2th Edition */ 119 | smc_pm.start_picker = 0x0001; 120 | smc_pm.start_map = 0x000a; /* 10d - 55d */ 121 | smc_pm.start_drive = 0x01f4; /* 500d - 518d */ 122 | smc_pm.start_storage = 0x03e8; /* 1000d - 1628d */ 123 | 124 | smc_pm.lu = lu; 125 | smc_personality_module_register(&smc_pm); 126 | 127 | init_slot_info(lu); 128 | 129 | update_stk_l_vpd_80(lu); 130 | update_stk_l_vpd_83(lu); 131 | init_smc_log_pages(lu); 132 | init_smc_mode_pages(lu); 133 | } 134 | -------------------------------------------------------------------------------- /usr/subprocess.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Run subprocess 3 | * 4 | * Copyright (C) 2012 Ivo De Decker ivo.dedecker@ugent.be 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | */ 21 | 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "logging.h" 33 | 34 | static pid_t pid; 35 | static int timedout; 36 | 37 | void alarm_timeout(int sig) 38 | { 39 | alarm(0); 40 | timedout = 1; 41 | if (pid) 42 | kill(pid, 9); 43 | } 44 | 45 | int run_command(char *command, int timeout) 46 | { 47 | pid = fork(); 48 | if (!pid) { 49 | /* child */ 50 | execlp("/bin/sh", "/bin/sh", "-c", command, (char *)NULL); 51 | } else if (pid < 0) { 52 | /* TODO error handling */ 53 | return -1; 54 | } else { 55 | signal(SIGALRM, alarm_timeout); 56 | timedout = 0; 57 | alarm(timeout); 58 | int status; 59 | 60 | while (waitpid(pid, &status, 0) <= 0) 61 | usleep(1); 62 | 63 | alarm(0); 64 | 65 | if (WIFEXITED(status)) { 66 | int res = WEXITSTATUS(status); 67 | return res; 68 | } else if (WIFSIGNALED(status)) { 69 | int sig = WTERMSIG(status); 70 | MHVTL_DBG(1, "command died with signal: %d " 71 | "(timedout: %d)\n", sig, timedout); 72 | return -sig; 73 | } 74 | } 75 | 76 | return -1; 77 | } 78 | -------------------------------------------------------------------------------- /usr/subprocess.h: -------------------------------------------------------------------------------- 1 | 2 | int run_command(char *command, int timeout); 3 | -------------------------------------------------------------------------------- /usr/validate_crc.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Validate Reed-Solomon CRC and CRC32C routines pass 4 | * basic sanity check at compile time 5 | * 6 | * Shamelessly lifted/copied from CASTOR utils/CRCtest.cpp 7 | * 8 | * Designed to abort if CRC32C or RS-CRC fails basic sanity check 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | uint32_t crc32c(uint32_t seed, const uint8_t *buf, size_t sz); 17 | uint32_t GenerateRSCRC(uint32_t seed, int sz, const uint8_t *buf); 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | const uint8_t block1[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 22 | 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 23 | 131, 137, 139, 149, 151, 157}; 24 | 25 | const uint8_t block2[] = {163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 26 | 223, 227, 229, 233, 239, 241, 251}; 27 | 28 | uint32_t computedCRC1 = crc32c(0, block1, sizeof(block1)); 29 | uint32_t computedCRC2 = crc32c(~computedCRC1, block2, sizeof(block2)); 30 | uint32_t computedCRC3 = crc32c(~crc32c(0, block1, sizeof(block1)), block2, sizeof(block2)); 31 | 32 | assert(computedCRC1 == 0xE8174F48); 33 | assert(computedCRC2 == 0x56DAB0A6); 34 | assert(computedCRC3 == 0x56DAB0A6); 35 | 36 | computedCRC1 = GenerateRSCRC(0, sizeof(block1), block1); 37 | computedCRC2 = GenerateRSCRC(computedCRC1, sizeof(block2), block2); 38 | computedCRC3 = GenerateRSCRC(GenerateRSCRC(0, sizeof(block1), block1), sizeof(block2), block2); 39 | 40 | assert(computedCRC1 == 0x733D4DCA); 41 | assert(computedCRC2 == 0x754ED37E); 42 | assert(computedCRC3 == 0x754ED37E); 43 | 44 | return 0; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /usr/vtltape_pem.h: -------------------------------------------------------------------------------- 1 | static char *certificate = 2 | "-----BEGIN CERTIFICATE-----\n" 3 | "MIID9zCCA2CgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox\n" 4 | "EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp\n" 5 | "YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy\n" 6 | "dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3\n" 7 | "DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMjAxMTYwNTA5NTlaFw0xMjAxMTQw\n" 8 | "NTA5NTlaMIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoG\n" 9 | "A1UEChMzUmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3Jp\n" 10 | "dHkgKFJJQUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNr\n" 11 | "b3YgYWwtVHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluMIGf\n" 12 | "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7QdDfFIrJn3X24hKmpkyk3TG0Ivxd\n" 13 | "K2wWmDPXq1wjr8lUTwrA6hM5Ba9N36jLieWpXhviLOWu9DBza5GmtgCuXloATKTC\n" 14 | "94xOdKHlciTVujG3wDlLDB5e710Kar84nnj6VueL1RyZ0bmP5PANa4mbGW9Tqc7J\n" 15 | "CkBTTW2y9d0SgQIDAQABo4IBFTCCAREwHQYDVR0OBBYEFEn7RXISxMzhRaHTCJ6V\n" 16 | "xCxtVT8XMIHhBgNVHSMEgdkwgdaAFEn7RXISxMzhRaHTCJ6VxCxtVT8XoYG6pIG3\n" 17 | "MIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoGA1UEChMz\n" 18 | "UmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3JpdHkgKFJJ\n" 19 | "QUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNrb3YgYWwt\n" 20 | "VHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluggEAMAwGA1Ud\n" 21 | "EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAYQo95V/NY+eKxYxkhibZiUQygph+\n" 22 | "gTfgbDG20MsnH6+8//w5ArHauFCgDrf0P2VyACgq+N4pBTWFGaAaLwbjKy9HCe2E\n" 23 | "j9C91tO1CqDS4MJkDB5AP13FTkK6fP1ZCiTQranOAp3DlGWTTWsFVyW5kVfQ9diS\n" 24 | "ZOyJZ9Fit5XM2X0=\n" 25 | "-----END CERTIFICATE-----\n"; 26 | -------------------------------------------------------------------------------- /vagrant/README.MD: -------------------------------------------------------------------------------- 1 | # Testing with Vagrant 2 | To test mhvtl on different distros, we use vagrant to spin up virtual boxes with different distros and install mhvtl from source on each box. 3 | 4 | ## Prerequisites 5 | 6 | To be able to test with Vagrant, you need: 7 | 8 | - Vagrant (tested with 2.2.4) 9 | - Virtualbox (tested with 5.2.26) 10 | 11 | ## Test in different Operating Systems 12 | 13 | Run any of the following commands to test the code on different GNU/Linux distributions. 14 | 15 | ``` 16 | Vagrant up ubuntu 17 | ``` 18 | 19 | or 20 | 21 | ``` 22 | Vagrant up centos 23 | ``` 24 | 25 | or 26 | 27 | ``` 28 | Vagrant up opensuse 29 | ``` 30 | **_NOTE:_** OpenSUSE in currently not working 31 | 32 | The test will build and install mhvtl from source in the virtual machine. If the output looks something like this, then the installation went fine: 33 | ``` 34 | ... 35 | ubuntu: Show your tape libraries now! 36 | ubuntu: [2:0:0:0] disk VBOX HARDDISK 1.0 /dev/sda /dev/sg0 37 | ubuntu: [2:0:1:0] disk VBOX HARDDISK 1.0 /dev/sdb /dev/sg1 38 | ubuntu: [3:0:0:0] mediumx STK L700 0106 - /dev/sg7 39 | ubuntu: [3:0:1:0] tape IBM ULT3580-TD5 0106 - /dev/sg6 40 | ubuntu: [3:0:2:0] tape IBM ULT3580-TD5 0106 - /dev/sg11 41 | ubuntu: [3:0:3:0] tape IBM ULT3580-TD4 0106 - /dev/sg4 42 | ubuntu: [3:0:4:0] tape IBM ULT3580-TD4 0106 - /dev/sg8 43 | ubuntu: [3:0:8:0] mediumx STK L80 0106 - /dev/sg3 44 | ubuntu: [3:0:9:0] tape STK T10000B 0106 - /dev/sg5 45 | ubuntu: [3:0:10:0] tape STK T10000B 0106 - /dev/sg2 46 | ubuntu: [3:0:11:0] tape STK T10000B 0106 - /dev/sg9 47 | ubuntu: [3:0:12:0] tape STK T10000B 0106 - /dev/sg10 48 | ubuntu: Found some virtual tapes, success! 49 | ``` 50 | 51 | ### Cleanup 52 | 53 | When you are done, and you want to remove the box, run the following command: 54 | 55 | ``` 56 | Vagrant destroy -f 57 | ``` 58 | -------------------------------------------------------------------------------- /vagrant/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | def gui_enabled? 5 | !ENV.fetch('GUI', '').empty? 6 | end 7 | 8 | Vagrant.configure("2") do |config| 9 | config.vm.box_check_update = false 10 | 11 | config.vm.define "ubuntu" do |instance| 12 | instance.vm.box = "generic/ubuntu1804" 13 | instance.vm.network "private_network", ip: "192.168.56.20" 14 | end 15 | 16 | config.vm.define "rocky" do |instance| 17 | instance.vm.hostname = "rocky" 18 | instance.vm.box = "rockylinux/8" 19 | instance.vm.network "private_network", ip: "192.168.56.21" 20 | end 21 | 22 | config.vm.define "centos8" do |instance| 23 | instance.vm.box = "centos/8" 24 | instance.vm.network "private_network", ip: "192.168.56.22" 25 | end 26 | 27 | config.vm.define "centos" do |instance| 28 | instance.vm.box = "geerlingguy/centos7" 29 | instance.vm.network "private_network", ip: "192.168.56.23" 30 | end 31 | 32 | config.vm.define "opensuse" do |instance| 33 | instance.vm.box = "opensuse/Leap-15.2.x86_64" 34 | instance.vm.network "private_network", ip: "192.168.56.24" 35 | end 36 | 37 | config.vm.define "alma" do |instance| 38 | instance.vm.hostname = "alma" 39 | instance.vm.box = "almalinux/9" 40 | instance.vm.network "private_network", ip: "192.168.56.25" 41 | config.vbguest.auto_update = false 42 | end 43 | 44 | config.vm.provider "virtualbox" do |vb| 45 | vb.memory = "2048" 46 | vb.gui = gui_enabled? 47 | end 48 | 49 | config.vm.synced_folder "../", "/vagrant_data" 50 | 51 | config.vm.provision "shell", inline: <<-SHELL 52 | cd /vagrant_data/vagrant 53 | sudo ./install.sh 54 | SHELL 55 | end 56 | -------------------------------------------------------------------------------- /webgui/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | mhvtl configuration"; 9 | 10 | echo "
"; 11 | 12 | echo "
"; 13 | 14 | phpinfo(); 15 | 16 | ?> 17 | 18 | 19 | 20 | --------------------------------------------------------------------------------