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