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