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