[Stgt-devel] [Patch 3/3] Re-work of SMC support
Mark Harvey
mark_harvey
Tue Jun 26 01:23:07 CEST 2007
Darn,
A typo in patch description:
"Includes all SCSI op codes defined in SSC as MANDATORY."
Should read:
"Includes all SCSI op codes defined in SMC as MANDATORY."
Regards
Mark
-----Original Message-----
From: stgt-devel-bounces at lists.berlios.de
[mailto:stgt-devel-bounces at lists.berlios.de] On Behalf Of Mark Harvey
Sent: Saturday, 23 June 2007 6:14 PM
To: stgt-devel at lists.berlios.de
Subject: [Stgt-devel] [Patch 3/3] Re-work of SMC support
>From 921b883ce4bb5f015d9d950c2f9b7e4fc89b1ba6 Mon Sep 17 00:00:00 2001
From: Mark Harvey <markh794 at gmail.com>
Date: Sat, 23 Jun 2007 17:34:03 +1000
Subject: Initial commit of SMC module.
Includes all SCSI op codes defined in SSC as MANDATORY.
As yet, does not contain any way of signaling the DATA TRANSFER DEVICE
a piece of medium has been moved / loaded.
doc/README.lu_configuration updated with SMC specific options.
scripts/tgt-core-test updated to create an SMC device as well.
Signed-off-by: Mark Harvey <markh794 at gmail.com>
---
doc/README.lu_configuration | 43 +++
scripts/tgt-core-test | 96 +++++-
usr/Makefile | 5 +-
usr/media.h | 30 ++
usr/mmc.c | 19 +-
usr/osd.c | 18 +
usr/sbc.c | 19 +-
usr/scc.c | 18 +-
usr/smc.c | 811
+++++++++++++++++++++++++++++++++++++++++++
usr/smc.h | 77 ++++
usr/spc.c | 18 +-
usr/spc.h | 2 +-
usr/tgtadm.c | 2 +
usr/tgtd.h | 5 +-
14 files changed, 1143 insertions(+), 20 deletions(-)
create mode 100644 usr/media.h
create mode 100644 usr/smc.c
create mode 100644 usr/smc.h
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 dce8d3c..bd168dc 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..a04a27c
--- /dev/null
+++ b/usr/media.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 Mark Harvey markh794 at gmail dot 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 891cb60..0672877 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,26 @@ static int mmc_lu_init(struct scsi_lu *lu)
return 0;
}
+static int mmc_lu_config(struct scsi_lu *lu, char * params)
+{
+ char * mmc_params;
+ int ret;
+
+ mmc_params = malloc(strlen(params) + 1);
+ if (!mmc_params)
+ return -ENOMEM;
+ mmc_params[0] = '\0';
+ ret = spc_lu_config(lu, params, mmc_params);
+ if (strlen(mmc_params)) /* We should not have any params left
over */
+ ret = TGTADM_INVALID_REQUEST;
+ free(mmc_params);
+ return ret;
+}
+
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..2574086 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,26 @@ static int osd_lu_init(struct scsi_lu *lu)
return 0;
}
+static int osd_lu_config(struct scsi_lu *lu, char * params)
+{
+ char * osd_params;
+ int ret;
+
+ osd_params = malloc(strlen(params) + 1);
+ if (!osd_params)
+ return -ENOMEM;
+ osd_params[0] = '\0';
+ ret = spc_lu_config(lu, params, osd_params);
+ if (strlen(osd_params)) /* We should not have any params left
over */
+ ret = TGTADM_INVALID_REQUEST;
+ free(osd_params);
+ return ret;
+}
+
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..739f25c 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,26 @@ static int sbc_lu_init(struct scsi_lu *lu)
return 0;
}
+static int sbc_lu_config(struct scsi_lu *lu, char *params)
+{
+ char *sbc_params;
+ int ret;
+
+ sbc_params = malloc(strlen(params) + 1);
+ if (!sbc_params)
+ return TGTADM_NOMEM;
+ sbc_params[0] = '\0';
+ ret = spc_lu_config(lu, params, sbc_params);
+ if (strlen(sbc_params)) /* We should not have any params left
over */
+ ret = TGTADM_INVALID_REQUEST;
+ free(sbc_params);
+ return ret;
+}
+
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 28cd813..38d892e 100644
--- a/usr/scc.c
+++ b/usr/scc.c
@@ -50,10 +50,26 @@ static int scc_lu_init(struct scsi_lu *lu)
return 0;
}
+static int scc_lu_config(struct scsi_lu *lu, char *params)
+{
+ char *scc_params;
+ int ret;
+
+ scc_params = malloc(strlen(params) + 1);
+ if (!scc_params)
+ return TGTADM_NOMEM;
+ scc_params[0] = '\0';
+ ret = spc_lu_config(lu, params, scc_params);
+ if (strlen(scc_params)) /* We should not have any params left
over */
+ ret = TGTADM_INVALID_REQUEST;
+ free(scc_params);
+ return ret;
+}
+
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/smc.c b/usr/smc.c
new file mode 100644
index 0000000..c94be41
--- /dev/null
+++ b/usr/smc.c
@@ -0,0 +1,811 @@
+/*
+ * 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 <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);
+
+/* ********************************************************
+ * 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 vol_tag)
+{
+ if (vol_tag)
+ 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 vol_tag, int start, int
count)
+{
+ int element_sz;
+ int size;
+
+ element_sz = determine_element_sz(dvcid, vol_tag);
+
+ /* 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
vol_tag)
+{
+ int ret = determine_element_sz(dvcid, vol_tag);
+
+ *(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);
+ }
+ if (vol_tag) {
+ if (s->barcode[0] == ' ')
+ memset( &data[12], 0x20, 32); /* Pad with spaces
*/
+ else
+ snprintf((char *)&data[12], 32, "%-32s",
s->barcode);
+ }
+
+return ret;
+}
+
+/* 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
+ * vol_tag : 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 vol_tag)
+{
+ struct slot *s;
+ int count = 0;
+ int len = 0;
+ int elem_sz = determine_element_sz(dvcid, vol_tag);
+
+ 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[8+len],
+ s, elem_type, dvcid,
vol_tag);
+ }
+ }
+ if (count == 1) /* Record first found slot Address */
+ *first = s->slot_addr;
+ }
+
+ /* Fill in Element Status Page Header */
+ data[0] = elem_type;
+ data[1] = (vol_tag) ? 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 vol_tag;
+ 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;
+ vol_tag = (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, vol_tag);
+
+ 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, vol_tag);
+ len = count * elementSize;
+ count += build_element_descriptors(&data[len],
&smc->slots,
+ ELEMENT_STORAGE, &first,
+ req_start_elem,
+ dvcid, vol_tag);
+ len += count * elementSize;
+ count += build_element_descriptors(&data[len],
&smc->slots,
+ ELEMENT_MAP, &first,
+ req_start_elem,
+ dvcid, vol_tag);
+ len += count * elementSize;
+ count += build_element_descriptors(&data[len],
&smc->slots,
+ ELEMENT_DATA_TRANSFER, &first,
+ req_start_elem,
+ dvcid, vol_tag);
+ break;
+ case ELEMENT_MEDIUM_TRANSPORT:
+ count = build_element_descriptors(&data[len],
&smc->slots,
+ ELEMENT_MEDIUM_TRANSPORT,
&first,
+ req_start_elem,
+ dvcid, vol_tag);
+ break;
+ case ELEMENT_STORAGE:
+ count = build_element_descriptors(&data[len],
&smc->slots,
+ ELEMENT_STORAGE, &first,
+ req_start_elem,
+ dvcid, vol_tag);
+ break;
+ case ELEMENT_MAP:
+ count = build_element_descriptors(&data[len],
&smc->slots,
+ ELEMENT_MAP, &first,
+ req_start_elem,
+ dvcid, vol_tag);
+ break;
+ case ELEMENT_DATA_TRANSFER:
+ count = build_element_descriptors(&data[len],
&smc->slots,
+ ELEMENT_DATA_TRANSFER, &first,
+ req_start_elem,
+ dvcid, vol_tag);
+ break;
+ default:
+ goto sense;
+ break;
+ }
+
+ /* Lastly, fill in data header */
+ len = element_status_data_hdr(data, dvcid, vol_tag, 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 : %d\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, int 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;
+ int lun = 0;
+ char *smc_params;
+
+ smc_params = malloc(strlen(params) + 1);
+ if (!smc_params)
+ return TGTADM_NOMEM;
+ smc_params[0] = '\0';
+ err = spc_lu_config(lu, params, smc_params);
+
+ if (!strncmp("targetOps", smc_params, 9))
+ smc_params = smc_params + 10;
+
+ while ((p = strsep(&smc_params, ",")) != 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;
+ }
+ }
+
+ free(smc_params);
+
+ 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;
+}
+
+/* ***********************************
+ * 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..fc37f9d
--- /dev/null
+++ b/usr/smc.h
@@ -0,0 +1,77 @@
+/*
+ * SCSI Medium Changer Command
+ *
+ * Copyright (C) 2007 Mark Harvey markh794 at gmail dot 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;
+ uint8_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..19a0403 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -500,7 +500,19 @@ 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 * ret_param' for further processing by the
+ * 'target' from which it was called.
+ *
+ * Note: It is the callers responsibility to make sure *ret_param has
enough
+ * room to store up to "strlen(params) + 1" - In case we can not parse
any
+ * params locally.
+ */
+int spc_lu_config(struct scsi_lu *lu, char *params, char *ret_param)
+{
int err = 0;
char *p;
char buf[256];
@@ -551,7 +563,9 @@ 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(ret_param, p);
+ strcat(ret_param, ",");
err = TGTADM_INVALID_REQUEST;
}
}
diff --git a/usr/spc.h b/usr/spc.h
index c7e38c0..559a14e 100644
--- a/usr/spc.h
+++ b/usr/spc.h
@@ -16,7 +16,7 @@ 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, char
*ret_params);
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/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..271b260 100644
--- a/usr/tgtd.h
+++ b/usr/tgtd.h
@@ -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 {
--
1.5.2.1
_______________________________________________
Stgt-devel mailing list
Stgt-devel at lists.berlios.de
https://lists.berlios.de/mailman/listinfo/stgt-devel
More information about the stgt
mailing list