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