xref: /illumos-gate/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_pgr.c (revision 5bbb4db2c3f208d12bf0fd11769728f9e5ba66a2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/atomic.h>
27 #include <sys/conf.h>
28 #include <sys/byteorder.h>
29 #include <sys/scsi/scsi_types.h>
30 #include <sys/scsi/generic/persist.h>
31 
32 #include <lpif.h>
33 #include <stmf.h>
34 #include <stmf_ioctl.h>
35 #include <stmf_sbd.h>
36 #include <sbd_impl.h>
37 #include <portif.h>
38 #include <stmf_sbd_ioctl.h>
39 
40 #define	MAX_PGR_PARAM_LIST_LENGTH	(256 * 1024)
41 
42 int  sbd_pgr_reservation_conflict(scsi_task_t *);
43 void sbd_pgr_reset(sbd_lu_t *);
44 void sbd_pgr_initialize_it(scsi_task_t *);
45 void sbd_handle_pgr_in_cmd(scsi_task_t *, stmf_data_buf_t *);
46 void sbd_handle_pgr_out_cmd(scsi_task_t *, stmf_data_buf_t *);
47 void sbd_handle_pgr_out_data(scsi_task_t *, stmf_data_buf_t *);
48 void sbd_pgr_keylist_dealloc(sbd_lu_t *);
49 uint32_t sbd_get_tptid_length_for_devid(scsi_devid_desc_t *);
50 uint32_t sbd_devid_desc_to_tptid(scsi_devid_desc_t *, scsi_transport_id_t *);
51 scsi_devid_desc_t *sbd_tptid_to_devid_desc(scsi_transport_id_t *, uint32_t *);
52 char *sbd_get_devid_string(sbd_lu_t *);
53 void sbd_base16_str_to_binary(char *c, int, uint8_t *);
54 
55 sbd_status_t sbd_pgr_meta_init(sbd_lu_t *);
56 sbd_status_t sbd_pgr_meta_load(sbd_lu_t *);
57 sbd_status_t sbd_pgr_meta_write(sbd_lu_t *);
58 static void sbd_swap_pgr_info(sbd_pgr_info_t *);
59 static void sbd_swap_pgrkey_info(sbd_pgr_key_info_t *);
60 static void sbd_pgr_key_free(sbd_pgr_key_t *);
61 static void sbd_pgr_remove_key(sbd_lu_t *, sbd_pgr_key_t *);
62 static uint32_t sbd_pgr_remove_keys(sbd_lu_t *, sbd_it_data_t *,
63 	sbd_pgr_key_t *, uint64_t, boolean_t);
64 static boolean_t sbd_pgr_key_compare(sbd_pgr_key_t *, scsi_devid_desc_t *,
65 	scsi_devid_desc_t *rpt);
66 static sbd_pgr_key_t *sbd_pgr_key_alloc(scsi_devid_desc_t *,
67 	scsi_devid_desc_t *, int8_t, int8_t);
68 
69 static void sbd_pgr_set_pgr_check_flag(sbd_lu_t *, boolean_t);
70 static void sbd_pgr_set_ua_conditions(sbd_lu_t *, sbd_it_data_t *, uint8_t);
71 static void sbd_pgr_in_read_keys(scsi_task_t *, stmf_data_buf_t *);
72 static void sbd_pgr_in_report_capabilities(scsi_task_t *, stmf_data_buf_t *);
73 static void sbd_pgr_in_read_reservation(scsi_task_t *, stmf_data_buf_t *);
74 static void sbd_pgr_in_read_full_status(scsi_task_t *, stmf_data_buf_t *);
75 static void sbd_pgr_out_register(scsi_task_t *, stmf_data_buf_t *);
76 static void sbd_pgr_out_reserve(scsi_task_t *);
77 static void sbd_pgr_out_release(scsi_task_t *);
78 static void sbd_pgr_out_clear(scsi_task_t *);
79 static void sbd_pgr_out_preempt(scsi_task_t *, stmf_data_buf_t *);
80 static void sbd_pgr_out_register_and_move(scsi_task_t *, stmf_data_buf_t *);
81 
82 static sbd_pgr_key_t *sbd_pgr_do_register(sbd_lu_t *, sbd_it_data_t *,
83 	scsi_devid_desc_t *, scsi_devid_desc_t *, uint8_t, uint64_t);
84 static void sbd_pgr_do_unregister(sbd_lu_t *, sbd_it_data_t *, sbd_pgr_key_t *);
85 static void sbd_pgr_do_release(sbd_lu_t *, sbd_it_data_t *, uint8_t);
86 static void sbd_pgr_do_reserve(sbd_pgr_t *, sbd_pgr_key_t *, sbd_it_data_t *it,
87 	stmf_scsi_session_t *, scsi_cdb_prout_t *);
88 
89 extern sbd_status_t sbd_write_meta_section(sbd_lu_t *, sm_section_hdr_t *);
90 extern sbd_status_t sbd_read_meta_section(sbd_lu_t *, sm_section_hdr_t **,
91 	uint16_t);
92 extern void sbd_swap_section_hdr(sm_section_hdr_t *);
93 extern void sbd_handle_short_write_transfers(scsi_task_t *task,
94 	stmf_data_buf_t *dbuf, uint32_t cdb_xfer_size);
95 extern void sbd_handle_short_read_transfers(scsi_task_t *task,
96 	stmf_data_buf_t *dbuf, uint8_t *p, uint32_t cdb_xfer_size,
97 	uint32_t cmd_xfer_size);
98 extern uint16_t stmf_scsilib_get_lport_rtid(scsi_devid_desc_t *devid);
99 extern scsi_devid_desc_t *stmf_scsilib_get_devid_desc(uint16_t rtpid);
100 extern char sbd_ctoi(char c);
101 
102 /*
103  *
104  *
105  *   +-----------+
106  *   |           |sl_it_list
107  *   |           |---------------------------------------+
108  *   |           |                                       |
109  *   |  sbd_lu_t |                                       |
110  *   |           |                                       |
111  *   |           |                                       |
112  *   |           |                                       |
113  *   +-----+-----+                                       V
114  *         |                                          +-------+
115  *         V                                          |       |
116  *   +-----------+ pgr_key_list               +------>|       |
117  *   |           |------------+  +-->(NULL)   | +- ---|sbd_it |
118  *   |           |            |  |            | |     | _data |
119  *   | sbd_pgr_t |            V  |            | |     |       |
120  *   |           |          +-------+         | |     +-------+
121  *   |           |---+      |       |         | |         |
122  *   |           |   |      |sbd_pgr|---------+ |         v
123  *   +-----------+   |      | _key_t|<----------+     +-------+
124  *                   |      |       |                 |       |
125  *                   |      |       |                 |       |
126  *                   |      +-------+        +--------|       |
127  *                   |         |^            |        |       |
128  *                   |         ||            |        |       |
129  *                   |         v|            |        +-------+
130  *                   |      +-------+        |            |
131  *                   |      |       |        |            v
132  *                   |      |ALL_TG_|<-------+        +-------+
133  *                   |      |PT = 1 |<---------+      |       |
134  *                   |      |       |---+      |      |       |
135  *                   |      |       |   |      +------|       |
136  *          (pgr_rsvholder  +-------+   V             |       |
137  *             pgr_flags&      |^     (NUll)          |       |
138  *              RSVD_ONE)      ||                     +-------+
139  *                   |         v|                         |
140  *                   |      +-------+                     v
141  *                   |      |       |                 +-------+
142  *                   |      |  not  |                 |       |
143  *                   |      |claimed|---+             |       |
144  *                   |      |       |   |        +----| unreg |
145  *                   |      |       |   V        |    |       |
146  *                   |      +-------+ (NUll)     V    |       |
147  *                   |         |^              (NUll) +-------+
148  *                   |         ||                         |
149  *                   |         v|                         v
150  *                   |      +-------+                 +-------+
151  *                   |      |       |                 |       |
152  *                   |      |reserv-|<----------------|       |
153  *                   +----->|  ation|---------------->|       |
154  *                          |holder |                 |       |
155  *                          |key    |                 |       |
156  *                          +-------+                 +-------+
157  *                              |^                        |
158  *                              ||                        v
159  *                              v|                    +-------+
160  *                           +-------+                |       |
161  *                           |       |                |       |
162  *                           |  not  |---+       +----| unreg |
163  *                           |claimed|   |       |    |       |
164  *                           |       |   V       V    |       |
165  *                           |       | (NUll)  (NUll) +-------+
166  *                           +-------+                    |
167  *                              |                         v
168  *                              v                      (NULL)
169  *                           (NULL)
170  *
171  *
172  */
173 
174 #define	PGR_CONFLICT_FREE_CMDS(cdb)	( \
175 	/* ----------------------- */                                      \
176 	/* SPC-3 (rev 23) Table 31 */                                      \
177 	/* ----------------------- */                                      \
178 	((cdb[0]) == SCMD_INQUIRY)					|| \
179 	((cdb[0]) == SCMD_LOG_SENSE_G1)					|| \
180 	((cdb[0]) == SCMD_PERSISTENT_RESERVE_IN)			|| \
181 	((cdb[0]) == SCMD_REPORT_LUNS)					|| \
182 	((cdb[0]) == SCMD_REQUEST_SENSE)				|| \
183 	((cdb[0]) == SCMD_TEST_UNIT_READY)				|| \
184 	/* PREVENT ALLOW MEDIUM REMOVAL with prevent == 0 */               \
185 	((((cdb[0]) == SCMD_DOORLOCK) && (((cdb[4]) & 0x3) == 0)))	|| \
186 	/* SERVICE ACTION IN with READ MEDIA SERIAL NUMBER (0x01) */       \
187 	(((cdb[0]) == SCMD_SVC_ACTION_IN_G5) && (                          \
188 	    ((cdb[1]) & 0x1F) == 0x01))					|| \
189 	/* MAINTENANCE IN with service actions REPORT ALIASES (0x0Bh) */   \
190 	/* REPORT DEVICE IDENTIFIER (0x05)  REPORT PRIORITY (0x0Eh) */     \
191 	/* REPORT TARGET PORT GROUPS (0x0A) REPORT TIMESTAMP (0x0F) */     \
192 	(((cdb[0]) == SCMD_MAINTENANCE_IN) && (                            \
193 	    (((cdb[1]) & 0x1F) == 0x0B) ||                                 \
194 	    (((cdb[1]) & 0x1F) == 0x05) ||                                 \
195 	    (((cdb[1]) & 0x1F) == 0x0E) ||                                 \
196 	    (((cdb[1]) & 0x1F) == 0x0A) ||                                 \
197 	    (((cdb[1]) & 0x1F) == 0x0F)))				|| \
198 	/* REGISTER and REGISTER_AND_IGNORE_EXISTING_KEY */                \
199 	/* actions for PERSISTENT RESERVE OUT command */                   \
200 	(((cdb[0]) == SCMD_PERSISTENT_RESERVE_OUT) && (                    \
201 	    (((cdb[1]) & 0x1F) == PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY) || \
202 	    (((cdb[1]) & 0x1F) == PR_OUT_REGISTER))) 			|| \
203 	/* ----------------------- */                                      \
204 	/* SBC-3 (rev 17) Table 3  */                                      \
205 	/* ----------------------- */                                      \
206 	/* READ CAPACITY(10) */                                            \
207 	((cdb[0]) == SCMD_READ_CAPACITY)				|| \
208 	/* READ CAPACITY(16) */                                            \
209 	(((cdb[0]) == SCMD_SVC_ACTION_IN_G4) && (                          \
210 	    ((cdb[1]) & 0x1F) == 0x10))					|| \
211 	/* START STOP UNIT with START bit 0 and POWER CONDITION 0  */      \
212 	(((cdb[0]) == SCMD_START_STOP) && (                                \
213 	    (((cdb[4]) & 0xF0) == 0) && (((cdb[4]) & 0x01) == 0))))
214 /* End of PGR_CONFLICT_FREE_CMDS */
215 
216 /* Commands allowed for registered IT nexues but not reservation holder */
217 #define	PGR_REGISTERED_POSSIBLE_CMDS(cdb)	( \
218 	(((cdb[0]) == SCMD_PERSISTENT_RESERVE_OUT) && (                \
219 	    (((cdb[1]) & 0x1F) == PR_OUT_RELEASE)		||     \
220 	    (((cdb[1]) & 0x1F) == PR_OUT_CLEAR)			||     \
221 	    (((cdb[1]) & 0x1F) == PR_OUT_PREEMPT)		||     \
222 	    (((cdb[1]) & 0x1F) == PR_OUT_PREEMPT_ABORT))))
223 
224 /* List of commands allowed when WR_EX type reservation held */
225 #define	PGR_READ_POSSIBLE_CMDS(c)	(  \
226 	((c) == SCMD_READ)		|| \
227 	((c) == SCMD_READ_G1)		|| \
228 	((c) == SCMD_READ_G4)		|| \
229 	((c) == SCMD_READ_G5)		|| \
230 	/* READ FETCH (10) (16) */         \
231 	((c) == SCMD_READ_POSITION)	|| \
232 	((c) == 0x90)			|| \
233 	/* READ DEFECT DATA */             \
234 	((c) == SCMD_READ_DEFECT_LIST)	|| \
235 	((c) == 0xB7)			|| \
236 	/* VERIFY (10) (16) (12) */        \
237 	((c) == SCMD_VERIFY)		|| \
238 	((c) == SCMD_VERIFY_G4)		|| \
239 	((c) == SCMD_VERIFY_G5)		|| \
240 	/* XDREAD (10) */                  \
241 	((c) == 0x52))
242 
243 #define	PGR_RESERVATION_HOLDER(pgr, key, it)	( \
244 	((pgr)->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS) || ( \
245 	    ((pgr)->pgr_rsvholder) && ((pgr)->pgr_rsvholder == (key)) && \
246 	    ((key)->pgr_key_it) && ((key)->pgr_key_it == (it))))
247 
248 #define	PGR_SET_FLAG(flg, val)		(atomic_or_8(&(flg), (val)))
249 #define	PGR_CLEAR_FLAG(flg, val)	(atomic_and_8(&(flg), ~(val)))
250 #define	PGR_CLEAR_RSV_FLAG(flg)		(atomic_and_8(&(flg), \
251 	(~(SBD_PGR_RSVD_ALL_REGISTRANTS | SBD_PGR_RSVD_ONE))))
252 
253 #define	PGR_VALID_SCOPE(scope)	((scope) == PR_LU_SCOPE)
254 #define	PGR_VALID_TYPE(type)	( \
255 				((type) == PGR_TYPE_WR_EX)	|| \
256 				((type) == PGR_TYPE_EX_AC)	|| \
257 				((type) == PGR_TYPE_WR_EX_RO)	|| \
258 				((type) == PGR_TYPE_EX_AC_RO)	|| \
259 				((type) == PGR_TYPE_WR_EX_AR)	|| \
260 				((type) == PGR_TYPE_EX_AC_AR))
261 
262 #define	ALIGNED_TO_WORD_BOUNDARY(i)	(((i) + 7) & ~7)
263 
264 static void
265 sbd_swap_pgr_info(sbd_pgr_info_t *spi)
266 {
267 	sbd_swap_section_hdr(&spi->pgr_sms_header);
268 	if (spi->pgr_data_order == SMS_DATA_ORDER)
269 		return;
270 	spi->pgr_sms_header.sms_chksum += SMS_DATA_ORDER - spi->pgr_data_order;
271 	spi->pgr_rsvholder_indx		= BSWAP_32(spi->pgr_rsvholder_indx);
272 	spi->pgr_numkeys		= BSWAP_32(spi->pgr_numkeys);
273 }
274 
275 static void
276 sbd_swap_pgrkey_info(sbd_pgr_key_info_t *key)
277 {
278 	key->pgr_key			= BSWAP_64(key->pgr_key);
279 	key->pgr_key_lpt_len		= BSWAP_16(key->pgr_key_lpt_len);
280 	key->pgr_key_rpt_len		= BSWAP_16(key->pgr_key_rpt_len);
281 }
282 
283 sbd_status_t
284 sbd_pgr_meta_init(sbd_lu_t *slu)
285 {
286 	sbd_pgr_info_t	*spi = NULL;
287 	uint32_t 	sz;
288 	sbd_status_t	ret;
289 
290 	sz = sizeof (sbd_pgr_info_t);
291 	spi = (sbd_pgr_info_t *)kmem_zalloc(sz, KM_SLEEP);
292 	spi->pgr_data_order = SMS_DATA_ORDER;
293 	spi->pgr_sms_header.sms_size = sz;
294 	spi->pgr_sms_header.sms_id = SMS_ID_PGR_INFO;
295 	spi->pgr_sms_header.sms_data_order = SMS_DATA_ORDER;
296 
297 	ret = sbd_write_meta_section(slu, (sm_section_hdr_t *)spi);
298 	kmem_free(spi, sz);
299 	return (ret);
300 }
301 
302 sbd_status_t
303 sbd_pgr_meta_load(sbd_lu_t *slu)
304 {
305 	sbd_pgr_t		*pgr = slu->sl_pgr;
306 	sbd_pgr_info_t		*spi = NULL;
307 	sbd_pgr_key_t		*key, *last_key = NULL;
308 	sbd_pgr_key_info_t	*spi_key;
309 	sbd_status_t		ret = SBD_SUCCESS;
310 	scsi_devid_desc_t	*lpt, *rpt;
311 	uint8_t			*ptr, *keyoffset,  *endoffset;
312 	uint32_t		i, sz;
313 
314 	ret = sbd_read_meta_section(slu, (sm_section_hdr_t **)&spi,
315 	    SMS_ID_PGR_INFO);
316 	if (ret != SBD_SUCCESS) {
317 		/* No PGR section found, means volume made before PGR support */
318 		if (ret == SBD_NOT_FOUND) {
319 			/* So just create a default PGR section */
320 			ret = sbd_pgr_meta_init(slu);
321 		}
322 		return (ret);
323 	}
324 	if (spi->pgr_data_order != SMS_DATA_ORDER) {
325 		sbd_swap_pgr_info(spi);
326 	}
327 
328 	pgr->pgr_flags = spi->pgr_flags;
329 	if (pgr->pgr_flags & SBD_PGR_APTPL) {
330 		pgr->pgr_rsv_type = spi->pgr_rsv_type;
331 		pgr->pgr_rsv_scope = spi->pgr_rsv_scope;
332 	} else {
333 		PGR_CLEAR_RSV_FLAG(pgr->pgr_flags);
334 	}
335 	PGR_CLEAR_FLAG(slu->sl_pgr->pgr_flags, SBD_PGR_ALL_KEYS_HAS_IT);
336 
337 	endoffset	= (uint8_t *)spi;
338 	endoffset	+= spi->pgr_sms_header.sms_size;
339 	keyoffset	= (uint8_t *)(spi + 1);
340 	for (i = 1; i <= spi->pgr_numkeys; i++) {
341 
342 		spi_key = (sbd_pgr_key_info_t *)keyoffset;
343 		if (spi->pgr_data_order != SMS_DATA_ORDER) {
344 			sbd_swap_pgrkey_info(spi_key);
345 		}
346 
347 		/* Calculate the size and next offset */
348 		sz = ALIGNED_TO_WORD_BOUNDARY(sizeof (sbd_pgr_key_info_t) - 1 +
349 		    spi_key->pgr_key_lpt_len + spi_key->pgr_key_rpt_len);
350 		keyoffset += sz;
351 
352 		/* Validate the key fields */
353 		if (spi_key->pgr_key_rpt_len == 0 || endoffset < keyoffset ||
354 		    (spi_key->pgr_key_lpt_len == 0 &&
355 		    !(spi_key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT))) {
356 			char *lun_name = sbd_get_devid_string(slu);
357 			sbd_pgr_keylist_dealloc(slu);
358 			kmem_free(spi, spi->pgr_sms_header.sms_size);
359 			cmn_err(CE_WARN, "sbd_pgr_meta_load: Failed to load "
360 			    "PGR meta data for lun %s.", lun_name);
361 			kmem_free(lun_name, strlen(lun_name) + 1);
362 			return (SBD_META_CORRUPTED);
363 		}
364 
365 		lpt = (scsi_devid_desc_t *)spi_key->pgr_key_it;
366 		ptr = (uint8_t *)spi_key->pgr_key_it + spi_key->pgr_key_lpt_len;
367 		rpt = (scsi_devid_desc_t *)ptr;
368 		key = sbd_pgr_key_alloc(lpt, rpt, spi_key->pgr_key_lpt_len,
369 		    spi_key->pgr_key_rpt_len);
370 
371 		key->pgr_key		= spi_key->pgr_key;
372 		key->pgr_key_flags	= spi_key->pgr_key_flags;
373 		key->pgr_key_prev	= last_key;
374 
375 		if (last_key) {
376 			last_key->pgr_key_next = key;
377 		} else {
378 			pgr->pgr_keylist = key;
379 		}
380 		last_key = key;
381 
382 		if ((pgr->pgr_flags & SBD_PGR_RSVD_ONE) &&
383 		    (i == spi->pgr_rsvholder_indx)) {
384 			pgr->pgr_rsvholder = key;
385 		}
386 	}
387 
388 	kmem_free(spi, spi->pgr_sms_header.sms_size);
389 	return (ret);
390 }
391 
392 sbd_status_t
393 sbd_pgr_meta_write(sbd_lu_t *slu)
394 {
395 	sbd_pgr_key_t		*key;
396 	sbd_pgr_info_t		*spi;
397 	sbd_pgr_key_info_t	*spi_key;
398 	sbd_pgr_t		*pgr = slu->sl_pgr;
399 	sbd_status_t		ret = SBD_SUCCESS;
400 	uint32_t		sz, totalsz;
401 
402 	/* Calculate total pgr meta section size needed */
403 	sz = sizeof (sbd_pgr_info_t);
404 	if (pgr->pgr_flags & SBD_PGR_APTPL) {
405 		key = pgr->pgr_keylist;
406 		while (key != NULL) {
407 			sz = ALIGNED_TO_WORD_BOUNDARY(sz +
408 			    sizeof (sbd_pgr_key_info_t) - 1 +
409 			    key->pgr_key_lpt_len + key->pgr_key_rpt_len);
410 			key = key->pgr_key_next;
411 		}
412 	}
413 	totalsz = sz;
414 
415 	spi = (sbd_pgr_info_t *)kmem_zalloc(totalsz, KM_SLEEP);
416 	spi->pgr_flags		= pgr->pgr_flags;
417 	spi->pgr_rsv_type	= pgr->pgr_rsv_type;
418 	spi->pgr_rsv_scope	= pgr->pgr_rsv_scope;
419 	spi->pgr_data_order	= SMS_DATA_ORDER;
420 	spi->pgr_numkeys	= 0;
421 
422 	spi->pgr_sms_header.sms_size = totalsz;
423 	spi->pgr_sms_header.sms_id = SMS_ID_PGR_INFO;
424 	spi->pgr_sms_header.sms_data_order = SMS_DATA_ORDER;
425 
426 	if (pgr->pgr_flags & SBD_PGR_APTPL) {
427 		uint8_t *ptr;
428 		key = pgr->pgr_keylist;
429 		sz = sizeof (sbd_pgr_info_t);
430 		while (key != NULL) {
431 			spi_key = (sbd_pgr_key_info_t *)((uint8_t *)spi + sz);
432 			spi_key->pgr_key = key->pgr_key;
433 			spi_key->pgr_key_lpt_len = key->pgr_key_lpt_len;
434 			spi_key->pgr_key_rpt_len = key->pgr_key_rpt_len;
435 			ptr = spi_key->pgr_key_it;
436 			bcopy(key->pgr_key_lpt_id, ptr, key->pgr_key_lpt_len);
437 			ptr += key->pgr_key_lpt_len;
438 			bcopy(key->pgr_key_rpt_id, ptr, key->pgr_key_rpt_len);
439 
440 			spi->pgr_numkeys++;
441 			if (key == pgr->pgr_rsvholder) {
442 				spi->pgr_rsvholder_indx = spi->pgr_numkeys;
443 			}
444 
445 			sz = ALIGNED_TO_WORD_BOUNDARY(sz +
446 			    sizeof (sbd_pgr_key_info_t) - 1 +
447 			    key->pgr_key_lpt_len + key->pgr_key_rpt_len);
448 			key = key->pgr_key_next;
449 		}
450 	}
451 
452 	ret = sbd_write_meta_section(slu, (sm_section_hdr_t *)spi);
453 	kmem_free(spi, totalsz);
454 	if (ret != SBD_SUCCESS) {
455 		sbd_pgr_key_t	*tmp_list;
456 		tmp_list = pgr->pgr_keylist;
457 		pgr->pgr_keylist = NULL;
458 		if (sbd_pgr_meta_load(slu) != SBD_SUCCESS) {
459 			char *lun_name = sbd_get_devid_string(slu);
460 			cmn_err(CE_WARN, "sbd_pgr_meta_write: Failed to revert "
461 			    "back to existing PGR state after meta write "
462 			    "failure, may cause PGR inconsistancy for lun %s.",
463 			    lun_name);
464 			kmem_free(lun_name, strlen(lun_name) + 1);
465 			pgr->pgr_keylist = tmp_list;
466 		} else {
467 			key = pgr->pgr_keylist;
468 			pgr->pgr_keylist = tmp_list;
469 			sbd_pgr_set_pgr_check_flag(slu, B_TRUE);
470 			sbd_pgr_keylist_dealloc(slu);
471 			pgr->pgr_keylist = key;
472 		}
473 
474 	}
475 	return (ret);
476 }
477 
478 static sbd_pgr_key_t *
479 sbd_pgr_key_alloc(scsi_devid_desc_t *lptid, scsi_devid_desc_t *rptid,
480 					int8_t lpt_len, int8_t rpt_len)
481 {
482 	sbd_pgr_key_t *key;
483 
484 	key = (sbd_pgr_key_t *)kmem_zalloc(sizeof (sbd_pgr_key_t), KM_SLEEP);
485 
486 	if (lpt_len >= sizeof (scsi_devid_desc_t)) {
487 		ASSERT(lptid);
488 		key->pgr_key_lpt_len = lpt_len;
489 		key->pgr_key_lpt_id  = (scsi_devid_desc_t *)kmem_zalloc(
490 		    lpt_len, KM_SLEEP);
491 		bcopy(lptid, key->pgr_key_lpt_id, lpt_len);
492 	}
493 
494 	if (rpt_len >= sizeof (scsi_devid_desc_t)) {
495 		ASSERT(rptid);
496 		key->pgr_key_rpt_len = rpt_len;
497 		key->pgr_key_rpt_id  = (scsi_devid_desc_t *)kmem_zalloc(
498 		    rpt_len, KM_SLEEP);
499 		bcopy(rptid, key->pgr_key_rpt_id, rpt_len);
500 	}
501 
502 	return (key);
503 }
504 
505 static void
506 sbd_pgr_key_free(sbd_pgr_key_t *key)
507 {
508 	if (key->pgr_key_lpt_id) {
509 		kmem_free(key->pgr_key_lpt_id, key->pgr_key_lpt_len);
510 	}
511 	if (key->pgr_key_rpt_id) {
512 		kmem_free(key->pgr_key_rpt_id, key->pgr_key_rpt_len);
513 	}
514 	kmem_free(key, sizeof (sbd_pgr_key_t));
515 }
516 
517 void
518 sbd_pgr_keylist_dealloc(sbd_lu_t *slu)
519 {
520 	sbd_pgr_t	*pgr  = slu->sl_pgr;
521 	sbd_it_data_t	*it;
522 	sbd_pgr_key_t	*key;
523 
524 	mutex_enter(&slu->sl_lock);
525 	for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
526 		it->pgr_key_ptr = NULL;
527 	}
528 	mutex_exit(&slu->sl_lock);
529 
530 	while (pgr->pgr_keylist != NULL) {
531 		key = pgr->pgr_keylist;
532 		pgr->pgr_keylist = key->pgr_key_next;
533 		sbd_pgr_key_free(key);
534 	}
535 }
536 
537 /*
538  * Reset and clear the keys, Can be used in the case of Lun Reset
539  */
540 void
541 sbd_pgr_reset(sbd_lu_t *slu)
542 {
543 	sbd_pgr_t	*pgr  = slu->sl_pgr;
544 
545 	rw_enter(&pgr->pgr_lock, RW_WRITER);
546 	if (!(pgr->pgr_flags & SBD_PGR_APTPL)) {
547 		sbd_pgr_keylist_dealloc(slu);
548 		pgr->pgr_PRgeneration	= 0;
549 		pgr->pgr_rsvholder	= NULL;
550 		pgr->pgr_rsv_type	= 0;
551 		pgr->pgr_flags		= 0;
552 	}
553 	rw_exit(&pgr->pgr_lock);
554 }
555 
556 static void
557 sbd_pgr_remove_key(sbd_lu_t *slu, sbd_pgr_key_t *key)
558 {
559 	sbd_pgr_t *pgr  = slu->sl_pgr;
560 	sbd_it_data_t *it;
561 
562 	ASSERT(key);
563 
564 	mutex_enter(&slu->sl_lock);
565 	if (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) {
566 		for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
567 			if (it->pgr_key_ptr == key)
568 				it->pgr_key_ptr = NULL;
569 		}
570 	} else {
571 		if (key->pgr_key_it) {
572 			key->pgr_key_it->pgr_key_ptr = NULL;
573 		}
574 	}
575 	mutex_exit(&slu->sl_lock);
576 
577 	if (key->pgr_key_next) {
578 		key->pgr_key_next->pgr_key_prev = key->pgr_key_prev;
579 	}
580 	if (key->pgr_key_prev) {
581 		key->pgr_key_prev->pgr_key_next = key->pgr_key_next;
582 	} else {
583 		pgr->pgr_keylist =  key->pgr_key_next;
584 	}
585 
586 	sbd_pgr_key_free(key);
587 }
588 
589 /*
590  * Remove keys depends on boolean variable "match"
591  * match = B_TRUE  ==>	Remove all keys which matches the given svc_key,
592  *			except for IT equal to given "my_it".
593  * match = B_FALSE ==>	Remove all keys which does not matches the svc_key,
594  *			except for IT equal to given "my_it"
595  */
596 static uint32_t
597 sbd_pgr_remove_keys(sbd_lu_t *slu, sbd_it_data_t *my_it, sbd_pgr_key_t *my_key,
598 				uint64_t svc_key, boolean_t match)
599 {
600 	sbd_pgr_t	*pgr  = slu->sl_pgr;
601 	sbd_it_data_t	*it;
602 	sbd_pgr_key_t	*nextkey, *key = pgr->pgr_keylist;
603 	uint32_t	count = 0;
604 
605 	while (key) {
606 
607 		nextkey = key->pgr_key_next;
608 		if (match == B_TRUE && key->pgr_key == svc_key ||
609 		    match == B_FALSE && key->pgr_key != svc_key) {
610 			/*
611 			 * If the key is registered by current IT keep it,
612 			 * but just remove pgr pointers from other ITs
613 			 */
614 			if (key == my_key) {
615 				mutex_enter(&slu->sl_lock);
616 				for (it = slu->sl_it_list; it != NULL;
617 				    it = it->sbd_it_next) {
618 					if (it->pgr_key_ptr == key &&
619 					    it != my_it)
620 						it->pgr_key_ptr = NULL;
621 				}
622 				mutex_exit(&slu->sl_lock);
623 			} else {
624 				sbd_pgr_remove_key(slu, key);
625 			}
626 			count++;
627 		}
628 		key = nextkey;
629 	}
630 	return (count);
631 }
632 
633 static void
634 sbd_pgr_set_ua_conditions(sbd_lu_t *slu, sbd_it_data_t *my_it, uint8_t ua)
635 {
636 	sbd_it_data_t *it;
637 
638 	mutex_enter(&slu->sl_lock);
639 	for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
640 		if (it == my_it)
641 			continue;
642 		it->sbd_it_ua_conditions |= ua;
643 	}
644 	mutex_exit(&slu->sl_lock);
645 }
646 
647 /*
648  * Set the SBD_IT_PGR_CHECK_FLAG  depends on variable "registered". See Below.
649  *
650  *   If
651  *     registered is B_TRUE  => Set PGR_CHECK_FLAG on all registered IT nexus
652  *     registered is B_FALSE => Set PGR_CHECK_FLAG on all unregistered IT nexus
653  */
654 static void
655 sbd_pgr_set_pgr_check_flag(sbd_lu_t *slu, boolean_t registered)
656 {
657 	sbd_it_data_t *it;
658 
659 	PGR_CLEAR_FLAG(slu->sl_pgr->pgr_flags, SBD_PGR_ALL_KEYS_HAS_IT);
660 	mutex_enter(&slu->sl_lock);
661 	for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
662 		if (it->pgr_key_ptr) {
663 			if (registered == B_TRUE)  {
664 				it->sbd_it_flags |=  SBD_IT_PGR_CHECK_FLAG;
665 			}
666 		} else {
667 			if (registered == B_FALSE)
668 				it->sbd_it_flags |=  SBD_IT_PGR_CHECK_FLAG;
669 		}
670 	}
671 	mutex_exit(&slu->sl_lock);
672 }
673 
674 static boolean_t
675 sbd_pgr_key_compare(sbd_pgr_key_t *key, scsi_devid_desc_t *lpt,
676 					scsi_devid_desc_t *rpt)
677 {
678 	scsi_devid_desc_t *id;
679 
680 	id = key->pgr_key_rpt_id;
681 	if ((rpt->ident_length != id->ident_length) ||
682 	    (memcmp(id->ident, rpt->ident, id->ident_length) != 0)) {
683 			return (B_FALSE);
684 	}
685 
686 	/*
687 	 * You can skip target port name comparison if ALL_TG_PT flag
688 	 * is set for this key;
689 	 */
690 	if (!(key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) && lpt) {
691 		id = key->pgr_key_lpt_id;
692 		if ((lpt->ident_length != id->ident_length) ||
693 		    (memcmp(id->ident, lpt->ident, id->ident_length) != 0)) {
694 				return (B_FALSE);
695 		}
696 	}
697 	return (B_TRUE);
698 }
699 
700 
701 sbd_pgr_key_t *
702 sbd_pgr_key_registered(sbd_pgr_t *pgr, scsi_devid_desc_t *lpt,
703 					scsi_devid_desc_t *rpt)
704 {
705 	sbd_pgr_key_t *key;
706 
707 	for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next) {
708 		if (sbd_pgr_key_compare(key, lpt, rpt) == B_TRUE) {
709 			return (key);
710 		}
711 	}
712 	return (NULL);
713 }
714 
715 void
716 sbd_pgr_initialize_it(scsi_task_t *task)
717 {
718 	sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
719 	stmf_scsi_session_t *ses = task->task_session;
720 	sbd_it_data_t *it = slu->sl_it_list;
721 	sbd_pgr_t		*pgr = slu->sl_pgr;
722 	sbd_pgr_key_t		*key;
723 	scsi_devid_desc_t	*lpt, *rpt, *id;
724 
725 	if (pgr->pgr_flags & SBD_PGR_ALL_KEYS_HAS_IT)
726 		return;
727 	rpt = ses->ss_rport_id;
728 	lpt = ses->ss_lport->lport_id;
729 
730 	rw_enter(&pgr->pgr_lock, RW_WRITER);
731 	PGR_SET_FLAG(pgr->pgr_flags,  SBD_PGR_ALL_KEYS_HAS_IT);
732 	for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next) {
733 
734 		if ((!(key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT)) &&
735 		    key->pgr_key_it != NULL)
736 			continue;
737 		/*
738 		 * SBD_PGR_ALL_KEYS_HAS_IT is set only if no single key
739 		 * in the list has SBD_PGR_KEY_ALL_TG_PT flag set and
740 		 * pgr_key_it all keys points to some IT
741 		 */
742 		PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_ALL_KEYS_HAS_IT);
743 
744 		/* Check if key matches with given lpt rpt combination */
745 		if (sbd_pgr_key_compare(key, lpt, rpt) == B_FALSE)
746 			continue;
747 
748 		/* IT nexus devid information matches with this key */
749 		if (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) {
750 			/*
751 			 * If ALL_TG_PT is set, pgr_key_it will point to NULL,
752 			 * unless pgr->pgr_rsvholder pointing to this key.
753 			 * In that case, pgr_key_it should point to the IT
754 			 * which initiated that reservation.
755 			 */
756 			if (pgr->pgr_rsvholder == key) {
757 				id = key->pgr_key_lpt_id;
758 				if (lpt->ident_length == id->ident_length) {
759 					if (memcmp(id->ident, lpt->ident,
760 					    id->ident_length) == 0)
761 						key->pgr_key_it = it;
762 				}
763 			}
764 
765 		} else {
766 			key->pgr_key_it = it;
767 		}
768 
769 		mutex_enter(&slu->sl_lock);
770 		it->pgr_key_ptr = key;
771 		mutex_exit(&slu->sl_lock);
772 		rw_exit(&pgr->pgr_lock);
773 		return;
774 	}
775 	rw_exit(&pgr->pgr_lock);
776 }
777 
778 /*
779  * Check for any PGR Reservation conflict. return 0 if access allowed
780  */
781 int
782 sbd_pgr_reservation_conflict(scsi_task_t *task)
783 {
784 	sbd_lu_t	*slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
785 	sbd_pgr_t	*pgr = slu->sl_pgr;
786 	sbd_it_data_t	*it  = (sbd_it_data_t *)task->task_lu_itl_handle;
787 
788 	/* If Registered */
789 	if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS && it->pgr_key_ptr)
790 			return (0);
791 
792 	/* If you are registered */
793 	if (pgr->pgr_flags & SBD_PGR_RSVD_ONE) {
794 		rw_enter(&pgr->pgr_lock, RW_READER);
795 
796 		/*
797 		 * Note: it->pgr_key_ptr is protected by sl_lock. Also,
798 		 *    it is expected to change its value only with pgr_lock
799 		 *    held. Hence we are safe to read its value without
800 		 *    grabbing sl_lock. But make sure that the value used is
801 		 *    not from registers by using "volatile" keyword.
802 		 *    Since this funtion is in performance path, we may want
803 		 *    to avoid grabbing sl_lock.
804 		 */
805 		if ((volatile sbd_pgr_key_t *)it->pgr_key_ptr) {
806 			/* If you are the reservation holder */
807 			if (pgr->pgr_rsvholder == it->pgr_key_ptr &&
808 			    it->pgr_key_ptr->pgr_key_it == it) {
809 				rw_exit(&pgr->pgr_lock);
810 				return (0);
811 			}
812 
813 			/* If reserve type is not EX_AC */
814 			if (pgr->pgr_rsv_type != PGR_TYPE_EX_AC) {
815 				/* If reserve type is WR_EX allow read */
816 				if (pgr->pgr_rsv_type == PGR_TYPE_WR_EX) {
817 					if (PGR_READ_POSSIBLE_CMDS(
818 					    task->task_cdb[0])) {
819 						rw_exit(&pgr->pgr_lock);
820 						return (0);
821 					}
822 				/* For all other reserve types allow access */
823 				} else {
824 					rw_exit(&pgr->pgr_lock);
825 					return (0);
826 				}
827 			}
828 
829 			/* If registered, allow these commands */
830 			if (PGR_REGISTERED_POSSIBLE_CMDS(task->task_cdb)) {
831 				rw_exit(&pgr->pgr_lock);
832 				return (0);
833 			}
834 		}
835 		rw_exit(&pgr->pgr_lock);
836 	}
837 
838 	/* For any case, allow these commands */
839 	if (PGR_CONFLICT_FREE_CMDS(task->task_cdb)) {
840 		return (0);
841 	}
842 
843 	/* Give read access if reservation type WR_EX for registrants */
844 	if (pgr->pgr_rsv_type == PGR_TYPE_WR_EX_RO ||
845 	    pgr->pgr_rsv_type == PGR_TYPE_WR_EX_AR) {
846 		if (PGR_READ_POSSIBLE_CMDS(task->task_cdb[0]))
847 			return (0);
848 	}
849 
850 	/* If  you reached here, No access for you */
851 	return (1);
852 }
853 
854 void
855 sbd_handle_pgr_in_cmd(scsi_task_t *task, stmf_data_buf_t *initial_dbuf)
856 {
857 
858 	sbd_lu_t	*slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
859 	sbd_pgr_t	*pgr = slu->sl_pgr;
860 	scsi_cdb_prin_t *pr_in;
861 
862 	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN);
863 
864 	pr_in = (scsi_cdb_prin_t *)task->task_cdb;
865 
866 	rw_enter(&pgr->pgr_lock, RW_READER);
867 	switch (pr_in->action) {
868 	case PR_IN_READ_KEYS:
869 		sbd_pgr_in_read_keys(task, initial_dbuf);
870 		break;
871 	case PR_IN_READ_RESERVATION:
872 		sbd_pgr_in_read_reservation(task, initial_dbuf);
873 		break;
874 	case PR_IN_REPORT_CAPABILITIES:
875 		sbd_pgr_in_report_capabilities(task, initial_dbuf);
876 		break;
877 	case PR_IN_READ_FULL_STATUS:
878 		sbd_pgr_in_read_full_status(task, initial_dbuf);
879 		break;
880 	default :
881 		stmf_scsilib_send_status(task, STATUS_CHECK,
882 		    STMF_SAA_INVALID_FIELD_IN_CDB);
883 		break;
884 	}
885 	rw_exit(&pgr->pgr_lock);
886 }
887 
888 void
889 sbd_handle_pgr_out_cmd(scsi_task_t *task, stmf_data_buf_t *initial_dbuf)
890 {
891 
892 	scsi_cdb_prout_t *pr_out = (scsi_cdb_prout_t *)task->task_cdb;
893 	uint32_t param_len;
894 
895 	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_OUT);
896 
897 	switch (pr_out->action) {
898 		case PR_OUT_REGISTER:
899 		case PR_OUT_RESERVE:
900 		case PR_OUT_RELEASE:
901 		case PR_OUT_CLEAR:
902 		case PR_OUT_PREEMPT:
903 		case PR_OUT_PREEMPT_ABORT:
904 		case PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY:
905 		case PR_OUT_REGISTER_MOVE:
906 			param_len = READ_SCSI32(pr_out->param_len, uint32_t);
907 			if (param_len < MAX_PGR_PARAM_LIST_LENGTH &&
908 			    param_len > 0) {
909 				sbd_handle_short_write_transfers(task,
910 				    initial_dbuf, param_len);
911 			} else {
912 				stmf_scsilib_send_status(task, STATUS_CHECK,
913 				    STMF_SAA_PARAM_LIST_LENGTH_ERROR);
914 			}
915 			break;
916 		default :
917 			stmf_scsilib_send_status(task, STATUS_CHECK,
918 			    STMF_SAA_INVALID_FIELD_IN_CDB);
919 			break;
920 	}
921 }
922 
923 void
924 sbd_handle_pgr_out_data(scsi_task_t *task, stmf_data_buf_t *dbuf)
925 {
926 	sbd_lu_t	*slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
927 	scsi_cdb_prout_t	*pr_out	= (scsi_cdb_prout_t *)task->task_cdb;
928 	sbd_it_data_t		*it	= task->task_lu_itl_handle;
929 	sbd_pgr_t		*pgr	= slu->sl_pgr;
930 	sbd_pgr_key_t		*key;
931 	scsi_prout_plist_t	*plist;
932 	uint64_t		rsv_key;
933 	uint8_t			*buf, buflen;
934 
935 	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_OUT);
936 
937 	if (dbuf == NULL || dbuf->db_data_size < 24) {
938 		stmf_scsilib_send_status(task, STATUS_CHECK,
939 		    STMF_SAA_PARAM_LIST_LENGTH_ERROR);
940 		return;
941 	}
942 
943 	buf = dbuf->db_sglist[0].seg_addr;
944 	buflen = dbuf->db_data_size;
945 	plist = (scsi_prout_plist_t *)buf;
946 
947 	/* SPC3 - 6.12.1 */
948 	if (pr_out->action != PR_OUT_REGISTER_MOVE && buflen != 24) {
949 		if ((pr_out->action !=
950 		    PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY &&
951 		    pr_out->action != PR_OUT_REGISTER) ||
952 		    plist->spec_i_pt == 0) {
953 			stmf_scsilib_send_status(task, STATUS_CHECK,
954 			    STMF_SAA_PARAM_LIST_LENGTH_ERROR);
955 			return;
956 		}
957 	}
958 
959 	/*
960 	 * Common Reservation Conflict Checks
961 	 *
962 	 * It is okey to handle REGISTER_MOVE with same plist here,
963 	 * because we are only accessing reservation key feild.
964 	 */
965 	rw_enter(&pgr->pgr_lock, RW_WRITER);
966 
967 	/*
968 	 * Currently it is not mandatory to have volatile keyword here,
969 	 * because, it->pgr_key_ptr is not accessed yet. But still
970 	 * keeping it to safe gaurd against any possible future changes.
971 	 */
972 	key = (sbd_pgr_key_t *)((volatile sbd_pgr_key_t *)it->pgr_key_ptr);
973 	if (pr_out->action != PR_OUT_REGISTER &&
974 	    pr_out->action != PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY) {
975 		/* if IT is not yet registered send conflict status */
976 		if (key == NULL) {
977 			if (pr_out->action == PR_OUT_REGISTER_MOVE &&
978 			    SBD_PGR_RSVD_NONE(pgr)) {
979 				stmf_scsilib_send_status(task, STATUS_CHECK,
980 				    STMF_SAA_INVALID_FIELD_IN_CDB);
981 
982 			} else {
983 				stmf_scsilib_send_status(task,
984 				    STATUS_RESERVATION_CONFLICT, 0);
985 			}
986 			rw_exit(&pgr->pgr_lock);
987 			return;
988 		}
989 
990 		/* Given reservation key should matches with registered key */
991 		rsv_key = READ_SCSI64(plist->reservation_key, uint64_t);
992 		if (key->pgr_key != rsv_key) {
993 			stmf_scsilib_send_status(task,
994 			    STATUS_RESERVATION_CONFLICT, 0);
995 			rw_exit(&pgr->pgr_lock);
996 			return;
997 		}
998 	}
999 
1000 	switch (pr_out->action) {
1001 	case PR_OUT_REGISTER:
1002 	case PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY:
1003 		sbd_pgr_out_register(task, dbuf);
1004 		break;
1005 	case PR_OUT_REGISTER_MOVE:
1006 		sbd_pgr_out_register_and_move(task, dbuf);
1007 		break;
1008 	case PR_OUT_RESERVE:
1009 		sbd_pgr_out_reserve(task);
1010 		break;
1011 	case PR_OUT_RELEASE:
1012 		sbd_pgr_out_release(task);
1013 		break;
1014 	case PR_OUT_CLEAR:
1015 		sbd_pgr_out_clear(task);
1016 		break;
1017 	case PR_OUT_PREEMPT:
1018 	case PR_OUT_PREEMPT_ABORT:
1019 		sbd_pgr_out_preempt(task, dbuf);
1020 		break;
1021 	default :
1022 		stmf_scsilib_send_status(task, STATUS_CHECK,
1023 		    STMF_SAA_INVALID_FIELD_IN_CDB);
1024 		break;
1025 	}
1026 	rw_exit(&pgr->pgr_lock);
1027 }
1028 
1029 static void
1030 sbd_pgr_in_read_keys(scsi_task_t *task, stmf_data_buf_t *initial_dbuf)
1031 {
1032 	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
1033 	sbd_pgr_t	*pgr   =  slu->sl_pgr;
1034 	sbd_pgr_key_t	*key;
1035 	scsi_prin_readrsrv_t *buf;
1036 	uint32_t buf_size, cdb_len, numkeys = 0;
1037 	uint64_t *reg_key;
1038 
1039 	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN);
1040 
1041 	cdb_len = READ_SCSI16(&task->task_cdb[7], uint16_t);
1042 	for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next)
1043 		++numkeys;
1044 	buf_size = 8 + numkeys * 8; /* minimum 8 bytes */
1045 	buf = kmem_zalloc(buf_size, KM_SLEEP);
1046 	SCSI_WRITE32(buf->PRgeneration, pgr->pgr_PRgeneration);
1047 	SCSI_WRITE32(buf->add_len, numkeys * 8);
1048 
1049 	reg_key = (uint64_t *)&buf->key_list;
1050 	for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next) {
1051 		SCSI_WRITE64(reg_key, key->pgr_key);
1052 		reg_key++;
1053 	}
1054 	sbd_handle_short_read_transfers(task, initial_dbuf, (uint8_t *)buf,
1055 	    cdb_len, buf_size);
1056 	kmem_free(buf, buf_size);
1057 }
1058 
1059 static void
1060 sbd_pgr_in_read_reservation(scsi_task_t *task, stmf_data_buf_t *initial_dbuf)
1061 {
1062 	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
1063 	sbd_pgr_t	*pgr   =  slu->sl_pgr;
1064 	scsi_prin_readrsrv_t *buf;
1065 	uint32_t cdb_len, buf_len, buf_size = 24;
1066 
1067 	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN);
1068 
1069 	cdb_len = READ_SCSI16(&task->task_cdb[7], uint16_t);
1070 	buf = kmem_zalloc(buf_size, KM_SLEEP); /* fixed size cdb, 24 bytes */
1071 	SCSI_WRITE32(buf->PRgeneration, pgr->pgr_PRgeneration);
1072 
1073 	if (SBD_PGR_RSVD_NONE(pgr)) {
1074 		SCSI_WRITE32(buf->add_len, 0);
1075 		buf_len = 8;
1076 	} else {
1077 		if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS) {
1078 			SCSI_WRITE64(
1079 			    buf->key_list.res_key_list[0].reservation_key, 0);
1080 		} else {
1081 			SCSI_WRITE64(
1082 			    buf->key_list.res_key_list[0].reservation_key,
1083 			    pgr->pgr_rsvholder->pgr_key);
1084 		}
1085 		buf->key_list.res_key_list[0].type = pgr->pgr_rsv_type;
1086 		buf->key_list.res_key_list[0].scope = pgr->pgr_rsv_scope;
1087 		SCSI_WRITE32(buf->add_len, 16);
1088 		buf_len = 24;
1089 	}
1090 
1091 	sbd_handle_short_read_transfers(task, initial_dbuf, (uint8_t *)buf,
1092 	    cdb_len, buf_len);
1093 	kmem_free(buf, buf_size);
1094 }
1095 
1096 static void
1097 sbd_pgr_in_report_capabilities(scsi_task_t *task,
1098 				stmf_data_buf_t *initial_dbuf)
1099 {
1100 	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
1101 	sbd_pgr_t	*pgr   =  slu->sl_pgr;
1102 	scsi_prin_rpt_cap_t buf;
1103 	uint32_t cdb_len;
1104 
1105 	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN);
1106 	ASSERT(pgr != NULL);
1107 
1108 	bzero(&buf, sizeof (buf));
1109 	buf.ptpl_c		= 1;   /* Persist Through Power Loss C */
1110 	buf.atp_c		= 1;   /* All Target Ports Capable */
1111 	buf.sip_c		= 1;   /* Specify Initiator Ports Capable */
1112 	buf.crh			= 0;   /* Supports Reserve/Release exception */
1113 	buf.tmv			= 1;   /* Type Mask Valid */
1114 	buf.pr_type.wr_ex	= 1;   /* Write Exclusve */
1115 	buf.pr_type.ex_ac	= 1;   /* Exclusive Access */
1116 	buf.pr_type.wr_ex_ro	= 1;   /* Write Exclusive Registrants Only */
1117 	buf.pr_type.ex_ac_ro	= 1;   /* Exclusive Access Registrants Only */
1118 	buf.pr_type.wr_ex_ar	= 1;   /* Write Exclusive All Registrants */
1119 	buf.pr_type.ex_ac_ar	= 1;   /* Exclusive Access All Registrants */
1120 
1121 	/* Persist Though Power Loss Active */
1122 	buf.ptpl_a = pgr->pgr_flags & SBD_PGR_APTPL;
1123 	SCSI_WRITE16(&buf.length, 8);
1124 	cdb_len = READ_SCSI16(&task->task_cdb[7], uint16_t);
1125 	sbd_handle_short_read_transfers(task, initial_dbuf, (uint8_t *)&buf,
1126 	    cdb_len, 8);
1127 }
1128 
1129 static void
1130 sbd_pgr_in_read_full_status(scsi_task_t *task,
1131 				stmf_data_buf_t *initial_dbuf)
1132 {
1133 	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
1134 	sbd_pgr_t	*pgr   = slu->sl_pgr;
1135 	sbd_pgr_key_t	*key;
1136 	scsi_prin_status_t 	*sts;
1137 	scsi_prin_full_status_t	*buf;
1138 	uint32_t 		i, buf_size, cdb_len, tptid_len;
1139 	uint8_t			*offset;
1140 
1141 	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN);
1142 	ASSERT(pgr != NULL);
1143 
1144 	cdb_len = READ_SCSI16(&task->task_cdb[7], uint16_t);
1145 
1146 	buf_size = 8; /* PRgeneration and additional length fields */
1147 	for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next) {
1148 		tptid_len = sbd_get_tptid_length_for_devid(key->pgr_key_rpt_id);
1149 		buf_size  = buf_size + 24 + tptid_len;
1150 	}
1151 
1152 	buf = kmem_zalloc(buf_size, KM_SLEEP);
1153 	SCSI_WRITE32(buf->PRgeneration, pgr->pgr_PRgeneration);
1154 	SCSI_WRITE32(buf->add_len, buf_size - 8);
1155 
1156 	offset	= (uint8_t *)&buf->full_desc[0];
1157 	key	= pgr->pgr_keylist;
1158 	i	= 0;
1159 	while (key) {
1160 		sts = (scsi_prin_status_t *)offset;
1161 		SCSI_WRITE64(sts->reservation_key, key->pgr_key);
1162 		if ((pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS) ||
1163 		    (pgr->pgr_rsvholder && pgr->pgr_rsvholder == key)) {
1164 				sts->r_holder	= 1;
1165 				sts->type 	= pgr->pgr_rsv_type;
1166 				sts->scope	= pgr->pgr_rsv_scope;
1167 		}
1168 
1169 		if (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) {
1170 			sts->all_tg_pt = 1;
1171 		} else {
1172 			SCSI_WRITE16(sts->rel_tgt_port_id,
1173 			    stmf_scsilib_get_lport_rtid(key->pgr_key_lpt_id));
1174 		}
1175 		tptid_len = sbd_devid_desc_to_tptid(key->pgr_key_rpt_id,
1176 		    &sts->trans_id);
1177 		SCSI_WRITE32(sts->add_len, tptid_len);
1178 		offset = offset + tptid_len + 24;
1179 		key = key->pgr_key_next;
1180 		++i;
1181 	}
1182 	ASSERT(offset <= (uint8_t *)buf + buf_size);
1183 
1184 	sbd_handle_short_read_transfers(task, initial_dbuf, (uint8_t *)buf,
1185 	    cdb_len, buf_size);
1186 	kmem_free(buf, buf_size);
1187 }
1188 
1189 static void
1190 sbd_pgr_out_register(scsi_task_t *task, stmf_data_buf_t *dbuf)
1191 {
1192 	sbd_lu_t	*slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
1193 	sbd_pgr_t		*pgr	= slu->sl_pgr;
1194 	stmf_scsi_session_t	*ses	= task->task_session;
1195 	sbd_it_data_t		*it	= task->task_lu_itl_handle;
1196 	sbd_pgr_key_t		*key	= it->pgr_key_ptr;
1197 	scsi_cdb_prout_t	*pr_out	= (scsi_cdb_prout_t *)task->task_cdb;
1198 	scsi_prout_plist_t	*plist;
1199 	uint8_t			*buf, buflen;
1200 	uint64_t		rsv_key, svc_key;
1201 
1202 	buf = dbuf->db_sglist[0].seg_addr;
1203 	plist = (scsi_prout_plist_t *)buf;
1204 	buflen = dbuf->db_data_size;
1205 	rsv_key = READ_SCSI64(plist->reservation_key, uint64_t);
1206 	svc_key = READ_SCSI64(plist->service_key, uint64_t);
1207 
1208 	/* Handling already registered IT session */
1209 	if (key) {
1210 
1211 		if (pr_out->action == PR_OUT_REGISTER &&
1212 		    key->pgr_key != rsv_key) {
1213 			stmf_scsilib_send_status(task,
1214 			    STATUS_RESERVATION_CONFLICT, 0);
1215 			return;
1216 		}
1217 		if (plist->spec_i_pt) {
1218 			stmf_scsilib_send_status(task, STATUS_CHECK,
1219 			    STMF_SAA_INVALID_FIELD_IN_CDB);
1220 			return;
1221 		}
1222 
1223 		if (plist->all_tg_pt !=
1224 		    (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT)) {
1225 			stmf_scsilib_send_status(task, STATUS_CHECK,
1226 			    STMF_SAA_INVALID_FIELD_IN_CDB);
1227 			return;
1228 		}
1229 
1230 		if (svc_key == 0) {
1231 			sbd_pgr_do_unregister(slu, it, key);
1232 		} else {
1233 			key->pgr_key = svc_key;
1234 		}
1235 
1236 		goto sbd_pgr_reg_done;
1237 	}
1238 
1239 	/* Handling unregistered IT session */
1240 	if (pr_out->action == PR_OUT_REGISTER && rsv_key != 0) {
1241 		stmf_scsilib_send_status(task, STATUS_RESERVATION_CONFLICT, 0);
1242 		return;
1243 	}
1244 
1245 	if (svc_key == 0) {
1246 		/* Do we need to consider aptpl here? I don't think so */
1247 		pgr->pgr_PRgeneration++;
1248 		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1249 		return;
1250 	}
1251 
1252 	if (plist->spec_i_pt) {
1253 		uint8_t *tpd, *tpdmax;
1254 		uint32_t tpdlen, max_tpdnum, tpdnum, i, adnlen = 0;
1255 		scsi_devid_desc_t **newdevids;
1256 		scsi_devid_desc_t *rpt, *lpt = ses->ss_lport->lport_id;
1257 
1258 		if (pr_out->action == PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY) {
1259 			stmf_scsilib_send_status(task, STATUS_CHECK,
1260 			    STMF_SAA_INVALID_FIELD_IN_CDB);
1261 			return;
1262 		}
1263 
1264 		if (plist->all_tg_pt)
1265 			lpt = NULL;
1266 
1267 		/* Validate the given length */
1268 		if (buflen >= sizeof (scsi_prout_plist_t) - 1 + 4)
1269 			adnlen = READ_SCSI32(plist->apd, uint32_t);
1270 		if (adnlen < sizeof (scsi_transport_id_t) + 4 ||
1271 		    buflen < sizeof (scsi_prout_plist_t) - 1 + adnlen) {
1272 			stmf_scsilib_send_status(task, STATUS_CHECK,
1273 			    STMF_SAA_PARAM_LIST_LENGTH_ERROR);
1274 			return;
1275 		}
1276 		tpdmax = plist->apd + adnlen + 4;
1277 		tpdlen = adnlen;
1278 		max_tpdnum = tpdlen / sizeof (scsi_transport_id_t);
1279 		newdevids  = kmem_zalloc(sizeof (scsi_devid_desc_t *) *
1280 		    max_tpdnum, KM_SLEEP);
1281 		tpdnum = 0;
1282 		/* Check the validity of given TransportIDs */
1283 		while (tpdlen != 0) {
1284 			tpd = tpdmax - tpdlen;
1285 			rpt = sbd_tptid_to_devid_desc((scsi_transport_id_t *)
1286 			    tpd, &tpdlen);
1287 			if (rpt == NULL)
1288 				break;
1289 			/* make sure that there is no duplicates */
1290 			for (i = 0; i < tpdnum; i++) {
1291 				if (rpt->ident_length ==
1292 				    newdevids[i]->ident_length &&
1293 				    (memcmp(rpt->ident, newdevids[i]->ident,
1294 				    rpt->ident_length) == 0)) {
1295 					break;
1296 				}
1297 			}
1298 			newdevids[tpdnum] = rpt;
1299 			tpdnum++;
1300 			if (i < tpdnum - 1)
1301 				break;
1302 			/* Check if the given IT nexus is already registered */
1303 			if (sbd_pgr_key_registered(pgr, lpt, rpt))
1304 				break;
1305 		}
1306 
1307 		for (i = 0; i < tpdnum; i++) {
1308 			rpt = newdevids[i];
1309 			if (tpdlen == 0) {
1310 				(void) sbd_pgr_do_register(slu, NULL,
1311 				    ses->ss_lport->lport_id, rpt,
1312 				    plist->all_tg_pt, svc_key);
1313 			}
1314 			kmem_free(rpt, sizeof (scsi_devid_desc_t) - 1 +
1315 			    rpt->ident_length);
1316 		}
1317 		kmem_free(newdevids,
1318 		    sizeof (scsi_devid_desc_t *) * max_tpdnum);
1319 		if (tpdlen != 0) {
1320 			stmf_scsilib_send_status(task, STATUS_CHECK,
1321 			    STMF_SAA_INVALID_FIELD_IN_CDB);
1322 			return;
1323 		}
1324 	}
1325 
1326 	(void) sbd_pgr_do_register(slu, it, ses->ss_lport->lport_id,
1327 	    ses->ss_rport_id, plist->all_tg_pt, svc_key);
1328 
1329 sbd_pgr_reg_done:
1330 
1331 	if (pgr->pgr_flags & SBD_PGR_APTPL || plist->aptpl) {
1332 		if (plist->aptpl)
1333 			PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
1334 		else
1335 			PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
1336 
1337 		if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1338 			stmf_scsilib_send_status(task, STATUS_CHECK,
1339 			    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1340 			return;
1341 		}
1342 	}
1343 
1344 	pgr->pgr_PRgeneration++;
1345 	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1346 }
1347 
1348 static sbd_pgr_key_t *
1349 sbd_pgr_do_register(sbd_lu_t *slu, sbd_it_data_t *it, scsi_devid_desc_t *lpt,
1350 		scsi_devid_desc_t *rpt,	uint8_t all_tg_pt, uint64_t svc_key)
1351 {
1352 	sbd_pgr_t		*pgr = slu->sl_pgr;
1353 	sbd_pgr_key_t		*key;
1354 	uint16_t		lpt_len, rpt_len;
1355 
1356 	lpt_len	= sizeof (scsi_devid_desc_t) - 1 + lpt->ident_length;
1357 	rpt_len	= sizeof (scsi_devid_desc_t) - 1 + rpt->ident_length;
1358 
1359 	key = sbd_pgr_key_alloc(lpt, rpt, lpt_len, rpt_len);
1360 	key->pgr_key = svc_key;
1361 
1362 	if (all_tg_pt) {
1363 		key->pgr_key_flags |= SBD_PGR_KEY_ALL_TG_PT;
1364 		/* set PGR_CHECK flag for all unregistered IT nexus */
1365 		sbd_pgr_set_pgr_check_flag(slu, B_FALSE);
1366 	} else {
1367 		key->pgr_key_it = it;
1368 	}
1369 
1370 	if (it) {
1371 		mutex_enter(&slu->sl_lock);
1372 		it->pgr_key_ptr = key;
1373 		mutex_exit(&slu->sl_lock);
1374 	}
1375 
1376 	key->pgr_key_next = pgr->pgr_keylist;
1377 	if (pgr->pgr_keylist) {
1378 		pgr->pgr_keylist->pgr_key_prev = key;
1379 	}
1380 	pgr->pgr_keylist = key;
1381 
1382 	return (key);
1383 }
1384 
1385 static void
1386 sbd_pgr_do_unregister(sbd_lu_t *slu, sbd_it_data_t *it, sbd_pgr_key_t *key)
1387 {
1388 	if (slu->sl_pgr->pgr_rsvholder == key) {
1389 		sbd_pgr_do_release(slu, it, SBD_UA_RESERVATIONS_RELEASED);
1390 	}
1391 
1392 	sbd_pgr_remove_key(slu, key);
1393 	if (slu->sl_pgr->pgr_keylist == NULL) {
1394 		PGR_CLEAR_RSV_FLAG(slu->sl_pgr->pgr_flags);
1395 	}
1396 }
1397 
1398 static void
1399 sbd_pgr_out_reserve(scsi_task_t *task)
1400 {
1401 	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
1402 	stmf_scsi_session_t	*ses	= task->task_session;
1403 	scsi_cdb_prout_t	*pr_out	= (scsi_cdb_prout_t *)task->task_cdb;
1404 	sbd_it_data_t		*it	= task->task_lu_itl_handle;
1405 	sbd_pgr_t		*pgr	= slu->sl_pgr;
1406 	sbd_pgr_key_t		*key	= it->pgr_key_ptr;
1407 
1408 	ASSERT(key);
1409 
1410 	if (!(PGR_VALID_SCOPE(pr_out->scope) && PGR_VALID_TYPE(pr_out->type))) {
1411 		stmf_scsilib_send_status(task, STATUS_CHECK,
1412 		    STMF_SAA_INVALID_FIELD_IN_CDB);
1413 		return;
1414 	}
1415 
1416 	if (SBD_PGR_RSVD(pgr)) {
1417 		if (PGR_RESERVATION_HOLDER(pgr, key, it)) {
1418 			if (pgr->pgr_rsv_type != pr_out->type ||
1419 			    pgr->pgr_rsv_scope != pr_out->scope) {
1420 				stmf_scsilib_send_status(task,
1421 				    STATUS_RESERVATION_CONFLICT, 0);
1422 				return;
1423 			}
1424 		} else {
1425 			stmf_scsilib_send_status(task,
1426 			    STATUS_RESERVATION_CONFLICT, 0);
1427 			return;
1428 
1429 		}
1430 	/* In case there is no reservation exist */
1431 	} else {
1432 		sbd_pgr_do_reserve(pgr, key, it, ses, pr_out);
1433 		if (pgr->pgr_flags & SBD_PGR_APTPL) {
1434 			if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1435 				stmf_scsilib_send_status(task, STATUS_CHECK,
1436 				    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1437 				return;
1438 			}
1439 		}
1440 	}
1441 
1442 	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1443 }
1444 
1445 static void
1446 sbd_pgr_do_reserve(sbd_pgr_t *pgr, sbd_pgr_key_t *key, sbd_it_data_t *it,
1447 			stmf_scsi_session_t *ses, scsi_cdb_prout_t *pr_out)
1448 {
1449 	scsi_devid_desc_t	*lpt;
1450 	uint16_t		lpt_len;
1451 
1452 	pgr->pgr_rsv_type = pr_out->type;
1453 	pgr->pgr_rsv_scope = pr_out->scope;
1454 	if (pr_out->type == PGR_TYPE_WR_EX_AR ||
1455 	    pr_out->type == PGR_TYPE_EX_AC_AR) {
1456 		PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_RSVD_ALL_REGISTRANTS);
1457 	} else {
1458 		if (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) {
1459 			lpt = key->pgr_key_lpt_id;
1460 			lpt_len = key->pgr_key_lpt_len;
1461 			if (lpt_len > 0 && lpt != NULL) {
1462 				kmem_free(lpt, lpt_len);
1463 			}
1464 			lpt = ses->ss_lport->lport_id;
1465 			lpt_len = sizeof (scsi_devid_desc_t) - 1 +
1466 			    lpt->ident_length;
1467 			key->pgr_key_lpt_len = lpt_len;
1468 			key->pgr_key_lpt_id = (scsi_devid_desc_t *)
1469 			    kmem_zalloc(lpt_len, KM_SLEEP);
1470 			bcopy(lpt, key->pgr_key_lpt_id, lpt_len);
1471 			key->pgr_key_it = it;
1472 		}
1473 
1474 		PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_RSVD_ONE);
1475 		pgr->pgr_rsvholder = key;
1476 	}
1477 }
1478 
1479 static void
1480 sbd_pgr_out_release(scsi_task_t *task)
1481 {
1482 	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
1483 	scsi_cdb_prout_t	*pr_out	= (scsi_cdb_prout_t *)task->task_cdb;
1484 	sbd_it_data_t		*it	= task->task_lu_itl_handle;
1485 	sbd_pgr_t		*pgr	= slu->sl_pgr;
1486 	sbd_pgr_key_t		*key	= it->pgr_key_ptr;
1487 
1488 	ASSERT(key);
1489 
1490 	if (SBD_PGR_RSVD(pgr)) {
1491 		if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS ||
1492 		    pgr->pgr_rsvholder == key) {
1493 			if (pgr->pgr_rsv_type != pr_out->type ||
1494 			    pgr->pgr_rsv_scope != pr_out->scope) {
1495 				stmf_scsilib_send_status(task, STATUS_CHECK,
1496 				    STMF_SAA_INVALID_RELEASE_OF_PR);
1497 				return;
1498 			}
1499 			sbd_pgr_do_release(slu, it,
1500 			    SBD_UA_RESERVATIONS_RELEASED);
1501 		}
1502 	}
1503 	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1504 }
1505 
1506 static void
1507 sbd_pgr_do_release(sbd_lu_t *slu, sbd_it_data_t *it, uint8_t ua_condition)
1508 {
1509 
1510 	sbd_pgr_t *pgr    =  slu->sl_pgr;
1511 
1512 	/* Reset pgr_flags */
1513 	PGR_CLEAR_RSV_FLAG(pgr->pgr_flags);
1514 	pgr->pgr_rsvholder = NULL;
1515 
1516 	/* set unit attention condition if necessary */
1517 	if (pgr->pgr_rsv_type != PGR_TYPE_WR_EX &&
1518 	    pgr->pgr_rsv_type != PGR_TYPE_EX_AC) {
1519 		sbd_pgr_set_ua_conditions(slu, it, ua_condition);
1520 	}
1521 	pgr->pgr_rsv_type = 0;
1522 }
1523 
1524 static void
1525 sbd_pgr_out_clear(scsi_task_t *task)
1526 {
1527 	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
1528 	sbd_it_data_t		*it	= task->task_lu_itl_handle;
1529 	sbd_pgr_t		*pgr	= slu->sl_pgr;
1530 
1531 	ASSERT(it->pgr_key_ptr);
1532 
1533 	PGR_CLEAR_RSV_FLAG(pgr->pgr_flags);
1534 	pgr->pgr_rsvholder = NULL;
1535 	pgr->pgr_rsv_type = 0;
1536 	mutex_enter(&slu->sl_lock);
1537 	/* Remove all pointers from IT to pgr keys */
1538 	for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
1539 		it->pgr_key_ptr = NULL;
1540 	}
1541 	mutex_exit(&slu->sl_lock);
1542 	sbd_pgr_keylist_dealloc(slu);
1543 	sbd_pgr_set_ua_conditions(slu, it, SBD_UA_RESERVATIONS_PREEMPTED);
1544 	if (pgr->pgr_flags & SBD_PGR_APTPL) {
1545 		if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1546 			stmf_scsilib_send_status(task, STATUS_CHECK,
1547 			    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1548 			return;
1549 		}
1550 	}
1551 	pgr->pgr_PRgeneration++;
1552 	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1553 }
1554 
1555 static void
1556 sbd_pgr_out_preempt(scsi_task_t *task, stmf_data_buf_t *dbuf)
1557 {
1558 	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
1559 	stmf_scsi_session_t	*ses	= task->task_session;
1560 	scsi_cdb_prout_t	*pr_out	= (scsi_cdb_prout_t *)task->task_cdb;
1561 	sbd_it_data_t		*it	= task->task_lu_itl_handle;
1562 	sbd_pgr_t		*pgr	= slu->sl_pgr;
1563 	sbd_pgr_key_t		*key	= it->pgr_key_ptr;
1564 	scsi_prout_plist_t	*plist;
1565 	uint8_t			*buf, change_rsv = 0;
1566 	uint64_t		svc_key;
1567 
1568 	ASSERT(key);
1569 
1570 	buf = dbuf->db_sglist[0].seg_addr;
1571 	plist = (scsi_prout_plist_t *)buf;
1572 	svc_key = READ_SCSI64(plist->service_key, uint64_t);
1573 
1574 	if (SBD_PGR_RSVD_NONE(pgr)) {
1575 		if (svc_key == 0 ||
1576 		    sbd_pgr_remove_keys(slu, it, key, svc_key, B_TRUE) == 0) {
1577 			stmf_scsilib_send_status(task,
1578 			    STATUS_RESERVATION_CONFLICT, 0);
1579 			return;
1580 		}
1581 
1582 	} else if (pgr->pgr_flags & SBD_PGR_RSVD_ONE) {
1583 		if (svc_key == 0) {
1584 			stmf_scsilib_send_status(task, STATUS_CHECK,
1585 			    STMF_SAA_INVALID_FIELD_IN_CDB);
1586 			return;
1587 		}
1588 
1589 		/* Validity check of scope and type */
1590 		if (pgr->pgr_rsvholder->pgr_key == svc_key) {
1591 			if (!(PGR_VALID_SCOPE(pr_out->scope) &&
1592 			    PGR_VALID_TYPE(pr_out->type))) {
1593 				stmf_scsilib_send_status(task, STATUS_CHECK,
1594 				    STMF_SAA_INVALID_FIELD_IN_CDB);
1595 				return;
1596 			}
1597 		}
1598 
1599 		if (pgr->pgr_rsvholder != key &&
1600 		    pgr->pgr_rsvholder->pgr_key == svc_key) {
1601 			sbd_pgr_do_release(slu, it,
1602 			    SBD_UA_REGISTRATIONS_PREEMPTED);
1603 			change_rsv = 1;
1604 		}
1605 
1606 		if (pgr->pgr_rsvholder == key &&
1607 		    pgr->pgr_rsvholder->pgr_key == svc_key) {
1608 			if (pr_out->scope != pgr->pgr_rsv_scope ||
1609 			    pr_out->type != pgr->pgr_rsv_type) {
1610 				sbd_pgr_do_release(slu, it,
1611 				    SBD_UA_REGISTRATIONS_PREEMPTED);
1612 				change_rsv = 1;
1613 			}
1614 		} else {
1615 			/*
1616 			 * Remove matched keys in all cases, except when the
1617 			 * current IT nexus holds the reservation and the given
1618 			 * svc_key matches with registered key.
1619 			 * Note that, if the reservation is held by another
1620 			 * IT nexus, and svc_key matches registered key for
1621 			 * that IT nexus, sbd_pgr_remove_key() is not expected
1622 			 * return 0. Hence, returning check condition after
1623 			 * releasing the reservation does not arise.
1624 			 */
1625 			if (sbd_pgr_remove_keys(slu, it, key, svc_key, B_TRUE)
1626 			    == 0) {
1627 				stmf_scsilib_send_status(task,
1628 				    STATUS_RESERVATION_CONFLICT, 0);
1629 				return;
1630 			}
1631 		}
1632 
1633 		if (change_rsv) {
1634 			sbd_pgr_do_reserve(pgr, key, it, ses, pr_out);
1635 		}
1636 
1637 	} else if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS) {
1638 		if (svc_key == 0) {
1639 			if (!(PGR_VALID_SCOPE(pr_out->scope) &&
1640 			    PGR_VALID_TYPE(pr_out->type))) {
1641 				stmf_scsilib_send_status(task, STATUS_CHECK,
1642 				    STMF_SAA_INVALID_FIELD_IN_CDB);
1643 				return;
1644 			}
1645 			sbd_pgr_do_release(slu, it,
1646 			    SBD_UA_REGISTRATIONS_PREEMPTED);
1647 			(void) sbd_pgr_remove_keys(slu, it, key, 0, B_FALSE);
1648 			sbd_pgr_do_reserve(pgr, key, it, ses, pr_out);
1649 		} else {
1650 			if (sbd_pgr_remove_keys(slu, it, key, svc_key, B_TRUE)
1651 			    == 0) {
1652 				stmf_scsilib_send_status(task,
1653 				    STATUS_RESERVATION_CONFLICT, 0);
1654 				return;
1655 			}
1656 		}
1657 	}
1658 
1659 	if (pgr->pgr_flags & SBD_PGR_APTPL) {
1660 		if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1661 			stmf_scsilib_send_status(task, STATUS_CHECK,
1662 			    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1663 			return;
1664 		}
1665 	}
1666 
1667 	pgr->pgr_PRgeneration++;
1668 
1669 	if (pr_out->action == PR_OUT_PREEMPT_ABORT) {
1670 		stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED,
1671 		    (void *)slu->sl_lu);
1672 	}
1673 	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1674 }
1675 
1676 static void
1677 sbd_pgr_out_register_and_move(scsi_task_t *task, stmf_data_buf_t *dbuf)
1678 {
1679 	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
1680 	sbd_it_data_t		*it	= task->task_lu_itl_handle;
1681 	sbd_pgr_t		*pgr	= slu->sl_pgr;
1682 	sbd_pgr_key_t		*key	= it->pgr_key_ptr;
1683 	scsi_devid_desc_t	*lpt, *rpt;
1684 	sbd_pgr_key_t		*newkey;
1685 	scsi_prout_reg_move_plist_t *plist;
1686 	uint8_t			*buf, lpt_len;
1687 	uint32_t		tpd_len;
1688 	uint64_t		svc_key;
1689 
1690 	/*
1691 	 * Check whether the key holds the reservation or current reservation
1692 	 * is of type all registrants.
1693 	 */
1694 	if (pgr->pgr_rsvholder != key) {
1695 		stmf_scsilib_send_status(task, STATUS_RESERVATION_CONFLICT, 0);
1696 		return;
1697 	}
1698 
1699 	buf = dbuf->db_sglist[0].seg_addr;
1700 	plist = (scsi_prout_reg_move_plist_t *)buf;
1701 	svc_key = READ_SCSI64(plist->service_key, uint64_t);
1702 	if (svc_key == 0) {
1703 		stmf_scsilib_send_status(task, STATUS_CHECK,
1704 		    STMF_SAA_INVALID_FIELD_IN_CDB);
1705 		return;
1706 	}
1707 
1708 	lpt = stmf_scsilib_get_devid_desc(READ_SCSI16(plist->rel_tgt_port_id,
1709 	    uint16_t));
1710 	if (lpt == NULL) {
1711 		stmf_scsilib_send_status(task, STATUS_CHECK,
1712 		    STMF_SAA_INVALID_FIELD_IN_CDB);
1713 		return;
1714 	}
1715 
1716 	tpd_len = READ_SCSI32(plist->tptid_len, uint32_t);
1717 	rpt = sbd_tptid_to_devid_desc((scsi_transport_id_t *)plist->tptid,
1718 	    &tpd_len);
1719 	if (rpt == NULL) {
1720 		stmf_scsilib_send_status(task, STATUS_CHECK,
1721 		    STMF_SAA_INVALID_FIELD_IN_PARAM_LIST);
1722 		return;
1723 	} else if (rpt->ident_length == key->pgr_key_rpt_id->ident_length &&
1724 	    (memcmp(rpt->ident, key->pgr_key_rpt_id->ident, rpt->ident_length)
1725 	    == 0)) {
1726 		kmem_free(rpt, sizeof (rpt) - 1 + rpt->ident_length);
1727 		kmem_free(lpt, sizeof (lpt) - 1 + lpt->ident_length);
1728 		stmf_scsilib_send_status(task, STATUS_CHECK,
1729 		    STMF_SAA_INVALID_FIELD_IN_PARAM_LIST);
1730 		return;
1731 	}
1732 
1733 	newkey = sbd_pgr_key_registered(pgr, lpt, rpt);
1734 	if (newkey) {
1735 		/* Set the pgr_key, irrespective of what it currently holds */
1736 		newkey->pgr_key = svc_key;
1737 
1738 		/* all_tg_pt is set for found key, copy lpt info to the key */
1739 		if (newkey->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) {
1740 			if (newkey->pgr_key_lpt_id &&
1741 			    newkey->pgr_key_lpt_len > 0) {
1742 				kmem_free(newkey->pgr_key_lpt_id,
1743 				    newkey->pgr_key_lpt_len);
1744 			}
1745 			lpt_len = sizeof (scsi_devid_desc_t) - 1 +
1746 			    lpt->ident_length;
1747 			newkey->pgr_key_lpt_len = lpt_len;
1748 			newkey->pgr_key_lpt_id = (scsi_devid_desc_t *)
1749 			    kmem_zalloc(lpt_len, KM_SLEEP);
1750 			bcopy(lpt, newkey->pgr_key_lpt_id, lpt_len);
1751 		}
1752 	} else  {
1753 		newkey = sbd_pgr_do_register(slu, NULL, lpt, rpt, 0, svc_key);
1754 	}
1755 
1756 	kmem_free(rpt, sizeof (scsi_devid_desc_t) - 1 + rpt->ident_length);
1757 	kmem_free(lpt, sizeof (scsi_devid_desc_t) - 1 + lpt->ident_length);
1758 
1759 	/* Now reserve the key corresponding to the specified IT nexus */
1760 	pgr->pgr_rsvholder = newkey;
1761 
1762 	if (plist->unreg) {
1763 		sbd_pgr_do_unregister(slu, it, key);
1764 	}
1765 
1766 	/* Since we do not have IT nexus information, set PGR_CHEK flag */
1767 	sbd_pgr_set_pgr_check_flag(slu, B_TRUE);
1768 
1769 	/* Write to disk if currenty aptpl is set or given task is setting it */
1770 	if (pgr->pgr_flags & SBD_PGR_APTPL || plist->aptpl) {
1771 		if (plist->aptpl)
1772 			PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
1773 		else
1774 			PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
1775 
1776 		if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
1777 			stmf_scsilib_send_status(task, STATUS_CHECK,
1778 			    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
1779 			return;
1780 		}
1781 	}
1782 
1783 	pgr->pgr_PRgeneration++;
1784 	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
1785 }
1786 
1787 void
1788 sbd_pgr_remove_it_handle(sbd_lu_t *sl, sbd_it_data_t *my_it) {
1789 	sbd_it_data_t *it;
1790 
1791 	rw_enter(&sl->sl_pgr->pgr_lock, RW_WRITER);
1792 	mutex_enter(&sl->sl_lock);
1793 	for (it = sl->sl_it_list; it != NULL; it = it->sbd_it_next) {
1794 		if (it == my_it) {
1795 			if (it->pgr_key_ptr) {
1796 				sbd_pgr_key_t *key = it->pgr_key_ptr;
1797 				if (key->pgr_key_it == it) {
1798 					key->pgr_key_it = NULL;
1799 					sl->sl_pgr->pgr_flags &=
1800 					    ~SBD_PGR_ALL_KEYS_HAS_IT;
1801 				}
1802 			}
1803 			break;
1804 		}
1805 	}
1806 	mutex_exit(&sl->sl_lock);
1807 	rw_exit(&sl->sl_pgr->pgr_lock);
1808 
1809 }
1810 
1811 scsi_devid_desc_t *
1812 sbd_tptid_to_devid_desc(scsi_transport_id_t *tptid, uint32_t *tptid_len)
1813 {
1814 
1815 	scsi_devid_desc_t *devid = NULL;
1816 	uint16_t ident_len,  sz;
1817 
1818 	struct scsi_fc_transport_id	*fcid;
1819 	struct iscsi_transport_id	*iscsiid;
1820 	struct scsi_srp_transport_id	*srpid;
1821 	char	eui_str[20+1];
1822 
1823 	switch (tptid->protocol_id) {
1824 
1825 	case PROTOCOL_FIBRE_CHANNEL:
1826 
1827 		if (*tptid_len < 24 || tptid->format_code != 0) {
1828 			return (NULL);
1829 		}
1830 		*tptid_len -= 24;
1831 		ident_len = 20; /* wwn.XXXXXXXXXXXXXXXX */
1832 		fcid	= (scsi_fc_transport_id_t *)tptid;
1833 		sz	= sizeof (scsi_devid_desc_t) - 1 + ident_len;
1834 		devid	= (scsi_devid_desc_t *)kmem_zalloc(sz, KM_SLEEP);
1835 		stmf_wwn_to_devid_desc(devid, fcid->port_name,
1836 		    PROTOCOL_FIBRE_CHANNEL);
1837 		return (devid);
1838 
1839 	case PROTOCOL_iSCSI:
1840 
1841 		if (tptid->format_code != 0 && tptid->format_code != 1) {
1842 			return (NULL);
1843 		}
1844 		iscsiid 	= (iscsi_transport_id_t *)tptid;
1845 		ident_len 	= READ_SCSI16(iscsiid->add_len, uint16_t);
1846 		if (*tptid_len < sizeof (iscsi_transport_id_t) + ident_len) {
1847 			return (NULL);
1848 		}
1849 		*tptid_len -= (sizeof (iscsi_transport_id_t) + ident_len);
1850 		sz	= sizeof (scsi_devid_desc_t) - 1 + ident_len;
1851 		devid	= (scsi_devid_desc_t *)kmem_zalloc(sz, KM_SLEEP);
1852 		(void) memcpy(devid->ident, iscsiid->iscsi_name, ident_len);
1853 		/* LINTED E_ASSIGN_NARROW_CONV */
1854 		devid->ident_length	= ident_len;
1855 		devid->protocol_id	= tptid->protocol_id;
1856 		devid->code_set		= CODE_SET_ASCII;
1857 		return (devid);
1858 
1859 	case PROTOCOL_SRP:
1860 		if (*tptid_len < 24 || tptid->format_code != 0) {
1861 			return (NULL);
1862 		}
1863 		*tptid_len -= 24;
1864 		srpid	= (scsi_srp_transport_id_t *)tptid;
1865 		ident_len = sizeof (eui_str) - 1; /* eui.XXXXXXXXXXXXXXXX */
1866 		sz	= sizeof (scsi_devid_desc_t) - 1 + ident_len;
1867 		devid	= (scsi_devid_desc_t *)kmem_zalloc(sz, KM_SLEEP);
1868 		/* ASSUME: initiator-extension of srp_name is zero */
1869 		(void) snprintf(eui_str, sizeof (eui_str), "eui.%016llX",
1870 		    (u_longlong_t)BE_IN64(srpid->srp_name));
1871 		bcopy(eui_str, devid->ident, ident_len);
1872 		/* LINTED E_ASSIGN_NARROW_CONV */
1873 		devid->ident_length	= ident_len;
1874 		devid->protocol_id	= tptid->protocol_id;
1875 		devid->code_set		= CODE_SET_ASCII;
1876 		return (devid);
1877 
1878 	default:
1879 		cmn_err(CE_NOTE, "sbd_tptid_to_devid_desc: received unknown"
1880 		    "protocol id 0x%x", tptid->protocol_id);
1881 		return (NULL);
1882 	}
1883 }
1884 
1885 /*
1886  * Changes devid_desc to corresponding TransportID format
1887  * Returns : Total length used by TransportID
1888  * Note    :- No buffer length checking
1889  */
1890 uint32_t
1891 sbd_devid_desc_to_tptid(scsi_devid_desc_t *devid, scsi_transport_id_t *tptid)
1892 {
1893 	struct scsi_fc_transport_id	*fcid;
1894 	struct iscsi_transport_id	*iscsiid;
1895 	struct scsi_srp_transport_id	*srpid;
1896 	uint32_t ident_len,  sz = 0;
1897 
1898 	switch (devid->protocol_id) {
1899 	case PROTOCOL_FIBRE_CHANNEL:
1900 		fcid = (scsi_fc_transport_id_t *)tptid;
1901 		tptid->format_code = 0;
1902 		tptid->protocol_id = devid->protocol_id;
1903 		/* convert from "wwn.XXXXXXXXXXXXXXXX" to 8-byte binary */
1904 		ASSERT(strncmp("wwn.", (char *)devid->ident, 4) == 0);
1905 		sbd_base16_str_to_binary((char *)devid->ident + 4, 16,
1906 		    fcid->port_name);
1907 		sz = 24;
1908 		break;
1909 
1910 	case PROTOCOL_iSCSI:
1911 		iscsiid = (iscsi_transport_id_t *)tptid;
1912 		ident_len = devid->ident_length;
1913 		tptid->format_code = 0;
1914 		tptid->protocol_id = devid->protocol_id;
1915 		SCSI_WRITE16(iscsiid->add_len, ident_len);
1916 		(void) memcpy(iscsiid->iscsi_name, devid->ident, ident_len);
1917 		sz = ALIGNED_TO_WORD_BOUNDARY(4 + ident_len);
1918 		break;
1919 
1920 	case PROTOCOL_SRP:
1921 		srpid = (scsi_srp_transport_id_t *)tptid;
1922 		tptid->format_code = 0;
1923 		tptid->protocol_id = devid->protocol_id;
1924 		/* convert from "eui.XXXXXXXXXXXXXXXX" to 8-byte binary */
1925 		ASSERT(strncmp("eui.", (char *)devid->ident, 4) == 0);
1926 		sbd_base16_str_to_binary((char *)devid->ident+4, 16,
1927 		    srpid->srp_name);
1928 		/* ASSUME: initiator-extension part of srp_name is zero */
1929 		sz = 24;
1930 		break;
1931 
1932 	default :
1933 		cmn_err(CE_NOTE, "sbd_devid_desc_to_tptid: received unknown"
1934 		    " protocol id 0x%x", devid->protocol_id);
1935 		break;
1936 	}
1937 
1938 	return (sz);
1939 }
1940 
1941 uint32_t
1942 sbd_get_tptid_length_for_devid(scsi_devid_desc_t *devid)
1943 {
1944 	uint32_t sz = 0;
1945 	switch (devid->protocol_id) {
1946 	case PROTOCOL_SRP:
1947 	case PROTOCOL_FIBRE_CHANNEL:
1948 		sz = 24;
1949 		break;
1950 	case PROTOCOL_iSCSI:
1951 		sz = 4 + devid->ident_length;
1952 		break;
1953 	}
1954 	sz = ALIGNED_TO_WORD_BOUNDARY(sz);
1955 	sz = (sz > 0 && sz < 24) ? 24 : sz;
1956 
1957 	return (sz);
1958 }
1959 
1960 char *
1961 sbd_get_devid_string(sbd_lu_t *sl)
1962 {
1963 	char *str = (char *)kmem_zalloc(33, KM_SLEEP);
1964 	(void) snprintf(str, 33,
1965 	    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
1966 	    sl->sl_device_id[4], sl->sl_device_id[5], sl->sl_device_id[6],
1967 	    sl->sl_device_id[7], sl->sl_device_id[8], sl->sl_device_id[9],
1968 	    sl->sl_device_id[10], sl->sl_device_id[11], sl->sl_device_id[12],
1969 	    sl->sl_device_id[13], sl->sl_device_id[14], sl->sl_device_id[15],
1970 	    sl->sl_device_id[16], sl->sl_device_id[17], sl->sl_device_id[18],
1971 	    sl->sl_device_id[19]);
1972 	return (str);
1973 }
1974 
1975 /* Convert from Hex value in ASCII format to the equivalent bytes */
1976 void
1977 sbd_base16_str_to_binary(char *c, int len, uint8_t *dp)
1978 {
1979 	int		ii;
1980 
1981 	ASSERT((len & 1) == 0);
1982 
1983 	for (ii = 0; ii < len / 2; ii++) {
1984 		char nibble1, nibble2;
1985 		char enc_char = *c++;
1986 		nibble1 = sbd_ctoi(enc_char);
1987 
1988 		enc_char = *c++;
1989 		nibble2 = sbd_ctoi(enc_char);
1990 
1991 		dp[ii] = (nibble1 << 4) | nibble2;
1992 	}
1993 }
1994