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