summaryrefslogtreecommitdiff
path: root/deleted_files
diff options
context:
space:
mode:
authordm120769 <none@none>2007-08-20 20:07:56 -0700
committerdm120769 <none@none>2007-08-20 20:07:56 -0700
commit2cb5f2d8d3edf24c4304283afef8e0558d839bbd (patch)
treebf98e7d1db657a6c7501531530f11ebc46fba014 /deleted_files
parent8b79e857d6e0e451d2bfffef5af697d008e9b28c (diff)
downloadillumos-gate-2cb5f2d8d3edf24c4304283afef8e0558d839bbd.tar.gz
backout 6415440: breaks x86 build
--HG-- rename : usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c => deleted_files/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c rename : usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h => deleted_files/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h rename : usr/src/uts/common/sys/scsi/generic/persist.h => deleted_files/usr/src/uts/common/sys/scsi/generic/persist.h
Diffstat (limited to 'deleted_files')
-rw-r--r--deleted_files/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c1913
-rw-r--r--deleted_files/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h165
-rw-r--r--deleted_files/usr/src/uts/common/sys/scsi/generic/persist.h398
3 files changed, 2476 insertions, 0 deletions
diff --git a/deleted_files/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c b/deleted_files/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c
new file mode 100644
index 0000000000..99da20d627
--- /dev/null
+++ b/deleted_files/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/deleted_files/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h b/deleted_files/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h
new file mode 100644
index 0000000000..7ebc085a1b
--- /dev/null
+++ b/deleted_files/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/deleted_files/usr/src/uts/common/sys/scsi/generic/persist.h b/deleted_files/usr/src/uts/common/sys/scsi/generic/persist.h
new file mode 100644
index 0000000000..613c91cf12
--- /dev/null
+++ b/deleted_files/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 */