[PATCH] [Target_Core_Mod/ALUA]: Add initial support forMAINTENANCE_IN+REPORT_TARGET_PORT_GROUP
From: Nicholas A. Bellinger
Date: Mon Feb 02 2009 - 03:49:20 EST
Greetings all,
This patch adds initial support for Asymmetric Logical Unit Assignment (ALUA) in
Target_Core_Mod. It adds some basic ALUA infrastructure and adds
se_cmd_t->transport_emulate_cdb usage in transport_generic_cmd_sequencer() for
MAINTENANCE_IN+REPORT_TARGET_PORT_GROUP emulation.
It also sets SCCS=1 + TPGS=1 bits in INQUIRY response data, as well
changing Target_Core_Mod/IBLOCK to return linux/include/scsi/scsi.h:SCSI_SPC_2
so that SPC-3 shows up in INQUIRY response data.
Here is what it looks like in action with sg3_utils for the updated
INQUIRY response information for a Target_Core_Mod/IBLOCK across a
LIO-Target v3.0 iSCSI Target Port:
initiator# sg_inq -v /dev/sdh
inquiry cdb: 12 00 00 00 24 00
standard INQUIRY:
PQual=0 Device_type=0 RMB=0 version=0x05 [SPC-3]
[AERC=0] [TrmTsk=0] NormACA=0 HiSUP=0 Resp_data_format=0
SCCS=1 ACC=0 TPGS=1 3PC=0 Protect=0 BQue=0
EncServ=0 MultiP=0 [MChngr=0] [ACKREQQ=0] Addr16=0
[RelAdr=0] WBus16=1 Sync=1 Linked=0 [TranDis=0] CmdQue=1
length=36 (0x24) Peripheral device type: disk
Vendor identification: LIO-ORG
Product identification: IBLOCK
Product revision level: v3.0
inquiry cdb: 12 01 00 00 fc 00
inquiry cdb: 12 01 80 00 fc 00
Unit serial number: eEaqKo-gYF8-vnDA-jJhf-Xqzy-pjGF-G6Y50v
And for MAINTENANCE_IN+REPORT_TARGET_PORT_GROUP
initiator# sg_rtpg -v /dev/sdh
report target port groups cdb: a3 0a 00 00 00 00 00 00 04 00 00 00
Report list length = 16
Report target port groups:
target port group id : 0x0 , Pref=0
target port group asymmetric access state : 0x00
T_SUP : 0, O_SUP : 0, U_SUP : 0, S_SUP : 0, AN_SUP : 0, AO_SUP : 1
status code : 0x02
vendor unique status : 0x00
target port count : 01
Relative target port ids:
0x01
This is the initial support for implict non-transitional aware ALUA.
Functionality for both explict and implict transitional ALUA will be
added in future patch series. The latter will be able to be controlled
via Target_Core_Mod/ConfigFS and ConfigFS aware $FABRIC_MODs.
This patch is made against lio-core-2.6.git/master
and tested on v2.6.29-rc2 x86 32-bit HVM. The lio-core-2.6.git tree can be
found at:
http://git.kernel.org/?p=linux/kernel/git/nab/lio-core-2.6.git;a=summary
Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx>
---
drivers/lio-core/Makefile | 1 +
drivers/lio-core/target_core_alua.c | 157 ++++++++++++++++++++++++++++++
drivers/lio-core/target_core_alua.h | 38 +++++++
drivers/lio-core/target_core_base.h | 13 +++
drivers/lio-core/target_core_device.c | 1 +
drivers/lio-core/target_core_iblock.c | 2 +-
drivers/lio-core/target_core_transport.c | 35 ++++++-
drivers/lio-core/target_core_transport.h | 1 +
8 files changed, 243 insertions(+), 5 deletions(-)
create mode 100644 drivers/lio-core/target_core_alua.c
create mode 100644 drivers/lio-core/target_core_alua.h
diff --git a/drivers/lio-core/Makefile b/drivers/lio-core/Makefile
index 98a5ef3..7691c32 100644
--- a/drivers/lio-core/Makefile
+++ b/drivers/lio-core/Makefile
@@ -34,6 +34,7 @@ target_core_mod-objs := target_core_configfs.o \
target_core_hba.o \
target_core_plugin.o \
target_core_pr.o \
+ target_core_alua.o \
target_core_scdb.o \
target_core_seobj.o \
target_core_tpg.o \
diff --git a/drivers/lio-core/target_core_alua.c b/drivers/lio-core/target_core_alua.c
new file mode 100644
index 0000000..af94532
--- /dev/null
+++ b/drivers/lio-core/target_core_alua.c
@@ -0,0 +1,157 @@
+/*********************************************************************************
+ * Filename: target_core_pr.c
+ *
+ * This file contains SPC-3 compliant asymmetric logical unit assigntment (ALUA)
+ *
+ * Copyright (c) 2009 Rising Tide, Inc.
+ * Copyright (c) 2009 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@xxxxxxxxxx>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *********************************************************************************/
+
+#define TARGET_CORE_ALUA_C
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include <target_core_base.h>
+#include <target_core_device.h>
+#include <target_core_hba.h>
+#include <target_core_transport.h>
+#include <target_core_alua.h>
+#include <target_core_transport_plugin.h>
+#include <target_core_fabric_ops.h>
+#include <target_core_configfs.h>
+
+#undef TARGET_CORE_ALUA_C
+
+extern int core_scsi3_emulate_report_target_port_groups (se_cmd_t *cmd)
+{
+ se_lun_t *lun = SE_LUN(cmd);
+ se_port_t *port;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u32 rd_len = 0, off = 4;
+ u16 tg_pg = 0;
+ u8 tg_pg_count = 1; // Assume 1 for now
+
+ if (!(lun)) {
+ printk(KERN_ERR "SPC-3 ALUA se_lun_t is NULL!\n");
+ return(PYX_TRANSPORT_LOGICAL_UNIT_COMMUNICATION_FAILURE);
+ }
+ if (!(port = lun->lun_sep)) {
+ printk(KERN_ERR "SPC-3 ALUA se_port_t is NULL\n");
+ return(PYX_TRANSPORT_LOGICAL_UNIT_COMMUNICATION_FAILURE);
+ }
+ /*
+ * PREF: Preferred target port bit
+ */
+// buf[off] = 0x80;
+ /*
+ * Set the ASYMMETRIC ACCESS State
+ */
+ buf[off++] |= ALUA_ACCESS_STATE_ACTIVE_OPTMIZED;
+ /*
+ * Set supported ASYMMETRIC ACCESS State bits
+ */
+// buf[off] = 0x80; // T_SUP
+// buf[off] |= 0x40; // O_SUP
+// buf[off] |= 0x8; // U_SUP
+// buf[off] |= 0x4; // S_SUP
+// buf[off] |= 0x2; // AN_SUP
+ buf[off++] |= 0x1; // AO_SUP
+ /*
+ * TARGET PORT GROUP
+ */
+ buf[off++] = ((tg_pg >> 8) & 0xff);
+ buf[off++] = (tg_pg & 0xff);
+
+ off++; // Skip over Reserved
+ /*
+ * STATUS CODE
+ */
+ buf[off++] = ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA;
+ /*
+ * Vendor Specific field
+ */
+ buf[off++] = 0x00;
+ /*
+ * TARGET PORT COUNT
+ */
+ buf[off++] = tg_pg_count;
+
+ rd_len += 8;
+ /*
+ * Start Target Port descriptor format
+ *
+ * See spc4r17 section 6.2.7 Table 247
+ */
+ off += 2; // Skip over Obsolete
+ /*
+ * Set RELATIVE TARGET PORT IDENTIFIER
+ */
+ buf[off++] = ((port->sep_rtpi >> 8) & 0xff);
+ buf[off++] = (port->sep_rtpi & 0xff);
+
+ rd_len += 4;
+ /*
+ * Set the RETURN DATA LENGTH set in the header of the DataIN Payload
+ */
+ buf[0] = ((rd_len >> 24) & 0xff);
+ buf[1] = ((rd_len >> 16) & 0xff);
+ buf[2] = ((rd_len >> 8) & 0xff);
+ buf[3] = (rd_len & 0xff);
+
+ return(0);
+}
+
+extern int core_setup_alua (se_device_t *dev)
+{
+ se_subsystem_dev_t *su_dev = dev->se_sub_dev;
+ t10_alua_t *alua = T10_ALUA(su_dev);
+ /*
+ * If this device is from Target_Core_Mod/pSCSI, use the ALUA logic
+ * of the Underlying SCSI hardware. In Linux/SCSI terms, this can
+ * cause a problem because libata and some SATA RAID HBAs appear
+ * under Linux/SCSI, but emulate SCSI logic themselves.
+ */
+ if ((TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) &&
+ !(DEV_ATTRIB(dev)->emulate_alua)) {
+ alua->alua_type = SPC_ALUA_PASSTHROUGH;
+ printk("%s: Using SPC_ALUA_PASSTHROUGH, no ALUA emulation\n",
+ TRANSPORT(dev)->name);
+ return(0);
+ }
+ /*
+ * If SPC-3 or above is reported by real or emulated se_device_t,
+ * use emulated ALUA.
+ */
+ if (TRANSPORT(dev)->get_device_rev(dev) >= SCSI_3) {
+ alua->alua_type = SPC3_ALUA_EMULATED;
+ printk("%s: Enabling ALUA Emulation for SPC-3 device\n",
+ TRANSPORT(dev)->name);
+ } else {
+ alua->alua_type = SPC2_ALUA_DISABLED;
+ printk("%s: Disabling ALUA for SPC-2 device\n",
+ TRANSPORT(dev)->name);
+ }
+
+ return(0);
+}
diff --git a/drivers/lio-core/target_core_alua.h b/drivers/lio-core/target_core_alua.h
new file mode 100644
index 0000000..e08cbf4
--- /dev/null
+++ b/drivers/lio-core/target_core_alua.h
@@ -0,0 +1,38 @@
+#ifndef TARGET_CORE_ALUA_H
+#define TARGET_CORE_ALUA_H
+
+/*
+ * INQUIRY response data, TPGS Field
+ *
+ * from spc4r17 section 6.4.2 Table 135
+ */
+#define TPGS_NO_ALUA 0x00
+#define TPGS_IMPLICT_ALUA 0x10
+#define TPGS_EXPLICT_ALUA 0x20
+#define TPGS_EXPLICT_AND_IMPLICT_ALUA 0x40
+
+/*
+ * ASYMMETRIC ACCESS STATE field
+ *
+ * from spc4r17 section 6.27 Table 245
+ */
+#define ALUA_ACCESS_STATE_ACTIVE_OPTMIZED 0x0
+#define ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED 0x1
+#define ALUA_ACCESS_STATE_STANDBY 0x2
+#define ALUA_ACCESS_STATE_UNAVAILABLE 0x3
+#define ALUA_ACCESS_STATE_OFFLINE 0xe
+#define ALUA_ACCESS_STATE_TRANSITION 0xf
+
+/*
+ * REPORT_TARGET_PORT_GROUP STATUS CODE
+ *
+ * from spc4r17 section 6.27 Table 246
+ */
+#define ALUA_STATUS_NONE 0x00
+#define ALUA_STATUS_ALTERED_BY_EXPLICT_STPG 0x01
+#define ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA 0x02
+
+extern int core_scsi3_emulate_report_target_port_groups (struct se_cmd_s *);
+extern int core_setup_alua (struct se_device_s *);
+
+#endif // TARGET_CORE_ALUA_H
diff --git a/drivers/lio-core/target_core_base.h b/drivers/lio-core/target_core_base.h
index 5e979ff..a5208e8 100644
--- a/drivers/lio-core/target_core_base.h
+++ b/drivers/lio-core/target_core_base.h
@@ -179,6 +179,16 @@ typedef struct se_obj_s {
atomic_t obj_access_count;
} ____cacheline_aligned se_obj_t;
+typedef enum {
+ SPC_ALUA_PASSTHROUGH,
+ SPC2_ALUA_DISABLED,
+ SPC3_ALUA_EMULATED
+} t10_alua_index_t;
+
+typedef struct t10_alua_s {
+ t10_alua_index_t alua_type;
+} ____cacheline_aligned t10_alua_t;
+
typedef struct t10_evpd_s {
unsigned char device_identifier[INQUIRY_EVPD_DEVICE_IDENTIFIER_LEN];
int protocol_identifier_set;
@@ -508,6 +518,7 @@ typedef struct se_dev_attrib_s {
int status_thread;
int status_thread_tur;
int emulate_reservations;
+ int emulate_alua;
u32 hw_max_sectors;
u32 max_sectors;
u32 hw_queue_depth;
@@ -522,6 +533,7 @@ typedef struct se_subsystem_dev_s {
struct se_hba_s *se_dev_hba;
struct se_device_s *se_dev_ptr;
se_dev_attrib_t se_dev_attrib;
+ t10_alua_t t10_alua; /* T10 Asymmetric Logical Unit Assignment Information */
t10_wwn_t t10_wwn; /* T10 Inquiry and EVPD WWN Information */
t10_reservation_template_t t10_reservation; /* T10 SPC-2 + SPC-3 Reservations */
spinlock_t se_dev_lock;
@@ -530,6 +542,7 @@ typedef struct se_subsystem_dev_s {
struct config_group se_dev_pr_group; /* For T10 Reservations */
} ____cacheline_aligned se_subsystem_dev_t;
+#define T10_ALUA(su_dev) (&(su_dev)->t10_alua)
#define T10_RES(su_dev) (&(su_dev)->t10_reservation)
typedef struct se_device_s {
diff --git a/drivers/lio-core/target_core_device.c b/drivers/lio-core/target_core_device.c
index 53741d8..ced583a 100644
--- a/drivers/lio-core/target_core_device.c
+++ b/drivers/lio-core/target_core_device.c
@@ -791,6 +791,7 @@ extern void se_dev_set_default_attribs (se_device_t *dev)
DEV_ATTRIB(dev)->status_thread = DA_STATUS_THREAD;
DEV_ATTRIB(dev)->status_thread_tur = DA_STATUS_THREAD_TUR;
DEV_ATTRIB(dev)->emulate_reservations = DA_EMULATE_RESERVATIONS;
+ DEV_ATTRIB(dev)->emulate_alua = DA_EMULATE_ALUA;
/*
* max_sectors is based on subsystem plugin dependent requirements.
*/
diff --git a/drivers/lio-core/target_core_iblock.c b/drivers/lio-core/target_core_iblock.c
index a94526c..d71d766 100644
--- a/drivers/lio-core/target_core_iblock.c
+++ b/drivers/lio-core/target_core_iblock.c
@@ -836,7 +836,7 @@ extern u32 iblock_get_blocksize (se_device_t *dev)
extern u32 iblock_get_device_rev (se_device_t *dev)
{
- return(SCSI_3);
+ return(SCSI_SPC_2); // Returns SPC-3 in Initiator Data
}
extern u32 iblock_get_device_type (se_device_t *dev)
diff --git a/drivers/lio-core/target_core_transport.c b/drivers/lio-core/target_core_transport.c
index 5bb13b2..7254f02 100644
--- a/drivers/lio-core/target_core_transport.c
+++ b/drivers/lio-core/target_core_transport.c
@@ -59,6 +59,7 @@
#include <target_core_hba.h>
#include <target_core_scdb.h>
#include <target_core_pr.h>
+#include <target_core_alua.h>
#include <target_core_transport.h>
#include <target_core_plugin.h>
#include <target_core_seobj.h>
@@ -2099,6 +2100,10 @@ extern se_device_t *transport_add_device_to_core_hba (
*/
core_setup_reservations(dev);
/*
+ * Setup the Asymmetric Logical Unit Assignment for se_device_t
+ */
+ core_setup_alua(dev);
+ /*
* Startup the se_device_t processing thread
*/
transport_generic_activate_device(dev);
@@ -4044,6 +4049,19 @@ extern int transport_generic_emulate_inquiry (
buf[1] = 0x80;
buf[2] = TRANSPORT(dev)->get_device_rev(dev);
buf[4] = 31;
+ /*
+ * Enable SCCS and TPGS fields for Emulated ALUA
+ */
+ if (T10_ALUA(dev->se_sub_dev)->alua_type == SPC3_ALUA_EMULATED) {
+ /*
+ * Set SCCS for MAINTENANCE_IN + REPORT_TARGET_PORT_GROUPS
+ */
+ buf[5] = 0x80;
+ /*
+ * Set TPGS field, see spc4r17 section 6.4.2 Table 135
+ */
+ buf[5] |= TPGS_IMPLICT_ALUA;
+ }
buf[7] = 0x32; /* Sync=1 and CmdQue=1 */
sprintf((unsigned char *)&buf[8], "LIO-ORG");
@@ -4612,16 +4630,25 @@ static int transport_generic_cmd_sequencer (
break;
case 0xa3:
SET_GENERIC_TRANSPORT_FUNCTIONS(cmd);
- if (TRANSPORT(dev)->get_device_type(dev) == TYPE_RAID) {
+ if (TRANSPORT(dev)->get_device_type(dev) != TYPE_ROM) {
// MAINTENANCE_IN from SCC-2
+ /*
+ * Check for emulated MI_REPORT_TARGET_PGS.
+ */
+ if (cdb[1] == MI_REPORT_TARGET_PGS) {
+ cmd->transport_emulate_cdb =
+ (T10_ALUA(su_dev)->alua_type == SPC3_ALUA_EMULATED) ?
+ &core_scsi3_emulate_report_target_port_groups :
+ NULL;
+ }
size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
} else {
// GPCMD_SEND_KEY from multi media commands
size = (cdb[8] << 8) + cdb[9];
}
- CMD_ORIG_OBJ_API(cmd)->get_mem_SG(cmd->se_orig_obj_ptr, cmd);
+ CMD_ORIG_OBJ_API(cmd)->get_mem_buf(cmd->se_orig_obj_ptr, cmd);
transport_get_maps(cmd);
- ret = 1;
+ ret = 2;
break;
case MODE_SELECT:
SET_GENERIC_TRANSPORT_FUNCTIONS(cmd);
@@ -4700,7 +4727,7 @@ static int transport_generic_cmd_sequencer (
break;
case 0xa4:
SET_GENERIC_TRANSPORT_FUNCTIONS(cmd);
- if (TRANSPORT(dev)->get_device_type(dev) == TYPE_RAID) {
+ if (TRANSPORT(dev)->get_device_type(dev) != TYPE_ROM) {
// MAINTENANCE_OUT from SCC-2
size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
} else {
diff --git a/drivers/lio-core/target_core_transport.h b/drivers/lio-core/target_core_transport.h
index 768b8c7..70131d1 100644
--- a/drivers/lio-core/target_core_transport.h
+++ b/drivers/lio-core/target_core_transport.h
@@ -99,6 +99,7 @@
#define DA_STATUS_THREAD 0 /* Disabled by default */
#define DA_STATUS_THREAD_TUR 0 /* Disabled by default */
#define DA_EMULATE_RESERVATIONS 0 /* No Emulation for PSCSI by default */
+#define DA_EMULATE_ALUA 0 /* No Emulation for PSCSI by default */
#define DA_STATUS_MAX_SECTORS_MIN 16
#define DA_STATUS_MAX_SECTORS_MAX 8192
--
1.5.4.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/