[Stgt-devel] tape drive not supported yet?
FUJITA Tomonori
fujita.tomonori
Wed Jul 16 09:51:38 CEST 2008
On Sat, 12 Jul 2008 19:40:21 +0200
Albert Pauw <albert.pauw at gmail.com> wrote:
> Tried to set up a tape drive target:
>
> LUN=$(($LUN+1))
> ID=Tape
> SN=54321
> tgtadm --lld iscsi --op new --mode logicalunit --tid $TID --lun $LUN \
> --device-type tape
>
> Unfortunately, tgtadm tells me:
>
> tgtadm: type emulation isn't supported yet
>
> Is this correct?
You are talking about vtl, right?
Here's aftab azmi's vtl patch:
https://lists.berlios.de/pipermail/stgt-devel/2008-May/001610.html
I've cleaned up it and my initiator can find a tape drive with this
pathc. However, seems that this patch has several issues to solve.
Mark's comments are:
https://lists.berlios.de/pipermail/stgt-devel/2008-May/001622.html
I need vtl to just work on the tape initiator driver. I'll try to
improve the vtl support but probabaly I don't have time to make the
vtl support good enough for real usage.
BTW, here's an example how to setup a tape drive with this patch:
tgtadm --lld iscsi --op new --mode target --tid 1 -T iqn.2001-04.org.osrg:viola
tgtadm --lld iscsi --op new --mode logicalunit --tid 1 --lun 1 -b /var/tmp/image0 --device-type ssc --bstype ssc
=
diff --git a/usr/Makefile b/usr/Makefile
index 48de052..4aae4c5 100644
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -11,7 +11,7 @@ CFLAGS += -DISCSI
TGTD_OBJS += $(addprefix iscsi/, conn.o param.o session.o \
iscsid.o target.o chap.o transport.o iscsi_tcp.o \
isns.o libcrc32c.o)
-TGTD_OBJS += bs_rdwr.o bs_aio.o
+TGTD_OBJS += bs_rdwr.o bs_aio.o bs_ssc.o
LIBS += -lcrypto
ifneq ($(ISCSI_RDMA),)
@@ -57,7 +57,7 @@ LIBS += -lpthread
PROGRAMS += tgtd tgtadm
SCRIPTS += ../scripts/tgt-setup-lun
TGTD_OBJS += tgtd.o mgmt.o target.o scsi.o log.o driver.o util.o work.o \
- parser.o spc.o sbc.o mmc.o osd.o scc.o smc.o bs.o
+ parser.o spc.o sbc.o mmc.o osd.o scc.o smc.o ssc.o bs.o
MANPAGES = ../doc/manpages/tgtadm.8 ../doc/manpages/tgt-setup-lun.8
TGTD_DEP = $(TGTD_OBJS:.o=.d)
diff --git a/usr/bs_ssc.c b/usr/bs_ssc.c
new file mode 100644
index 0000000..78d5817
--- /dev/null
+++ b/usr/bs_ssc.c
@@ -0,0 +1,250 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/fs.h>
+#include <sys/epoll.h>
+
+#include "list.h"
+#include "util.h"
+#include "tgtd.h"
+#include "scsi.h"
+#include "bs_thread.h"
+
+#define TCLP_BIT 4
+#define LONG_BIT 2
+#define BT_BIT 1
+
+static void set_medium_error(int *result, uint8_t *key, uint16_t *asc)
+{
+ *result = SAM_STAT_CHECK_CONDITION;
+ *key = MEDIUM_ERROR;
+ *asc = ASC_READ_ERROR;
+}
+
+static void ssc_sense_data_build(struct scsi_cmd *cmd, uint8_t key,
+ uint16_t asc)
+{
+ int len = 0xa;
+ cmd->sense_buffer[0] = 0x70;
+ cmd->sense_buffer[2] = NO_SENSE;
+ cmd->sense_buffer[7] = len;
+ cmd->sense_buffer[12] = (asc >> 8) & 0xff;
+ cmd->sense_buffer[13] = asc & 0xff;
+ cmd->sense_len = len + 8;
+}
+
+static void rdwr_request(struct scsi_cmd *cmd)
+{
+ int ret, fd = cmd->dev->fd, code;
+ uint32_t length, i, transfer_length, residue;
+ int result = SAM_STAT_GOOD;
+ uint8_t key;
+ uint16_t asc;
+ uint8_t buff[512];
+ char *buf;
+ off_t rew;
+ uint64_t curr_pos;
+ uint32_t count;
+
+ ret = 0;
+ length = 0;
+ i = 0;
+ key = 0;
+ asc = 0;
+ transfer_length = 0;
+ residue = 0;
+ count = 0;
+ code = 0;
+
+ switch (cmd->scb[0]) {
+ case REZERO_UNIT:
+ rew = lseek(fd, 0, SEEK_SET);
+ curr_pos = lseek(fd, 0, SEEK_CUR);
+ if (ret)
+ set_medium_error(&result, &key, &asc);
+ eprintf("Rewind Successful, File Pointer at %" PRIu64",%m\n",
+ curr_pos);
+ break;
+ case WRITE_FILEMARKS:
+ length = sizeof(buff);
+ memset(buff, 28, sizeof(buff));
+ ret = write(fd, buff, length);
+
+ if (ret != length)
+ set_medium_error(&result, &key, &asc);
+ eprintf("Write Filemark Successfull %d\n", ret);
+ curr_pos = lseek(fd, 0, SEEK_CUR);
+ eprintf("File Pointer at %" PRIu64",%m\n", curr_pos);
+ break;
+ case READ_6:
+ length = scsi_get_in_length(cmd);
+ ret = read(fd, scsi_get_in_buffer(cmd), length);
+ buf = (char *)(unsigned long)scsi_get_in_buffer(cmd);
+ /* buf = (char *)buf; */
+ if (ret != length)
+ set_medium_error(&result, &key, &asc);
+ else {
+ for (i = 0; i < ret; i += 512) {
+ eprintf("buf[%d]=%d", i, buf[i]);
+ if (buf[i] == 28) {
+ result = SAM_STAT_CHECK_CONDITION;
+ key = NO_SENSE;
+ asc = ASC_MARK;
+ transfer_length = ((cmd->scb[2] << 16) |
+ (cmd->scb[3] << 8) |
+ (cmd->scb[4]));
+/* residue = */
+/* transfer_length - i << 9; */
+ residue = (length - i) << 9;
+ cmd->sense_buffer[3] = residue >> 24;
+ cmd->sense_buffer[3] = residue >> 16;
+ cmd->sense_buffer[3] = residue >> 8;
+ cmd->sense_buffer[3] = residue;
+
+ eprintf("File Mark Detected at %d,"
+ " Residue = %d %m\n",
+ i, residue);
+ }
+ }
+ }
+ eprintf("Executed READ_6, Read %d bytes\n", ret);
+ curr_pos = lseek(fd, 0, SEEK_CUR);
+ eprintf("File Pointer at %" PRIu64",%m\n", curr_pos);
+ break;
+ case WRITE_6:
+ length = scsi_get_out_length(cmd);
+ ret = write(fd, scsi_get_out_buffer(cmd), length);
+ if (ret != length)
+ set_medium_error(&result, &key, &asc);
+ eprintf("Executed WRITE_6, writen %d bytes\n", ret);
+ curr_pos = lseek(fd, 0, SEEK_CUR);
+ eprintf("File Pointer at %" PRIu64",%m\n", curr_pos);
+ break;
+ case SPACE:
+ code = cmd->scb[1];
+ count = (cmd->scb[2] << 16) | (cmd->scb[3] << 8) |
+ (cmd->scb[4]);
+
+ if (code == 0) {
+ for (i = 0; i < count; i++) {
+ ret = read(fd, buff, sizeof(buff));
+ if (ret != sizeof(buff))
+ set_medium_error(&result, &key, &asc);
+
+ curr_pos = lseek(fd, 0, SEEK_CUR);
+ eprintf("File Pointer at %" PRIu64",%m\n",
+ curr_pos);
+
+ if (buff[i*512] == 28) {
+ result = SAM_STAT_CHECK_CONDITION;
+ key = NO_SENSE;
+ asc = ASC_MARK;
+ }
+ }
+ } else if (code == 1) {
+ i = 0;
+ while (i < count) {
+ ret = read(fd, buff, sizeof(buff));
+ curr_pos = lseek(fd, 0, SEEK_CUR);
+ eprintf("File Pointer at %" PRIu64",%m\n",
+ curr_pos);
+ if (buff[i*512] == 28)
+ i++;
+ }
+ }
+ break;
+ case READ_POSITION:
+ {
+ int tclp = cmd->scb[1] & TCLP_BIT;
+ int long_bit = cmd->scb[1] & LONG_BIT;
+ int bt = cmd->scb[1] & BT_BIT;
+ uint8_t *data;
+
+ eprintf("Size of in_buffer = %d ", scsi_get_in_length(cmd));
+ if (tclp == 1 || tclp != long_bit || (bt == 1 && long_bit == 1))
+ result = SAM_STAT_CHECK_CONDITION;
+ else {
+ memset(buff, 0, sizeof(buff));
+ data = buff;
+ curr_pos = lseek(fd, 0, SEEK_CUR);
+ if (curr_pos == 0)
+ data[0] = 0xb4;
+ else
+ data[0] = 0x34;
+ memcpy(scsi_get_in_buffer(cmd), data, 20);
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ dprintf("io done %p %x %d %u\n", cmd, cmd->scb[0], ret, length);
+
+ scsi_set_result(cmd, result);
+
+ if (result != SAM_STAT_GOOD) {
+ eprintf("io error %p %x %d %d %" PRIu64 ", %m\n",
+ cmd, cmd->scb[0], ret, length, cmd->offset);
+ ssc_sense_data_build(cmd, key, asc);
+ }
+}
+
+
+static int bs_ssc_open(struct scsi_lu *lu, char *path, int *fd, uint64_t *size)
+{
+ int ret;
+ struct bs_thread_info *info = BS_THREAD_I(lu);
+ uint64_t curr_pos;
+
+ eprintf("In bs_ssc_open\n");
+ *fd = backed_file_open(path, O_RDWR | O_LARGEFILE, size);
+ if (*fd < 0) {
+ eprintf("Error in bs_ssc_open\n");
+ return *fd;
+ }
+ curr_pos = lseek(*fd, 0, SEEK_CUR);
+ eprintf("File %s File Pointer at %" PRIu64",%m\n", path, curr_pos);
+
+ ret = bs_thread_open(info, rdwr_request);
+ if (ret) {
+ close(*fd);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void bs_ssc_close(struct scsi_lu *lu)
+{
+ struct bs_thread_info *info = BS_THREAD_I(lu);
+
+ bs_thread_close(info);
+
+ close(lu->fd);
+}
+
+static int bs_ssc_cmd_done(struct scsi_cmd *cmd)
+{
+ return 0;
+}
+
+static struct backingstore_template ssc_bst = {
+ .bs_name = "ssc",
+ .bs_datasize = sizeof(struct bs_thread_info),
+ .bs_open = bs_ssc_open,
+ .bs_close = bs_ssc_close,
+ .bs_cmd_submit = bs_thread_cmd_submit,
+ .bs_cmd_done = bs_ssc_cmd_done,
+};
+
+__attribute__((constructor)) static void bs_ssc_constructor(void)
+{
+ register_backingstore_template(&ssc_bst);
+}
diff --git a/usr/ssc.c b/usr/ssc.c
new file mode 100644
index 0000000..4363d4b
--- /dev/null
+++ b/usr/ssc.c
@@ -0,0 +1,300 @@
+/*
+ * SCSI stream command processing
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <linux/fs.h>
+
+#include "list.h"
+#include "util.h"
+#include "tgtd.h"
+#include "tgtadm_error.h"
+#include "target.h"
+#include "driver.h"
+#include "scsi.h"
+#include "spc.h"
+#include "tgtadm_error.h"
+
+#define BLK_SHIFT 9
+
+
+static int ssc_rw(int host_no, struct scsi_cmd *cmd)
+{
+ int ret;
+ unsigned char key = ILLEGAL_REQUEST;
+ uint16_t asc = ASC_LUN_NOT_SUPPORTED;
+
+ ret = device_reserved(cmd);
+ if (ret)
+ return SAM_STAT_RESERVATION_CONFLICT;
+
+ cmd->scsi_cmd_done = target_cmd_io_done;
+
+/* cmd->offset = (((cmd->scb[2] << 16) | (cmd->scb[3] << 8) | */
+/* (cmd->scb[4])) << BLK_SHIFT); */
+
+ ret = cmd->dev->bst->bs_cmd_submit(cmd);
+ if (ret) {
+ key = HARDWARE_ERROR;
+ asc = ASC_INTERNAL_TGT_FAILURE;
+ } else {
+ set_cmd_mmapio(cmd);
+ return SAM_STAT_GOOD;
+ }
+
+ cmd->offset = 0;
+ scsi_set_in_resid_by_actual(cmd, 0);
+ scsi_set_out_resid_by_actual(cmd, 0);
+
+ sense_data_build(cmd, key, asc);
+ return SAM_STAT_CHECK_CONDITION;
+}
+
+static int ssc_read_block_limit(int host_no, struct scsi_cmd *cmd)
+{
+ uint8_t *data;
+ uint8_t buf[256];
+ uint16_t blk_len = 0x200;
+
+ memset(buf, 0, sizeof(buf));
+ data = buf;
+
+ data[0] = 9;
+ data[2] = blk_len >> 8;
+ data[3] = blk_len & 0x0ff;
+ data[5] = blk_len >> 8;
+ data[6] = blk_len & 0x0ff;
+
+ memcpy(scsi_get_in_buffer(cmd), data, 6);
+ eprintf("In ssc_read_block_limit \n");
+ return SAM_STAT_GOOD;
+}
+
+static int ssc_lu_init(struct scsi_lu *lu)
+{
+ uint64_t size;
+ uint8_t *data;
+
+ if (spc_lu_init(lu))
+ return TGTADM_NOMEM;
+
+ strncpy(lu->attrs.product_id, "VIRTUAL-TAPE",
+ sizeof(lu->attrs.product_id));
+ lu->attrs.version_desc[0] = 0x0200; /* SSC no version claimed */
+ lu->attrs.version_desc[1] = 0x0960; /* iSCSI */
+ lu->attrs.version_desc[2] = 0x0300; /* SPC-3 */
+
+ data = lu->mode_block_descriptor;
+ size = lu->size >> BLK_SHIFT;
+
+ *(uint32_t *)(data) = (size >> 32) ?
+ __cpu_to_be32(0xffffffff) : __cpu_to_be32(size);
+ *(uint32_t *)(data + 4) = __cpu_to_be32(1 << BLK_SHIFT);
+
+ /* Vendor uniq - However most apps seem to call for mode page 0*/
+ add_mode_page(lu, "0:0:0");
+ /* Disconnect page */
+ add_mode_page(lu, "2:0:14:0x80:0x80:0:0xa:0:0:0:0:0:0:0:0:0:0");
+ /* Data Compression Page */
+ add_mode_page(lu, "15:0:12:0:0:0:0:0:0:0:0:0:0:0:0");
+ /* Device Configuration Page */
+ add_mode_page(lu, "0x10:0:11:0:0:0:0:0:0:0:0:0x48:0:0");
+ /* Control page */
+ add_mode_page(lu, "10:0:10:2:0:0:0:0:0:0:0:2:0");
+ /* Informational Exceptions Control page */
+ add_mode_page(lu, "0x1c:0:10:8:0:0:0:0:0:0:0:0:0");
+
+ return 0;
+}
+
+static struct device_type_template ssc_template = {
+ .type = TYPE_TAPE,
+ .lu_init = ssc_lu_init,
+ .lu_config = spc_lu_config,
+ .lu_online = spc_lu_online,
+ .lu_offline = spc_lu_offline,
+ .lu_exit = spc_lu_exit,
+
+ .ops = {
+ {spc_test_unit,},
+ {ssc_rw,},
+ {spc_illegal_op,},
+ {spc_request_sense,},
+ {spc_illegal_op,},
+ {ssc_read_block_limit,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ {ssc_rw,},
+ {spc_illegal_op,},
+ {ssc_rw,},
+ {ssc_rw,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ /* 0x10 */
+ {ssc_rw,},
+ {ssc_rw,},
+ {spc_inquiry,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_mode_sense,},
+ {spc_start_stop,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ /* 0x20 */
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ /* 0x30 */
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {ssc_rw,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ [0x40 ... 0x4f] = {spc_illegal_op,},
+
+ /* 0x50 */
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_mode_sense,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ [0x60 ... 0x7f] = {spc_illegal_op,},
+
+ /* 0x80 */
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ /* 0x90 */
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ /* 0xA0 */
+ {spc_report_luns,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ [0xb0 ... 0xff] = {spc_illegal_op},
+ }
+};
+
+__attribute__((constructor)) static void ssc_init(void)
+{
+ device_type_register(&ssc_template);
+}
diff --git a/usr/tgtadm.c b/usr/tgtadm.c
index ddceb7f..9e90b40 100644
--- a/usr/tgtadm.c
+++ b/usr/tgtadm.c
@@ -306,6 +306,8 @@ static int str_to_device_type(char *str)
return TYPE_MEDIUM_CHANGER;
else if (!strcmp(str, "osd"))
return TYPE_OSD;
+ else if (!strcmp(str, "ssc"))
+ return TYPE_TAPE;
else if (!strcmp(str, "pt"))
return TYPE_SPT;
else {
More information about the stgt
mailing list