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