summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/Makefile2
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/Makefile.com2
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.c41
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.h11
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/main.c5
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/queue.h48
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/t10.h21
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/t10_raw_if.c47
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/t10_sam.c111
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/t10_sbc.c195
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/t10_sbc.h5
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/t10_spc.c55
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/t10_spc.h71
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c1913
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h165
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/target.h13
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/util_queue.c16
-rw-r--r--usr/src/lib/libiscsitgt/common/iscsitgt_impl.h1
-rw-r--r--usr/src/uts/common/sys/Makefile1
-rw-r--r--usr/src/uts/common/sys/scsi/generic/commands.h5
-rw-r--r--usr/src/uts/common/sys/scsi/generic/persist.h398
21 files changed, 2854 insertions, 272 deletions
diff --git a/usr/src/cmd/iscsi/iscsitgtd/Makefile b/usr/src/cmd/iscsi/iscsitgtd/Makefile
index bc62138311..f934118f45 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/Makefile
+++ b/usr/src/cmd/iscsi/iscsitgtd/Makefile
@@ -31,7 +31,7 @@ OBJS = main.o mgmt.o mgmt_create.o mgmt_list.o mgmt_modify.o mgmt_remove.o
OBJS += iscsi_authclient.o iscsi_authglue.o iscsi_cmd.o iscsi_conn.o
OBJS += iscsi_crc.o iscsi_ffp.o iscsi_login.o iscsi_sess.o radius.o
OBJS += t10_sam.o t10_spc.o t10_sbc.o t10_raw_if.o t10_ssc.o t10_osd.o
-OBJS += util.o util_err.o util_ifname.o util_port.o util_queue.o
+OBJS += t10_spc_pr.o util.o util_err.o util_ifname.o util_port.o util_queue.o
OBJS += isns_client.o isns.o
POFILE= iscsitgtd.po
POFILES = $(OBJS:%.o=%.po)
diff --git a/usr/src/cmd/iscsi/iscsitgtd/Makefile.com b/usr/src/cmd/iscsi/iscsitgtd/Makefile.com
index 27a6d55fd7..2400aab467 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/Makefile.com
+++ b/usr/src/cmd/iscsi/iscsitgtd/Makefile.com
@@ -34,7 +34,7 @@ COBJS = main.o mgmt.o mgmt_create.o mgmt_list.o mgmt_modify.o mgmt_remove.o
COBJS += iscsi_authclient.o iscsi_authglue.o iscsi_cmd.o iscsi_conn.o
COBJS += iscsi_crc.o iscsi_ffp.o iscsi_login.o iscsi_sess.o radius.o
COBJS += t10_sam.o t10_spc.o t10_sbc.o t10_raw_if.o t10_ssc.o t10_osd.o
-COBJS += util.o util_err.o util_ifname.o util_port.o util_queue.o
+COBJS += t10_spc_pr.o util.o util_err.o util_ifname.o util_port.o util_queue.o
COBJS += isns_client.o isns.o
OBJS= $(COBJS) $(DSRC:%.d=%.o)
SRCS= $(COBJS:%.o=../%.c) $(COMMON_SRCS)
diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.c b/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.c
index 12d7538ec9..b2ca1b0d1d 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.c
+++ b/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -71,8 +71,7 @@ session_init()
Boolean_t
session_alloc(iscsi_conn_t *c, uint8_t *isid)
{
- iscsi_sess_t *s,
- *n;
+ iscsi_sess_t *s, *n;
if (c->c_sess != NULL)
return (True);
@@ -94,7 +93,7 @@ session_alloc(iscsi_conn_t *c, uint8_t *isid)
}
(void) pthread_mutex_unlock(&sess_mutex);
- bcopy(isid, s->s_isid, 6);
+ bcopy(isid, &s->s_isid, 6);
(void) pthread_mutex_init(&s->s_mutex, NULL);
c->c_sess = s;
@@ -171,7 +170,7 @@ session_free(iscsi_sess_t *s)
static Boolean_t
session_remove_connection(iscsi_sess_t *s, iscsi_conn_t *c)
{
- bzero(s->s_isid, 6);
+ s->s_isid = 0;
return (True);
}
@@ -187,8 +186,8 @@ Boolean_t
convert_i_local(char *ip, char **rtn)
{
tgt_node_t *inode = NULL;
- char *iname,
- *name;
+ char *iname;
+ char *name;
while ((inode = tgt_node_next(main_config, XML_ELEMENT_INIT, inode)) !=
NULL) {
@@ -298,8 +297,8 @@ sess_process(void *v)
mgmt_request_t *mgmt;
name_request_t *nr;
t10_cmd_t *t10_cmd;
- char **buf,
- local_buf[16];
+ char **buf;
+ char local_buf[16];
int lun;
extern void dataout_callback(t10_cmd_t *t, char *data, size_t *xfer);
@@ -314,6 +313,12 @@ sess_process(void *v)
if (s->s_t10 == NULL) {
/*
+ * Persistent Reservervation Support requires
+ * access to both the transportID and iSCSI
+ * Session ID
+ */
+
+ /*
* The value of 0x960 comes from T10.
* See SPC-4, revision 1a, section 6.4.2,
* table 87
@@ -323,9 +328,12 @@ sess_process(void *v)
*/
s->s_t10 = t10_handle_create(s->s_t_name,
T10_TRANS_ISCSI, s->s_conn_head->c_tpgt,
+ s->s_conn_head->c_sess->s_i_name,
+ s->s_conn_head->c_sess->s_isid,
s->s_conn_head->c_max_burst_len,
s->s_t10q, dataout_callback);
}
+
if (t10_cmd_create(s->s_t10, cmd->c_lun, cmd->c_scb,
cmd->c_scb_len, (transport_t)cmd,
&t10_cmd) == False) {
@@ -553,12 +561,8 @@ session_validate(iscsi_sess_t *s)
{
iscsi_sess_t *check;
- queue_prt(s->s_mgmtq, Q_SESS_NONIO,
- "SES%x %s ISID[%02x%02x%02x%02x%02x%02x]\n",
- s->s_num, s->s_i_alias == NULL ? s->s_i_name : s->s_i_alias,
- s->s_isid[0], s->s_isid[1], s->s_isid[2],
- s->s_isid[3], s->s_isid[4], s->s_isid[5]);
-
+ queue_prt(s->s_mgmtq, Q_SESS_NONIO, "SES%x %s ISID[%016x]\n", s->s_num,
+ s->s_i_alias == NULL ? s->s_i_name : s->s_i_alias, s->s_isid);
/*
* SessionType=Discovery which means no target name and therefore
@@ -590,7 +594,7 @@ session_validate(iscsi_sess_t *s)
* reinstating a new iSCSI session in its place (with the
* same ISID).
*/
- if (bcmp(check->s_isid, s->s_isid, 6) == 0) {
+ if (check->s_isid == s->s_isid) {
queue_prt(s->s_mgmtq, Q_SESS_NONIO,
"SES%x Implicit shutdown\n", check->s_num);
if (check->s_conn_head->c_state == S5_LOGGED_IN)
@@ -681,7 +685,7 @@ sess_set_auth(iscsi_sess_t *isp)
}
if (iscsiAuthClientSetVersion(auth_client,
- iscsiAuthVersionRfc) != iscsiAuthStatusNoError) {
+ iscsiAuthVersionRfc) != iscsiAuthStatusNoError) {
syslog(LOG_ERR, "iscsi connection login failed - "
"unable to set version\n");
return;
@@ -716,8 +720,7 @@ sess_set_auth(iscsi_sess_t *isp)
}
if (iscsiAuthClientSetAuthRemote(auth_client,
- isp->sess_auth.auth_enabled) !=
- iscsiAuthStatusNoError) {
+ isp->sess_auth.auth_enabled) != iscsiAuthStatusNoError) {
syslog(LOG_ERR, "iscsi connection login failed - "
"unable to set remote authentication\n");
return;
diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.h b/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.h
index 4426046117..c0703f9dd4 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.h
+++ b/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.h
@@ -20,12 +20,12 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#ifndef _SESSION_H
-#define _SESSION_H
+#ifndef _ISCSI_SESS_H
+#define _ISCSI_SESS_H
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -92,7 +92,8 @@ typedef struct iscsi_sess {
char *s_i_name,
*s_i_alias,
*s_t_name;
- uint8_t s_isid[6];
+ uint64_t s_isid;
+
/*
* This is the highest packet number we've seen and is
* used during replies.
@@ -139,4 +140,4 @@ Boolean_t session_validate(struct iscsi_sess *s);
}
#endif
-#endif /* _SESSION_H */
+#endif /* _ISCSI_SESS_H */
diff --git a/usr/src/cmd/iscsi/iscsitgtd/main.c b/usr/src/cmd/iscsi/iscsitgtd/main.c
index 4ac843dba2..b19f856e25 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/main.c
+++ b/usr/src/cmd/iscsi/iscsitgtd/main.c
@@ -89,7 +89,8 @@ tgt_node_t *main_config,
Boolean_t enforce_strict_guid = True,
thin_provisioning = False,
disable_tpgs = False,
- dbg_timestamps = False;
+ dbg_timestamps = False,
+ pgr_persist = True;
int targets_vers_maj,
targets_vers_min,
main_vers_maj,
@@ -370,6 +371,8 @@ process_config(char *file)
&disable_tpgs);
(void) tgt_find_value_boolean(node, XML_ELEMENT_TIMESTAMPS,
&dbg_timestamps);
+ (void) tgt_find_value_boolean(node, XML_ELEMENT_PGR_PERSIST,
+ &pgr_persist);
if (tgt_find_value_int(node, XML_ELEMENT_LOGLVL,
&qlog_lvl) == True)
queue_log(True);
diff --git a/usr/src/cmd/iscsi/iscsitgtd/queue.h b/usr/src/cmd/iscsi/iscsitgtd/queue.h
index 5813187026..c4fad54edd 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/queue.h
+++ b/usr/src/cmd/iscsi/iscsitgtd/queue.h
@@ -41,29 +41,39 @@ extern "C" {
#include <iscsitgt_impl.h>
-#define Q_CONN_ERRS 0x00001
-#define Q_CONN_LOGIN 0x00002
-#define Q_CONN_NONIO 0x00004
-#define Q_CONN_IO 0x00008
-
-#define Q_SESS_ERRS 0x00010
-#define Q_SESS_LOGIN 0x00020
-#define Q_SESS_NONIO 0x00040
-#define Q_SESS_IO 0x00080
-
-#define Q_STE_ERRS 0x00100
-#define Q_STE_NONIO 0x00200
-#define Q_STE_IO 0x00400
-
-#define Q_GEN_ERRS 0x01000
-#define Q_GEN_DETAILS 0x02000
-
-#define Q_ISNS_DBG 0x10000
+/* Connections */
+#define Q_CONN_ERRS 0x00000001
+#define Q_CONN_LOGIN 0x00000002
+#define Q_CONN_NONIO 0x00000004
+#define Q_CONN_IO 0x00000008
+
+/* Sessions */
+#define Q_SESS_ERRS 0x00000010
+#define Q_SESS_LOGIN 0x00000020
+#define Q_SESS_NONIO 0x00000040
+#define Q_SESS_IO 0x00000080
+
+/* SCSI Target Emulation */
+#define Q_STE_ERRS 0x00000100
+#define Q_STE_NONIO 0x00000200
+#define Q_STE_IO 0x00000400
+
+/* General Errors */
+#define Q_GEN_ERRS 0x00001000
+#define Q_GEN_DETAILS 0x00002000
+
+/* ISCSI Debugging */
+#define Q_ISNS_DBG 0x00004000
+
+/* Persistent Reservations */
+#define Q_PR_ERRS 0x00010000
+#define Q_PR_NONIO 0x00020000
+#define Q_PR_IO 0x00040000
/*
* When used the queue request will be place at the head of the queue.
*/
-#define Q_HIGH 0x10000
+#define Q_HIGH 0x80000000
extern int qlog_lvl;
diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10.h b/usr/src/cmd/iscsi/iscsitgtd/t10.h
index 502304dccb..3160e7bc0d 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/t10.h
+++ b/usr/src/cmd/iscsi/iscsitgtd/t10.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -126,6 +126,8 @@ typedef enum {
#define T10_CMD_RESID(cmd) (cmd->c_resid)
#define T10_SENSE_LEN(cmd) (cmd->c_cmd_sense_len)
#define T10_SENSE_DATA(cmd) (cmd->c_cmd_sense)
+#define T10_PGR_TID(cmd) (cmd->c_lu->l_targ->s_transportID)
+#define T10_PGR_ISID(cmd) (cmd->c_lu->l_targ->s_isid)
#define T10_DEFAULT_TPG 1
@@ -341,7 +343,7 @@ typedef struct t10_lu_common {
Boolean_t l_fast_write_ack;
/*
- * AVL tree containing all I_T_Q nexus' which are actively using
+ * AVL tree containing all I_T_L nexus' which are actively using
* this LUN.
*/
avl_tree_t l_all_open;
@@ -427,6 +429,7 @@ typedef struct t10_lu_impl {
int l_targ_lun;
Boolean_t l_dsense_enabled;
+ Boolean_t l_pgr_read;
/*
* Statistics on a per ITL basis
@@ -463,7 +466,14 @@ typedef struct t10_targ_impl {
/*
* Target Port Set
*/
- int s_tp_grp;
+ int s_tpgt;
+
+ /*
+ * PERSISTENT RESERVATION support, the transportID & ISID
+ * SPC-3 revision 23, Section 7.5.4.5, Table 290
+ */
+ char *s_transportID;
+ uint64_t s_isid;
/*
* transport version number to use in standard inquiry data
@@ -528,8 +538,9 @@ void lu_buserr_handler(int sig, siginfo_t *sip, void *v);
* t10_handle_create -- create target handle to be used by transports
*/
t10_targ_handle_t
-t10_handle_create(char *targ_name, int trans_version, int tpg, int max_out,
- target_queue_t *transq, void (*datain_cb)(t10_cmd_t *, char *, size_t *));
+t10_handle_create(char *targ, int trans_vers, int tpg, char *tid, uint64_t isid,
+ int max_out, target_queue_t *tq,
+ void (*datain_cb)(t10_cmd_t *, char *, size_t *));
/*
* t10_handle_disable -- drains commands from emulation queues
diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_raw_if.c b/usr/src/cmd/iscsi/iscsitgtd/t10_raw_if.c
index 24d4bb722f..03f8422704 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_raw_if.c
+++ b/usr/src/cmd/iscsi/iscsitgtd/t10_raw_if.c
@@ -234,8 +234,8 @@ raw_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data,
static void
raw_read_tape(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
- size_t req_len,
- xfer;
+ size_t req_len;
+ size_t xfer;
off_t offset = 0;
raw_io_t *io;
Boolean_t last;
@@ -285,8 +285,8 @@ raw_read(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
union scsi_cdb *u = (union scsi_cdb *)cdb;
diskaddr_t addr;
off_t offset = 0;
- uint32_t cnt,
- min;
+ uint32_t cnt;
+ uint32_t min;
raw_io_t *io;
uint64_t err_blkno;
int sense_len;
@@ -499,8 +499,8 @@ raw_read_cmplt(emul_handle_t id)
static void
raw_write_tape(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
- size_t request_len,
- xfer;
+ size_t request_len;
+ size_t xfer;
raw_io_t *io;
request_len = (cdb[2] << 16) | (cdb[3] << 8) | cdb[4];
@@ -824,6 +824,37 @@ raw_release(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
}
static void
+raw_persist_in(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
+{
+ raw_io_t *io;
+
+ if ((io = do_datain(cmd, cdb, CDB_GROUP1, 0)) == NULL) {
+ trans_send_complete(cmd, STATUS_CHECK);
+ } else {
+ trans_send_complete(cmd, io->r_status);
+ raw_free_io(io);
+ }
+}
+
+static void
+raw_persist_out(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
+{
+ size_t len;
+
+ len = (cdb[5] << 24) | (cdb[6] << 16) | (cdb[7] << 8) | cdb[8];
+ do_dataout(cmd, cdb, cdb_len, len);
+}
+
+/*ARGSUSED*/
+static void
+raw_persist_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data,
+ size_t data_len)
+{
+ raw_io_t *io = (raw_io_t *)id;
+ trans_send_complete(cmd, do_uscsi(cmd, io, RawDataToDevice));
+}
+
+static void
raw_msense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
raw_io_t *io;
@@ -1351,8 +1382,8 @@ static scsi_cmd_table_t raw_table[] = {
{ spc_unsupported, NULL, NULL, NULL },
{ spc_unsupported, NULL, NULL, NULL },
{ spc_unsupported, NULL, NULL, NULL },
- { spc_unsupported, NULL, NULL, NULL },
- { spc_unsupported, NULL, NULL, NULL },
+ { raw_persist_in, NULL, NULL, "PERSISTENT_RESERVE_IN" },
+ { raw_persist_out, raw_persist_data, NULL, "PERSISTENT_RESERVE_OUT" },
/* 0x60 -- 0x6f */
{ spc_unsupported, NULL, NULL, NULL },
diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_sam.c b/usr/src/cmd/iscsi/iscsitgtd/t10_sam.c
index cebde4af45..582ab51f84 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_sam.c
+++ b/usr/src/cmd/iscsi/iscsitgtd/t10_sam.c
@@ -99,7 +99,7 @@ static int find_cmd_by_addr(const void *v1, const void *v2);
static sam_device_table_t sam_emul_table[];
/*
- * Global variables
+ * Local variables
*/
static avl_tree_t lu_list;
static pthread_mutex_t lu_list_mutex;
@@ -205,8 +205,9 @@ t10_aio_done(void *v)
* []----
*/
t10_targ_handle_t
-t10_handle_create(char *targ, int trans_version, int tpg, int max_out,
- target_queue_t *tq, void (*datain_cb)(t10_cmd_t *, char *, size_t *))
+t10_handle_create(char *targ, int trans_vers, int tpg, char *tid, uint64_t isid,
+ int max_out, target_queue_t *tq,
+ void (*datain_cb)(t10_cmd_t *, char *, size_t *))
{
t10_targ_impl_t *t = calloc(1, sizeof (t10_targ_impl_t));
@@ -217,12 +218,19 @@ t10_handle_create(char *targ, int trans_version, int tpg, int max_out,
t->s_targ_num = t10_num++;
(void) pthread_mutex_unlock(&t10_mutex);
t->s_targ_base = strdup(targ);
- t->s_trans_vers = trans_version;
+ t->s_trans_vers = trans_vers;
t->s_maxout = max_out;
t->s_to_transport = tq;
t->s_dataout_cb = datain_cb;
/*
+ * Persistent Reservervation Support requires access to both
+ * the transportID and iSCSI Session ID
+ */
+ t->s_transportID = strdup(tid);
+ t->s_isid = isid;
+
+ /*
* Once we actually support two or more transports it would be
* possible for a collision between the underlying transports
* target port group values since one wouldn't necessarily know
@@ -234,13 +242,13 @@ t10_handle_create(char *targ, int trans_version, int tpg, int max_out,
* to determine relative path numbering there's no issue with changing
* this later if need be.
*/
- switch (trans_version) {
+ switch (trans_vers) {
case T10_TRANS_ISCSI:
- t->s_tp_grp = 0x0000 | tpg;
+ t->s_tpgt = 0x0000 | tpg;
break;
case T10_TRANS_FC:
- t->s_tp_grp = 0x8000 | tpg;
+ t->s_tpgt = 0x8000 | tpg;
break;
}
@@ -286,8 +294,8 @@ t10_handle_destroy(t10_targ_handle_t tp)
{
t10_targ_impl_t *t = (t10_targ_impl_t *)tp;
t10_lu_impl_t *l;
- t10_cmd_t *c,
- *c2free;
+ t10_cmd_t *c;
+ t10_cmd_t *c2free;
int fast_free = 0;
(void) pthread_mutex_lock(&t->s_mutex);
@@ -348,6 +356,7 @@ t10_handle_destroy(t10_targ_handle_t tp)
(void) pthread_mutex_unlock(&t->s_mutex);
free(t->s_targ_base);
+ free(t->s_transportID);
free(t);
}
@@ -689,8 +698,8 @@ Boolean_t
t10_task_mgmt(t10_targ_handle_t t1, TaskOp_t op, int opt_lun, void *tag)
{
t10_targ_impl_t *t = (t10_targ_impl_t *)t1;
- t10_lu_impl_t search,
- *lu;
+ t10_lu_impl_t search;
+ t10_lu_impl_t *lu;
switch (op) {
case InventoryChange:
@@ -753,8 +762,8 @@ t10_targ_stat(t10_targ_handle_t t1, char **buf)
{
t10_targ_impl_t *t = (t10_targ_impl_t *)t1;
t10_lu_impl_t *itl;
- char lb[32],
- *p;
+ char lb[32];
+ char *p;
/*
* It's possible for the management interfaces to request stats
@@ -819,8 +828,8 @@ t10_thick_provision(char *target, int lun, target_queue_t *q)
t10_cmd_t *cmd = NULL;
uint8_t cdb[16]; /* ---- fake buffer ---- */
diskaddr_t offset = 0;
- size_t size,
- sync_size;
+ size_t size;
+ size_t sync_size;
msg_t *m = NULL;
target_queue_t *rq = NULL;
char path[MAXPATHLEN];
@@ -835,7 +844,7 @@ t10_thick_provision(char *target, int lun, target_queue_t *q)
* having something fixed/change in one location that isn't
* in another. Obvious right?
*/
- if ((t = t10_handle_create(target, 0, 0, 0, q, NULL)) == NULL) {
+ if ((t = t10_handle_create(target, 0, 0, "", 0, 0, q, NULL)) == NULL) {
queue_prt(mgmtq, Q_STE_ERRS, "STE%x Failed to create handle\n",
lun);
return (False);
@@ -1311,19 +1320,19 @@ trans_params_area(t10_cmd_t *cmd)
static Boolean_t
t10_find_lun(t10_targ_impl_t *t, int lun, t10_cmd_t *cmd)
{
- t10_lu_impl_t *l = NULL,
- search;
- avl_index_t wc = 0, /* where common */
- wt = 0; /* where target */
- char *guid = NULL,
- *str,
- *dataset = NULL;
- t10_lu_common_t lc,
- *common = NULL;
- tgt_node_t *n = NULL,
- *n1,
- *targ,
- *ll;
+ t10_lu_impl_t *l = NULL;
+ t10_lu_impl_t search;
+ avl_index_t wc = 0; /* where common */
+ avl_index_t wt = 0; /* where target */
+ char *guid = NULL;
+ char *str;
+ char *dataset = NULL;
+ t10_lu_common_t lc;
+ t10_lu_common_t *common = NULL;
+ tgt_node_t *n = NULL;
+ tgt_node_t *n1;
+ tgt_node_t *targ;
+ tgt_node_t *ll;
xmlTextReaderPtr r = NULL;
char path[MAXPATHLEN];
int xml_fd = -1;
@@ -1702,11 +1711,11 @@ lu_runner(void *v)
msg_t *m;
t10_lu_impl_t *itl;
t10_cmd_t *cmd;
- char *data,
- *path;
- size_t data_len,
- new_size,
- offset;
+ char *data;
+ char *path;
+ size_t data_len;
+ size_t new_size;
+ size_t offset;
ssize_t cc;
void *provo_err;
t10_shutdown_t *s;
@@ -1736,8 +1745,8 @@ lu_runner(void *v)
trans_send_complete(cmd, STATUS_CHECK);
} else {
lu->l_curr = cmd;
- (*cmd->c_lu->l_cmd)(cmd, cmd->c_cdb,
- cmd->c_cdb_len);
+ (*cmd->c_lu->l_cmd)
+ (cmd, cmd->c_cdb, cmd->c_cdb_len);
lu->l_curr = NULL;
}
break;
@@ -1896,13 +1905,13 @@ lu_runner(void *v)
cmd->c_data, cmd->c_data_len);
cmd->c_lu->l_cmds_read++;
cmd->c_lu->l_sects_read +=
- cmd->c_data_len / 512;
+ cmd->c_data_len / 512;
bcopy(cmd->c_data,
(char *)lu->l_mmap + cmd->c_offset,
cmd->c_data_len);
cmd->c_lu->l_cmds_write++;
cmd->c_lu->l_sects_write +=
- cmd->c_data_len / 512;
+ cmd->c_data_len / 512;
lu->l_curr = NULL;
lu->l_curr_provo = False;
provo_err = 0;
@@ -1920,7 +1929,7 @@ lu_runner(void *v)
lu->l_num, errno);
}
provo_err = (cc == cmd->c_data_len) ?
- (void *)0 : (void *)1;
+ (void *)0 : (void *)1;
}
/*
* acknowledge this op and wait for next
@@ -2119,13 +2128,13 @@ lu_remove_cmds(msg_t *m, void *v)
static Boolean_t
load_params(t10_lu_common_t *lu, char *basedir)
{
- char file[MAXPATHLEN],
- *str;
+ char file[MAXPATHLEN];
+ char *str;
int oflags = O_RDWR|O_LARGEFILE|O_NDELAY;
Boolean_t mmap_lun = True;
tgt_node_t *node = NULL;
- int version_maj = XML_VERS_LUN_MAJ,
- version_min = XML_VERS_LUN_MIN;
+ int version_maj = XML_VERS_LUN_MAJ;
+ int version_min = XML_VERS_LUN_MIN;
/*
* Clean up from previous call to this function. This occurs if
@@ -2398,8 +2407,8 @@ fallocate(int fd, off64_t len)
static int
find_lu_by_num(const void *v1, const void *v2)
{
- t10_lu_impl_t *l1 = (t10_lu_impl_t *)v1,
- *l2 = (t10_lu_impl_t *)v2;
+ t10_lu_impl_t *l1 = (t10_lu_impl_t *)v1;
+ t10_lu_impl_t *l2 = (t10_lu_impl_t *)v2;
if (l1->l_targ_lun < l2->l_targ_lun)
return (-1);
@@ -2416,8 +2425,8 @@ find_lu_by_num(const void *v1, const void *v2)
static int
find_lu_by_guid(const void *v1, const void *v2)
{
- t10_lu_common_t *l1 = (t10_lu_common_t *)v1,
- *l2 = (t10_lu_common_t *)v2;
+ t10_lu_common_t *l1 = (t10_lu_common_t *)v1;
+ t10_lu_common_t *l2 = (t10_lu_common_t *)v2;
int i;
if (l1->l_guid_len != l2->l_guid_len) {
@@ -2445,8 +2454,8 @@ find_lu_by_guid(const void *v1, const void *v2)
static int
find_lu_by_targ(const void *v1, const void *v2)
{
- t10_lu_impl_t *l1 = (t10_lu_impl_t *)v1,
- *l2 = (t10_lu_impl_t *)v2;
+ t10_lu_impl_t *l1 = (t10_lu_impl_t *)v1;
+ t10_lu_impl_t *l2 = (t10_lu_impl_t *)v2;
if ((uint64_t)(uintptr_t)l1->l_targ < (uint64_t)(uintptr_t)l2->l_targ)
return (-1);
@@ -2465,8 +2474,8 @@ find_lu_by_targ(const void *v1, const void *v2)
static int
find_cmd_by_addr(const void *v1, const void *v2)
{
- uint64_t cmd1 = (uint64_t)(uintptr_t)v1,
- cmd2 = (uint64_t)(uintptr_t)v2;
+ uint64_t cmd1 = (uint64_t)(uintptr_t)v1;
+ uint64_t cmd2 = (uint64_t)(uintptr_t)v2;
if (cmd1 < cmd2)
return (-1);
diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.c b/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.c
index 35014c7469..5fd90a561c 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.c
+++ b/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.c
@@ -49,10 +49,21 @@
#include "t10.h"
#include "t10_spc.h"
+#include "t10_spc_pr.h"
#include "t10_sbc.h"
#include "utility.h"
/*
+ * External declarations
+ */
+Boolean_t spc_pr_read(t10_cmd_t *);
+void spc_cmd_pr_in(t10_cmd_t *, uint8_t *, size_t);
+void spc_cmd_pr_out(t10_cmd_t *, uint8_t *, size_t);
+void spc_cmd_pr_out_data(t10_cmd_t *, emul_handle_t, size_t, char *, size_t);
+void sbc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len);
+Boolean_t spc_pgr_check(t10_cmd_t *, uint8_t *);
+
+/*
* Forward declarations
*/
static int sbc_mmap_overlap(const void *v1, const void *v2);
@@ -60,7 +71,6 @@ static void sbc_overlap_store(disk_io_t *io);
static void sbc_overlap_free(disk_io_t *io);
static void sbc_overlap_check(disk_io_t *io);
static void sbc_overlap_flush(disk_params_t *d);
-static void sbc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len);
static void sbc_data(t10_cmd_t *cmd, emul_handle_t e, size_t offset,
char *data, size_t data_len);
static disk_io_t *sbc_io_alloc(t10_cmd_t *c);
@@ -171,22 +181,6 @@ sbc_per_init(t10_lu_impl_t *itl)
void
sbc_per_fini(t10_lu_impl_t *itl)
{
- disk_params_t *d = (disk_params_t *)itl->l_common->l_dtype_params;
- t10_lu_impl_t *lu;
-
- if (d->d_reserve_owner == itl) {
-
- /*
- * Since we currently own the reservation, drop it,
- * and restore everyone elses command pointer.
- */
- lu = avl_first(&itl->l_common->l_all_open);
- do {
- lu->l_cmd = sbc_cmd;
- lu = AVL_NEXT(&itl->l_common->l_all_open, lu);
- } while (lu != NULL);
- d->d_reserve_owner = NULL;
- }
}
/*
@@ -196,11 +190,19 @@ sbc_per_fini(t10_lu_impl_t *itl)
* | This routine is called from within the SAM-3 Task router.
* []----
*/
-static void
+void
sbc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
scsi_cmd_table_t *e;
+ /*
+ * Determine if thre is persistent data for this I_T_L Nexus
+ */
+ if (cmd->c_lu->l_pgr_read == False) {
+ spc_pr_read(cmd);
+ cmd->c_lu->l_pgr_read = True;
+ }
+
e = &cmd->c_lu->l_cmd_table[cdb[0]];
#ifdef FULL_DEBUG
queue_prt(mgmtq, Q_STE_IO, "SBC%x LUN%d Cmd %s id=%p\n",
@@ -215,34 +217,60 @@ sbc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
* | sbc_cmd_reserve -- Run commands when another I_T_L has a reservation
* []----
*/
-static void
+void
sbc_cmd_reserved(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
- scsi_cmd_table_t *e;
+ disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ sbc_reserve_t *res = &p->d_sbc_reserve;
+ Boolean_t conflict = False;
+ /*
+ * SPC-3, revision 23, Table 31
+ * SPC commands that are allowed in the presence of various reservations
+ */
switch (cdb[0]) {
- case SCMD_TEST_UNIT_READY:
case SCMD_INQUIRY:
- case SCMD_REPORT_LUNS:
case SCMD_LOG_SENSE_G1:
+ case SCMD_PERSISTENT_RESERVE_IN:
case SCMD_READ_MEDIA_SERIAL:
+ case SCMD_REPORT_LUNS:
case SCMD_REPORT_TARGET_PORT_GROUPS:
case SCMD_REQUEST_SENSE:
- /*
- * SPC-2, revision 20, Section 5.5.1 table 10
- * The specification allows these three commands
- * to run even through there's a reservation in place.
- */
- e = &cmd->c_lu->l_cmd_table[cdb[0]];
-#ifdef FULL_DEBUG
- queue_prt(mgmtq, Q_STE_IO, "RESERVED: SBC%x LUN%d Cmd %s\n",
- cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num,
- e->cmd_name == NULL ? "(no name)" : e->cmd_name);
-#endif
- (*e->cmd_start)(cmd, cdb, cdb_len);
+ case SCMD_TEST_UNIT_READY:
break;
-
default:
+ pthread_rwlock_rdlock(&res->res_rwlock);
+ switch (res->res_type) {
+ case RT_NONE:
+ /* conflict = False; */
+ break;
+ case RT_PGR:
+ conflict = spc_pgr_check(cmd, cdb);
+ break;
+ default:
+ conflict = True;
+ break;
+ }
+ pthread_rwlock_unlock(&res->res_rwlock);
+ }
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGR%x LUN%d CDB:%s - sbc_cmd_reserved(%s:%s)\n",
+ cmd->c_lu->l_targ->s_targ_num,
+ cmd->c_lu->l_common->l_num,
+ cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name == NULL
+ ? "(no name)"
+ : cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name,
+ res->res_type == RT_PGR ? "PGR" :
+ res->res_type == RT_NONE ? "" : "unknown",
+ conflict ? "Conflict" : "Allowed");
+
+ /*
+ * If no conflict at this point, allow command
+ */
+ if (conflict == False) {
+ sbc_cmd(cmd, cdb, cdb_len);
+ } else {
trans_send_complete(cmd, STATUS_RESERVATION_CONFLICT);
}
}
@@ -295,8 +323,8 @@ sbc_read(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
union scsi_cdb *u = (union scsi_cdb *)cdb;
diskaddr_t addr;
off_t offset = 0;
- uint32_t cnt,
- min;
+ uint32_t cnt;
+ uint32_t min;
disk_io_t *io;
void *mmap_data = T10_MMAP_AREA(cmd);
uint64_t err_blkno;
@@ -984,7 +1012,7 @@ sbc_msense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
* to contain it's size.
*/
mode_hdr->length = sizeof (struct mode_header) - 1 +
- MODE_BLK_DESC_LENGTH;
+ MODE_BLK_DESC_LENGTH;
mode_hdr->bdesc_length = MODE_BLK_DESC_LENGTH;
/*
@@ -1057,7 +1085,7 @@ sbc_msense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
sizeof (struct mode_geometry);
np = io->da_data + sizeof (*mode_hdr) +
- mode_hdr->bdesc_length;
+ mode_hdr->bdesc_length;
if (io->da_data_len < (sizeof (struct mode_format) +
sizeof (struct mode_geometry) +
sizeof (struct mode_cache_scsi3) +
@@ -1207,8 +1235,8 @@ sbc_service_actiong4(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
static void
sbc_read_capacity16(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
- uint64_t capacity,
- lba;
+ uint64_t capacity;
+ uint64_t lba;
int rep_size; /* response data size */
struct scsi_capacity_16 *cap16;
disk_params_t *d;
@@ -1245,9 +1273,9 @@ sbc_read_capacity16(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
}
lba = (uint64_t)cdb[2] << 56 | (uint64_t)cdb[3] << 48 |
- (uint64_t)cdb[4] << 40 | (uint64_t)cdb[5] << 32 |
- (uint64_t)cdb[6] << 24 | (uint64_t)cdb[7] << 16 |
- (uint64_t)cdb[8] << 8 | (uint64_t)cdb[9];
+ (uint64_t)cdb[4] << 40 | (uint64_t)cdb[5] << 32 |
+ (uint64_t)cdb[6] << 24 | (uint64_t)cdb[7] << 16 |
+ (uint64_t)cdb[8] << 8 | (uint64_t)cdb[9];
io = sbc_io_alloc(cmd);
@@ -1286,57 +1314,12 @@ sbc_read_capacity16(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
/*ARGSUSED*/
static void
-sbc_reserve(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
-{
- disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
- t10_lu_impl_t *lu;
-
- if (p == NULL)
- return;
-
- if (cdb[1] & 0xe0 || SAM_CONTROL_BYTE_RESERVED(cdb[5])) {
- spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
- spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
- trans_send_complete(cmd, STATUS_CHECK);
- return;
- }
-
- if ((p->d_reserve_owner != NULL) &&
- (p->d_reserve_owner != cmd->c_lu)) {
-
- trans_send_complete(cmd, STATUS_RESERVATION_CONFLICT);
- return;
-
- } else if (p->d_reserve_owner == cmd->c_lu) {
-
- /*
- * According SPC-2 revision 20, section 7.21.2
- * It shall be permissible for an initiator to
- * reserve a logic unit that is currently reserved
- * by that initiator
- */
- trans_send_complete(cmd, STATUS_GOOD);
- } else {
-
- lu = avl_first(&cmd->c_lu->l_common->l_all_open);
- do {
- if (lu != cmd->c_lu)
- lu->l_cmd = sbc_cmd_reserved;
- lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu);
- } while (lu != NULL);
- p->d_reserve_owner = cmd->c_lu;
- trans_send_complete(cmd, STATUS_GOOD);
- }
-}
-
-/*ARGSUSED*/
-static void
sbc_release(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
- disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ disk_params_t *d = (disk_params_t *)T10_PARAMS_AREA(cmd);
t10_lu_impl_t *lu;
- if (p == NULL)
+ if (d == NULL)
return;
if (cdb[1] & 0xe0 || cdb[3] || cdb[4] ||
@@ -1347,7 +1330,7 @@ sbc_release(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
return;
}
- if (p->d_reserve_owner == NULL) {
+ if (d->d_sbc_reserve.res_type == RT_NONE) {
/*
* If nobody is the owner this command is successful.
@@ -1365,7 +1348,11 @@ sbc_release(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
lu->l_cmd = sbc_cmd;
lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu);
} while (lu != NULL);
- p->d_reserve_owner = NULL;
+
+ /*
+ * Remove reservation
+ */
+ d->d_sbc_reserve.res_type == RT_NONE;
trans_send_complete(cmd, STATUS_GOOD);
}
@@ -1376,10 +1363,10 @@ sbc_verify(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
/*LINTED*/
union scsi_cdb *u = (union scsi_cdb *)cdb;
diskaddr_t addr;
- uint32_t cnt,
- chk_size;
- uint64_t sz,
- err_blkno;
+ uint32_t cnt;
+ uint32_t chk_size;
+ uint64_t sz;
+ uint64_t err_blkno;
Boolean_t bytchk;
char *chk_block;
disk_io_t *io;
@@ -1572,6 +1559,7 @@ sbc_verify_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data,
spc_sense_create(cmd, KEY_MISCOMPARE, 0);
spc_sense_ascq(cmd, SPC_ASC_DATA_PATH, SPC_ASCQ_DATA_PATH);
trans_send_complete(cmd, STATUS_CHECK);
+ free(on_disk_buf);
sbc_io_free(io);
return;
}
@@ -1579,6 +1567,7 @@ sbc_verify_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data,
spc_sense_create(cmd, KEY_MISCOMPARE, 0);
spc_sense_ascq(cmd, SPC_ASC_MISCOMPARE, SPC_ASCQ_MISCOMPARE);
trans_send_complete(cmd, STATUS_CHECK);
+ free(on_disk_buf);
sbc_io_free(io);
return;
}
@@ -1776,8 +1765,8 @@ sbc_io_free(emul_handle_t e)
static int
sbc_mmap_overlap(const void *v1, const void *v2)
{
- disk_io_t *d1 = (disk_io_t *)v1,
- *d2 = (disk_io_t *)v2;
+ disk_io_t *d1 = (disk_io_t *)v1;
+ disk_io_t *d2 = (disk_io_t *)v2;
if ((d1->da_data + d1->da_data_len) < d2->da_data)
return (-1);
@@ -1904,8 +1893,8 @@ static scsi_cmd_table_t lba_table[] = {
{ spc_unsupported, NULL, NULL, NULL },
{ spc_unsupported, NULL, NULL, NULL },
{ spc_mselect, spc_mselect_data, NULL, "MODE_SELECT" },
- { sbc_reserve, NULL, NULL, "RESERVE" },
- { sbc_release, NULL, NULL, "RELEASE" },
+ { spc_unsupported, NULL, NULL, NULL },
+ { spc_unsupported, NULL, NULL, NULL },
{ spc_unsupported, NULL, NULL, NULL },
{ spc_unsupported, NULL, NULL, NULL },
{ sbc_msense, NULL, NULL, "MODE_SENSE" },
@@ -1984,8 +1973,8 @@ static scsi_cmd_table_t lba_table[] = {
{ spc_unsupported, NULL, NULL, NULL },
{ spc_unsupported, NULL, NULL, NULL },
{ spc_unsupported, NULL, NULL, NULL },
- { spc_unsupported, NULL, NULL, "PERSISTENT_IN" },
- { spc_unsupported, NULL, NULL, "PERSISTENT_OUT" },
+ { spc_cmd_pr_in, NULL, NULL, "PERSISTENT_RESERVE_IN" },
+ { spc_cmd_pr_out, spc_cmd_pr_out_data, NULL, "PERSISTENT_RESERVE_OUT" },
/* 0x60 -- 0x6f */
{ spc_unsupported, NULL, NULL, NULL },
diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.h b/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.h
index 4e79c88f29..2a965b1159 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.h
+++ b/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -120,8 +120,7 @@ typedef struct disk_params {
Boolean_t d_fast_write;
t10_lu_state_t d_state;
-
- t10_lu_impl_t *d_reserve_owner;
+ sbc_reserve_t d_sbc_reserve;
} disk_params_t;
typedef struct disk_io {
diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_spc.c b/usr/src/cmd/iscsi/iscsitgtd/t10_spc.c
index e38cfd070d..9ffd1a8570 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_spc.c
+++ b/usr/src/cmd/iscsi/iscsitgtd/t10_spc.c
@@ -51,7 +51,7 @@
#include "t10_spc.h"
#include "target.h"
-static void spc_free(emul_handle_t id);
+void spc_free(emul_handle_t id);
/*
* []----
@@ -134,13 +134,13 @@ spc_request_sense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
void
spc_inquiry(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
- uint8_t *rsp_buf,
- *rbp; /* temporary var */
+ uint8_t *rsp_buf;
+ uint8_t *rbp; /* temporary var */
struct scsi_inquiry *inq;
- uint32_t len,
- page83_len,
- rqst_len,
- rtn_len;
+ uint32_t len;
+ uint32_t page83_len;
+ uint32_t rqst_len;
+ uint32_t rtn_len;
struct vpd_hdr *vhp;
struct vpd_desc vd;
size_t scsi_len;
@@ -188,7 +188,7 @@ spc_inquiry(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
*/
scsi_len = ((strlen(cmd->c_lu->l_targ->s_targ_base) + 1) + 3) & ~3;
page83_len = (sizeof (struct vpd_desc) * 6) + scsi_len +
- (lu->l_guid_len * 3) + (sizeof (uint32_t) * 2);
+ (lu->l_guid_len * 3) + (sizeof (uint32_t) * 2);
/*
* We always allocate enough space so that the code can create
@@ -396,8 +396,8 @@ spc_inquiry(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
bcopy(&vd, rbp, sizeof (vd));
rbp += sizeof (vd);
- rbp[2] = hibyte(loword(cmd->c_lu->l_targ->s_tp_grp));
- rbp[3] = lobyte(loword(cmd->c_lu->l_targ->s_tp_grp));
+ rbp[2] = hibyte(loword(cmd->c_lu->l_targ->s_tpgt));
+ rbp[3] = lobyte(loword(cmd->c_lu->l_targ->s_tpgt));
rbp += vd.len;
/* ---- VPD descriptor ---- */
@@ -588,16 +588,16 @@ spc_report_luns(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
int expected_data;
uint8_t *buf = NULL;
- int entries = 0,
- len,
- len_network,
- select,
- lun_idx,
- lun_val;
+ int entries = 0;
+ int len;
+ int len_network;
+ int select;
+ int lun_idx;
+ int lun_val;
char *str;
- tgt_node_t *targ,
- *lun_list,
- *lun;
+ tgt_node_t *targ;
+ tgt_node_t *lun_list;
+ tgt_node_t *lun;
/*
* SPC-3 Revision 21c section 6.21
@@ -702,9 +702,9 @@ spc_report_tpgs(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
rtpg_hdr_t *r;
rtpg_desc_t *dp;
rtpg_targ_desc_t *tp;
- int rqst_len,
- alloc_len,
- i;
+ int rqst_len;
+ int alloc_len;
+ int i;
t10_lu_common_t *lu = cmd->c_lu->l_common;
t10_lu_impl_t *lu_per;
@@ -778,8 +778,8 @@ spc_report_tpgs(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
tp = &dp->targ_list[0];
lu_per = avl_first(&lu->l_all_open);
do {
- tp->rel_tpi[0] = hibyte(loword(lu_per->l_targ->s_tp_grp));
- tp->rel_tpi[1] = lobyte(loword(lu_per->l_targ->s_tp_grp));
+ tp->rel_tpi[0] = hibyte(loword(lu_per->l_targ->s_tpgt));
+ tp->rel_tpi[1] = lobyte(loword(lu_per->l_targ->s_tpgt));
lu_per = AVL_NEXT(&lu->l_all_open, lu_per);
tp++;
} while (lu_per != NULL);
@@ -815,7 +815,7 @@ spc_send_diag(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
trans_send_complete(cmd, STATUS_GOOD);
}
-static void
+void
spc_free(emul_handle_t id)
{
free(id);
@@ -1139,14 +1139,13 @@ spc_encode_lu_addr(uint8_t *buf, int select_field, uint32_t lun)
* SAM-3 revision 14, Section 4.9.7.
* 14-bit flat address space.
*/
- buf[0] = SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE |
- (lun >> 8 & 0x3f);
+ buf[0] = SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE | (lun >> 8 & 0x3f);
buf[1] = lun & 0xff;
} else if (select_field == SCSI_REPORTLUNS_SELECT_ALL) {
buf[0] = SCSI_REPORTLUNS_ADDRESS_EXTENDED_UNIT |
- SCSI_REPORTLUNS_ADDRESS_EXTENDED_6B;
+ SCSI_REPORTLUNS_ADDRESS_EXTENDED_6B;
/*
* 32-bit limitation. This format should be able to
* handle a 40-bit LUN.
diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_spc.h b/usr/src/cmd/iscsi/iscsitgtd/t10_spc.h
index 810dd7174f..1fe897f2fa 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_spc.h
+++ b/usr/src/cmd/iscsi/iscsitgtd/t10_spc.h
@@ -20,15 +20,19 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#ifndef _SPC_H
-#define _SPC_H
+#ifndef _T10_SPC_H
+#define _T10_SPC_H
#pragma ident "%Z%%M% %I% %E% SMI"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* []------------------------------------------------------------------[]
* | SPC-3 |
@@ -98,33 +102,60 @@ Boolean_t spc_encode_lu_addr(uint8_t *buf, int select_field, uint32_t lun);
* | by the code. |
* []------------------------------------------------------------------[]
*/
-#define SPC_ASC_INVALID_CDB 0x24
-#define SPC_ASCQ_INVALID_CDB 0x00
-#define SPC_ASC_PWR_RESET 0x29
-#define SPC_ASCQ_PWR_RESET 0x00
-#define SPC_ASC_PWR_ON 0x29
-#define SPC_ASCQ_PWR_ON 0x01
-#define SPC_ASC_BUS_RESET 0x29
-#define SPC_ASCQ_BUS_RESET 0x02
#define SPC_ASC_FM_DETECTED 0x00 /* file-mark detected */
#define SPC_ASCQ_FM_DETECTED 0x01
+
#define SPC_ASC_EOP 0x00 /* end-of-partition/medium detected */
#define SPC_ASCQ_EOP 0x02
-#define SPC_ASC_WRITE_ERROR 0x0c
-#define SPC_ASCQ_WRITE_ERROR 0x00
-#define SPC_ASC_CAP_CHANGE 0x2a
-#define SPC_ASCQ_CAP_CHANGE 0x09
+
#define SPC_ASC_IN_PROG 0x04
#define SPC_ASCQ_IN_PROG 0x07
-#define SPC_ASC_DATA_PATH 0x41
-#define SPC_ASCQ_DATA_PATH 0x00
+
+#define SPC_ASC_WRITE_ERROR 0x0c
+#define SPC_ASCQ_WRITE_ERROR 0x00
+
+#define SPC_ASC_PARAM_LIST_LEN 0x1a /* Parameter List Length Error */
+#define SPC_ASCQ_PARAM_LIST_LEN 0x00
+
#define SPC_ASC_MISCOMPARE 0x1d
#define SPC_ASCQ_MISCOMPARE 0x00
+
#define SPC_ASC_INVALID_LU 0x20
#define SPC_ASCQ_INVALID_LU 0x09
+
#define SPC_ASC_BLOCK_RANGE 0x21
#define SPC_ASCQ_BLOCK_RANGE 0x00
+#define SPC_ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x26
+#define SPC_ASCQ_INVALID_FIELD_IN_PARAMETER_LIST 0x00
+
+#define SPC_ASC_INVALID_CDB 0x24
+#define SPC_ASCQ_INVALID_CDB 0x00
+
+#define SPC_ASC_PARAMETERS_CHANGED 0x2a
+#define SPC_ASCQ_RES_PREEMPTED 0x03
+#define SPC_ASCQ_RES_RELEASED 0x04
+
+#define SPC_ASC_PWR_RESET 0x29
+#define SPC_ASCQ_PWR_RESET 0x00
+
+#define SPC_ASC_PWR_ON 0x29
+#define SPC_ASCQ_PWR_ON 0x01
+
+#define SPC_ASC_BUS_RESET 0x29
+#define SPC_ASCQ_BUS_RESET 0x02
+
+#define SPC_ASC_CAP_CHANGE 0x2a
+#define SPC_ASCQ_CAP_CHANGE 0x09
+
+#define SPC_ASC_DATA_PATH 0x41
+#define SPC_ASCQ_DATA_PATH 0x00
+
+#define SPC_ASC_MEMORY_OUT_OF 0x55 /* Auxillary Memory Out Of Space */
+#define SPC_ASCQ_MEMORY_OUT_OF 0x00
+#define SPC_ASCQ_RESERVATION_FAIL 0x02
+
+
/*
* []------------------------------------------------------------------[]
* | SAM-3, revision 14, section 5.2 - Command descriptor block (CDB) |
@@ -417,4 +448,8 @@ struct mode_info_ctrl {
#define SCSI_REPORTLUNS_ADDRESS_EXTENDED_MASK 0x30
#define SCSI_REPORTLUNS_SELECT_ALL 0x02
-#endif /* _SPC_H */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _T10_SPC_H */
diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c b/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c
new file mode 100644
index 0000000000..99da20d627
--- /dev/null
+++ b/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c
@@ -0,0 +1,1913 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * []------------------------------------------------------------------[]
+ * | Implementation of SPC-3 Persistent Reserve emulation |
+ * []------------------------------------------------------------------[]
+ */
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/asynch.h>
+#include <sys/param.h>
+#include <sys/sysmacros.h>
+#include <strings.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <assert.h>
+
+#include <sys/scsi/generic/sense.h>
+#include <sys/scsi/generic/status.h>
+#include <sys/scsi/generic/inquiry.h>
+#include <sys/scsi/generic/mode.h>
+#include <sys/scsi/generic/commands.h>
+#include <sys/scsi/generic/persist.h>
+
+#include "t10.h"
+#include "t10_spc.h"
+#include "t10_spc_pr.h"
+#include "t10_sbc.h"
+#include "target.h"
+
+/*
+ * External declarations
+ */
+void spc_free(emul_handle_t id);
+void sbc_cmd(t10_cmd_t *, uint8_t *, size_t);
+void sbc_cmd_reserved(t10_cmd_t *, uint8_t *, size_t);
+
+extern target_queue_t *mgmtq;
+
+/*
+ * Forward declarations
+ */
+static
+ spc_pr_rsrv_t *spc_pr_rsrv_find(scsi3_pgr_t *, uint64_t, uint64_t, char *);
+static
+ spc_pr_rsrv_t *spc_pr_rsrv_alloc(scsi3_pgr_t *, uint64_t, uint64_t, char *,
+ uint8_t, uint8_t);
+static
+ spc_pr_key_t *spc_pr_key_find(scsi3_pgr_t *, uint64_t, uint64_t, char *);
+static
+ spc_pr_key_t *spc_pr_key_alloc(scsi3_pgr_t *, uint64_t, uint64_t, char *);
+
+static void spc_pr_rsrv_release(t10_cmd_t *, scsi3_pgr_t *, spc_pr_rsrv_t *);
+static void spc_pr_key_free(scsi3_pgr_t *, spc_pr_key_t *);
+static void spc_pr_rsrv_free(scsi3_pgr_t *, spc_pr_rsrv_t *);
+static void spc_pr_erase(scsi3_pgr_t *);
+static void spc_pr_key_rsrv_init(scsi3_pgr_t *);
+
+static int spc_pr_register(t10_cmd_t *, void *, size_t);
+static int spc_pr_reserve(t10_cmd_t *, void *, size_t);
+static int spc_pr_release(t10_cmd_t *, void *, size_t);
+static int spc_pr_clear(t10_cmd_t *, void *, size_t);
+static int spc_pr_preempt(t10_cmd_t *, void *, size_t);
+static int spc_pr_register_and_move(t10_cmd_t *, void *, size_t);
+
+static int spc_pr_in_readkeys(char *, scsi3_pgr_t *, void *, uint16_t);
+static int spc_pr_in_readrsrv(char *, scsi3_pgr_t *, void *, uint16_t);
+static int spc_pr_in_repcap(char *, scsi3_pgr_t *, void *, uint16_t);
+static int spc_pr_in_fullstat(char *, scsi3_pgr_t *, void *, uint16_t);
+
+static int spc_pgr_isconflict(uint8_t *, uint_t);
+Boolean_t spc_pr_write(t10_cmd_t *);
+
+/*
+ * []----
+ * | spc_pgr_check -- PERSISTENT_RESERVE {IN|OUT} check of I_T_L
+ * | Refer to SPC-3, Section ?.?, Tables ?? and ??
+ * []----
+ */
+Boolean_t
+spc_pgr_check(t10_cmd_t *cmd, uint8_t *cdb)
+{
+ disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ sbc_reserve_t *res = &p->d_sbc_reserve;
+ scsi3_pgr_t *pgr = &res->res_scsi_3_pgr;
+ spc_pr_rsrv_t *rsrv;
+ Boolean_t conflict = False;
+
+ /*
+ * Check reservation commands.
+ */
+ switch (cdb[0]) {
+ /*
+ * Always dis-allow these commands.
+ */
+ case SCMD_RESERVE:
+ case SCMD_RESERVE_G1:
+ case SCMD_RELEASE:
+ case SCMD_RELEASE_G1:
+ conflict = True;
+ goto done;
+
+ /*
+ * Always allow these commands.
+ */
+ case SCMD_PERSISTENT_RESERVE_IN:
+ case SCMD_PERSISTENT_RESERVE_OUT:
+ conflict = False;
+ goto done;
+ }
+
+ /*
+ * If no reservations exist, allow all remaining command types.
+ */
+ assert(res->res_type == RT_PGR);
+ if (pgr->pgr_numrsrv == 0) {
+ conflict = False;
+ goto done;
+ }
+
+ /*
+ * At this point we know there is at least one reservation.
+ * If there is no reservation set on this service delivery
+ * port then conflict all remaining command types.
+ */
+ if (!(rsrv = spc_pr_rsrv_find(pgr, 0, 0, T10_PGR_TID(cmd)))) {
+ queue_prt(mgmtq, Q_PR_IO, "PGR Reserved on other port\n",
+ "\t%016x:%s\n", T10_PGR_ISID(cmd), T10_PGR_TID(cmd));
+ conflict = True;
+ goto done;
+ }
+
+ /*
+ * Check the command against the reservation type for this port.
+ */
+ switch (rsrv->r_type) {
+ case PGR_TYPE_WR_EX:
+ case PGR_TYPE_EX_AC:
+ if (T10_PGR_ISID(cmd) == rsrv->r_isid)
+ conflict = False;
+ else
+ conflict = spc_pgr_isconflict(cdb,
+ rsrv->r_type);
+ break;
+ case PGR_TYPE_WR_EX_RO:
+ case PGR_TYPE_EX_AC_RO:
+ if (spc_pr_key_find(
+ pgr, 0, T10_PGR_ISID(cmd), T10_PGR_TID(cmd)))
+ conflict = False;
+ else
+ conflict = spc_pgr_isconflict(cdb,
+ rsrv->r_type);
+ break;
+ case PGR_TYPE_WR_EX_AR:
+ case PGR_TYPE_EX_AC_AR:
+ if (spc_pr_key_find(pgr, 0, 0, T10_PGR_TID(cmd)))
+ conflict = False;
+ else
+ conflict = spc_pgr_isconflict(cdb,
+ rsrv->r_type);
+ break;
+ default:
+ conflict = True;
+ break;
+ }
+
+done:
+ queue_prt(mgmtq, Q_PR_IO, "PGR%d LUN%d CDB:%s - spc_pgr_check(%s)\n",
+ cmd->c_lu->l_targ->s_targ_num,
+ cmd->c_lu->l_common->l_num,
+ cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name == NULL
+ ? "(no name)"
+ : cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name,
+ (conflict) ? "Conflict" : "Allowed");
+
+ return (conflict);
+}
+
+/*
+ * []----
+ * | spc_pgr_isconflict
+ * | PGR reservation conflict checking.
+ * | SPC-3, Revision 23, Table 31
+ * []----
+ */
+static int
+spc_pgr_isconflict(uint8_t *cdb, uint_t type)
+{
+ Boolean_t conflict = False;
+
+ switch (cdb[0]) {
+ case SCMD_FORMAT:
+ case SCMD_EXTENDED_COPY:
+ case SCMD_LOG_SELECT_G1:
+ case SCMD_MODE_SELECT:
+ case SCMD_MODE_SELECT_G1:
+ case SCMD_MODE_SENSE:
+ case SCMD_MODE_SENSE_G1:
+ case SCMD_READ_ATTRIBUTE:
+ case SCMD_READ_BUFFER:
+ case SCMD_GDIAG: /* SCMD_RECEIVE_DIAGNOSTIC_RESULTS */
+ case SCMD_SDIAG: /* SCMD_SEND_DIAGNOSTIC_RESULTS */
+ case SCMD_WRITE_ATTRIBUTE:
+ case SCMD_WRITE_BUFFER:
+ conflict = True;
+ break;
+
+ case SCMD_DOORLOCK: /* SCMD_PREVENT_ALLOW_MEDIA_REMOVAL */
+ /*
+ * As per SPC-3, Revision 23, Table 31
+ * (prevent <> 0)
+ */
+ conflict = (cdb[4] & 0x1) ? True: False;
+ break;
+
+ case SCMD_REPORT_TARGET_PORT_GROUPS: /* SCMD_REPORT_ */
+ /*
+ * As pee SPC-3, Revision 23, Section 6.23
+ */
+ switch ((cdb[1] & 0x03)) {
+ /* SCMD_REPORT_SUPPORTED_OPERATION_CODES */
+ case 0x0c:
+ /* SCMD_REPORT_SUPPORTED_MANAGEMENT_FUNCTIONS */
+ case 0x0d:
+
+ conflict = True;
+ break;
+ }
+ break;
+
+ case SCMD_SET_DEVICE:
+ /*
+ * SPC-3, Revision 23, Section 6.29
+ */
+ switch ((cdb[1] & 0x1F)) {
+ case SCMD_SET_DEVICE_IDENTIFIER:
+ case SCMD_SET_PRIORITY:
+ case SCMD_SET_TARGET_PORT_GROUPS:
+ case SCMD_SET_TIMESTAMP:
+ conflict = True;
+ break;
+ }
+ break;
+
+ case SCMD_READ:
+ case SCMD_READ_G1:
+ case SCMD_READ_G4:
+ if (type == PGR_TYPE_EX_AC || type == PGR_TYPE_EX_AC_RO)
+ conflict = True;
+ break;
+ }
+
+ return (conflict);
+}
+
+
+/*
+ * []----
+ * | spc_cmd_pr_in -- PERSISTENT_RESERVE IN
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+/*ARGSUSED*/
+void
+spc_cmd_pr_in(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
+{
+ scsi_cdb_prin_t *p_prin = (scsi_cdb_prin_t *)cdb;
+ disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ sbc_reserve_t *res = &p->d_sbc_reserve;
+ scsi3_pgr_t *pgr = &res->res_scsi_3_pgr;
+ uint16_t alen;
+ size_t len;
+ void *buf;
+ Boolean_t status;
+
+ /*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.11 PERSISTENCE RESERVE IN
+ * Need to generate a CHECK CONDITION with ILLEGAL REQUEST
+ * and INVALID FIELD IN CDB (0x24/0x00) if any of the following is
+ * true.
+ * (1) The SERVICE ACTION field is 004h - 01fh,
+ * (2) The reserved area in byte 1 is set,
+ * (3) The reserved area in bytes 2 thru 6 are set,
+ * (4) If any of the reserved bits in the CONTROL byte are set.
+ */
+ if ((p_prin->action >= 0x4) || p_prin->resbits || p_prin->resbytes[0] ||
+ p_prin->resbytes[1] || p_prin->resbytes[2] || p_prin->resbytes[3] ||
+ p_prin->resbytes[4] || p_prin->control) {
+ spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
+ spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
+ trans_send_complete(cmd, STATUS_CHECK);
+ return;
+ }
+
+ /*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.11 PERSISTENCE RESERVE IN
+ * Acquire ALLOCATION LENGTH from bytes 7, 8
+ * A zero(0) length allocation is not an error and we should just
+ * acknowledge the operation.
+ */
+ if ((alen = SCSI_READ16(p_prin->alloc_len)) == 0) {
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGR:%d LUN:%d CDB:%s - spc_cmd_pr_in, len = 0\n",
+ cmd->c_lu->l_targ->s_targ_num,
+ cmd->c_lu->l_common->l_num,
+ cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name == NULL
+ ? "(no name)"
+ : cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name);
+
+ trans_send_complete(cmd, STATUS_GOOD);
+ return;
+ }
+
+ /*
+ * Allocate space with an alignment that will work for any casting.
+ */
+ if ((buf = memalign(sizeof (void *), alen)) == NULL) {
+ /*
+ * Lack of memory is not fatal, just too busy
+ */
+ trans_send_complete(cmd, STATUS_BUSY);
+ return;
+ } else {
+ bzero(buf, alen);
+ }
+
+ /*
+ * Start processing, lock reservation
+ */
+ pthread_rwlock_rdlock(&res->res_rwlock);
+
+ /*
+ * Per SPC-3, Revision 23, Table 102, validate ranget of service actions
+ */
+ switch (p_prin->action) {
+ case PR_IN_READ_KEYS:
+ len = spc_pr_in_readkeys(
+ T10_PGR_TID(cmd), pgr, buf, alen);
+ break;
+ case PR_IN_READ_RESERVATION:
+ len = spc_pr_in_readrsrv(
+ T10_PGR_TID(cmd), pgr, buf, alen);
+ break;
+ case PR_IN_REPORT_CAPABILITIES:
+ len = spc_pr_in_repcap(
+ T10_PGR_TID(cmd), pgr, buf, alen);
+ break;
+ case PR_IN_READ_FULL_STATUS:
+ len = spc_pr_in_fullstat(
+ T10_PGR_TID(cmd), pgr, buf, alen);
+ break;
+ default:
+ pthread_rwlock_unlock(&res->res_rwlock);
+ spc_free(buf);
+
+ /*
+ * Fail command
+ */
+ spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
+ spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
+ trans_send_complete(cmd, STATUS_CHECK);
+ return;
+ }
+
+ /*
+ * Complete processing, unlock reservation
+ */
+ pthread_rwlock_unlock(&res->res_rwlock);
+
+ /*
+ * Now send the selected Persistent Reservation response back
+ */
+ if (trans_send_datain(cmd, buf, alen, 0, spc_free, True, buf) == False)
+ trans_send_complete(cmd, STATUS_BUSY);
+}
+
+/*
+ * []----
+ * | spc_pr_in_readkey -
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+static int
+spc_pr_in_readkeys(char *transportID, scsi3_pgr_t *pgr, void *bp,
+ uint16_t alloc_len)
+{
+ int i = 0, max_buf_keys, hsize;
+ scsi_prin_readrsrv_t *buf = (scsi_prin_readrsrv_t *)bp;
+ spc_pr_key_t *key;
+
+ hsize = sizeof (buf->PRgeneration) + sizeof (buf->add_len);
+ max_buf_keys = ((int)alloc_len - hsize) / sizeof (key->k_key);
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGRIN readkeys - transportID=%s\n", transportID);
+
+ if (pgr->pgr_numkeys)
+ for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd;
+ key != (spc_pr_key_t *)&pgr->pgr_keylist;
+ key = (spc_pr_key_t *)key->k_link.lnk_fwd) {
+
+ if (strcmp(key->k_transportID, transportID))
+ continue;
+
+ if (i < max_buf_keys)
+ SCSI_WRITE64(buf->res_key_list[i].reservation_key,
+ key->k_key);
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGRIN readkeys - key:%016x, isid:%016x\n",
+ key->k_key, key->k_isid);
+
+ i++;
+ }
+
+ SCSI_WRITE32(buf->add_len, i * sizeof (key->k_key));
+ SCSI_WRITE32(buf->PRgeneration, pgr->pgr_generation);
+
+ return (hsize + min(SCSI_READ32(buf->add_len),
+ (int)(max_buf_keys * sizeof (key->k_key))));
+}
+
+/*
+ * []----
+ * | spc_pr_in_readresv -
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+static int
+spc_pr_in_readrsrv(
+ char *transportID, scsi3_pgr_t *pgr, void *bp, uint16_t alloc_len)
+{
+ int i = 0, max_buf_rsrv, hsize;
+ spc_pr_rsrv_t *rsrv;
+ scsi_prin_readrsrv_t *buf = (scsi_prin_readrsrv_t *)bp;
+
+ hsize = sizeof (buf->PRgeneration) + sizeof (buf->add_len);
+ max_buf_rsrv = ((int)alloc_len - hsize) / sizeof (scsi_prin_rsrvdesc_t);
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGRIN readrsrv - transportID=%s\n", transportID);
+
+ if (pgr->pgr_numrsrv)
+ for (rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd;
+ rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist;
+ rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd) {
+
+ if (strcmp(rsrv->r_transportID, transportID))
+ continue;
+
+ if (i < max_buf_rsrv) {
+ SCSI_WRITE64(buf->res_key_list[i].reservation_key,
+ rsrv->r_key);
+ buf->res_key_list[i].scope = rsrv->r_scope;
+ buf->res_key_list[i].type = rsrv->r_type;
+ }
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGRIN readrsrv - "
+ "key:%016x isid:%016x scope:%d type:%d \n",
+ rsrv->r_key, rsrv->r_isid, rsrv->r_scope, rsrv->r_type);
+
+ i++;
+ }
+
+ SCSI_WRITE32(buf->add_len, i * sizeof (scsi_prin_rsrvdesc_t));
+ SCSI_WRITE32(buf->PRgeneration, pgr->pgr_generation);
+
+ return (hsize + min(SCSI_READ32(buf->add_len),
+ (int)(max_buf_rsrv * sizeof (scsi_prin_rsrvdesc_t))));
+}
+
+/*
+ * []----
+ * | spc_pr_in_repcap -
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+/*
+ */
+static int
+spc_pr_in_repcap(
+ char *transportID, scsi3_pgr_t *pgr, void *bp, uint16_t alloc_len)
+{
+ scsi_prin_rpt_cap_t *buf = (scsi_prin_rpt_cap_t *)bp;
+
+ buf->crh = 0; /* Supports Reserve / Release */
+ buf->sip_c = 1; /* Specify Initiator Ports Capable */
+ buf->atp_c = 1; /* All Target Ports Capable */
+ buf->ptpl_c = 1; /* Persist Through Power Loss C */
+ buf->tmv = 1; /* Type Mask Valid */
+ buf->ptpl_a = pgr_persist; /* Persist Though Power Loss Active */
+ buf->pr_type.wr_ex = 1; /* Write Exclusve */
+ buf->pr_type.ex_ac = 1; /* Exclusive Access */
+ buf->pr_type.wr_ex_ro = 1; /* Write Exclusive Registrants Only */
+ buf->pr_type.ex_ac_ro = 1; /* Exclusive Access Registrants Only */
+ buf->pr_type.wr_ex_ar = 1; /* Write Exclusive All Registrants */
+ buf->pr_type.ex_ac_ar = 1; /* Exclusive Access All Registrants */
+
+ SCSI_WRITE16(buf->length, sizeof (scsi_prin_rpt_cap_t));
+
+ return (sizeof (scsi_prin_rpt_cap_t));
+}
+
+/*
+ * []----
+ * | spc_pr_in_fullstat -
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+/*
+ */
+static int
+spc_pr_in_fullstat(
+ char *transportID, scsi3_pgr_t *pgr, void *bp, uint16_t alloc_len)
+{
+ int i = 0, max_buf_rsrv, hsize;
+ spc_pr_rsrv_t *rsrv;
+ scsi_prin_full_status_t *buf = (scsi_prin_full_status_t *)bp;
+
+ hsize = sizeof (buf->PRgeneration) + sizeof (buf->add_len);
+ max_buf_rsrv = ((int)alloc_len - hsize) /
+ sizeof (scsi_prin_full_status_t);
+
+ if (pgr->pgr_numrsrv)
+ for (i = 0, rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd;
+ rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist;
+ rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd) {
+
+ if (i < max_buf_rsrv) {
+ SCSI_WRITE64(buf->full_desc[i].reservation_key,
+ rsrv->r_key);
+ buf->full_desc[i].all_tg_pt = 1;
+ buf->full_desc[i].r_holder =
+ strcmp(rsrv->r_transportID, transportID) ? 0 : 1;
+ buf->full_desc[i].scope = rsrv->r_scope;
+ buf->full_desc[i].type = rsrv->r_type;
+ SCSI_WRITE16(buf->full_desc[i].rel_tgt_port_id, 0);
+ SCSI_WRITE32(buf->full_desc[i].add_len,
+ sizeof (scsi_transport_id_t));
+ buf->full_desc[i].trans_id.protocol_id =
+ iSCSI_PROTOCOL_ID;
+ buf->full_desc[i].trans_id.format_code =
+ WW_UID_DEVICE_NAME;
+ SCSI_WRITE16(buf->full_desc[i].trans_id.add_len, 0);
+ sprintf(buf->full_desc[i].trans_id.iscsi_name, "");
+ }
+
+ i++;
+ }
+
+ SCSI_WRITE32(buf->add_len, i * sizeof (scsi_prin_rsrvdesc_t));
+ SCSI_WRITE32(buf->PRgeneration, pgr->pgr_generation);
+
+ return (hsize + min(SCSI_READ32(buf->add_len),
+ (int)(max_buf_rsrv * sizeof (scsi_prin_rsrvdesc_t))));
+
+}
+
+/*
+ * []----
+ * | spc_cmd_pr_out -- PERSISTENT_RESERVE OUT
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+/*ARGSUSED*/
+void
+spc_cmd_pr_out(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
+{
+ scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cdb;
+ disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ sbc_reserve_t *res = &p->d_sbc_reserve;
+ size_t len;
+ void *buf;
+
+ /*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.12 PERSISTENCE RESERVE OUT
+ * Need to generate a CHECK CONDITION with ILLEGAL REQUEST
+ * and INVALID FIELD IN CDB (0x24/0x00) if any of the following is
+ * true.
+ * (1) The SERVICE ACTION field is 008h - 01fh,
+ * (2) The reserved area in byte 1 is set,
+ * (3) The TYPE and SCOPE fields are invalid,
+ * (4) The reserved area in bytes 3 and 4 are set,
+ * (5) If any of the reserved bits in the CONTROL byte are set.
+ */
+ if ((p_prout->action >= 0x8) || p_prout->resbits ||
+ (p_prout->type >= 0x9) ||
+ (p_prout->scope >= 0x3) || p_prout->control) {
+ spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
+ spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
+ trans_send_complete(cmd, STATUS_CHECK);
+ return;
+ }
+
+ /*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.12 PERSISTENCE RESERVE OUT
+ * Acquire ALLOCATION LENGTH from bytes 5 thru 8
+ */
+ len = SCSI_READ32(p_prout->param_len);
+
+ /*
+ * Parameter list length shall contain 24 (0x18),
+ * the SPEC_I_PIT is zero (it is because we don't support SIP_C))
+ * the service action is not REGISTER AND MOVE
+ */
+ if ((p_prout->action != PR_OUT_REGISTER_MOVE) && (len != 24)) {
+ spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
+ spc_sense_ascq(cmd, SPC_ASC_PARAM_LIST_LEN, 0x00);
+ trans_send_complete(cmd, STATUS_CHECK);
+ return;
+ }
+
+ /*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.11.3.3 Persistent Reservation Scope
+ * SCOPE field shall be set to LU_SCOPE
+ */
+ if (p_prout->scope != PR_LU_SCOPE) {
+ pthread_rwlock_unlock(&res->res_rwlock);
+ spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
+ spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
+ trans_send_complete(cmd, STATUS_CHECK);
+ return;
+ }
+
+ /*
+ * Allocate space with an alignment that will work for any casting.
+ */
+ if ((buf = memalign(sizeof (void *), len)) == NULL) {
+ /*
+ * Lack of memory is not fatal, just too busy
+ */
+ trans_send_complete(cmd, STATUS_BUSY);
+ return;
+ }
+
+ /*
+ * Now request the Persistent Reserve OUT parameter list
+ */
+ if (trans_rqst_dataout(cmd, buf, len, 0, buf, spc_free) == False)
+ trans_send_complete(cmd, STATUS_BUSY);
+}
+
+/*
+ * []----
+ * | spc_cmd_pr_out_data -- DataIn phase of PERSISTENT_RESERVE OUT command
+ * []----
+ */
+/*ARGSUSED*/
+void
+spc_cmd_pr_out_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data,
+ size_t data_len)
+{
+ scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb;
+ disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data;
+ sbc_reserve_t *res = &p->d_sbc_reserve;
+ scsi3_pgr_t *pgr = &res->res_scsi_3_pgr;
+ t10_lu_impl_t *lu;
+ int status;
+
+ /*
+ * If this is the first time using the persistance data,
+ * initialize the reservation and resource key queues
+ */
+ pthread_rwlock_wrlock(&res->res_rwlock);
+ if (pgr->pgr_rsrvlist.lnk_fwd == NULL) {
+ spc_pr_key_rsrv_init(pgr);
+ }
+
+ /*
+ * Now process the action.
+ */
+ switch (p_prout->action) {
+ case PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY:
+ case PR_OUT_REGISTER:
+ /*
+ * PR_OUT_REGISTER_IGNORE differs from PR_OUT_REGISTER
+ * in that the reservation_key is ignored.
+ */
+ status = spc_pr_register(cmd, data, data_len);
+ break;
+
+ case PR_OUT_RESERVE:
+ status = spc_pr_reserve(cmd, data, data_len);
+ break;
+
+ case PR_OUT_RELEASE:
+ status = spc_pr_release(cmd, data, data_len);
+ break;
+
+ case PR_OUT_CLEAR:
+ status = spc_pr_clear(cmd, data, data_len);
+ break;
+
+ case PR_OUT_PREEMPT_ABORT:
+ case PR_OUT_PREEMPT:
+ /*
+ * PR_OUT_PREEMPT_ABORT differs from PR_OUT_PREEMPT
+ * in that all current acitivy for the preempted
+ * Initiators will be terminated.
+ */
+ status = spc_pr_preempt(cmd, data, data_len);
+ break;
+
+ case PR_OUT_REGISTER_MOVE:
+ /*
+ * PR_OUT_REGISTER_MOVE registers a key for another I_T
+ */
+ status = spc_pr_register_and_move(cmd, data, data_len);
+ break;
+ }
+
+ /*
+ * Check status of action performed.
+ */
+ if (status == STATUS_CHECK) {
+ /*
+ * Check condition required.
+ */
+ pthread_rwlock_unlock(&res->res_rwlock);
+ spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
+ spc_sense_ascq(cmd, cmd->c_lu->l_asc, cmd->c_lu->l_ascq);
+ trans_send_complete(cmd, STATUS_CHECK);
+ return;
+ }
+
+ /*
+ * Handle Failed processing status
+ */
+ if (status != STATUS_GOOD) {
+ pthread_rwlock_unlock(&res->res_rwlock);
+ trans_send_complete(cmd, status);
+ return;
+ }
+
+ /*
+ * Successful, bump the PRgeneration value
+ */
+ if (p_prout->action != PR_OUT_RESERVE &&
+ p_prout->action != PR_OUT_RELEASE)
+ pgr->pgr_generation++;
+
+ /*
+ * If Activate Persist Through Power Loss (APTPL) is set, persist
+ * this PGR data on disk
+ */
+ if (plist->aptpl || pgr->pgr_aptpl)
+ spc_pr_write(cmd);
+
+ /*
+ * When the last registration is removed, PGR is no longer
+ * active and we must reset the reservation type.
+ */
+ if (pgr->pgr_numkeys == 0 && pgr->pgr_numrsrv == 0) {
+ res->res_type = RT_NONE;
+ pgr->pgr_aptpl = 0;
+ } else {
+ res->res_type = RT_PGR;
+ }
+
+ /*
+ * Set the command dispatcher according to the reservation type
+ */
+ lu = avl_first(&cmd->c_lu->l_common->l_all_open);
+ do {
+ lu->l_cmd = (res->res_type == RT_NONE)
+ ? sbc_cmd
+ : sbc_cmd_reserved;
+ lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu);
+ } while (lu != NULL);
+
+ queue_prt(mgmtq, Q_PR_IO, "PGROUT:%d LUN:%d action:%s\n",
+ cmd->c_lu->l_targ->s_targ_num,
+ cmd->c_lu->l_common->l_num,
+ (p_prout->action == PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY)
+ ? "Register & ignore existing key"
+ : (p_prout->action == PR_OUT_REGISTER)
+ ? "Register"
+ : (p_prout->action == PR_OUT_RESERVE)
+ ? "Reserve"
+ : (p_prout->action == PR_OUT_RELEASE)
+ ? "Release"
+ : (p_prout->action == PR_OUT_CLEAR)
+ ? "Clear"
+ : (p_prout->action == PR_OUT_PREEMPT_ABORT)
+ ? "Preempt & abort"
+ : (p_prout->action == PR_OUT_PREEMPT)
+ ? "Preempt"
+ : (p_prout->action == PR_OUT_REGISTER_MOVE)
+ ? "Register & move"
+ : "Uknown");
+
+ /*
+ * Processing is complete, release mutex
+ */
+ pthread_rwlock_unlock(&res->res_rwlock);
+
+ /*
+ * Send back a succesful response
+ */
+ trans_send_complete(cmd, STATUS_GOOD);
+}
+
+/*
+ * []----
+ * | spc_pr_register
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+static int
+spc_pr_register(t10_cmd_t *cmd, void *data, size_t data_len)
+{
+ scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb;
+ scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data;
+ disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ sbc_reserve_t *res = &p->d_sbc_reserve;
+ scsi3_pgr_t *pgr = &res->res_scsi_3_pgr;
+ spc_pr_rsrv_t *rsrv;
+ spc_pr_key_t *key;
+ uint64_t reservation_key;
+ uint64_t service_key;
+ t10_lu_impl_t *lu;
+ t10_targ_impl_t *ti;
+
+ /*
+ * Validate Persistent Reserver Out parameter list
+ */
+ if (plist->obsolete1[0] || plist->obsolete1[1] ||
+ plist->obsolete1[2] || plist->obsolete1[3] ||
+ plist->resbits1 || plist->resbits2 || plist->resbytes1 ||
+ plist->obsolete2[0] || plist->obsolete2[1]) {
+ cmd->c_lu->l_status = KEY_ILLEGAL_REQUEST;
+ cmd->c_lu->l_asc = SPC_ASC_INVALID_CDB;
+ cmd->c_lu->l_ascq = 0;
+ return (STATUS_CHECK);
+ }
+
+ /*
+ * Determine if Activate Persist Trhough Power Loss (APTPL)
+ * is valid for this device server.
+ */
+ if (plist->aptpl && (pgr_persist == 0)) {
+ /* pgr - define SCSI-3 error codes */
+ cmd->c_lu->l_status = KEY_ILLEGAL_REQUEST;
+ cmd->c_lu->l_asc = SPC_ASC_INVALID_FIELD_IN_PARAMETER_LIST;
+ cmd->c_lu->l_ascq = 0;
+ return (STATUS_CHECK);
+ }
+
+ /*
+ * Get reservation values
+ */
+ reservation_key = SCSI_READ64(plist->reservation_key);
+ service_key = SCSI_READ64(plist->service_key);
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: register reservation:%016x, key:%016x\n",
+ reservation_key, service_key);
+
+ /*
+ * We may need register all initiators, depending on ALL_TG_TP
+ */
+ lu = avl_first(&cmd->c_lu->l_common->l_all_open);
+ do {
+ /*
+ * Find specified key
+ */
+ ti = lu->l_targ;
+ key = spc_pr_key_find(pgr, 0, ti->s_isid, ti->s_transportID);
+ if (key) {
+ /*
+ * What about ALL_TG_TP?
+ */
+ if (plist->all_tg_pt ||
+ (key->k_isid == T10_PGR_ISID(cmd))) {
+
+ if (p_prout->action == PR_OUT_REGISTER &&
+ key->k_key != reservation_key) {
+ /*
+ * The Initiator did not specify the
+ * existing key. Reservation conflict.
+ */
+ return (STATUS_RESERVATION_CONFLICT);
+ }
+ /*
+ * Change existing key ?
+ */
+ if (service_key) {
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: change "
+ "old:%016x = new:%016x\n",
+ key->k_key, service_key);
+
+ /*
+ * Overwrite (change) key
+ */
+ key->k_key = service_key;
+
+ } else {
+ /*
+ * Remove existing key
+ * NOTE: If we own the reservation then
+ * we must release it.
+ */
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: delete "
+ "old:%016x = new:%016x\n",
+ key->k_key, service_key);
+
+ rsrv = spc_pr_rsrv_find(pgr, 0,
+ ti->s_isid, ti->s_transportID);
+ if (rsrv) {
+ spc_pr_rsrv_release(
+ cmd, pgr, rsrv);
+ spc_pr_key_free(pgr, key);
+ }
+ }
+ }
+ } else {
+ /*
+ * What about ALL_TG_TP?
+ */
+ if (plist->all_tg_pt ||
+ (ti->s_isid == T10_PGR_ISID(cmd))) {
+ /*
+ * Process request from un-registered Initiator.
+ */
+ if ((p_prout->action == PR_OUT_REGISTER) &&
+ (reservation_key || service_key == 0)) {
+ /*
+ * Unregistered initiator is attempting
+ * to modify a key.
+ */
+ return (STATUS_RESERVATION_CONFLICT);
+ }
+
+ /*
+ * Allocate new key.
+ */
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: new:%016x\n", service_key);
+
+ key = spc_pr_key_alloc(pgr, service_key,
+ ti->s_isid, ti->s_transportID);
+ if (key == NULL) {
+ /* pgr - define SCSI-3 error codes */
+ cmd->c_lu->l_status =
+ KEY_ABORTED_COMMAND;
+ cmd->c_lu->l_asc =
+ SPC_ASC_MEMORY_OUT_OF;
+ cmd->c_lu->l_ascq =
+ SPC_ASCQ_RESERVATION_FAIL;
+ return (STATUS_CHECK);
+ }
+ }
+ }
+ lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu);
+ } while (lu != NULL);
+
+ /*
+ * Apply the last valid APTPL bit
+ * SPC-3, Revision 23
+ * Section 5.6.4.1 Preserving persistent reservervations and
+ * registrations through power loss
+ */
+ pgr->pgr_aptpl = plist->aptpl;
+
+ return (STATUS_GOOD);
+}
+
+/*
+ * []----
+ * | spc_pr_reserve
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+/* ARGSUSED */
+static int
+spc_pr_reserve(t10_cmd_t *cmd, void *data, size_t data_len)
+{
+ scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb;
+ disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ sbc_reserve_t *res = &p->d_sbc_reserve;
+ scsi3_pgr_t *pgr = &res->res_scsi_3_pgr;
+ spc_pr_rsrv_t *rsrv;
+ scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data;
+ uint64_t reservation_key;
+ int status;
+
+ /*
+ * Do not allow an unregistered initiator to
+ * make a reservation.
+ */
+ reservation_key = SCSI_READ64(plist->reservation_key);
+ if (!spc_pr_key_find(
+ pgr, reservation_key, T10_PGR_ISID(cmd), T10_PGR_TID(cmd))) {
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: reserve reservation:%016x not found\n",
+ reservation_key);
+
+ return (STATUS_RESERVATION_CONFLICT);
+ } else {
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: reserve reservation:%016x\n", reservation_key);
+
+ }
+
+ /*
+ * See if there is a reservation on this port by
+ * another Initiator. There can be only one LU_SCOPE
+ * reservation per ITL. We do not support extents.
+ */
+ if (rsrv = spc_pr_rsrv_find(pgr, 0, 0, T10_PGR_TID(cmd))) {
+ if (rsrv->r_isid != T10_PGR_ISID(cmd)) {
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: reserve %016x != %016x:%s\n",
+ rsrv->r_isid, T10_PGR_ISID(cmd),
+ T10_PGR_TID(cmd));
+
+ return (STATUS_RESERVATION_CONFLICT);
+ }
+ }
+
+ /*
+ * At this point there is either no reservation or the
+ * reservation is held by this Initiator.
+ */
+ if (rsrv != NULL) {
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT reserve(+) - transportID=%s\n"
+ "\tkey:%016x isid:%016x scope:%d type:%d \n",
+ rsrv->r_transportID, rsrv->r_key, rsrv->r_isid,
+ rsrv->r_scope, rsrv->r_type);
+
+ /*
+ * An Initiator cannot re-reserve. It must first
+ * release. But if its' type and scope match then
+ * return STATUS_GOOD.
+ */
+ if (rsrv->r_type == p_prout->type &&
+ rsrv->r_scope == p_prout->scope) {
+ status = STATUS_GOOD;
+ } else {
+ status = STATUS_RESERVATION_CONFLICT;
+ }
+ } else {
+ /*
+ * No reservation exists. Establish a new one.
+ */
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT reserve - transportID=%s\n"
+ "\tkey:%016x isid:%016x scope:%d type:%d \n",
+ T10_PGR_TID(cmd), reservation_key, T10_PGR_ISID(cmd),
+ p_prout->scope, p_prout->type);
+
+ rsrv = spc_pr_rsrv_alloc(pgr, reservation_key,
+ T10_PGR_ISID(cmd), T10_PGR_TID(cmd),
+ p_prout->scope, p_prout->type);
+ if (rsrv == NULL) {
+ cmd->c_lu->l_status = KEY_ABORTED_COMMAND;
+ cmd->c_lu->l_asc = SPC_ASC_MEMORY_OUT_OF;
+ cmd->c_lu->l_ascq = SPC_ASCQ_RESERVATION_FAIL;
+ status = STATUS_CHECK;
+ } else {
+ status = STATUS_GOOD;
+ }
+ }
+
+ return (status);
+}
+
+/*
+ * []----
+ * | spc_pr_release
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+static int
+spc_pr_release(t10_cmd_t *cmd, void *data, size_t data_len)
+{
+ scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb;
+ disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ sbc_reserve_t *res = &p->d_sbc_reserve;
+ scsi3_pgr_t *pgr = &res->res_scsi_3_pgr;
+ spc_pr_rsrv_t *rsrv;
+ scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data;
+ uint64_t reservation_key;
+ int status;
+
+ /*
+ * Do not allow an unregistered initiator to attempting to
+ * release a reservation.
+ */
+ reservation_key = SCSI_READ64(plist->reservation_key);
+ if (!spc_pr_key_find(
+ pgr, reservation_key, T10_PGR_ISID(cmd), T10_PGR_TID(cmd))) {
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: release reservation:%016x not found\n",
+ reservation_key);
+
+ return (STATUS_RESERVATION_CONFLICT);
+ } else {
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: release reservation:%016x\n", reservation_key);
+ }
+
+ if (!(rsrv = spc_pr_rsrv_find(
+ pgr, 0, T10_PGR_ISID(cmd), T10_PGR_TID(cmd)))) {
+ /*
+ * Releasing a non-existent reservation is allowed.
+ */
+ status = STATUS_GOOD;
+
+ } else if (p_prout->scope != rsrv->r_scope ||
+ p_prout->type != rsrv->r_type ||
+ reservation_key != rsrv->r_key) {
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT release failed - transportID=%s\n"
+ "\tkey:%016x isid:%016x scope:%d type:%d \n",
+ T10_PGR_TID(cmd), reservation_key, T10_PGR_ISID(cmd),
+ p_prout->scope, p_prout->type);
+
+ /*
+ * Scope and key must match to release.
+ */
+ cmd->c_lu->l_status = KEY_ILLEGAL_REQUEST;
+ cmd->c_lu->l_asc = SPC_ASC_PARAMETERS_CHANGED;
+ cmd->c_lu->l_ascq = SPC_ASCQ_RES_RELEASED;
+ status = STATUS_CHECK;
+ } else {
+ /*
+ * Now release the reservation.
+ */
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT release - transportID=%s\n"
+ "\tkey:%016x isid:%016x scope:%d type:%d \n",
+ rsrv->r_transportID, rsrv->r_key, rsrv->r_isid,
+ rsrv->r_scope, rsrv->r_type);
+
+ spc_pr_rsrv_release(cmd, pgr, rsrv);
+ status = STATUS_GOOD;
+ }
+
+ return (status);
+}
+
+/*
+ * []----
+ * | spc_pr_preempt
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+/* ARGSUSED */
+static int
+spc_pr_preempt(t10_cmd_t *cmd, void *data, size_t data_len)
+{
+ scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb;
+ t10_lu_impl_t *lu;
+ disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ sbc_reserve_t *res = &p->d_sbc_reserve;
+ scsi3_pgr_t *pgr = &res->res_scsi_3_pgr;
+ scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data;
+ uint64_t reservation_key;
+ uint64_t service_key;
+ spc_pr_key_t *key;
+ spc_pr_rsrv_t *rsrv;
+ int status = STATUS_GOOD;
+
+ /*
+ * Get reservation values
+ */
+ reservation_key = SCSI_READ64(plist->reservation_key);
+ service_key = SCSI_READ64(plist->service_key);
+
+
+ /*
+ * Initiator must be registered and service key (preempt key)
+ * must exist.
+ */
+ if ((!(key = spc_pr_key_find(pgr, service_key, 0, ""))) ||
+ (!(rsrv = spc_pr_rsrv_find(pgr, reservation_key,
+ T10_PGR_ISID(cmd), "")))) {
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: preempt failed reservation:%016x, key:%016x\n",
+ reservation_key, service_key);
+
+ return (STATUS_RESERVATION_CONFLICT);
+ } else {
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: preempt reservation:%016x, key:%016x\n",
+ reservation_key, service_key);
+ }
+
+ /*
+ * Preempt all keys matching service action key and free
+ * the associated structures. Do not set UNIT_ATTN for
+ * the Initiator which requested the action.
+ *
+ * Unlike the other Persistent Reservation commands, the preempt,
+ * preempt_and_abort and clear actions are service delivery port
+ * independent. So we remove matching keys across ports.
+ */
+ for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd;
+ key != (spc_pr_key_t *)&pgr->pgr_keylist;
+ key = (spc_pr_key_t *)key->k_link.lnk_fwd) {
+
+ /* Skip non-matching keys */
+ if (key->k_key != service_key)
+ continue;
+
+ /* Remove the registration key. */
+ spc_pr_key_free(pgr, key);
+
+ /* Do not set UNIT ATTN for calling Initiator */
+ if (key->k_isid == T10_PGR_ISID(cmd))
+ continue;
+
+ /*
+ * Find associated I_T Nexuses
+ */
+ lu = avl_first(&cmd->c_lu->l_common->l_all_open);
+ do {
+ lu->l_cmd = sbc_cmd;
+ lu->l_status = KEY_UNIT_ATTENTION;
+ lu->l_asc = SPC_ASC_PARAMETERS_CHANGED;
+ lu->l_ascq = SPC_ASCQ_RES_PREEMPTED;
+ lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu);
+ } while (lu != NULL);
+
+ /*
+ * Is this the preempt and abort?
+ */
+ if (p_prout->action == PR_OUT_PREEMPT_ABORT) {
+ queue_message_set(
+ cmd->c_lu->l_common->l_from_transports,
+ Q_HIGH, msg_reset_lu, (void *)cmd->c_lu);
+ }
+ }
+
+ /*
+ * Re-establish our registration key if we preempted it.
+ */
+ if (!(key = spc_pr_key_find(
+ pgr, reservation_key, T10_PGR_ISID(cmd), T10_PGR_TID(cmd)))) {
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: preempt - register:%016x, isid:%016x:%s\n",
+ reservation_key, T10_PGR_ISID(cmd), T10_PGR_TID(cmd));
+
+ key = spc_pr_key_alloc(pgr, reservation_key,
+ T10_PGR_ISID(cmd), T10_PGR_TID(cmd));
+ }
+
+ /*
+ * Now look for a matching reservation to preempt.
+ */
+ for (rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd;
+ rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist;
+ rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd) {
+
+ /* Skip non-matching keys */
+ if (rsrv->r_key != service_key)
+ continue;
+
+ /*
+ * Remove matching reservations on other ports
+ * and establish a new reservation on this port only.
+ * To change the fuctionality to preempt rather than
+ * delete the reservations on other ports just remove
+ * the following block of code.
+ */
+ if (strcmp(rsrv->r_transportID, T10_PGR_TID(cmd))) {
+ spc_pr_rsrv_free(pgr, rsrv);
+ continue;
+ }
+
+ rsrv->r_key = reservation_key;
+ rsrv->r_isid = T10_PGR_ISID(cmd);
+ rsrv->r_scope = p_prout->scope;
+ rsrv->r_type = p_prout->type;
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT preempt - transportID=%s\n"
+ "\tkey:%016x isid:%016x scope:%d type:%d \n",
+ rsrv->r_transportID, rsrv->r_key, rsrv->r_isid,
+ rsrv->r_scope, rsrv->r_type);
+ }
+
+ return (status);
+}
+
+/*
+ * []----
+ * | spc_pr_clear
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+/* ARGSUSED */
+static int
+spc_pr_clear(t10_cmd_t *cmd, void *data, size_t data_len)
+{
+ scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb;
+ disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ sbc_reserve_t *res = &p->d_sbc_reserve;
+ scsi3_pgr_t *pgr = &res->res_scsi_3_pgr;
+ scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data;
+ uint64_t reservation_key;
+ spc_pr_key_t *key;
+ t10_targ_impl_t *tp;
+ t10_lu_impl_t *lu;
+
+ /*
+ * Do not allow an unregistered initiator to attempting to
+ * clear the PGR.
+ */
+ reservation_key = SCSI_READ64(plist->reservation_key);
+ if (!spc_pr_key_find(pgr, reservation_key, T10_PGR_ISID(cmd), "")) {
+
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: clear pgr:%016x not found\n", reservation_key);
+
+ return (STATUS_RESERVATION_CONFLICT);
+ } else {
+ queue_prt(mgmtq, Q_PR_IO,
+ "PGROUT: clear pgr:%016x\n", reservation_key);
+ }
+
+ /*
+ * We need to set UNIT ATTENTION for all registered initiators.
+ */
+ for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd;
+ key != (spc_pr_key_t *)&pgr->pgr_keylist;
+ key = (spc_pr_key_t *)key->k_link.lnk_fwd) {
+
+ /* Do not set UNIT ATTN for calling Initiator */
+ if (key->k_isid == T10_PGR_ISID(cmd))
+ continue;
+ /*
+ * At this point the only way to get in here is to be the owner
+ * of the reservation.
+ */
+ lu = avl_first(&cmd->c_lu->l_common->l_all_open);
+ do {
+ lu->l_status = KEY_UNIT_ATTENTION;
+ lu->l_asc = SPC_ASC_PARAMETERS_CHANGED;
+ lu->l_ascq = SPC_ASCQ_RES_PREEMPTED;
+ lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu);
+ } while (lu != NULL);
+ }
+
+ /*
+ * Now erase the reservation and registration info.
+ */
+ spc_pr_erase(pgr);
+
+ return (STATUS_GOOD);
+}
+
+/*
+ * []----
+ * | spc_pr_register_and_move
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+static int
+spc_pr_register_and_move(t10_cmd_t *cmd, void *data, size_t data_len)
+{
+ return (STATUS_RESERVATION_CONFLICT);
+}
+
+/*
+ * []----
+ * | spc_pr_key_alloc -
+ * | Allocate a new registration key and add it to the key list.
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+static spc_pr_key_t *
+spc_pr_key_alloc(scsi3_pgr_t *pgr, uint64_t service_key, uint64_t isid,
+ char *transportID)
+{
+ spc_pr_key_t *key = (spc_pr_key_t *)
+ memalign(sizeof (void *), sizeof (spc_pr_key_t));
+
+ if (key != NULL) {
+ key->k_key = service_key;
+ key->k_isid = isid;
+ key->k_transportID = strdup(transportID);
+
+ insque(&key->k_link, pgr->pgr_keylist.lnk_bwd);
+
+ pgr->pgr_numkeys++;
+ assert(pgr->pgr_numkeys > 0);
+ }
+
+ return (key);
+}
+
+/*
+ * []----
+ * | spc_pr_key_rsrv_init -
+ * | Initialize registration & reservervation queues
+ * []----
+ */
+static void
+spc_pr_key_rsrv_init(scsi3_pgr_t *pgr)
+{
+ assert(pgr->pgr_numrsrv == 0);
+ assert(pgr->pgr_numkeys == 0);
+ pgr->pgr_rsrvlist.lnk_fwd = (key_link_t *)&pgr->pgr_rsrvlist.lnk_fwd;
+
+ assert(pgr->pgr_rsrvlist.lnk_bwd == NULL);
+ pgr->pgr_rsrvlist.lnk_bwd = (key_link_t *)&pgr->pgr_rsrvlist.lnk_fwd;
+
+ assert(pgr->pgr_keylist.lnk_fwd == NULL);
+ pgr->pgr_keylist.lnk_fwd = (key_link_t *)&pgr->pgr_keylist.lnk_fwd;
+
+ assert(pgr->pgr_keylist.lnk_bwd == NULL);
+ pgr->pgr_keylist.lnk_bwd = (key_link_t *)&pgr->pgr_keylist.lnk_fwd;
+}
+
+/*
+ * []----
+ * | spc_pr_key_free -
+ * | Free a registration key
+ * []----
+ */
+static void
+spc_pr_key_free(scsi3_pgr_t *pgr, spc_pr_key_t *key)
+{
+ remque(&key->k_link);
+ free(key->k_transportID);
+ free(key);
+
+ pgr->pgr_numkeys--;
+ assert(pgr->pgr_numkeys >= 0);
+}
+
+/*
+ * []----
+ * | spc_pr_key_find -
+ * | Find a registration key based on the key, owner id and port id.
+ * []----
+ */
+static spc_pr_key_t *
+spc_pr_key_find(scsi3_pgr_t *pgr, uint64_t key, uint64_t isid,
+ char *transportID)
+{
+ spc_pr_key_t *kp;
+ spc_pr_key_t *rval = NULL;
+
+
+ for (kp = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd;
+ kp != (spc_pr_key_t *)&pgr->pgr_keylist;
+ kp = (spc_pr_key_t *)kp->k_link.lnk_fwd) {
+ if ((key == 0 || kp->k_key == key) &&
+ (isid == 0 || kp->k_isid == isid) &&
+ (strlen(transportID) == 0 ||
+ (strcmp(kp->k_transportID, transportID) == 0))) {
+ rval = kp;
+ break;
+ }
+ }
+
+ return (rval);
+}
+
+
+/*
+ * []----
+ * | spc_pr_rsrv_alloc -
+ * | Allocate a new reservation and add it to the rsrv list.
+ * []----
+ */
+static spc_pr_rsrv_t *
+spc_pr_rsrv_alloc(scsi3_pgr_t *pgr, uint64_t service_key, uint64_t isid,
+ char *transportID, uint8_t scope, uint8_t type)
+{
+ spc_pr_rsrv_t *rsrv = (spc_pr_rsrv_t *)
+ memalign(sizeof (void *), sizeof (spc_pr_rsrv_t));
+
+ if (rsrv != NULL) {
+ rsrv->r_key = service_key;
+ rsrv->r_isid = isid;
+ rsrv->r_transportID = strdup(transportID);
+ rsrv->r_scope = scope;
+ rsrv->r_type = type;
+
+ insque(&rsrv->r_link, pgr->pgr_rsrvlist.lnk_bwd);
+
+ pgr->pgr_numrsrv++;
+ assert(pgr->pgr_numrsrv > 0);
+ }
+
+ return (rsrv);
+}
+
+
+/*
+ * []----
+ * | spc_pr_rsrv_free -
+ * | Free a reservation.
+ * []----
+ */
+static void
+spc_pr_rsrv_free(scsi3_pgr_t *pgr, spc_pr_rsrv_t *rsrv)
+{
+ remque(&rsrv->r_link);
+ free(rsrv->r_transportID);
+ free(rsrv);
+
+ pgr->pgr_numrsrv--;
+ assert(pgr->pgr_numrsrv >= 0);
+}
+
+/*
+ * []----
+ * | spc_pr_rsrv_find -
+ * | Find a reservation based on the key, owner id and port id.
+ * []----
+ */
+static spc_pr_rsrv_t *
+spc_pr_rsrv_find(scsi3_pgr_t *pgr, uint64_t key, uint64_t isid,
+ char *transportID)
+{
+ spc_pr_rsrv_t *rp, *rval = NULL;
+
+ for (rp = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd;
+ rp != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist;
+ rp = (spc_pr_rsrv_t *)rp->r_link.lnk_fwd) {
+ if ((key == 0 || rp->r_key == key) &&
+ (isid == 0 || rp->r_isid == isid) &&
+ (strlen(transportID) == 0 ||
+ (strcmp(rp->r_transportID, transportID) == 0))) {
+ rval = rp;
+ break;
+ }
+ }
+
+ return (rval);
+}
+
+/*
+ * []----
+ * | spc_pr_erase -
+ * | Find specified key / reservation and erease it
+ * []----
+ */
+/*
+ */
+static void
+spc_pr_erase(scsi3_pgr_t *pgr)
+{
+ spc_pr_key_t *key;
+ spc_pr_rsrv_t *rsrv;
+
+ while ((key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd) !=
+ (spc_pr_key_t *)&pgr->pgr_keylist) {
+ spc_pr_key_free(pgr, key);
+ }
+
+ assert(pgr->pgr_numkeys == 0);
+
+ while ((rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd) !=
+ (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist) {
+ spc_pr_rsrv_free(pgr, rsrv);
+ }
+
+ assert(pgr->pgr_numrsrv == 0);
+
+ pgr->pgr_generation = 0;
+ pgr->pgr_aptpl = 0;
+}
+
+/*
+ * []----
+ * | spc_pr_rsrv_release -
+ * | Release the reservation the perform any other required clearing actions.
+ * | Refer to SPC-3, Section 6.1, Tables ?? and ??
+ * []----
+ */
+static void
+spc_pr_rsrv_release(t10_cmd_t *cmd, scsi3_pgr_t *pgr, spc_pr_rsrv_t *rsrv)
+{
+ disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ t10_lu_impl_t *lu;
+ spc_pr_key_t *key;
+
+ /*
+ * For Registrants-Only mode set UNIT ATTN.
+ */
+ if (rsrv->r_type == PGR_TYPE_WR_EX_RO ||
+ rsrv->r_type == PGR_TYPE_EX_AC_RO) {
+
+ for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd;
+ key != (spc_pr_key_t *)&pgr->pgr_keylist;
+ key = (spc_pr_key_t *)key->k_link.lnk_fwd) {
+
+ /*
+ * No UNIT ATTN for the requesting Initiator.
+ */
+ if (key->k_isid == T10_PGR_ISID(cmd))
+ continue;
+
+ /*
+ * Find associated I_T Nexuses
+ */
+ lu = avl_first(&cmd->c_lu->l_common->l_all_open);
+ do {
+ lu->l_cmd = sbc_cmd;
+ lu->l_status = KEY_UNIT_ATTENTION;
+ lu->l_asc = SPC_ASC_PARAMETERS_CHANGED;
+ lu->l_ascq = SPC_ASCQ_RES_RELEASED;
+ lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open,
+ lu);
+ } while (lu != NULL);
+ }
+ }
+
+ /*
+ * Remove the reservation.
+ */
+ spc_pr_rsrv_free(pgr, rsrv);
+}
+
+/*
+ * []----
+ * | spc_pr_read -
+ * | Read in pgr keys and reservations for this device from backend storage.
+ * | At least the local pgr write lock must be held.
+ * []----
+ */
+Boolean_t
+spc_pr_read(t10_cmd_t *cmd)
+{
+ disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ sbc_reserve_t *res = &p->d_sbc_reserve;
+ scsi3_pgr_t *pgr = &res->res_scsi_3_pgr;
+ spc_pr_key_t *key;
+ spc_pr_rsrv_t *rsrv;
+ spc_pr_diskkey_t *klist;
+ spc_pr_diskrsrv_t *rlist;
+ spc_pr_persist_disk_t *buf = NULL;
+ t10_lu_impl_t *lu;
+ int i, pfd;
+ Boolean_t status = False;
+ char path[MAXPATHLEN];
+
+ /*
+ * If the pre-processor supported "#if .. sizeof", these would
+ * not be required here
+ */
+ assert(sizeof (spc_pr_diskkey_t) == 256);
+ assert(sizeof (spc_pr_diskrsrv_t) == 256);
+ assert(sizeof (spc_pr_persist_disk_t) == 512);
+
+ /*
+ * Open/create the PERSISTANCE file specification
+ */
+ (void) snprintf(path, MAXPATHLEN, "%s/%s/%s%d",
+ target_basedir, cmd->c_lu->l_targ->s_targ_base,
+ PERSISTANCEBASE, cmd->c_lu->l_common->l_num);
+ if ((pfd = open(path, O_RDONLY)) >= 0) {
+ struct stat pstat;
+ if ((fstat(pfd, &pstat)) == 0)
+ if (pstat.st_size > 0)
+ if (buf = malloc(pstat.st_size))
+ if (read(pfd, buf, pstat.st_size) ==
+ pstat.st_size)
+ status = True;
+ }
+
+ /*
+ * Clean up on no persistence file found
+ */
+ if (status == False) {
+ if (pfd >= 0)
+ close(pfd);
+ if (buf)
+ free(buf);
+ return (status);
+ }
+
+ /*
+ * If this is the first time using the persistance data,
+ * initialize the reservation and resource key queues
+ */
+ if (pgr->pgr_rsrvlist.lnk_fwd == NULL) {
+ spc_pr_key_rsrv_init(pgr);
+ }
+
+ /*
+ * Perform some vailidation
+ */
+ if ((buf->magic != PGRMAGIC) ||
+ (buf->revision != SPC_PGR_PERSIST_DATA_REVISION)) {
+ status = False;
+ goto done;
+ }
+
+ /*
+ * Get the registration keys.
+ */
+ klist = buf->keylist;
+ for (i = 0; i < buf->numkeys; i++) {
+ if (klist[i].rectype != PGRDISKKEY) {
+ status = False;
+ goto done;
+ }
+ key = spc_pr_key_alloc(pgr, klist[i].key, klist[i].isid,
+ klist[i].transportID);
+ if (key == NULL) {
+ status = False;
+ goto done;
+ }
+ }
+
+ /*
+ * Get the reservations.
+ */
+ rlist = (spc_pr_diskrsrv_t *)&buf->keylist[buf->numkeys];
+ for (i = 0; i < buf->numrsrv; i++) {
+ if (rlist[i].rectype != PGRDISKRSRV) {
+ status = False;
+ goto done;
+ }
+ rsrv = spc_pr_rsrv_alloc(pgr, rlist[i].key, rlist[i].isid,
+ rlist[i].transportID, rlist[i].scope, rlist[i].type);
+ if (rsrv == NULL) {
+ status = False;
+ goto done;
+ }
+ }
+
+ /*
+ * If there was data then set the reservation type.
+ */
+ if (pgr->pgr_numkeys > 0 || pgr->pgr_numrsrv > 0) {
+ res->res_type = RT_PGR;
+ pgr->pgr_generation = buf->generation;
+
+ /*
+ * Set the command dispatcher according to the reservation type
+ */
+ lu = avl_first(&cmd->c_lu->l_common->l_all_open);
+ do {
+ lu->l_cmd = sbc_cmd_reserved;
+ lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu);
+ } while (lu != NULL);
+ }
+
+done: pthread_rwlock_unlock(&res->res_rwlock);
+ free(buf);
+ return (status);
+}
+
+/*
+ * []----
+ * | spc_pr_write -
+ * | Write PGR keys and reservations for this device to backend storage.
+ * | At least the local pgr write lock must be held.
+ * []----
+ */
+Boolean_t
+spc_pr_write(t10_cmd_t *cmd)
+{
+ disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd);
+ sbc_reserve_t *res = &p->d_sbc_reserve;
+ scsi3_pgr_t *pgr = &res->res_scsi_3_pgr;
+ spc_pr_key_t *key;
+ spc_pr_rsrv_t *rsrv;
+ spc_pr_diskkey_t *klist;
+ spc_pr_diskrsrv_t *rlist;
+ spc_pr_persist_disk_t *buf;
+ ssize_t length, bufsize;
+ int i, pfd = -1;
+ char path[MAXPATHLEN];
+ Boolean_t status = True;
+
+ /*
+ * If the pre-processor supported "#if .. sizeof", these would
+ * not be required here
+ */
+ assert(sizeof (spc_pr_diskkey_t) == 256);
+ assert(sizeof (spc_pr_diskrsrv_t) == 256);
+ assert(sizeof (spc_pr_persist_disk_t) == 512);
+
+ /*
+ * Verify space requirements and allocate buffer memory.
+ * Space needed is header + keylist + rsrvlist.
+ * Subtract 1 from numkeys since header already defines
+ * the first element of the keylist.
+ * Round up the bufsize to the next FBA boundary.
+ */
+ bufsize = sizeof (spc_pr_persist_disk_t) +
+ (pgr->pgr_numkeys - 1) * sizeof (spc_pr_diskkey_t) +
+ pgr->pgr_numrsrv * sizeof (spc_pr_diskrsrv_t);
+ bufsize = roundup(bufsize, 512);
+ if ((buf = memalign(sizeof (void *), bufsize)) == NULL)
+ return (False);
+ else
+ bzero(buf, bufsize);
+
+ /*
+ * Build header.
+ */
+ buf->magic = PGRMAGIC;
+ buf->revision = SPC_PGR_PERSIST_DATA_REVISION;
+ buf->generation = pgr->pgr_generation;
+ buf->numkeys = pgr->pgr_numkeys;
+ buf->numrsrv = pgr->pgr_numrsrv;
+
+ /*
+ * Copy the keys.
+ */
+ klist = buf->keylist;
+ for (i = 0, key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd;
+ key != (spc_pr_key_t *)&pgr->pgr_keylist && i < pgr->pgr_numkeys;
+ key = (spc_pr_key_t *)key->k_link.lnk_fwd, i++) {
+
+ klist[i].rectype = PGRDISKKEY;
+ klist[i].reserved = 0;
+ klist[i].key = key->k_key;
+ klist[i].isid = key->k_isid;
+ strncpy(klist[i].transportID, key->k_transportID,
+ sizeof (klist[i].transportID));
+ }
+
+ /*
+ * Copy the reservations.
+ */
+ rlist = (spc_pr_diskrsrv_t *)&buf->keylist[pgr->pgr_numkeys];
+ for (i = 0, rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd;
+ rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist &&
+ i < pgr->pgr_numrsrv;
+ rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd, i++) {
+
+ rlist[i].rectype = PGRDISKRSRV;
+ rlist[i].reserved = 0;
+ rlist[i].scope = rsrv->r_scope;
+ rlist[i].type = rsrv->r_type;
+ rlist[i].key = rsrv->r_key;
+ rlist[i].isid = rsrv->r_isid;
+ strncpy(rlist[i].transportID, rsrv->r_transportID,
+ sizeof (rlist[i].transportID));
+ }
+
+ /*
+ * Open/create the PERSISTANCE file specification
+ */
+ (void) snprintf(path, MAXPATHLEN, "%s/%s/%s%d",
+ target_basedir, cmd->c_lu->l_targ->s_targ_base,
+ PERSISTANCEBASE, cmd->c_lu->l_common->l_num);
+ if ((pfd = open(path, O_WRONLY|O_CREAT)) >= 0) {
+ length = write(pfd, buf, bufsize);
+ close(pfd);
+ } else {
+ if ((pfd < 0) || (length != bufsize))
+ status = False;
+ }
+
+ /*
+ * Free allocated buffer
+ */
+ free(buf);
+ return (status);
+}
diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h b/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h
new file mode 100644
index 0000000000..7ebc085a1b
--- /dev/null
+++ b/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h
@@ -0,0 +1,165 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _T10_SPC_PR_H
+#define _T10_SPC_PR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * SPC-3 Persistent Reservation specific structures and defines
+ */
+
+/*
+ * Key Linked Lists
+ */
+typedef struct key_link {
+ union {
+ uint64_t align;
+ struct {
+ struct key_link *_lnk_fwd; /* Forward element */
+ struct key_link *_lnk_bwd; /* Backward element */
+ } key_ptr;
+ } key_link;
+} key_link_t;
+#define lnk_fwd key_link.key_ptr._lnk_fwd
+#define lnk_bwd key_link.key_ptr._lnk_bwd
+#define insque(a, b) do { \
+ ((key_link_t *)(a))->lnk_fwd = (key_link_t *)(b); \
+ ((key_link_t *)(a))->lnk_bwd = ((key_link_t *)(b))->lnk_bwd; \
+ ((key_link_t *)(b))->lnk_bwd = (key_link_t *)(a); \
+ ((key_link_t *)(a))->lnk_bwd->lnk_fwd = (key_link_t *)(a); \
+ } while (0)
+
+#define remque(A) do { \
+ ((key_link_t *)(A))->lnk_bwd->lnk_fwd = ((key_link_t *)(A))->lnk_fwd; \
+ ((key_link_t *)(A))->lnk_fwd->lnk_bwd = ((key_link_t *)(A))->lnk_bwd; \
+ } while (0)
+
+/*
+ * Reservation Types (res_type).
+ */
+typedef enum {
+ RT_NONE = 0, /* None */
+ RT_PGR /* SCSI-3 Persistent Reservation */
+} spc_reserve_types;
+
+/*
+ * Persistent reservation data.
+ */
+typedef struct spc_pr_key {
+ key_link_t k_link; /* Key linked list */
+ uint64_t k_key; /* registration key */
+ uint64_t k_isid; /* Owner ISID */
+ char *k_transportID; /* transport ID */
+} spc_pr_key_t;
+
+typedef struct spc_pr_rsrv {
+ key_link_t r_link; /* Key linked list */
+ uint64_t r_key; /* reservation key */
+ uint64_t r_isid; /* Owner ISID */
+ char *r_transportID; /* transport ID */
+ uint8_t r_scope; /* reservation scope */
+ uint8_t r_type; /* reservation type */
+} spc_pr_rsrv_t;
+
+/*
+ * Persistent Reservation data
+ */
+typedef struct scsi3_pgr {
+ uint32_t pgr_generation; /* PGR PRgeneration value */
+ uint16_t pgr_unused;
+ uint16_t pgr_bits : 15,
+ pgr_aptpl : 1; /* persistence data exists */
+ int32_t pgr_numkeys; /* # entries in key list */
+ int32_t pgr_numrsrv; /* # entries in rsrv list */
+ key_link_t pgr_keylist; /* Registration key list */
+ key_link_t pgr_rsrvlist; /* reservation list */
+} scsi3_pgr_t;
+
+typedef struct sbc_reserve {
+ spc_reserve_types res_type; /* standard or pr active */
+ pthread_rwlock_t res_rwlock; /* Lock for coordination */
+ scsi3_pgr_t res_scsi_3_pgr; /* SCSI-3 PGR */
+} sbc_reserve_t;
+
+/*
+ * On-disk PGR data.
+ *
+ * NOTE: The following three structures should be rounded up to 256 bytes each
+ * to prevent potential problems with on-disk data.
+ */
+typedef struct spc_pr_diskkey {
+ uint32_t rectype; /* record type */
+ uint32_t reserved;
+ uint64_t key; /* registration key */
+ uint64_t isid; /* Owner ISID */
+ char transportID[228]; /* transport ID */
+ char filler[4]; /* Unsed, round to 256 bytes */
+} spc_pr_diskkey_t;
+
+typedef struct spc_pr_diskrsrv {
+ uint32_t rectype; /* record type */
+ uint16_t reserved;
+ uint8_t scope; /* reservation scope */
+ uint8_t type; /* reservation type */
+ uint64_t key; /* reservation key */
+ uint64_t isid; /* Owner ISID */
+ char transportID[228]; /* Transport ID */
+ char filler[4]; /* Unsed, round to 256 bytes */
+} spc_pr_diskrsrv_t;
+
+typedef struct spc_pr_persist_disk {
+ uint64_t magic; /* magic number */
+ uint32_t revision; /* header format revision */
+ uint32_t generation; /* pgr generation count */
+ int32_t numkeys; /* # items in key list */
+ int32_t numrsrv; /* # items in rsrv list */
+ char filler[232]; /* Unused, round to 256 bytes */
+
+/*
+ * After the header the data is laid out as follows:
+ * spc_pr_diskkey_t keylist[];
+ * spc_pr_diskrsrv_t rsrvlist[];
+ */
+ spc_pr_diskkey_t keylist[1];
+} spc_pr_persist_disk_t;
+
+
+#define SPC_PGR_PERSIST_DATA_REVISION 0x01 /* REVISON = 1 */
+#define PGRMAGIC 0x5047524D41474943LL /* "PGRMAGIC" */
+#define PGRDISKKEY 0x5047526B /* "PGRk" */
+#define PGRDISKRSRV 0x50475272 /* "PGRr" */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _T10_SPC_PR_H */
diff --git a/usr/src/cmd/iscsi/iscsitgtd/target.h b/usr/src/cmd/iscsi/iscsitgtd/target.h
index 2314d44327..9b3dba830e 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/target.h
+++ b/usr/src/cmd/iscsi/iscsitgtd/target.h
@@ -76,10 +76,18 @@ extern "C" {
#define PARAMBASE "params."
#define LUNBASE "lun."
#define OSDBASE "osd_root."
-
+#define PERSISTANCEBASE "pgr."
#define ISCSI_TARGET_ALIAS "TargetAlias"
/*
+ * Base file name for persistent reservation data (PR). The format used is pr.
+ * This name is used both to build the PR name and when searching the target
+ * directory for persistent reservation data. Don't change these names unless
+ * the upgrade path has been thought about.
+ */
+#define PRBASE "persistent_reservations"
+
+/*
* The IQN names that are created use libuuid + the local target name
* as the idr_str portion of: iqn.1986-03.com.sun:<version>:<id_str>
* In case this changes we also include a version number. Currently
@@ -201,7 +209,8 @@ extern int main_vers_maj,
extern Boolean_t enforce_strict_guid,
thin_provisioning,
disable_tpgs,
- dbg_timestamps;
+ dbg_timestamps,
+ pgr_persist;
extern pthread_mutex_t targ_config_mutex;
extern umem_cache_t *iscsi_cmd_cache,
*t10_cmd_cache,
diff --git a/usr/src/cmd/iscsi/iscsitgtd/util_queue.c b/usr/src/cmd/iscsi/iscsitgtd/util_queue.c
index 3899cc4624..e40ebcbc30 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/util_queue.c
+++ b/usr/src/cmd/iscsi/iscsitgtd/util_queue.c
@@ -196,8 +196,8 @@ void
queue_walker_free(target_queue_t *q, Boolean_t (*func)(msg_t *m, void *v),
void *v1)
{
- msg_t *m, /* current working message */
- *n; /* next message */
+ msg_t *m; /* current working message */
+ msg_t *n; /* next message */
(void) pthread_mutex_lock(&q->q_mutex);
m = q->q_head;
@@ -234,8 +234,8 @@ queue_walker_free(target_queue_t *q, Boolean_t (*func)(msg_t *m, void *v),
void
queue_reset(target_queue_t *q)
{
- msg_t *m,
- *n;
+ msg_t *m;
+ msg_t *n;
(void) pthread_mutex_lock(&q->q_mutex);
m = q->q_head;
@@ -301,8 +301,8 @@ queue_message_free(msg_t *m)
void
queue_free(target_queue_t *q, void (*free_func)(msg_t *))
{
- msg_t *m,
- *n;
+ msg_t *m;
+ msg_t *n;
(void) pthread_mutex_lock(&q->q_mutex);
m = q->q_head;
@@ -343,8 +343,8 @@ queue_str(target_queue_t *q, uint32_t lvl, msg_type_t type, char *fmt)
{
int len;
char *m;
- hrtime_t h = gethrtime(),
- delta;
+ hrtime_t h = gethrtime();
+ hrtime_t delta;
static hrtime_t last_h = 0;
(void) pthread_mutex_lock(&q_mutex);
diff --git a/usr/src/lib/libiscsitgt/common/iscsitgt_impl.h b/usr/src/lib/libiscsitgt/common/iscsitgt_impl.h
index bb5ba7f887..3f97ad1a65 100644
--- a/usr/src/lib/libiscsitgt/common/iscsitgt_impl.h
+++ b/usr/src/lib/libiscsitgt/common/iscsitgt_impl.h
@@ -145,6 +145,7 @@ typedef enum {
#define XML_ELEMENT_VALIDATE "validate"
#define XML_ELEMENT_MORESPACE "more-space-required"
#define XML_VALUE_TRUE "true"
+#define XML_ELEMENT_PGR_PERSIST "PGR-persist"
typedef enum {
NodeFree,
diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile
index b4591f05d9..a2d180667b 100644
--- a/usr/src/uts/common/sys/Makefile
+++ b/usr/src/uts/common/sys/Makefile
@@ -788,6 +788,7 @@ SCSIGENHDRS= \
inquiry.h \
message.h \
mode.h \
+ persist.h \
sense.h \
status.h
diff --git a/usr/src/uts/common/sys/scsi/generic/commands.h b/usr/src/uts/common/sys/scsi/generic/commands.h
index 6dffa0495b..02732fe83c 100644
--- a/usr/src/uts/common/sys/scsi/generic/commands.h
+++ b/usr/src/uts/common/sys/scsi/generic/commands.h
@@ -332,6 +332,11 @@ extern "C" {
#define SCMD_GROUP5 0xA0
#define SCMD_REPORT_LUNS 0xA0
#define SCMD_REPORT_TARGET_PORT_GROUPS 0xA3
+#define SCMD_SET_DEVICE 0xA4
+#define SCMD_SET_DEVICE_IDENTIFIER 0x06
+#define SCMD_SET_PRIORITY 0x0e
+#define SCMD_SET_TARGET_PORT_GROUPS 0x0a
+#define SCMD_SET_TIMESTAMP 0x0f
#define SCMD_READ_G5 0xA8
#define SCMD_WRITE_G5 0xAA
#define SCMD_READ_MEDIA_SERIAL 0xAB
diff --git a/usr/src/uts/common/sys/scsi/generic/persist.h b/usr/src/uts/common/sys/scsi/generic/persist.h
new file mode 100644
index 0000000000..613c91cf12
--- /dev/null
+++ b/usr/src/uts/common/sys/scsi/generic/persist.h
@@ -0,0 +1,398 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_SCSI_GENERIC_PERSIST_H
+#define _SYS_SCSI_GENERIC_PERSIST_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * SCSI Persistence Data
+ *
+ * Format of data returned as a result of PERSISTENCE RESERVER { IN | OUT }
+ */
+
+/*
+ * SPC-3 revision 23, Section 6.11.1, Table 102
+ * Persistent Reservations
+ * Persistent Reserve In service actions
+ */
+#define PR_IN_READ_KEYS 0x0 /* Read all registered reservation keys */
+#define PR_IN_READ_RESERVATION 0x1 /* Reads th persistent reservations */
+#define PR_IN_REPORT_CAPABILITIES 0x2 /* Returns capability information */
+#define PR_IN_READ_FULL_STATUS 0x3 /* Reads complete information about all */
+ /* registrations and the persistent */
+ /* reservations, if any */
+/*
+ * SPC-3 revision 23, Section 6.11.3.3, Table 106
+ * Persistent reservation scope codes
+ */
+#define PR_LU_SCOPE 0x0 /* Persistent reservation applies to */
+ /* full logical unit */
+/*
+ * SPC-3 revision 23, Section 6.11.3.4, Table 107
+ * Persistent Reservations
+ * Persistent reservation type codes
+ */
+#define PGR_TYPE_WR_EX 0x1 /* Write Exclusive */
+#define PGR_TYPE_EX_AC 0x3 /* Exclusive Access */
+#define PGR_TYPE_WR_EX_RO 0x5 /* Write Exclusive, Registrants Only */
+#define PGR_TYPE_EX_AC_RO 0x6 /* Exclusive Access, Registrants Only */
+#define PGR_TYPE_WR_EX_AR 0x7 /* Write Exclusive, All Registrants */
+#define PGR_TYPE_EX_AC_AR 0x8 /* Exclusive Access, All Registrants */
+
+/*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.11.5 PERSISTENCE RESERVE IN
+ * Table 111 - full status descriptor format
+ */
+/* Table 289 - iSCSI Initiator Device TransportID format */
+
+#define iSCSI_PROTOCOL_ID 0x5 /* Table 262 - iSCSI Protocol ID */
+#define WW_UID_DEVICE_NAME 0x0 /* Table 288 - iSCSI Transport IDs */
+
+
+#if defined(_BIT_FIELDS_LTOH)
+/*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.11.1 PERSISTENCE RESERVE IN
+ * Table 101 - PERSISTENCE RESERVE IN command
+ */
+typedef struct scsi_cdb_prin {
+ uint8_t cmd;
+ uint8_t action : 5,
+ resbits : 3;
+ uint8_t resbytes[5];
+ uint8_t alloc_len[2];
+ uint8_t control;
+} scsi_cdb_prin_t;
+
+/*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.11.2 PERSISTENCE RESERVE IN
+ * Table 103/104/105 - parameter data for READS KEYS
+ */
+typedef struct scsi_prin_rsrvdesc {
+ uint8_t reservation_key[8];
+ uint8_t obsolete1[4];
+ uint8_t resbytes;
+ uint8_t type : 4,
+ scope : 4;
+ uint8_t obsolete2[2];
+} scsi_prin_rsrvdesc_t;
+typedef struct scsi_prin_readrsrv {
+ uint8_t PRgeneration[4];
+ uint8_t add_len[4];
+ scsi_prin_rsrvdesc_t res_key_list[1];
+} scsi_prin_readrsrv_t;
+
+/*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.11.4 PERSISTENCE RESERVE IN
+ * Table 108 - parameter data for REPORT CAPABILTIES
+ */
+typedef struct scsi_per_res_type {
+ uint8_t resbits1 : 1,
+ wr_ex : 1,
+ resbits2 : 1,
+ ex_ac : 1,
+ resbits3 : 1,
+ wr_ex_ro : 1,
+ ex_ac_ro : 1,
+ wr_ex_ar : 1;
+ uint8_t ex_ac_ar : 1,
+ resbits4 : 7;
+} scsi_per_res_type_t;
+typedef struct scsi_prin_rpt_cap {
+ uint8_t length[2];
+ uint8_t ptpl_c : 1,
+ resbits1 : 1,
+ atp_c : 1,
+ sip_c : 1,
+ crh : 1,
+ resbits2 : 3;
+ uint8_t ptpl_a : 1,
+ resbits3 : 6,
+ tmv : 1;
+ scsi_per_res_type_t pr_type;
+ uint8_t resbytes[2];
+} scsi_prin_rpt_cap_t;
+
+/*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.11.5 PERSISTENCE RESERVE IN
+ * Table 110/111 - parameter data for READ FULL STATUS
+ * Table 281 - TransportId format
+ */
+typedef struct scsi_transport_id {
+ uint8_t protocol_id : 4,
+ resbits : 2,
+ format_code : 2;
+ uint8_t add_len[2];
+ char iscsi_name[1];
+} scsi_transport_id_t;
+typedef struct scsi_prin_status_t {
+ uint8_t reservation_key[8];
+ uint8_t resbytes1[4];
+ uint8_t r_holder : 1,
+ all_tg_pt : 1,
+ resbits : 6;
+ uint8_t type : 4,
+ scope : 4;
+ uint8_t resbytes2[4];
+ uint8_t rel_tgt_port_id[2];
+ uint8_t add_len[4];
+ scsi_transport_id_t trans_id;
+} scsi_prin_status_t;
+typedef struct scsi_prin_full_status {
+ uint8_t PRgeneration[4];
+ uint8_t add_len[4];
+ scsi_prin_status_t full_desc[1];
+} scsi_prin_full_status_t;
+
+/*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.12.1 PERSISTENCE RESERVE OUT
+ * Table 112 - PERSISTENCE RESERVE OUT command
+ */
+typedef struct scsi_cdb_prout {
+ uint8_t cmd;
+ uint8_t action : 5,
+ resbits : 3;
+ uint8_t type : 4,
+ scope : 4;
+ uint8_t resbytes[2];
+ uint8_t param_len[4];
+ uint8_t control;
+} scsi_cdb_prout_t;
+
+/*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.12.3 PERSISTENCE RESERVE OUT
+ * Table 114 - PERSISTENCE RESERVE OUT parameter list
+ */
+typedef struct scsi_prout_plist {
+ uint8_t reservation_key[8];
+ uint8_t service_key[8];
+ uint8_t obsolete1[4];
+ uint8_t aptpl : 1,
+ resbits1 : 1,
+ all_tg_pt : 1,
+ spec_i_pt : 1,
+ resbits2 : 4;
+ uint8_t resbytes1;
+ uint8_t obsolete2[2];
+ uint8_t apd[1];
+} scsi_prout_plist_t;
+
+#elif defined(_BIT_FIELDS_HTOL)
+/*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.11.1 PERSISTENCE RESERVE IN
+ * Table 101 - PERSISTENCE RESERVE IN command
+ */
+typedef struct scsi_cdb_prin {
+ uint8_t cmd;
+ uint8_t resbits : 3,
+ action : 5;
+ uint8_t resbytes[5];
+ uint8_t alloc_len[2];
+ uint8_t control;
+} scsi_cdb_prin_t;
+
+/*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.11.2 PERSISTENCE RESERVE IN
+ * Table 103/104/105 - parameter data for READS KEYS
+ */
+typedef struct scsi_prin_rsrvdesc {
+ uint8_t reservation_key[8];
+ uint8_t obsolete1[4];
+ uint8_t resbytes;
+ uint8_t scope : 4,
+ type : 4;
+ uint8_t obsolete2[8];
+} scsi_prin_rsrvdesc_t;
+typedef struct scsi_prin_readrsrv {
+ uint8_t PRgeneration[4];
+ uint8_t add_len[4];
+ scsi_prin_rsrvdesc_t res_key_list[1];
+} scsi_prin_readrsrv_t;
+
+/*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.11.4 PERSISTENCE RESERVE IN
+ * Table 108 - parameter data for REPORT CAPABILTIES
+ */
+typedef struct scsi_per_res_type {
+ uint8_t wr_ex_ar : 1,
+ ex_ac_ro : 1,
+ wr_ex_ro : 1,
+ resbits3 : 1,
+ ex_ac : 1,
+ resbits2 : 1,
+ wr_ex : 1,
+ resbits1 : 1;
+ uint8_t resbits4 : 7,
+ ex_ac_ar : 1;
+} scsi_per_res_type_t;
+typedef struct scsi_prin_rpt_cap {
+ uint8_t length[2];
+ uint8_t resbits2 : 3,
+ crh : 1,
+ sip_c : 1,
+ atp_c : 1,
+ resbits1 : 1,
+ ptpl_c : 1;
+ uint8_t tmv : 1,
+ resbits3 : 6,
+ ptpl_a : 1;
+ scsi_per_res_type_t pr_type;
+ uint8_t resbytes[2];
+} scsi_prin_rpt_cap_t;
+
+/*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.11.5 PERSISTENCE RESERVE IN
+ * Table 110/111 - parameter data for READ FULL STATUS
+ * Table 281 - TransportId format
+ */
+typedef struct scsi_transport_id {
+ uint8_t format_code : 2,
+ resbits : 2,
+ protocol_id : 4;
+ uint8_t add_len[2];
+ char iscsi_name[1];
+} scsi_transport_id_t;
+typedef struct scsi_prin_status_t {
+ uint8_t reservation_key[8];
+ uint8_t resbytes1[4];
+ uint8_t resbits : 6,
+ all_tg_pt : 1,
+ r_holder : 1;
+ uint8_t scope : 4,
+ type : 4;
+ uint8_t resbytes2[4];
+ uint8_t rel_tgt_port_id[2];
+ uint8_t add_len[4];
+ scsi_transport_id_t trans_id;
+} scsi_prin_status_t;
+typedef struct scsi_prin_full_status {
+ uint8_t PRgeneration[4];
+ uint8_t add_len[4];
+ scsi_prin_status_t full_desc[1];
+} scsi_prin_full_status_t;
+
+/*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.12.1 PERSISTENCE RESERVE OUT
+ * Table 112 - PERSISTENCE RESERVE OUT command
+ */
+typedef struct scsi_cdb_prout {
+ uint8_t cmd;
+ uint8_t resbits : 3,
+ action : 5;
+ uint8_t scope : 4,
+ type : 4;
+ uint8_t resbytes[2];
+ uint8_t param_len[4];
+ uint8_t control;
+} scsi_cdb_prout_t;
+
+/*
+ * Information obtained from:
+ * SPC-3, Revision 23
+ * Section 6.12.3 PERSISTENCE RESERVE OUT
+ * Table 114 - PERSISTENCE RESERVE OUT parameter list
+ */
+typedef struct scsi_prout_plist {
+ uint8_t reservation_key[8];
+ uint8_t service_key[8];
+ uint8_t obsolete1[4];
+ uint8_t resbits1 : 4,
+ spec_i_pt : 1,
+ all_tg_pt : 1,
+ resbits2 : 1,
+ aptpl : 1;
+ uint8_t resbytes1;
+ uint8_t obsolete2[2];
+ uint8_t apd[1];
+} scsi_prout_plist_t;
+
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif /* _BIT_FIELDS_LTOH */
+
+
+/*
+ * SPC-3 revision 23, Section 6.12.2, Table 113
+ * Persistent Reservations
+ * Persistent Reserve Out service action codes
+ */
+#define PR_OUT_REGISTER 0x0 /* Register/unregister a reservation */
+ /* key with the device server */
+#define PR_OUT_RESERVE 0x1 /* Create a persistent reservation */
+ /* having a specified SCOPE & TYPE */
+#define PR_OUT_RELEASE 0x2 /* Release the selected persistent */
+ /* reservation */
+#define PR_OUT_CLEAR 0x3 /* Clears all reservation keys and */
+ /* all persistent reservations */
+#define PR_OUT_PREEMPT 0x4 /* Preempts persistent reservations */
+ /* and/or removes reservations */
+#define PR_OUT_PREEMPT_ABORT 0x5 /* Preempts persistent reservations */
+ /* and/or removes reservations, and */
+ /* aborts all tasks for all preempted */
+ /* I_T nexuses */
+#define PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY 0x06
+ /* Register a reservation key with */
+ /* the device server, or unregister a */
+ /* reservation key */
+#define PR_OUT_REGISTER_MOVE 0x7 /* Register a reservation key for */
+ /* another I_T nexus with the device */
+ /* server and move a persistent */
+ /* reservation to the I_T nexus */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SCSI_GENERIC_PERSIST_H */