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 263 sbd_swap_pgr_info(sbd_pgr_info_t *spi) 264 { 265 sbd_swap_section_hdr(&spi->pgr_sms_header); 266 if (spi->pgr_data_order == SMS_DATA_ORDER) 267 return; 268 spi->pgr_sms_header.sms_chksum += SMS_DATA_ORDER - spi->pgr_data_order; 269 spi->pgr_rsvholder_indx = BSWAP_32(spi->pgr_rsvholder_indx); 270 spi->pgr_numkeys = BSWAP_32(spi->pgr_numkeys); 271 } 272 273 static void 274 sbd_swap_pgrkey_info(sbd_pgr_key_info_t *key) 275 { 276 key->pgr_key = BSWAP_64(key->pgr_key); 277 key->pgr_key_lpt_len = BSWAP_16(key->pgr_key_lpt_len); 278 key->pgr_key_rpt_len = BSWAP_16(key->pgr_key_rpt_len); 279 } 280 281 sbd_status_t 282 sbd_pgr_meta_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 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 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 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 * 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 * 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