--- old/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_pgr.c	Mon Aug  5 17:27:18 2019
+++ new/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_pgr.c	Mon Aug  5 17:27:18 2019
@@ -20,6 +20,8 @@
  */
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <sys/atomic.h>
@@ -39,7 +41,7 @@
 
 #define	MAX_PGR_PARAM_LIST_LENGTH	(256 * 1024)
 
-int  sbd_pgr_reservation_conflict(scsi_task_t *);
+int  sbd_pgr_reservation_conflict(scsi_task_t *, struct sbd_lu *sl);
 void sbd_pgr_reset(sbd_lu_t *);
 void sbd_pgr_initialize_it(scsi_task_t *, sbd_it_data_t *);
 void sbd_handle_pgr_in_cmd(scsi_task_t *, stmf_data_buf_t *);
@@ -82,6 +84,7 @@
 static void sbd_pgr_do_reserve(sbd_pgr_t *, sbd_pgr_key_t *, sbd_it_data_t *it,
 	stmf_scsi_session_t *, scsi_cdb_prout_t *);
 
+static boolean_t sbd_pgr_should_save(sbd_lu_t *);
 extern sbd_status_t sbd_write_meta_section(sbd_lu_t *, sm_section_hdr_t *);
 extern sbd_status_t sbd_read_meta_section(sbd_lu_t *, sm_section_hdr_t **,
 	uint16_t);
@@ -295,6 +298,22 @@
 	return (ret);
 }
 
+/*
+ * Evaluate common cases where a PERSISTENT RESERVE OUT CDB handler should call
+ * sbd_pgr_meta_write().
+ */
+static boolean_t
+sbd_pgr_should_save(sbd_lu_t *slu)
+{
+	sbd_pgr_t		*pgr = slu->sl_pgr;
+
+	if (stmf_is_pgr_aptpl_always() == B_TRUE ||
+	    (pgr->pgr_flags & (SBD_PGR_APTPL)))
+		return (B_TRUE);
+	else
+		return (B_FALSE);
+}
+
 sbd_status_t
 sbd_pgr_meta_load(sbd_lu_t *slu)
 {
@@ -323,7 +342,12 @@
 	}
 
 	pgr->pgr_flags = spi->pgr_flags;
-	if (pgr->pgr_flags & SBD_PGR_APTPL) {
+	/*
+	 * We reload APTPL reservations when:
+	 *  1. Global override is enabled
+	 *  2. APTPL was explicitly asserted in the PERSISTENT RESERVE OUT CDB
+	 */
+	if (stmf_is_pgr_aptpl_always() || (pgr->pgr_flags & SBD_PGR_APTPL)) {
 		pgr->pgr_rsv_type = spi->pgr_rsv_type;
 		pgr->pgr_rsv_scope = spi->pgr_rsv_scope;
 	} else {
@@ -413,6 +437,7 @@
 	return (ret);
 
 sbd_pgr_meta_load_failed:
+	/* CSTYLED */
 	{
 	char *lun_name = sbd_get_devid_string(slu);
 	sbd_pgr_keylist_dealloc(slu);
@@ -436,7 +461,7 @@
 
 	/* Calculate total pgr meta section size needed */
 	sz = sizeof (sbd_pgr_info_t);
-	if (pgr->pgr_flags & SBD_PGR_APTPL) {
+	if ((pgr->pgr_flags & SBD_PGR_APTPL) || stmf_is_pgr_aptpl_always()) {
 		key = pgr->pgr_keylist;
 		while (key != NULL) {
 			sz = ALIGNED_TO_8BYTE_BOUNDARY(sz +
@@ -458,7 +483,7 @@
 	spi->pgr_sms_header.sms_id = SMS_ID_PGR_INFO;
 	spi->pgr_sms_header.sms_data_order = SMS_DATA_ORDER;
 
-	if (pgr->pgr_flags & SBD_PGR_APTPL) {
+	if ((pgr->pgr_flags & SBD_PGR_APTPL) || stmf_is_pgr_aptpl_always()) {
 		uint8_t *ptr;
 		key = pgr->pgr_keylist;
 		sz = sizeof (sbd_pgr_info_t);
@@ -484,8 +509,12 @@
 			key = key->pgr_key_next;
 		}
 	}
-
+	rw_downgrade(&pgr->pgr_lock);
 	ret = sbd_write_meta_section(slu, (sm_section_hdr_t *)spi);
+	if (!rw_tryupgrade(&pgr->pgr_lock)) {
+		rw_exit(&pgr->pgr_lock);
+		rw_enter(&pgr->pgr_lock, RW_WRITER);
+	}
 	kmem_free(spi, totalsz);
 	if (ret != SBD_SUCCESS) {
 		sbd_pgr_key_t	*tmp_list;
@@ -578,7 +607,8 @@
 	sbd_pgr_t	*pgr  = slu->sl_pgr;
 
 	rw_enter(&pgr->pgr_lock, RW_WRITER);
-	if (!(pgr->pgr_flags & SBD_PGR_APTPL)) {
+	if (!(pgr->pgr_flags & SBD_PGR_APTPL) &&
+	    stmf_is_pgr_aptpl_always() == B_FALSE) {
 		sbd_pgr_keylist_dealloc(slu);
 		pgr->pgr_PRgeneration	= 0;
 		pgr->pgr_rsvholder	= NULL;
@@ -812,9 +842,8 @@
  * Check for any PGR Reservation conflict. return 0 if access allowed
  */
 int
-sbd_pgr_reservation_conflict(scsi_task_t *task)
+sbd_pgr_reservation_conflict(scsi_task_t *task, sbd_lu_t *slu)
 {
-	sbd_lu_t	*slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
 	sbd_pgr_t	*pgr = slu->sl_pgr;
 	sbd_it_data_t	*it  = (sbd_it_data_t *)task->task_lu_itl_handle;
 
@@ -1386,7 +1415,7 @@
 
 sbd_pgr_reg_done:
 
-	if (pgr->pgr_flags & SBD_PGR_APTPL || plist->aptpl) {
+	if (plist->aptpl || (sbd_pgr_should_save(slu) == B_TRUE)) {
 		if (plist->aptpl)
 			PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
 		else
@@ -1491,7 +1520,7 @@
 	/* In case there is no reservation exist */
 	} else {
 		sbd_pgr_do_reserve(pgr, key, it, ses, pr_out);
-		if (pgr->pgr_flags & SBD_PGR_APTPL) {
+		if (sbd_pgr_should_save(slu) == B_TRUE) {
 			if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
 				stmf_scsilib_send_status(task, STATUS_CHECK,
 				    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
@@ -1548,6 +1577,11 @@
 
 	ASSERT(key);
 
+	/*
+	 * XXX this does not honor APTPL
+	 * (i.e., changes made to a formerly-persistent reservation are not
+	 *  updated here!!!)
+	 */
 	if (SBD_PGR_RSVD(pgr)) {
 		if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS ||
 		    pgr->pgr_rsvholder == key) {
@@ -1559,6 +1593,27 @@
 			}
 			sbd_pgr_do_release(slu, it,
 			    SBD_UA_RESERVATIONS_RELEASED);
+
+			/*
+			 * XXX T10 SPC-3 5.6.10.2 says nothing about what to
+			 * do in the event of a failure updating the
+			 * PGR nvram store for a reservation associated with
+			 * an APTPL-enabled (see SPC-3 5.6.4.1) I_T
+			 * registration during a RELEASE service action.
+			 *
+			 * Technically, the CDB completed successfully, as per
+			 * the spec, but at some point we may need to enter
+			 * a recovery mode on the initiator(s) if we power cycle
+			 * the target at the wrong instant...
+			 */
+			if (sbd_pgr_should_save(slu) == B_TRUE) {
+				if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
+					stmf_scsilib_send_status(task,
+					    STATUS_CHECK, /* CSTYLED */
+					    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
+					return;
+				}
+			}
 		}
 	}
 	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
@@ -1602,7 +1657,7 @@
 	mutex_exit(&slu->sl_lock);
 	sbd_pgr_keylist_dealloc(slu);
 	sbd_pgr_set_ua_conditions(slu, it, SBD_UA_RESERVATIONS_PREEMPTED);
-	if (pgr->pgr_flags & SBD_PGR_APTPL) {
+	if (sbd_pgr_should_save(slu) == B_TRUE) {
 		if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
 			stmf_scsilib_send_status(task, STATUS_CHECK,
 			    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
@@ -1717,7 +1772,7 @@
 		}
 	}
 
-	if (pgr->pgr_flags & SBD_PGR_APTPL) {
+	if (sbd_pgr_should_save(slu) == B_TRUE) {
 		if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
 			stmf_scsilib_send_status(task, STATUS_CHECK,
 			    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
@@ -1831,8 +1886,8 @@
 	}
 
 
-	/* Write to disk if currenty aptpl is set or given task is setting it */
-	if (pgr->pgr_flags & SBD_PGR_APTPL || plist->aptpl) {
+	/* Write to disk if aptpl is currently set or this task is setting it */
+	if (plist->aptpl || (sbd_pgr_should_save(slu) == B_TRUE)) {
 		if (plist->aptpl)
 			PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
 		else
