[Stgt-devel] rework of smc module
Mark Harvey
markh794
Thu Jun 28 10:24:45 CEST 2007
OK - Not a patch but a 'proof oc concept' type patch.
If this method of lu_config() is ok, then I'll put together a proper patch.
Regards
Mark
diff --git a/doc/README.lu_configuration b/doc/README.lu_configuration
index d63668a..47e4912 100644
--- a/doc/README.lu_configuration
+++ b/doc/README.lu_configuration
@@ -84,6 +84,49 @@ tgtadm --lld iscsi --mode logicalunit --op update --tid 1 --lun 2 \
--params mode_page=0x1c:0:10:8:0:0:0:0:0:0:0:0:0
+SMC unique options
+------------------
+
+--params have several unique key=value pairs ontop of all other modules.
+ - element_type=<1|2|3|4>
+ - start_address=Number between 1 & 65535
+ - quantity=Number between 1 & 65535
+ - sides=1|2
+ - address=Number between 1 & 65535
+ - barcode="Char string up to 10 chars"
+ - tid=<number>
+ - lun=<number>
+
+Several of these parameters 'work together'
+
+e.g. To add 'quantity' slots as 'element_type' starting at 'start_address'
+ - element_type=<1|2|3|4>
+ - start_address=Number between 1 & 65535
+ - quantity=Number between 1 & 65535
+
+Note: start_address + quantity should not overlap with any other slots..
+
+
+While 'configuring slot 'address' of 'element_type':
+ - Set barcode of meda (occupy slot)
+ - If element type is DATA TRANSFER DEVICE, then define TID & LUN of device.
+
+ - element_type=<1|2|3|4>
+ - address=Number between 1 & 65535
+ - barcode="String up to 10 chars"
+ - sides=<1|2>
+ - tid=<tid of device which belongs at this address>
+ - lun=<lun of device which belongs at this address>
+
+
+It is the responsibility of the user not to configure overlapping slots
+of differing types.
+
+Slot types:
+ 1 -> Medium Transport (picker arm)
+ 2 -> Storage Element
+ 3 -> Import/Export Element
+ 4 -> Data Transfer device (CD drive, tape drive, MO drive etc)
Please refer to scripts/tgt-core-test for a working example.
diff --git a/scripts/tgt-core-test b/scripts/tgt-core-test
index a31be1b..b2ab6c0 100755
--- a/scripts/tgt-core-test
+++ b/scripts/tgt-core-test
@@ -17,15 +17,6 @@ fi
if [ ! -f $HOME/hd_block ]; then
dd if=/dev/zero of=$HOME/hd_block bs=1M count=8
fi
-if [ ! -f $HOME/cd_block0 ]; then
- dd if=/dev/zero of=$HOME/cd_block0 bs=1M count=8
-fi
-if [ ! -f $HOME/cd_block1 ]; then
- dd if=/dev/zero of=$HOME/cd_block1 bs=1M count=8
-fi
-if [ ! -f $HOME/cd_block2 ]; then
- dd if=/dev/zero of=$HOME/cd_block2 bs=1M count=8
-fi
set -x
@@ -85,10 +76,13 @@ tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
--params mode_page=0x1c:0:10:8:0:0:0:0:0:0:0:0:0
-
for LUN in 2 3 4; do
+ if [ ! -f $HOME/cdrom$LUN ]; then
+ dd if=/dev/zero of=$HOME/cdrom$LUN bs=1M count=8
+ fi
+
# Create LUN - CD/ROM
- tgtadm --lld iscsi --mode logicalunit --op new --tid $TID --lun $LUN -b $HOME/cd_block0 --device-type=cd
+ tgtadm --lld iscsi --mode logicalunit --op new --tid $TID --lun $LUN -b $HOME/cdrom$LUN --device-type=cd
tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
--params vendor_id=VirtualCD,product_id=CD101,product_rev=0010,scsi_sn=XYZZY1$LUN,removable=1
# Vendor Uniq - Mode page 0..
@@ -102,6 +96,86 @@ for LUN in 2 3 4; do
--params mode_page=0x1c:0:10:8:0:0:0:0:0:0:0:0:0
done
+###############################################################################
+# Set up SMC Medium Changer
+###############################################################################
+LUN=5
+if [ ! -f $HOME/smc ]; then
+ dd if=/dev/zero of=$HOME/smc bs=1k count=1
+fi
+
+tgtadm --lld iscsi --mode logicalunit --op new --tid $TID --lun $LUN \
+ -b $HOME/smc --device-type=changer
+
+#### Set up mode pages ####
+# From smc3-06.pdf
+# Page 0x02: Disconnect/Reconnect SPC-3
+# Page 0x0a: Control SPC-3
+# Page 0x18: Protocol Specific LUN SPC-3
+# Page 0x19: Protocol Specific Port SPC-3
+# Page 0x1a: Power Condition SPC-3
+# Page 0x1c: Informational Exceptions Control SPC-3
+# Page 0x1d: Element Address Assignment SMC-3 7.3.4
+# Page 0x1e: Transport Geometry Parameters SMC-3 7.3.5
+# Page 0x1f: Device Capabilities SMC-3 7.3.2
+# Page 0x1f/Subpage 0x41: Extended Device Capabilities SMC-3 7.3.3
+
+# Dummy 'page 0'
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=0:0:0
+# Disconnect/Reconnect
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=2:0:14:0x80:0x80:0:0xa:0:0:0:0:0:0:0:0:0:0
+# Power Condition
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=0x1a:0:18:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
+# Informational Exceptions Control Mode Page
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=0x1c:0:10:8:0:0:0:0:0:0:0:0:0
+# Element Address Assignment - Setup afterwards.
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=0x1d:0:0x12:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
+# Transport Geometry Parameters
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=0x1e:0:2:0:0
+# Device Capabilities
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params mode_page=0x1f:0:0x12:0x0f:7:0x0f:0x0f:0x0f:0x0f:0:0:0:0:0x0f:0x0f:0x0f:0x0f:0:0:0:0
+
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params vendor_id=STK,product_id=L700,product_rev=0010,scsi_sn=XYZZY_0,removable=1
+
+
+## Add Data Transfer devices (3 drives)
+# Define slot address for devices.
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params element_type=4,start_address=1,quantity=3
+# Now define which device at each address.
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params element_type=4,address=1,tid=1,lun=2
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params element_type=4,address=2,tid=1,lun=3
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params element_type=4,address=3,tid=1,lun=4
+
+# Medium Transport Elements (robot arm / picker)
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params element_type=1,start_address=16,quantity=1
+
+## Storage Elements - 8 starting at addr 1024
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params element_type=2,start_address=1024,quantity=8
+# Add 'media' to slots
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params element_type=2,address=1024,barcode=ABC123,Sides=1
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params element_type=2,address=1026,barcode=ULT001L3,Sides=1
+
+# Import/Export Elements - 5 starting at addr 32
+tgtadm --lld iscsi --mode logicalunit --op update --tid $TID --lun $LUN \
+ --params element_type=3,start_address=32,quantity=5
+
+
# Allow ALL initiators to connect to this target
tgtadm --lld iscsi --mode target --op bind --tid $TID -I ALL
diff --git a/usr/Makefile b/usr/Makefile
index 14be34b..c7fb2ca 100644
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -43,8 +43,9 @@ INCLUDES += -I.
CFLAGS += -Wall -g -O2 -Wstrict-prototypes -fPIC -D_LARGEFILE64_SOURCE $(INCLUDES)
PROGRAMS += tgtd tgtadm
-TGTD_OBJS += tgtd.o mgmt.o target.o spc.o sbc.o mmc.o osd.o spt.o scc.o scsi.o log.o \
- driver.o util.o work.o parser.o
+TGTD_OBJS += tgtd.o mgmt.o target.o \
+ spc.o sbc.o mmc.o osd.o spt.o scc.o smc.o \
+ scsi.o log.o driver.o util.o work.o parser.o
all: $(PROGRAMS)
diff --git a/usr/media.h b/usr/media.h
new file mode 100644
index 0000000..9b88765
--- /dev/null
+++ b/usr/media.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 Mark Harvey markh794 at gmail.com
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _MEDIA_H_
+#define _MEDIA_H_
+
+enum c_type { /* Cartridge Types - Ref: smc3r06 - Table 20, page 37 */
+ CART_UNSPECIFIED,
+ CART_DATA,
+ CART_CLEAN,
+ CART_DIAGNOSTICS,
+ CART_WORM,
+ CART_MICROCODE,
+};
+
+#endif /* _MEDIA_H_ */
+
diff --git a/usr/mmc.c b/usr/mmc.c
index 17cc741..a71568a 100644
--- a/usr/mmc.c
+++ b/usr/mmc.c
@@ -38,6 +38,7 @@
#include "util.h"
#include "tgtd.h"
#include "target.h"
+#include "tgtadm_error.h"
#include "driver.h"
#include "scsi.h"
#include "spc.h"
@@ -174,10 +175,15 @@ static int mmc_lu_init(struct scsi_lu *lu)
return 0;
}
+static int mmc_lu_config(struct scsi_lu *lu, char * params)
+{
+ return spc_lu_config(lu, params, NULL);
+}
+
static struct device_type_template mmc_template = {
.type = TYPE_ROM,
.lu_init = mmc_lu_init,
- .lu_config = spc_lu_config,
+ .lu_config = mmc_lu_config,
.ops = {
{spc_test_unit,},
{spc_illegal_op,},
diff --git a/usr/osd.c b/usr/osd.c
index a48db32..0d8457a 100644
--- a/usr/osd.c
+++ b/usr/osd.c
@@ -29,6 +29,7 @@
#include "list.h"
#include "util.h"
#include "tgtd.h"
+#include "tgtadm_error.h"
#include "target.h"
#include "driver.h"
#include "scsi.h"
@@ -68,9 +69,15 @@ static int osd_lu_init(struct scsi_lu *lu)
return 0;
}
+static int osd_lu_config(struct scsi_lu *lu, char * params)
+{
+ return spc_lu_config(lu, params, NULL);
+}
+
static struct device_type_template osd_template = {
.type = TYPE_OSD,
.lu_init = osd_lu_init,
+ .lu_config = osd_lu_config,
.ops = {
[0x00 ... 0x0f] = {spc_illegal_op},
diff --git a/usr/sbc.c b/usr/sbc.c
index 5996081..70ea127 100644
--- a/usr/sbc.c
+++ b/usr/sbc.c
@@ -34,6 +34,7 @@
#include "list.h"
#include "util.h"
#include "tgtd.h"
+#include "tgtadm_error.h"
#include "target.h"
#include "driver.h"
#include "scsi.h"
@@ -222,10 +223,15 @@ static int sbc_lu_init(struct scsi_lu *lu)
return 0;
}
+static int sbc_lu_config(struct scsi_lu *lu, char *params)
+{
+ return spc_lu_config(lu, params, NULL);
+}
+
static struct device_type_template sbc_template = {
.type = TYPE_DISK,
.lu_init = sbc_lu_init,
- .lu_config = spc_lu_config,
+ .lu_config = sbc_lu_config,
.ops = {
{spc_test_unit,},
{spc_illegal_op,},
diff --git a/usr/scc.c b/usr/scc.c
index 0a154a5..2977dd6 100644
--- a/usr/scc.c
+++ b/usr/scc.c
@@ -50,10 +50,15 @@ static int scc_lu_init(struct scsi_lu *lu)
return 0;
}
+static int scc_lu_config(struct scsi_lu *lu, char *params)
+{
+ return spc_lu_config(lu, params, NULL);
+}
+
static struct device_type_template scc_template = {
.type = TYPE_RAID,
.lu_init = scc_lu_init,
- .lu_config = spc_lu_config,
+ .lu_config = scc_lu_config,
.ops = {
{spc_test_unit,},
{spc_illegal_op,},
diff --git a/usr/sense_codes.h b/usr/sense_codes.h
index 210753a..5de28dc 100644
--- a/usr/sense_codes.h
+++ b/usr/sense_codes.h
@@ -1,7 +1,7 @@
/*
* The SCSI sense key Additional Sense Code / Additional Sense Code Qualifier
*
- * Copyright (C) 2007 Mark Harvey markh794 at gmail dot com
+ * Reference : www.t10.org
*
* 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
diff --git a/usr/smc.c b/usr/smc.c
new file mode 100644
index 0000000..4dcfad3
--- /dev/null
+++ b/usr/smc.c
@@ -0,0 +1,824 @@
+/*
+ * SCSI Medium Changer command processing
+ * Based on smc3r06.pdf document from t10.org
+ *
+ * (C) 2004-2007 FUJITA Tomonori <tomof at acm.org>
+ * (C) 2005-2007 Mike Christie <michaelc at cs.wisc.edu>
+ * (C) 2007 Mark Harvey <markh794 at gmail.com>
+ *
+ * SCSI target emulation code is based on Ardis's iSCSI implementation.
+ * http://www.ardistech.com/iscsi/
+ * Copyright (C) 2002-2003 Ardis Technolgies <roman at ardistech.com>,
+ * licensed under the terms of the GNU GPL v2.0,
+ *
+ * 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 <inttypes.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 "target.h"
+#include "driver.h"
+#include "tgtadm_error.h"
+#include "scsi.h"
+#include "spc.h"
+#include "sense_codes.h"
+#include "parser.h"
+#include "smc.h"
+#include "media.h"
+
+struct slot *slot_lookup(struct list_head *head, int element_type, int address);
+static void set_slot_full(struct slot *s, uint16_t src);
+static void set_slot_empty(struct slot *s);
+static int test_slot_full(struct slot *s);
+struct lu_phy_attr *lu_attr_lookup(int tid, uint64_t lun);
+
+/* ********************************************************
+ * READ_ELEMENT_STATUS
+ *
+ * Ref: Working Draft SCSI Media Changer-3 (smc3r06.pdf), chapter 6.10
+ *
+ * The READ ELEMENT STATUS command request that the device server report the
+ * status of its internal elements to the application client.
+ * Support for READ ELEMENT STATUS command is mandatory.
+ * ******************************************************** */
+static int determine_element_sz(uint8_t dvcid, uint8_t voltag)
+{
+ if (voltag)
+ return (dvcid) ? 86 : 52;
+ else
+ return (dvcid) ? 50 : 16;
+}
+
+/* Fill in Element Status Header - Always 8 bytes long */
+static int element_status_data_hdr(uint8_t *data, uint8_t dvcid,
+ uint8_t voltag, int start, int count)
+{
+ int element_sz;
+ int size;
+
+ element_sz = determine_element_sz(dvcid, voltag);
+
+ /* First Element address reported */
+ *(uint16_t *)(data) = __cpu_to_be16(start);
+
+ /* Number of elements available */
+ *(uint16_t *)(data + 2) = __cpu_to_be16(count);
+
+ /* Byte count is the length required to return all valid data.
+ * Allocated length is how much data the initiator will accept */
+ size = ((8 + (count * element_sz)) & 0xffffff);
+ *(uint32_t *)(data + 4) = __cpu_to_be32(size);
+
+return size;
+}
+
+static int add_element_descriptor(uint8_t *data, struct slot *s,
+ uint8_t element_type, uint8_t dvcid, uint8_t voltag)
+{
+ struct lu_phy_attr *attr = NULL;
+ int i; /* data[] index */
+
+ *(uint16_t *)(data) = __cpu_to_be16(s->slot_addr);
+ data[2] = s->status;
+ data[3] = 0; /* Reserved */
+ data[4] = (s->asc >> 8) & 0xff; /* Additional Sense Code */
+ data[5] = s->asc & 0xff; /* Additional Sense Code Qualifier */
+ /* [6], [7] & [8] reserved */
+ data[9] = (s->cart_type & 0xf);
+ if (s->last_addr) { /* Source address is valid ? */
+ data[9] |= 0x80;
+ *(uint16_t *)(data + 10) = __cpu_to_be16(s->last_addr);
+ }
+ i = 12;
+ if (voltag) {
+ if (s->barcode[0] == ' ')
+ memset( &data[i], 0x20, 32); /* Pad with spaces */
+ else
+ snprintf((char *)&data[i], 32, "%-32s", s->barcode);
+
+ /* Reserve additional 4 bytes if dvcid is set */
+ i += (dvcid) ? 36 : 32;
+ }
+ if (element_type == ELEMENT_DATA_TRANSFER)
+ attr = lu_attr_lookup(s->drive_tid, s->drive_lun);
+ if (dvcid && attr) {
+ data[i] = 2; /* ASCII code set */
+ data[i + 1] = attr->device_type;
+ data[i + 2] = 0; /* reserved */
+ data[i + 3] = 34; /* Length */
+ snprintf((char *)&data[i + 4], 9, "%-8s", attr->vendor_id);
+ snprintf((char *)&data[i + 12], 17, "%-16s", attr->product_id);
+ snprintf((char *)&data[i + 28], 11, "%-10s", attr->scsi_sn);
+ }
+
+return determine_element_sz(dvcid, voltag);
+}
+
+/* Fill in Element details
+ *
+ * Fill each Element Descriptor for slot *s
+ *
+ * data : pointer
+ * head : Slot struct head
+ * element_type : Slot type we are interested in.
+ * first : Return address of first slot found
+ * start : Start processing from this element #
+ * dvcid : Device ID
+ * voltag : Volume tag (barcode)
+ *
+ * Return number of elements
+ */
+static int build_element_descriptors(uint8_t *data, struct list_head *head,
+ uint8_t elem_type, int *first,
+ uint16_t start,
+ uint8_t dvcid, uint8_t voltag)
+{
+ struct slot *s;
+ int count = 0;
+ int len = 8;
+ int elem_sz = determine_element_sz(dvcid, voltag);
+
+ list_for_each_entry(s, head, slot_siblings) {
+ if (s->element_type == elem_type) {
+ if (s->slot_addr >= start) {
+ count++;
+ len += add_element_descriptor(&data[len],
+ s, elem_type, dvcid, voltag);
+ }
+ }
+ if (count == 1) /* Record first found slot Address */
+ *first = s->slot_addr;
+ }
+
+ /* Fill in Element Status Page Header */
+ data[0] = elem_type;
+ data[1] = (voltag) ? 0x80 : 0; /* Primary Vol Tag set */
+ *(uint16_t *)(data + 2) = __cpu_to_be16(elem_sz);
+
+ /* Total number of bytes in all element descriptors */
+ *(uint32_t *)(data + 4) = __cpu_to_be32((elem_sz * count) & 0xffffff);
+
+return count;
+}
+
+/* *********************************************
+ * READ ELEMENT STATUS op code
+ * ********************************************* */
+static int smc_read_element_status(int host_no, struct scsi_cmd *cmd)
+{
+ struct smc_info *smc = (struct smc_info *)cmd->dev->smc_p;
+ uint8_t *data;
+ uint8_t *scb;
+ uint8_t element_type;
+ uint8_t voltag;
+ uint16_t req_start_elem;
+// FIXME: Take into account number of slots requested..
+// uint16_t number = __be16_to_cpu(*(uint16_t *)(scb[4]));
+ uint8_t dvcid; /* Device ID */
+ uint32_t alloc_len;
+ uint16_t count = 0;
+ int first = 0; /* First valid slot location */
+ int len = 8;
+ int elementSize;
+ int ret;
+ unsigned char key = ILLEGAL_REQUEST;
+ uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
+
+ scb = cmd->scb;
+ element_type = scb[1] & 0x0f;
+ voltag = (scb[1] & 0x10) >> 4;
+ dvcid = scb[6] & 0x01;
+ req_start_elem = __be16_to_cpu(*(uint16_t *)(scb + 2));
+ alloc_len = 0xffffff & __be32_to_cpu(*(uint32_t *)(scb + 6));
+
+ elementSize = determine_element_sz(dvcid, voltag);
+
+ cmd->len = 0;
+ if (cmd->dev) {
+ ret = device_reserved(cmd);
+ if (ret) {
+ dprintf("Reservation Conflict\n");
+ return SAM_STAT_RESERVATION_CONFLICT;
+ }
+ }
+
+ if (pagesize < alloc_len) {
+ dprintf("Can't allocate enough memory for cmd\n");
+ key = HARDWARE_ERROR;
+ asc = ASC_INTERNAL_TGT_FAILURE;
+ goto sense;
+ }
+ if ((data = valloc(pagesize)) == NULL) {
+ dprintf("valloc(%lu) failed\n", pagesize);
+ key = HARDWARE_ERROR;
+ asc = ASC_INTERNAL_TGT_FAILURE;
+ goto sense;
+ }
+ memset(data, 0, pagesize);
+
+ if (scb[11]) /* Reserved byte */
+ goto sense;
+
+ switch(element_type) {
+ case ELEMENT_ANY:
+ /* Return element in type order */
+ count = build_element_descriptors(&data[len], &smc->slots,
+ ELEMENT_MEDIUM_TRANSPORT, &first,
+ req_start_elem,
+ dvcid, voltag);
+ len = count * elementSize;
+ count += build_element_descriptors(&data[len], &smc->slots,
+ ELEMENT_STORAGE, &first,
+ req_start_elem,
+ dvcid, voltag);
+ len += count * elementSize;
+ count += build_element_descriptors(&data[len], &smc->slots,
+ ELEMENT_MAP, &first,
+ req_start_elem,
+ dvcid, voltag);
+ len += count * elementSize;
+ count += build_element_descriptors(&data[len], &smc->slots,
+ ELEMENT_DATA_TRANSFER, &first,
+ req_start_elem,
+ dvcid, voltag);
+ break;
+ case ELEMENT_MEDIUM_TRANSPORT:
+ count = build_element_descriptors(&data[len], &smc->slots,
+ ELEMENT_MEDIUM_TRANSPORT, &first,
+ req_start_elem,
+ dvcid, voltag);
+ break;
+ case ELEMENT_STORAGE:
+ count = build_element_descriptors(&data[len], &smc->slots,
+ ELEMENT_STORAGE, &first,
+ req_start_elem,
+ dvcid, voltag);
+ break;
+ case ELEMENT_MAP:
+ count = build_element_descriptors(&data[len], &smc->slots,
+ ELEMENT_MAP, &first,
+ req_start_elem,
+ dvcid, voltag);
+ break;
+ case ELEMENT_DATA_TRANSFER:
+ count = build_element_descriptors(&data[len], &smc->slots,
+ ELEMENT_DATA_TRANSFER, &first,
+ req_start_elem,
+ dvcid, voltag);
+ break;
+ default:
+ goto sense;
+ break;
+ }
+
+ /* Lastly, fill in data header */
+ len = element_status_data_hdr(data, dvcid, voltag, first, count);
+
+ cmd->len = min_t(int, len, alloc_len);
+ cmd->uaddr = (unsigned long) data;
+ cmd->rw = READ;
+
+ return SAM_STAT_GOOD;
+
+sense:
+ cmd->len = 0;
+ sense_data_build(cmd, key, asc);
+ return SAM_STAT_CHECK_CONDITION;
+}
+
+/* *********************************************
+ * MOVE MEDIUM op code
+ * ********************************************* */
+static int smc_move_medium(int host_no, struct scsi_cmd *cmd)
+{
+ struct smc_info *smc = (struct smc_info *)cmd->dev->smc_p;
+ uint8_t *scb;
+ uint16_t src;
+ uint16_t dest;
+ uint8_t invert;
+ struct slot *src_slot = NULL;
+ struct slot *dest_slot = NULL;
+ struct slot *s;
+ int key = ILLEGAL_REQUEST;
+ uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
+
+ scb = cmd->scb;
+ src = __be16_to_cpu(*(uint16_t *)(scb + 4));
+ dest = __be16_to_cpu(*(uint16_t *)(scb + 6));
+ invert = scb[10] & 1;
+
+ list_for_each_entry(s, &smc->slots, slot_siblings) {
+ if (s->slot_addr == src)
+ src_slot = s;
+ if (s->slot_addr == dest)
+ dest_slot = s;
+ }
+
+ if (src_slot) {
+ if (!test_slot_full(src_slot)) {
+ asc = ASC_MEDIUM_SRC_EMPTY;
+ goto sense;
+ }
+ } else /* Could not find src slot - Error */
+ goto sense;
+
+ if (dest_slot) {
+ if (test_slot_full(dest_slot)) {
+ asc = ASC_MEDIUM_DEST_FULL;
+ goto sense;
+ }
+ } else /* Could not find dest slot - Error */
+ goto sense;
+
+ if (invert)
+ if (s->sides == 1) /* Use default INVALID FIELD IN CDB */
+ goto sense;
+
+ memcpy(&dest_slot->barcode, &src_slot->barcode, sizeof(s->barcode));
+ set_slot_empty(src_slot);
+ set_slot_full(dest_slot, src);
+ cmd->len = 0;
+ return SAM_STAT_GOOD;
+
+sense:
+ cmd->len = 0;
+ sense_data_build(cmd, key, asc);
+ return SAM_STAT_CHECK_CONDITION;
+}
+
+/* *********************************************
+ * **** House keeping routines ****
+ * ********************************************* */
+
+/* Any housekeeping required at logical unit setup */
+static int smc_lu_init(struct scsi_lu *lu)
+{
+ struct smc_info *smc;
+
+ smc = zalloc(sizeof(struct smc_info));
+ if (smc)
+ lu->smc_p = smc;
+ else
+ return -ENOMEM;
+
+ spc_lu_init(lu);
+
+ strncpy(lu->attrs.product_id, "VIRTUAL-CHANGER",
+ sizeof(lu->attrs.product_id));
+ lu->attrs.version_desc[0] = 0x0480; /* SMC-3 no version claimed */
+ lu->attrs.version_desc[1] = 0x0960; /* iSCSI */
+ lu->attrs.version_desc[2] = 0x0300; /* SPC-3 */
+
+ INIT_LIST_HEAD(&lu->mode_pages);
+
+ /* Vendor uniq - However most apps seem to call for mode page 0*/
+ add_mode_page(lu, "0:0:0");
+ /* Control page */
+ add_mode_page(lu, "10:0:10:2:0:0:0:0:0:0:0:2:0");
+ /* Power Condition */
+ add_mode_page(lu, "0x1a:0:10:8:0:0:0:0:0:0:0:0:0");
+ /* Informational Exceptions Control page */
+ add_mode_page(lu, "0x1c:0:10:8:0:0:0:0:0:0:0:0:0");
+ /* Address Assignment */
+ add_mode_page(lu, "0x1d:0:0x12:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0");
+ /* Transport Geometry Params */
+ add_mode_page(lu, "0x1e:0:2:0:0");
+ /* Device Capabilities */
+ add_mode_page(lu, "0x1f:0:0x12:15:7:15:15:15:15:0:0:0:0:15:15:15:15:0:0:0:0");
+
+ INIT_LIST_HEAD(&smc->slots);
+
+ lu->attrs.online = 1; /* Library will now report as Online */
+ lu->attrs.reset = 1; /* Poweron/reset occurred */
+ lu->attrs.removable = 1; /* Default to removable media */
+
+ return 0;
+}
+
+/* Any housekeeping required at shutdown */
+static void smc_lu_exit(struct scsi_lu *lu)
+{
+ struct smc_info *smc = lu->smc_p;
+
+ dprintf("Medium Changer shutdown() called\n");
+
+ free(smc);
+}
+
+/* **************************************
+ * General utilities related to slot(s)
+ * **************************************/
+/* Set slot status to full */
+static void set_slot_full(struct slot *s, uint16_t src)
+{
+ s->status |= 1;
+ s->last_addr=src;
+}
+
+/* Set slot status to empty */
+static void set_slot_empty(struct slot *s)
+{
+ s-> status &= 0xfe;
+ s->last_addr=0;
+ memset(s->barcode, ' ', sizeof(s->barcode));
+}
+
+static int test_slot_full(struct slot *s)
+{
+ return s->status && 1;
+}
+
+static int slot_insert(struct list_head *head, int element_type, int address)
+{
+ struct slot *s;
+
+ if ((s = zalloc(sizeof(struct slot))) == NULL)
+ return TGTADM_NOMEM;
+
+ s->slot_addr = address;
+ s->element_type = element_type;
+ s->sides = 1;
+ if (element_type == ELEMENT_DATA_TRANSFER) /* Drive */
+ s->asc = ASC_INITIALIZING_REQUIRED;
+
+ list_add_tail(&s->slot_siblings, head);
+
+ return 0;
+}
+
+/*
+ * If both address & element type specified, check both values,
+ * else just check param that is defined.
+ *
+ * Return NULL if record not found.
+ */
+struct slot *slot_lookup(struct list_head *head, int element_type, int address)
+{
+ struct slot *s;
+
+ list_for_each_entry(s, head, slot_siblings) {
+ if (element_type && address) {
+ if ((s->slot_addr == address) &&
+ (s->element_type == element_type))
+ return s;
+ } else if (element_type) {
+ if (s->element_type == element_type)
+ return s;
+ } else if (address) {
+ if (s->slot_addr == address)
+ return s;
+ }
+ }
+ return NULL;
+}
+
+static void slot_dump(struct list_head *head)
+{
+ struct slot *s;
+
+ list_for_each_entry(s, head, slot_siblings)
+ if (s) {
+ dprintf("Slot %d Information\n", s->slot_addr);
+ dprintf(" Last Addr: %d\n", s->last_addr);
+ dprintf(" Type: %d\n", s->element_type);
+ dprintf(" Barcode: %s\n", s->barcode);
+ dprintf(" TID : %d\n", s->drive_tid);
+ dprintf(" LUN : %" PRIu64 "\n", s->drive_lun);
+ dprintf(" ASC/ASCQ : %d\n\n", s->asc);
+ }
+}
+
+/* **************************************
+ * Adding Slots within the SMC device
+ * **************************************/
+static int add_slt(struct scsi_lu *lu, int element_type, int start_addr, int quantity)
+{
+ struct smc_info *smc = lu->smc_p;
+ int ret = TGTADM_INVALID_REQUEST;
+ struct mode *m;
+ struct slot *s;
+ uint16_t *element;
+ int sv_addr;
+ int qnty_save;
+ int i;
+
+ /* Update MODE PAGE 0x1d params */
+ if ((m = mode_page_lookup(&lu->mode_pages, 0x1d)) == NULL) {
+ dprintf("Failed to find Element Address Assignment mode pg\n");
+ return TGTADM_UNKNOWN_ERR;
+ }
+ element = (uint16_t *)m->mode_data;
+
+ if (element_type && start_addr && quantity) {
+ /* Fiddle with element offset.*/
+ switch(element_type) {
+ case ELEMENT_MEDIUM_TRANSPORT: /* Medium Transport */
+ break;
+ case ELEMENT_MAP: /* Import/Export Elements */
+ element += 4;
+ break;
+ case ELEMENT_STORAGE: /* Storage Elements */
+ element += 2;
+ break;
+ case ELEMENT_DATA_TRANSFER: /* Data Transfer Elements */
+ element += 6;
+ break;
+ default:
+ goto dont_do_slots;
+ break;
+ }
+
+ /* Get existing values */
+ sv_addr = __be16_to_cpu(element[0]);
+ qnty_save = __be16_to_cpu(element[1]);
+
+ /* Add existing values + passed params to config */
+ if (sv_addr)
+ element[0] =
+ __cpu_to_be16(min_t(int, start_addr, sv_addr));
+ else
+ element[0] = __cpu_to_be16(start_addr);
+ element[1] = __cpu_to_be16(quantity + qnty_save);
+
+ s = slot_lookup(&smc->slots, element_type, start_addr);
+ if (s) // Opps... Found a slot at this address..
+ goto dont_do_slots;
+
+ ret = TGTADM_SUCCESS;
+ for(i=start_addr; i < (start_addr + quantity); i++)
+ if (slot_insert(&smc->slots, element_type, i))
+ ret = TGTADM_INVALID_REQUEST;
+ }
+
+dont_do_slots:
+ return ret;
+}
+
+/* **************************************
+ * Configuring Slots within the SMC device
+ * **************************************/
+static int config_slot(struct scsi_lu *lu, int element_type,
+ int address, int tid, uint64_t lun, char *barcode, int sides)
+{
+ struct smc_info *smc = lu->smc_p;
+ struct mode *m = NULL;
+ struct slot *s = NULL;
+ int ret = TGTADM_INVALID_REQUEST;
+
+ switch(element_type) {
+ case ELEMENT_MEDIUM_TRANSPORT:
+ /* If medium has more than one side, set the 'rotate' bit */
+ m = mode_page_lookup(&lu->mode_pages, 0x1e);
+ if (m) {
+ m->mode_data[0] = (sides > 1) ? 1 : 0;
+ ret = TGTADM_SUCCESS;
+ }
+ break;
+ case ELEMENT_STORAGE:
+ case ELEMENT_MAP:
+ if ((s = slot_lookup(&smc->slots, element_type, address)) == NULL)
+ break; // Slot not found..
+ strncpy(s->barcode, barcode, sizeof(s->barcode));
+ set_slot_full(s, 0);
+ ret = TGTADM_SUCCESS;
+ break;
+ case ELEMENT_DATA_TRANSFER:
+ if (!tid)
+ break; /* Fail if no TID specified */
+ if ((s = slot_lookup(&smc->slots, element_type, address)) == NULL)
+ break; // Slot not found..
+ s->asc = NO_ADDITIONAL_SENSE;
+ s->drive_tid = tid;
+ s->drive_lun = lun;
+ ret = TGTADM_SUCCESS;
+ break;
+ }
+ return ret;
+}
+
+/* ***********************************
+ * Command argument processing
+ * ***********************************/
+#define ADD 1
+#define CONFIGURE 2
+
+static int __smc_lu_config(struct scsi_lu *lu, char *params)
+{
+ struct smc_info *smc = (struct smc_info *)lu->smc_p;
+ int err = 0;
+ char *p;
+ char barcode[20] = "";
+ char buf[20];
+ int operation = 0;
+ int element_type = 0;
+ int start_addr = 0;
+ int quantity = 0;
+ int sides = 1;
+ int address = 0;
+ int tid = 0;
+ uint64_t lun = 0;
+
+ while ((p = strsep(¶ms, ",")) != NULL) {
+ substring_t args[MAX_OPT_ARGS];
+ int token;
+ if (!*p)
+ continue;
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case Opt_element_type:
+ match_strncpy(buf, &args[0], sizeof(buf));
+ element_type = atoi(buf);
+ break;
+ case Opt_start_address:
+ match_strncpy(buf, &args[0], sizeof(buf));
+ start_addr = atoi(buf);
+ operation = ADD;
+ break;
+ case Opt_quantity:
+ match_strncpy(buf, &args[0], sizeof(buf));
+ quantity = atoi(buf);
+ break;
+ case Opt_sides:
+ match_strncpy(buf, &args[0], sizeof(buf));
+ sides = atoi(buf);
+ break;
+ case Opt_address:
+ match_strncpy(buf, &args[0], sizeof(buf));
+ address = atoi(buf);
+ operation = CONFIGURE;
+ break;
+ case Opt_barcode:
+ match_strncpy(barcode, &args[0], sizeof(barcode));
+ break;
+ case Opt_tid:
+ match_strncpy(buf, &args[0], sizeof(buf));
+ tid = atoi(buf);
+ break;
+ case Opt_lun:
+ match_strncpy(buf, &args[0], sizeof(buf));
+ lun = atoi(buf);
+ break;
+ case Opt_dump:
+ slot_dump(&smc->slots);
+ break;
+ default:
+ err = TGTADM_UNKNOWN_PARAM;
+ }
+ }
+
+ switch(operation) {
+ case ADD:
+ err = add_slt(lu, element_type, start_addr, quantity);
+ break;
+ case CONFIGURE:
+ err = config_slot(lu, element_type, address, tid,
+ lun, barcode, sides);
+ break;
+ }
+ return err;
+}
+
+static int smc_lu_config(struct scsi_lu *lu, char *params)
+{
+ int (*smc_p)(struct scsi_lu *lu, char *args) = __smc_lu_config;
+
+ return spc_lu_config(lu, params, smc_p);
+}
+
+/* ***********************************
+ * Device Template - entry routines
+ * ***********************************/
+struct device_type_template smc_template = {
+ .type = TYPE_MEDIUM_CHANGER,
+ .lu_init = smc_lu_init,
+ .lu_exit = smc_lu_exit,
+ .lu_config = smc_lu_config,
+ .ops = {
+ {spc_test_unit,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_request_sense,},
+ {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,},
+
+ /* 0x10 */
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {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_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ [0x20 ... 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 ... 0x9f] = {spc_illegal_op,},
+
+ /* 0xA0 */
+ {spc_report_luns,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {smc_move_medium,},
+ {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_test_unit,},
+
+ /* 0xB0 */
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ {smc_read_element_status,}, // Mandatory
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+ {spc_illegal_op,},
+
+ [0xc0 ... 0xff] = {spc_illegal_op},
+ }
+};
+
+__attribute__((constructor)) static void smc_init(void)
+{
+ device_type_register(&smc_template);
+}
diff --git a/usr/smc.h b/usr/smc.h
new file mode 100644
index 0000000..7c789e3
--- /dev/null
+++ b/usr/smc.h
@@ -0,0 +1,77 @@
+/*
+ * SCSI Medium Changer Command
+ *
+ * Copyright (C) 2007 Mark Harvey markh794 at gmail.com
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SMC_H_
+#define _SMC_H_
+
+/**************************************************
+ * Slot description
+ **************************************************/
+#define ELEMENT_ANY 0
+#define ELEMENT_MEDIUM_TRANSPORT 1
+#define ELEMENT_STORAGE 2
+#define ELEMENT_MAP 3
+#define ELEMENT_DATA_TRANSFER 4
+
+struct slot {
+ struct list_head slot_siblings;
+ uint8_t element_type; /* Element Type 1, 2, 3 or 4 */
+ uint8_t cart_type; /* 0 Unspecified, 1 Data, 2 Cleaning */
+ uint16_t slot_addr; /* 65535 slots should be enough.. */
+ uint16_t last_addr; /* Where the media came from.. */
+ uint16_t asc; /* Additional sense code */
+ uint8_t status; /* Used for MAP status bits */
+ uint8_t sides; /* Number of sides this media. */
+ char barcode[11]; /* Up to 10 char barcode */
+ /* Only used if slot contains a drive. */
+ uint8_t drive_tid;
+ uint64_t drive_lun;
+};
+
+/**************************************************
+ * Data structure for SMC device
+ * Top of the 'tree'
+ **************************************************/
+struct smc_info {
+ struct list_head slots;
+};
+
+enum {
+ Opt_element_type, Opt_start_address,
+ Opt_quantity, Opt_sides,
+ Opt_address, Opt_barcode,
+ Opt_tid, Opt_lun,
+ Opt_type, Opt_dump,
+ Opt_err,
+};
+
+static match_table_t tokens = {
+ {Opt_element_type, "element_type=%s"},
+ {Opt_start_address, "start_address=%s"},
+ {Opt_quantity, "quantity=%s"},
+ {Opt_sides, "sides=%s"},
+ {Opt_address, "address=%s"},
+ {Opt_barcode, "barcode=%s"},
+ {Opt_tid, "tid=%s"},
+ {Opt_lun, "lun=%s"},
+ {Opt_type, "type=%s"},
+ {Opt_dump, "dump=%s"},
+ {Opt_err, NULL},
+};
+#endif // _SMC_H_
diff --git a/usr/spc.c b/usr/spc.c
index 3eb605c..8df63d7 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -500,10 +500,24 @@ static match_table_t tokens = {
{Opt_err, NULL},
};
-int spc_lu_config(struct scsi_lu *lu, char *params) {
+/*
+ * Parse options received from user.
+ *
+ * User options are in 'char * params', while any unprocessed options
+ * are copied into 'char * extra_args' for further processing by the
+ * 'target' from which it was called.
+ */
+int spc_lu_config(struct scsi_lu *lu, char *params,
+ int (*xxx_lu_config)(struct scsi_lu *lu, char *args))
+{
int err = 0;
char *p;
char buf[256];
+ char *extra_args;
+
+ extra_args = zalloc(strlen(params) + 1);
+ if (!extra_args)
+ return TGTADM_NOMEM;
if (!strncmp("targetOps", params, 9))
params = params + 10;
@@ -525,15 +539,15 @@ int spc_lu_config(struct scsi_lu *lu, char *params) {
break;
case Opt_vendor_id:
match_strncpy(lu->attrs.vendor_id, &args[0],
- sizeof(lu->attrs.vendor_id));
+ sizeof(lu->attrs.vendor_id) - 1);
break;
case Opt_product_id:
match_strncpy(lu->attrs.product_id, &args[0],
- sizeof(lu->attrs.product_id));
+ sizeof(lu->attrs.product_id) - 1);
break;
case Opt_product_rev:
match_strncpy(lu->attrs.product_rev, &args[0],
- sizeof(lu->attrs.product_rev));
+ sizeof(lu->attrs.product_rev) - 1);
break;
case Opt_sense_format:
match_strncpy(buf, &args[0], sizeof(buf));
@@ -551,10 +565,19 @@ int spc_lu_config(struct scsi_lu *lu, char *params) {
match_strncpy(buf, &args[0], sizeof(buf));
err = add_mode_page(lu, buf);
break;
- default:
+ default: /* Append any unprocessed args to ret_param */
+ strcat(extra_args, p);
+ strcat(extra_args, ",");
err = TGTADM_INVALID_REQUEST;
}
}
+
+ /* Call module uniq param handling routine */
+ if (strlen(extra_args) && xxx_lu_config)
+ err = xxx_lu_config(lu, extra_args);
+
+ free(extra_args);
+
return err;
}
@@ -565,8 +588,9 @@ int spc_lu_config(struct scsi_lu *lu, char *params) {
*/
int spc_lu_init(struct scsi_lu *lu)
{
- strncpy(lu->attrs.vendor_id, VENDOR_ID, sizeof(lu->attrs.vendor_id));
- memcpy(lu->attrs.product_rev, "0001", 4);
+ snprintf(lu->attrs.vendor_id, sizeof(lu->attrs.vendor_id) - 1,
+ "%-16s", VENDOR_ID);
+ snprintf(lu->attrs.product_rev, 4, "%s", "0001");
lu->attrs.removable = 0;
lu->attrs.sense_format = 0;
lu->attrs.online = 0;
diff --git a/usr/spc.h b/usr/spc.h
index c7e38c0..47c1dc6 100644
--- a/usr/spc.h
+++ b/usr/spc.h
@@ -16,7 +16,8 @@ extern int spc_test_unit(int host_no, struct scsi_cmd *cmd);
extern int spc_request_sense(int host_no, struct scsi_cmd *cmd);
extern int spc_illegal_op(int host_no, struct scsi_cmd *cmd);
extern int spc_lu_init(struct scsi_lu *lu);
-extern int spc_lu_config(struct scsi_lu *lu, char * params);
+extern int spc_lu_config(struct scsi_lu *lu, char *params,
+ int (*func)(struct scsi_lu *lu, char *args));
extern void dump_cdb(struct scsi_cmd *cmd);
extern int spc_mode_sense(int host_no, struct scsi_cmd *cmd);
struct mode *mode_page_lookup(struct list_head *head, uint8_t page);
diff --git a/usr/target.c b/usr/target.c
index d3c9cb8..997f3f2 100644
--- a/usr/target.c
+++ b/usr/target.c
@@ -341,6 +341,17 @@ int tgt_device_destroy(int tid, uint64_t lun, int force)
return 0;
}
+struct lu_phy_attr *lu_attr_lookup(int tid, uint64_t lun)
+{
+ struct target *target;
+ struct scsi_lu *lu;
+
+ lu = __device_lookup(tid, lun, &target);
+ if (!lu)
+ return NULL;
+ return &lu->attrs;
+}
+
int device_reserve(struct scsi_cmd *cmd)
{
struct scsi_lu *lu;
diff --git a/usr/tgtadm.c b/usr/tgtadm.c
index c2315b6..0631a7d 100644
--- a/usr/tgtadm.c
+++ b/usr/tgtadm.c
@@ -300,6 +300,8 @@ static int str_to_device_type(char *str)
exit(EINVAL);
} else if (!strcmp(str, "cd"))
return TYPE_ROM;
+ else if (!strcmp(str, "changer"))
+ return TYPE_MEDIUM_CHANGER;
else if (!strcmp(str, "osd"))
return TYPE_OSD;
else if (!strcmp(str, "pt"))
diff --git a/usr/tgtd.h b/usr/tgtd.h
index bbacae2..02a834b 100644
--- a/usr/tgtd.h
+++ b/usr/tgtd.h
@@ -73,7 +73,7 @@ struct backingstore_template {
int (*bs_open)(struct scsi_lu *dev, char *path, int *fd, uint64_t *size);
void (*bs_close)(struct scsi_lu *dev);
int (*bs_cmd_submit)(struct scsi_cmd *cmd);
- int (*bs_cmd_done) (struct scsi_cmd *cmd);
+ int (*bs_cmd_done)(struct scsi_cmd *cmd);
};
struct scsi_lu {
@@ -100,8 +100,11 @@ struct scsi_lu {
uint8_t mode_block_descriptor[BLOCK_DESCRIPTOR_LEN];
struct list_head mode_pages;
- /* TODO: needs a structure for lots of device parameters */
struct lu_phy_attr attrs;
+
+ /* TODO: needs a structure for lots of device parameters */
+ /* Currently only used by smc module */
+ void *smc_p;
};
struct scsi_cmd {
More information about the stgt
mailing list