1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/atomic.h> 26 #include <sys/conf.h> 27 #include <sys/byteorder.h> 28 #include <sys/scsi/scsi_types.h> 29 #include <sys/scsi/generic/persist.h> 30 31 #include <sys/lpif.h> 32 #include <sys/stmf.h> 33 #include <sys/stmf_ioctl.h> 34 #include <sys/portif.h> 35 #include <sys/stmf_sbd_ioctl.h> 36 37 #include "stmf_sbd.h" 38 #include "sbd_impl.h" 39 40 #define MAX_PGR_PARAM_LIST_LENGTH (256 * 1024) 41 42 int sbd_pgr_reservation_conflict(scsi_task_t *); 43 void sbd_pgr_reset(sbd_lu_t *); 44 void sbd_pgr_initialize_it(scsi_task_t *, sbd_it_data_t *); 45 void sbd_handle_pgr_in_cmd(scsi_task_t *, stmf_data_buf_t *); 46 void sbd_handle_pgr_out_cmd(scsi_task_t *, stmf_data_buf_t *); 47 void sbd_handle_pgr_out_data(scsi_task_t *, stmf_data_buf_t *); 48 void sbd_pgr_keylist_dealloc(sbd_lu_t *); 49 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, sbd_it_data_t *it) 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_pgr_t *pgr = slu->sl_pgr; 721 sbd_pgr_key_t *key; 722 scsi_devid_desc_t *lpt, *rpt, *id; 723 724 if (pgr->pgr_flags & SBD_PGR_ALL_KEYS_HAS_IT) 725 return; 726 rpt = ses->ss_rport_id; 727 lpt = ses->ss_lport->lport_id; 728 729 rw_enter(&pgr->pgr_lock, RW_WRITER); 730 PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_ALL_KEYS_HAS_IT); 731 for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next) { 732 733 if ((!(key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT)) && 734 key->pgr_key_it != NULL) 735 continue; 736 /* 737 * SBD_PGR_ALL_KEYS_HAS_IT is set only if no single key 738 * in the list has SBD_PGR_KEY_ALL_TG_PT flag set and 739 * pgr_key_it all keys points to some IT 740 */ 741 PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_ALL_KEYS_HAS_IT); 742 743 /* Check if key matches with given lpt rpt combination */ 744 if (sbd_pgr_key_compare(key, lpt, rpt) == B_FALSE) 745 continue; 746 747 /* IT nexus devid information matches with this key */ 748 if (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) { 749 /* 750 * If ALL_TG_PT is set, pgr_key_it will point to NULL, 751 * unless pgr->pgr_rsvholder pointing to this key. 752 * In that case, pgr_key_it should point to the IT 753 * which initiated that reservation. 754 */ 755 if (pgr->pgr_rsvholder == key) { 756 id = key->pgr_key_lpt_id; 757 if (lpt->ident_length == id->ident_length) { 758 if (memcmp(id->ident, lpt->ident, 759 id->ident_length) == 0) 760 key->pgr_key_it = it; 761 } 762 } 763 764 } else { 765 key->pgr_key_it = it; 766 } 767 768 mutex_enter(&slu->sl_lock); 769 it->pgr_key_ptr = key; 770 mutex_exit(&slu->sl_lock); 771 rw_exit(&pgr->pgr_lock); 772 return; 773 } 774 rw_exit(&pgr->pgr_lock); 775 } 776 777 /* 778 * Check for any PGR Reservation conflict. return 0 if access allowed 779 */ 780 int 781 sbd_pgr_reservation_conflict(scsi_task_t *task) 782 { 783 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private; 784 sbd_pgr_t *pgr = slu->sl_pgr; 785 sbd_it_data_t *it = (sbd_it_data_t *)task->task_lu_itl_handle; 786 787 /* If Registered */ 788 if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS && it->pgr_key_ptr) 789 return (0); 790 791 /* If you are registered */ 792 if (pgr->pgr_flags & SBD_PGR_RSVD_ONE) { 793 rw_enter(&pgr->pgr_lock, RW_READER); 794 795 /* 796 * Note: it->pgr_key_ptr is protected by sl_lock. Also, 797 * it is expected to change its value only with pgr_lock 798 * held. Hence we are safe to read its value without 799 * grabbing sl_lock. But make sure that the value used is 800 * not from registers by using "volatile" keyword. 801 * Since this funtion is in performance path, we may want 802 * to avoid grabbing sl_lock. 803 */ 804 if ((volatile sbd_pgr_key_t *)it->pgr_key_ptr) { 805 /* If you are the reservation holder */ 806 if (pgr->pgr_rsvholder == it->pgr_key_ptr && 807 it->pgr_key_ptr->pgr_key_it == it) { 808 rw_exit(&pgr->pgr_lock); 809 return (0); 810 } 811 812 /* If reserve type is not EX_AC */ 813 if (pgr->pgr_rsv_type != PGR_TYPE_EX_AC) { 814 /* If reserve type is WR_EX allow read */ 815 if (pgr->pgr_rsv_type == PGR_TYPE_WR_EX) { 816 if (PGR_READ_POSSIBLE_CMDS( 817 task->task_cdb[0])) { 818 rw_exit(&pgr->pgr_lock); 819 return (0); 820 } 821 /* For all other reserve types allow access */ 822 } else { 823 rw_exit(&pgr->pgr_lock); 824 return (0); 825 } 826 } 827 828 /* If registered, allow these commands */ 829 if (PGR_REGISTERED_POSSIBLE_CMDS(task->task_cdb)) { 830 rw_exit(&pgr->pgr_lock); 831 return (0); 832 } 833 } 834 rw_exit(&pgr->pgr_lock); 835 } 836 837 /* For any case, allow these commands */ 838 if (PGR_CONFLICT_FREE_CMDS(task->task_cdb)) { 839 return (0); 840 } 841 842 /* Give read access if reservation type WR_EX for registrants */ 843 if (pgr->pgr_rsv_type == PGR_TYPE_WR_EX_RO || 844 pgr->pgr_rsv_type == PGR_TYPE_WR_EX_AR) { 845 if (PGR_READ_POSSIBLE_CMDS(task->task_cdb[0])) 846 return (0); 847 } 848 849 /* If you reached here, No access for you */ 850 return (1); 851 } 852 853 void 854 sbd_handle_pgr_in_cmd(scsi_task_t *task, stmf_data_buf_t *initial_dbuf) 855 { 856 857 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private; 858 sbd_pgr_t *pgr = slu->sl_pgr; 859 scsi_cdb_prin_t *pr_in; 860 861 ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN); 862 863 pr_in = (scsi_cdb_prin_t *)task->task_cdb; 864 865 rw_enter(&pgr->pgr_lock, RW_READER); 866 switch (pr_in->action) { 867 case PR_IN_READ_KEYS: 868 sbd_pgr_in_read_keys(task, initial_dbuf); 869 break; 870 case PR_IN_READ_RESERVATION: 871 sbd_pgr_in_read_reservation(task, initial_dbuf); 872 break; 873 case PR_IN_REPORT_CAPABILITIES: 874 sbd_pgr_in_report_capabilities(task, initial_dbuf); 875 break; 876 case PR_IN_READ_FULL_STATUS: 877 sbd_pgr_in_read_full_status(task, initial_dbuf); 878 break; 879 default : 880 stmf_scsilib_send_status(task, STATUS_CHECK, 881 STMF_SAA_INVALID_FIELD_IN_CDB); 882 break; 883 } 884 rw_exit(&pgr->pgr_lock); 885 } 886 887 void 888 sbd_handle_pgr_out_cmd(scsi_task_t *task, stmf_data_buf_t *initial_dbuf) 889 { 890 891 scsi_cdb_prout_t *pr_out = (scsi_cdb_prout_t *)task->task_cdb; 892 uint32_t param_len; 893 894 ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_OUT); 895 896 switch (pr_out->action) { 897 case PR_OUT_REGISTER: 898 case PR_OUT_RESERVE: 899 case PR_OUT_RELEASE: 900 case PR_OUT_CLEAR: 901 case PR_OUT_PREEMPT: 902 case PR_OUT_PREEMPT_ABORT: 903 case PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY: 904 case PR_OUT_REGISTER_MOVE: 905 param_len = READ_SCSI32(pr_out->param_len, uint32_t); 906 if (param_len < MAX_PGR_PARAM_LIST_LENGTH && 907 param_len > 0) { 908 sbd_handle_short_write_transfers(task, 909 initial_dbuf, param_len); 910 } else { 911 stmf_scsilib_send_status(task, STATUS_CHECK, 912 STMF_SAA_PARAM_LIST_LENGTH_ERROR); 913 } 914 break; 915 default : 916 stmf_scsilib_send_status(task, STATUS_CHECK, 917 STMF_SAA_INVALID_FIELD_IN_CDB); 918 break; 919 } 920 } 921 922 void 923 sbd_handle_pgr_out_data(scsi_task_t *task, stmf_data_buf_t *dbuf) 924 { 925 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private; 926 scsi_cdb_prout_t *pr_out = (scsi_cdb_prout_t *)task->task_cdb; 927 sbd_it_data_t *it = task->task_lu_itl_handle; 928 sbd_pgr_t *pgr = slu->sl_pgr; 929 sbd_pgr_key_t *key; 930 scsi_prout_plist_t *plist; 931 uint64_t rsv_key; 932 uint8_t *buf, buflen; 933 934 ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_OUT); 935 936 if (dbuf == NULL || dbuf->db_data_size < 24) { 937 stmf_scsilib_send_status(task, STATUS_CHECK, 938 STMF_SAA_PARAM_LIST_LENGTH_ERROR); 939 return; 940 } 941 942 buf = dbuf->db_sglist[0].seg_addr; 943 buflen = dbuf->db_data_size; 944 plist = (scsi_prout_plist_t *)buf; 945 946 /* SPC3 - 6.12.1 */ 947 if (pr_out->action != PR_OUT_REGISTER_MOVE && buflen != 24) { 948 if ((pr_out->action != 949 PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY && 950 pr_out->action != PR_OUT_REGISTER) || 951 plist->spec_i_pt == 0) { 952 stmf_scsilib_send_status(task, STATUS_CHECK, 953 STMF_SAA_PARAM_LIST_LENGTH_ERROR); 954 return; 955 } 956 } 957 958 /* 959 * Common Reservation Conflict Checks 960 * 961 * It is okey to handle REGISTER_MOVE with same plist here, 962 * because we are only accessing reservation key feild. 963 */ 964 rw_enter(&pgr->pgr_lock, RW_WRITER); 965 966 /* 967 * Currently it is not mandatory to have volatile keyword here, 968 * because, it->pgr_key_ptr is not accessed yet. But still 969 * keeping it to safe gaurd against any possible future changes. 970 */ 971 key = (sbd_pgr_key_t *)((volatile sbd_pgr_key_t *)it->pgr_key_ptr); 972 if (pr_out->action != PR_OUT_REGISTER && 973 pr_out->action != PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY) { 974 /* if IT is not yet registered send conflict status */ 975 if (key == NULL) { 976 if (pr_out->action == PR_OUT_REGISTER_MOVE && 977 SBD_PGR_RSVD_NONE(pgr)) { 978 stmf_scsilib_send_status(task, STATUS_CHECK, 979 STMF_SAA_INVALID_FIELD_IN_CDB); 980 981 } else { 982 stmf_scsilib_send_status(task, 983 STATUS_RESERVATION_CONFLICT, 0); 984 } 985 rw_exit(&pgr->pgr_lock); 986 return; 987 } 988 989 /* Given reservation key should matches with registered key */ 990 rsv_key = READ_SCSI64(plist->reservation_key, uint64_t); 991 if (key->pgr_key != rsv_key) { 992 stmf_scsilib_send_status(task, 993 STATUS_RESERVATION_CONFLICT, 0); 994 rw_exit(&pgr->pgr_lock); 995 return; 996 } 997 } 998 999 switch (pr_out->action) { 1000 case PR_OUT_REGISTER: 1001 case PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY: 1002 sbd_pgr_out_register(task, dbuf); 1003 break; 1004 case PR_OUT_REGISTER_MOVE: 1005 sbd_pgr_out_register_and_move(task, dbuf); 1006 break; 1007 case PR_OUT_RESERVE: 1008 sbd_pgr_out_reserve(task); 1009 break; 1010 case PR_OUT_RELEASE: 1011 sbd_pgr_out_release(task); 1012 break; 1013 case PR_OUT_CLEAR: 1014 sbd_pgr_out_clear(task); 1015 break; 1016 case PR_OUT_PREEMPT: 1017 case PR_OUT_PREEMPT_ABORT: 1018 sbd_pgr_out_preempt(task, dbuf); 1019 break; 1020 default : 1021 stmf_scsilib_send_status(task, STATUS_CHECK, 1022 STMF_SAA_INVALID_FIELD_IN_CDB); 1023 break; 1024 } 1025 rw_exit(&pgr->pgr_lock); 1026 } 1027 1028 static void 1029 sbd_pgr_in_read_keys(scsi_task_t *task, stmf_data_buf_t *initial_dbuf) 1030 { 1031 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private; 1032 sbd_pgr_t *pgr = slu->sl_pgr; 1033 sbd_pgr_key_t *key; 1034 scsi_prin_readrsrv_t *buf; 1035 uint32_t buf_size, cdb_len, numkeys = 0; 1036 uint64_t *reg_key; 1037 1038 ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN); 1039 1040 cdb_len = READ_SCSI16(&task->task_cdb[7], uint16_t); 1041 for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next) 1042 ++numkeys; 1043 buf_size = 8 + numkeys * 8; /* minimum 8 bytes */ 1044 buf = kmem_zalloc(buf_size, KM_SLEEP); 1045 SCSI_WRITE32(buf->PRgeneration, pgr->pgr_PRgeneration); 1046 SCSI_WRITE32(buf->add_len, numkeys * 8); 1047 1048 reg_key = (uint64_t *)&buf->key_list; 1049 for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next) { 1050 SCSI_WRITE64(reg_key, key->pgr_key); 1051 reg_key++; 1052 } 1053 sbd_handle_short_read_transfers(task, initial_dbuf, (uint8_t *)buf, 1054 cdb_len, buf_size); 1055 kmem_free(buf, buf_size); 1056 } 1057 1058 static void 1059 sbd_pgr_in_read_reservation(scsi_task_t *task, stmf_data_buf_t *initial_dbuf) 1060 { 1061 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private; 1062 sbd_pgr_t *pgr = slu->sl_pgr; 1063 scsi_prin_readrsrv_t *buf; 1064 uint32_t cdb_len, buf_len, buf_size = 24; 1065 1066 ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN); 1067 1068 cdb_len = READ_SCSI16(&task->task_cdb[7], uint16_t); 1069 buf = kmem_zalloc(buf_size, KM_SLEEP); /* fixed size cdb, 24 bytes */ 1070 SCSI_WRITE32(buf->PRgeneration, pgr->pgr_PRgeneration); 1071 1072 if (SBD_PGR_RSVD_NONE(pgr)) { 1073 SCSI_WRITE32(buf->add_len, 0); 1074 buf_len = 8; 1075 } else { 1076 if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS) { 1077 SCSI_WRITE64( 1078 buf->key_list.res_key_list[0].reservation_key, 0); 1079 } else { 1080 SCSI_WRITE64( 1081 buf->key_list.res_key_list[0].reservation_key, 1082 pgr->pgr_rsvholder->pgr_key); 1083 } 1084 buf->key_list.res_key_list[0].type = pgr->pgr_rsv_type; 1085 buf->key_list.res_key_list[0].scope = pgr->pgr_rsv_scope; 1086 SCSI_WRITE32(buf->add_len, 16); 1087 buf_len = 24; 1088 } 1089 1090 sbd_handle_short_read_transfers(task, initial_dbuf, (uint8_t *)buf, 1091 cdb_len, buf_len); 1092 kmem_free(buf, buf_size); 1093 } 1094 1095 static void 1096 sbd_pgr_in_report_capabilities(scsi_task_t *task, 1097 stmf_data_buf_t *initial_dbuf) 1098 { 1099 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private; 1100 sbd_pgr_t *pgr = slu->sl_pgr; 1101 scsi_prin_rpt_cap_t buf; 1102 uint32_t cdb_len; 1103 1104 ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN); 1105 ASSERT(pgr != NULL); 1106 1107 bzero(&buf, sizeof (buf)); 1108 buf.ptpl_c = 1; /* Persist Through Power Loss C */ 1109 buf.atp_c = 1; /* All Target Ports Capable */ 1110 buf.sip_c = 1; /* Specify Initiator Ports Capable */ 1111 buf.crh = 0; /* Supports Reserve/Release exception */ 1112 buf.tmv = 1; /* Type Mask Valid */ 1113 buf.pr_type.wr_ex = 1; /* Write Exclusve */ 1114 buf.pr_type.ex_ac = 1; /* Exclusive Access */ 1115 buf.pr_type.wr_ex_ro = 1; /* Write Exclusive Registrants Only */ 1116 buf.pr_type.ex_ac_ro = 1; /* Exclusive Access Registrants Only */ 1117 buf.pr_type.wr_ex_ar = 1; /* Write Exclusive All Registrants */ 1118 buf.pr_type.ex_ac_ar = 1; /* Exclusive Access All Registrants */ 1119 1120 /* Persist Though Power Loss Active */ 1121 buf.ptpl_a = pgr->pgr_flags & SBD_PGR_APTPL; 1122 SCSI_WRITE16(&buf.length, 8); 1123 cdb_len = READ_SCSI16(&task->task_cdb[7], uint16_t); 1124 sbd_handle_short_read_transfers(task, initial_dbuf, (uint8_t *)&buf, 1125 cdb_len, 8); 1126 } 1127 1128 static void 1129 sbd_pgr_in_read_full_status(scsi_task_t *task, 1130 stmf_data_buf_t *initial_dbuf) 1131 { 1132 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private; 1133 sbd_pgr_t *pgr = slu->sl_pgr; 1134 sbd_pgr_key_t *key; 1135 scsi_prin_status_t *sts; 1136 scsi_prin_full_status_t *buf; 1137 uint32_t i, buf_size, cdb_len, tptid_len; 1138 uint8_t *offset; 1139 1140 ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN); 1141 ASSERT(pgr != NULL); 1142 1143 cdb_len = READ_SCSI16(&task->task_cdb[7], uint16_t); 1144 1145 buf_size = 8; /* PRgeneration and additional length fields */ 1146 for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next) { 1147 tptid_len = sbd_get_tptid_length_for_devid(key->pgr_key_rpt_id); 1148 buf_size = buf_size + 24 + tptid_len; 1149 } 1150 1151 buf = kmem_zalloc(buf_size, KM_SLEEP); 1152 SCSI_WRITE32(buf->PRgeneration, pgr->pgr_PRgeneration); 1153 SCSI_WRITE32(buf->add_len, buf_size - 8); 1154 1155 offset = (uint8_t *)&buf->full_desc[0]; 1156 key = pgr->pgr_keylist; 1157 i = 0; 1158 while (key) { 1159 sts = (scsi_prin_status_t *)offset; 1160 SCSI_WRITE64(sts->reservation_key, key->pgr_key); 1161 if ((pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS) || 1162 (pgr->pgr_rsvholder && pgr->pgr_rsvholder == key)) { 1163 sts->r_holder = 1; 1164 sts->type = pgr->pgr_rsv_type; 1165 sts->scope = pgr->pgr_rsv_scope; 1166 } 1167 1168 if (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) { 1169 sts->all_tg_pt = 1; 1170 } else { 1171 SCSI_WRITE16(sts->rel_tgt_port_id, 1172 stmf_scsilib_get_lport_rtid(key->pgr_key_lpt_id)); 1173 } 1174 tptid_len = sbd_devid_desc_to_tptid(key->pgr_key_rpt_id, 1175 &sts->trans_id); 1176 SCSI_WRITE32(sts->add_len, tptid_len); 1177 offset = offset + tptid_len + 24; 1178 key = key->pgr_key_next; 1179 ++i; 1180 } 1181 ASSERT(offset <= (uint8_t *)buf + buf_size); 1182 1183 sbd_handle_short_read_transfers(task, initial_dbuf, (uint8_t *)buf, 1184 cdb_len, buf_size); 1185 kmem_free(buf, buf_size); 1186 } 1187 1188 static void 1189 sbd_pgr_out_register(scsi_task_t *task, stmf_data_buf_t *dbuf) 1190 { 1191 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private; 1192 sbd_pgr_t *pgr = slu->sl_pgr; 1193 stmf_scsi_session_t *ses = task->task_session; 1194 sbd_it_data_t *it = task->task_lu_itl_handle; 1195 sbd_pgr_key_t *key = it->pgr_key_ptr; 1196 scsi_cdb_prout_t *pr_out = (scsi_cdb_prout_t *)task->task_cdb; 1197 scsi_prout_plist_t *plist; 1198 uint8_t *buf, buflen; 1199 uint64_t rsv_key, svc_key; 1200 1201 buf = dbuf->db_sglist[0].seg_addr; 1202 plist = (scsi_prout_plist_t *)buf; 1203 buflen = dbuf->db_data_size; 1204 rsv_key = READ_SCSI64(plist->reservation_key, uint64_t); 1205 svc_key = READ_SCSI64(plist->service_key, uint64_t); 1206 1207 /* Handling already registered IT session */ 1208 if (key) { 1209 1210 if (pr_out->action == PR_OUT_REGISTER && 1211 key->pgr_key != rsv_key) { 1212 stmf_scsilib_send_status(task, 1213 STATUS_RESERVATION_CONFLICT, 0); 1214 return; 1215 } 1216 if (plist->spec_i_pt) { 1217 stmf_scsilib_send_status(task, STATUS_CHECK, 1218 STMF_SAA_INVALID_FIELD_IN_CDB); 1219 return; 1220 } 1221 1222 if (plist->all_tg_pt != 1223 (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT)) { 1224 stmf_scsilib_send_status(task, STATUS_CHECK, 1225 STMF_SAA_INVALID_FIELD_IN_CDB); 1226 return; 1227 } 1228 1229 if (svc_key == 0) { 1230 sbd_pgr_do_unregister(slu, it, key); 1231 } else { 1232 key->pgr_key = svc_key; 1233 } 1234 1235 goto sbd_pgr_reg_done; 1236 } 1237 1238 /* Handling unregistered IT session */ 1239 if (pr_out->action == PR_OUT_REGISTER && rsv_key != 0) { 1240 stmf_scsilib_send_status(task, STATUS_RESERVATION_CONFLICT, 0); 1241 return; 1242 } 1243 1244 if (svc_key == 0) { 1245 /* Do we need to consider aptpl here? I don't think so */ 1246 pgr->pgr_PRgeneration++; 1247 stmf_scsilib_send_status(task, STATUS_GOOD, 0); 1248 return; 1249 } 1250 1251 if (plist->spec_i_pt) { 1252 uint8_t *tpd, *tpdmax; 1253 uint32_t tpdlen, max_tpdnum, tpdnum, i, adnlen = 0; 1254 scsi_devid_desc_t **newdevids; 1255 scsi_devid_desc_t *rpt, *lpt = ses->ss_lport->lport_id; 1256 1257 if (pr_out->action == PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY) { 1258 stmf_scsilib_send_status(task, STATUS_CHECK, 1259 STMF_SAA_INVALID_FIELD_IN_CDB); 1260 return; 1261 } 1262 1263 if (plist->all_tg_pt) 1264 lpt = NULL; 1265 1266 /* Validate the given length */ 1267 if (buflen >= sizeof (scsi_prout_plist_t) - 1 + 4) 1268 adnlen = READ_SCSI32(plist->apd, uint32_t); 1269 if (adnlen < sizeof (scsi_transport_id_t) + 4 || 1270 buflen < sizeof (scsi_prout_plist_t) - 1 + adnlen) { 1271 stmf_scsilib_send_status(task, STATUS_CHECK, 1272 STMF_SAA_PARAM_LIST_LENGTH_ERROR); 1273 return; 1274 } 1275 tpdmax = plist->apd + adnlen + 4; 1276 tpdlen = adnlen; 1277 max_tpdnum = tpdlen / sizeof (scsi_transport_id_t); 1278 newdevids = kmem_zalloc(sizeof (scsi_devid_desc_t *) * 1279 max_tpdnum, KM_SLEEP); 1280 tpdnum = 0; 1281 /* Check the validity of given TransportIDs */ 1282 while (tpdlen != 0) { 1283 tpd = tpdmax - tpdlen; 1284 rpt = sbd_tptid_to_devid_desc((scsi_transport_id_t *) 1285 tpd, &tpdlen); 1286 if (rpt == NULL) 1287 break; 1288 /* make sure that there is no duplicates */ 1289 for (i = 0; i < tpdnum; i++) { 1290 if (rpt->ident_length == 1291 newdevids[i]->ident_length && 1292 (memcmp(rpt->ident, newdevids[i]->ident, 1293 rpt->ident_length) == 0)) { 1294 break; 1295 } 1296 } 1297 newdevids[tpdnum] = rpt; 1298 tpdnum++; 1299 if (i < tpdnum - 1) 1300 break; 1301 /* Check if the given IT nexus is already registered */ 1302 if (sbd_pgr_key_registered(pgr, lpt, rpt)) 1303 break; 1304 } 1305 1306 for (i = 0; i < tpdnum; i++) { 1307 rpt = newdevids[i]; 1308 if (tpdlen == 0) { 1309 (void) sbd_pgr_do_register(slu, NULL, 1310 ses->ss_lport->lport_id, rpt, 1311 plist->all_tg_pt, svc_key); 1312 } 1313 kmem_free(rpt, sizeof (scsi_devid_desc_t) - 1 + 1314 rpt->ident_length); 1315 } 1316 kmem_free(newdevids, 1317 sizeof (scsi_devid_desc_t *) * max_tpdnum); 1318 if (tpdlen != 0) { 1319 stmf_scsilib_send_status(task, STATUS_CHECK, 1320 STMF_SAA_INVALID_FIELD_IN_CDB); 1321 return; 1322 } 1323 } 1324 1325 (void) sbd_pgr_do_register(slu, it, ses->ss_lport->lport_id, 1326 ses->ss_rport_id, plist->all_tg_pt, svc_key); 1327 1328 sbd_pgr_reg_done: 1329 1330 if (pgr->pgr_flags & SBD_PGR_APTPL || plist->aptpl) { 1331 if (plist->aptpl) 1332 PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL); 1333 else 1334 PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_APTPL); 1335 1336 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) { 1337 stmf_scsilib_send_status(task, STATUS_CHECK, 1338 STMF_SAA_INSUFFICIENT_REG_RESOURCES); 1339 return; 1340 } 1341 } 1342 1343 pgr->pgr_PRgeneration++; 1344 stmf_scsilib_send_status(task, STATUS_GOOD, 0); 1345 } 1346 1347 static sbd_pgr_key_t * 1348 sbd_pgr_do_register(sbd_lu_t *slu, sbd_it_data_t *it, scsi_devid_desc_t *lpt, 1349 scsi_devid_desc_t *rpt, uint8_t all_tg_pt, uint64_t svc_key) 1350 { 1351 sbd_pgr_t *pgr = slu->sl_pgr; 1352 sbd_pgr_key_t *key; 1353 uint16_t lpt_len, rpt_len; 1354 1355 lpt_len = sizeof (scsi_devid_desc_t) - 1 + lpt->ident_length; 1356 rpt_len = sizeof (scsi_devid_desc_t) - 1 + rpt->ident_length; 1357 1358 key = sbd_pgr_key_alloc(lpt, rpt, lpt_len, rpt_len); 1359 key->pgr_key = svc_key; 1360 1361 if (all_tg_pt) { 1362 key->pgr_key_flags |= SBD_PGR_KEY_ALL_TG_PT; 1363 /* set PGR_CHECK flag for all unregistered IT nexus */ 1364 sbd_pgr_set_pgr_check_flag(slu, B_FALSE); 1365 } else { 1366 key->pgr_key_it = it; 1367 } 1368 1369 if (it) { 1370 mutex_enter(&slu->sl_lock); 1371 it->pgr_key_ptr = key; 1372 mutex_exit(&slu->sl_lock); 1373 } 1374 1375 key->pgr_key_next = pgr->pgr_keylist; 1376 if (pgr->pgr_keylist) { 1377 pgr->pgr_keylist->pgr_key_prev = key; 1378 } 1379 pgr->pgr_keylist = key; 1380 1381 return (key); 1382 } 1383 1384 static void 1385 sbd_pgr_do_unregister(sbd_lu_t *slu, sbd_it_data_t *it, sbd_pgr_key_t *key) 1386 { 1387 if (slu->sl_pgr->pgr_rsvholder == key) { 1388 sbd_pgr_do_release(slu, it, SBD_UA_RESERVATIONS_RELEASED); 1389 } 1390 1391 sbd_pgr_remove_key(slu, key); 1392 if (slu->sl_pgr->pgr_keylist == NULL) { 1393 PGR_CLEAR_RSV_FLAG(slu->sl_pgr->pgr_flags); 1394 } 1395 } 1396 1397 static void 1398 sbd_pgr_out_reserve(scsi_task_t *task) 1399 { 1400 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private; 1401 stmf_scsi_session_t *ses = task->task_session; 1402 scsi_cdb_prout_t *pr_out = (scsi_cdb_prout_t *)task->task_cdb; 1403 sbd_it_data_t *it = task->task_lu_itl_handle; 1404 sbd_pgr_t *pgr = slu->sl_pgr; 1405 sbd_pgr_key_t *key = it->pgr_key_ptr; 1406 1407 ASSERT(key); 1408 1409 if (!(PGR_VALID_SCOPE(pr_out->scope) && PGR_VALID_TYPE(pr_out->type))) { 1410 stmf_scsilib_send_status(task, STATUS_CHECK, 1411 STMF_SAA_INVALID_FIELD_IN_CDB); 1412 return; 1413 } 1414 1415 if (SBD_PGR_RSVD(pgr)) { 1416 if (PGR_RESERVATION_HOLDER(pgr, key, it)) { 1417 if (pgr->pgr_rsv_type != pr_out->type || 1418 pgr->pgr_rsv_scope != pr_out->scope) { 1419 stmf_scsilib_send_status(task, 1420 STATUS_RESERVATION_CONFLICT, 0); 1421 return; 1422 } 1423 } else { 1424 stmf_scsilib_send_status(task, 1425 STATUS_RESERVATION_CONFLICT, 0); 1426 return; 1427 1428 } 1429 /* In case there is no reservation exist */ 1430 } else { 1431 sbd_pgr_do_reserve(pgr, key, it, ses, pr_out); 1432 if (pgr->pgr_flags & SBD_PGR_APTPL) { 1433 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) { 1434 stmf_scsilib_send_status(task, STATUS_CHECK, 1435 STMF_SAA_INSUFFICIENT_REG_RESOURCES); 1436 return; 1437 } 1438 } 1439 } 1440 1441 stmf_scsilib_send_status(task, STATUS_GOOD, 0); 1442 } 1443 1444 static void 1445 sbd_pgr_do_reserve(sbd_pgr_t *pgr, sbd_pgr_key_t *key, sbd_it_data_t *it, 1446 stmf_scsi_session_t *ses, scsi_cdb_prout_t *pr_out) 1447 { 1448 scsi_devid_desc_t *lpt; 1449 uint16_t lpt_len; 1450 1451 pgr->pgr_rsv_type = pr_out->type; 1452 pgr->pgr_rsv_scope = pr_out->scope; 1453 if (pr_out->type == PGR_TYPE_WR_EX_AR || 1454 pr_out->type == PGR_TYPE_EX_AC_AR) { 1455 PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_RSVD_ALL_REGISTRANTS); 1456 } else { 1457 if (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) { 1458 lpt = key->pgr_key_lpt_id; 1459 lpt_len = key->pgr_key_lpt_len; 1460 if (lpt_len > 0 && lpt != NULL) { 1461 kmem_free(lpt, lpt_len); 1462 } 1463 lpt = ses->ss_lport->lport_id; 1464 lpt_len = sizeof (scsi_devid_desc_t) - 1 + 1465 lpt->ident_length; 1466 key->pgr_key_lpt_len = lpt_len; 1467 key->pgr_key_lpt_id = (scsi_devid_desc_t *) 1468 kmem_zalloc(lpt_len, KM_SLEEP); 1469 bcopy(lpt, key->pgr_key_lpt_id, lpt_len); 1470 key->pgr_key_it = it; 1471 } 1472 1473 PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_RSVD_ONE); 1474 pgr->pgr_rsvholder = key; 1475 } 1476 } 1477 1478 static void 1479 sbd_pgr_out_release(scsi_task_t *task) 1480 { 1481 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private; 1482 scsi_cdb_prout_t *pr_out = (scsi_cdb_prout_t *)task->task_cdb; 1483 sbd_it_data_t *it = task->task_lu_itl_handle; 1484 sbd_pgr_t *pgr = slu->sl_pgr; 1485 sbd_pgr_key_t *key = it->pgr_key_ptr; 1486 1487 ASSERT(key); 1488 1489 if (SBD_PGR_RSVD(pgr)) { 1490 if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS || 1491 pgr->pgr_rsvholder == key) { 1492 if (pgr->pgr_rsv_type != pr_out->type || 1493 pgr->pgr_rsv_scope != pr_out->scope) { 1494 stmf_scsilib_send_status(task, STATUS_CHECK, 1495 STMF_SAA_INVALID_RELEASE_OF_PR); 1496 return; 1497 } 1498 sbd_pgr_do_release(slu, it, 1499 SBD_UA_RESERVATIONS_RELEASED); 1500 } 1501 } 1502 stmf_scsilib_send_status(task, STATUS_GOOD, 0); 1503 } 1504 1505 static void 1506 sbd_pgr_do_release(sbd_lu_t *slu, sbd_it_data_t *it, uint8_t ua_condition) 1507 { 1508 1509 sbd_pgr_t *pgr = slu->sl_pgr; 1510 1511 /* Reset pgr_flags */ 1512 PGR_CLEAR_RSV_FLAG(pgr->pgr_flags); 1513 pgr->pgr_rsvholder = NULL; 1514 1515 /* set unit attention condition if necessary */ 1516 if (pgr->pgr_rsv_type != PGR_TYPE_WR_EX && 1517 pgr->pgr_rsv_type != PGR_TYPE_EX_AC) { 1518 sbd_pgr_set_ua_conditions(slu, it, ua_condition); 1519 } 1520 pgr->pgr_rsv_type = 0; 1521 } 1522 1523 static void 1524 sbd_pgr_out_clear(scsi_task_t *task) 1525 { 1526 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private; 1527 sbd_it_data_t *it = task->task_lu_itl_handle; 1528 sbd_pgr_t *pgr = slu->sl_pgr; 1529 1530 ASSERT(it->pgr_key_ptr); 1531 1532 PGR_CLEAR_RSV_FLAG(pgr->pgr_flags); 1533 pgr->pgr_rsvholder = NULL; 1534 pgr->pgr_rsv_type = 0; 1535 mutex_enter(&slu->sl_lock); 1536 /* Remove all pointers from IT to pgr keys */ 1537 for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) { 1538 it->pgr_key_ptr = NULL; 1539 } 1540 mutex_exit(&slu->sl_lock); 1541 sbd_pgr_keylist_dealloc(slu); 1542 sbd_pgr_set_ua_conditions(slu, it, SBD_UA_RESERVATIONS_PREEMPTED); 1543 if (pgr->pgr_flags & SBD_PGR_APTPL) { 1544 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) { 1545 stmf_scsilib_send_status(task, STATUS_CHECK, 1546 STMF_SAA_INSUFFICIENT_REG_RESOURCES); 1547 return; 1548 } 1549 } 1550 pgr->pgr_PRgeneration++; 1551 stmf_scsilib_send_status(task, STATUS_GOOD, 0); 1552 } 1553 1554 static void 1555 sbd_pgr_out_preempt(scsi_task_t *task, stmf_data_buf_t *dbuf) 1556 { 1557 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private; 1558 stmf_scsi_session_t *ses = task->task_session; 1559 scsi_cdb_prout_t *pr_out = (scsi_cdb_prout_t *)task->task_cdb; 1560 sbd_it_data_t *it = task->task_lu_itl_handle; 1561 sbd_pgr_t *pgr = slu->sl_pgr; 1562 sbd_pgr_key_t *key = it->pgr_key_ptr; 1563 scsi_prout_plist_t *plist; 1564 uint8_t *buf, change_rsv = 0; 1565 uint64_t svc_key; 1566 1567 ASSERT(key); 1568 1569 buf = dbuf->db_sglist[0].seg_addr; 1570 plist = (scsi_prout_plist_t *)buf; 1571 svc_key = READ_SCSI64(plist->service_key, uint64_t); 1572 1573 if (SBD_PGR_RSVD_NONE(pgr)) { 1574 if (svc_key == 0 || 1575 sbd_pgr_remove_keys(slu, it, key, svc_key, B_TRUE) == 0) { 1576 stmf_scsilib_send_status(task, 1577 STATUS_RESERVATION_CONFLICT, 0); 1578 return; 1579 } 1580 1581 } else if (pgr->pgr_flags & SBD_PGR_RSVD_ONE) { 1582 if (svc_key == 0) { 1583 stmf_scsilib_send_status(task, STATUS_CHECK, 1584 STMF_SAA_INVALID_FIELD_IN_CDB); 1585 return; 1586 } 1587 1588 /* Validity check of scope and type */ 1589 if (pgr->pgr_rsvholder->pgr_key == svc_key) { 1590 if (!(PGR_VALID_SCOPE(pr_out->scope) && 1591 PGR_VALID_TYPE(pr_out->type))) { 1592 stmf_scsilib_send_status(task, STATUS_CHECK, 1593 STMF_SAA_INVALID_FIELD_IN_CDB); 1594 return; 1595 } 1596 } 1597 1598 if (pgr->pgr_rsvholder != key && 1599 pgr->pgr_rsvholder->pgr_key == svc_key) { 1600 sbd_pgr_do_release(slu, it, 1601 SBD_UA_REGISTRATIONS_PREEMPTED); 1602 change_rsv = 1; 1603 } 1604 1605 if (pgr->pgr_rsvholder == key && 1606 pgr->pgr_rsvholder->pgr_key == svc_key) { 1607 if (pr_out->scope != pgr->pgr_rsv_scope || 1608 pr_out->type != pgr->pgr_rsv_type) { 1609 sbd_pgr_do_release(slu, it, 1610 SBD_UA_REGISTRATIONS_PREEMPTED); 1611 change_rsv = 1; 1612 } 1613 } else { 1614 /* 1615 * Remove matched keys in all cases, except when the 1616 * current IT nexus holds the reservation and the given 1617 * svc_key matches with registered key. 1618 * Note that, if the reservation is held by another 1619 * IT nexus, and svc_key matches registered key for 1620 * that IT nexus, sbd_pgr_remove_key() is not expected 1621 * return 0. Hence, returning check condition after 1622 * releasing the reservation does not arise. 1623 */ 1624 if (sbd_pgr_remove_keys(slu, it, key, svc_key, B_TRUE) 1625 == 0) { 1626 stmf_scsilib_send_status(task, 1627 STATUS_RESERVATION_CONFLICT, 0); 1628 return; 1629 } 1630 } 1631 1632 if (change_rsv) { 1633 sbd_pgr_do_reserve(pgr, key, it, ses, pr_out); 1634 } 1635 1636 } else if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS) { 1637 if (svc_key == 0) { 1638 if (!(PGR_VALID_SCOPE(pr_out->scope) && 1639 PGR_VALID_TYPE(pr_out->type))) { 1640 stmf_scsilib_send_status(task, STATUS_CHECK, 1641 STMF_SAA_INVALID_FIELD_IN_CDB); 1642 return; 1643 } 1644 sbd_pgr_do_release(slu, it, 1645 SBD_UA_REGISTRATIONS_PREEMPTED); 1646 (void) sbd_pgr_remove_keys(slu, it, key, 0, B_FALSE); 1647 sbd_pgr_do_reserve(pgr, key, it, ses, pr_out); 1648 } else { 1649 if (sbd_pgr_remove_keys(slu, it, key, svc_key, B_TRUE) 1650 == 0) { 1651 stmf_scsilib_send_status(task, 1652 STATUS_RESERVATION_CONFLICT, 0); 1653 return; 1654 } 1655 } 1656 } 1657 1658 if (pgr->pgr_flags & SBD_PGR_APTPL) { 1659 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) { 1660 stmf_scsilib_send_status(task, STATUS_CHECK, 1661 STMF_SAA_INSUFFICIENT_REG_RESOURCES); 1662 return; 1663 } 1664 } 1665 1666 pgr->pgr_PRgeneration++; 1667 1668 if (pr_out->action == PR_OUT_PREEMPT_ABORT) { 1669 stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED, 1670 (void *)slu->sl_lu); 1671 } 1672 stmf_scsilib_send_status(task, STATUS_GOOD, 0); 1673 } 1674 1675 static void 1676 sbd_pgr_out_register_and_move(scsi_task_t *task, stmf_data_buf_t *dbuf) 1677 { 1678 sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private; 1679 sbd_it_data_t *it = task->task_lu_itl_handle; 1680 sbd_pgr_t *pgr = slu->sl_pgr; 1681 sbd_pgr_key_t *key = it->pgr_key_ptr; 1682 scsi_devid_desc_t *lpt, *rpt; 1683 sbd_pgr_key_t *newkey; 1684 scsi_prout_reg_move_plist_t *plist; 1685 uint8_t *buf, lpt_len; 1686 uint32_t tpd_len; 1687 uint64_t svc_key; 1688 1689 /* 1690 * Check whether the key holds the reservation or current reservation 1691 * is of type all registrants. 1692 */ 1693 if (pgr->pgr_rsvholder != key) { 1694 stmf_scsilib_send_status(task, STATUS_RESERVATION_CONFLICT, 0); 1695 return; 1696 } 1697 1698 buf = dbuf->db_sglist[0].seg_addr; 1699 plist = (scsi_prout_reg_move_plist_t *)buf; 1700 svc_key = READ_SCSI64(plist->service_key, uint64_t); 1701 if (svc_key == 0) { 1702 stmf_scsilib_send_status(task, STATUS_CHECK, 1703 STMF_SAA_INVALID_FIELD_IN_CDB); 1704 return; 1705 } 1706 1707 lpt = stmf_scsilib_get_devid_desc(READ_SCSI16(plist->rel_tgt_port_id, 1708 uint16_t)); 1709 if (lpt == NULL) { 1710 stmf_scsilib_send_status(task, STATUS_CHECK, 1711 STMF_SAA_INVALID_FIELD_IN_CDB); 1712 return; 1713 } 1714 1715 tpd_len = READ_SCSI32(plist->tptid_len, uint32_t); 1716 rpt = sbd_tptid_to_devid_desc((scsi_transport_id_t *)plist->tptid, 1717 &tpd_len); 1718 if (rpt == NULL) { 1719 stmf_scsilib_send_status(task, STATUS_CHECK, 1720 STMF_SAA_INVALID_FIELD_IN_PARAM_LIST); 1721 return; 1722 } else if (rpt->ident_length == key->pgr_key_rpt_id->ident_length && 1723 (memcmp(rpt->ident, key->pgr_key_rpt_id->ident, rpt->ident_length) 1724 == 0)) { 1725 kmem_free(rpt, sizeof (rpt) - 1 + rpt->ident_length); 1726 kmem_free(lpt, sizeof (lpt) - 1 + lpt->ident_length); 1727 stmf_scsilib_send_status(task, STATUS_CHECK, 1728 STMF_SAA_INVALID_FIELD_IN_PARAM_LIST); 1729 return; 1730 } 1731 1732 newkey = sbd_pgr_key_registered(pgr, lpt, rpt); 1733 if (newkey) { 1734 /* Set the pgr_key, irrespective of what it currently holds */ 1735 newkey->pgr_key = svc_key; 1736 1737 /* all_tg_pt is set for found key, copy lpt info to the key */ 1738 if (newkey->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) { 1739 if (newkey->pgr_key_lpt_id && 1740 newkey->pgr_key_lpt_len > 0) { 1741 kmem_free(newkey->pgr_key_lpt_id, 1742 newkey->pgr_key_lpt_len); 1743 } 1744 lpt_len = sizeof (scsi_devid_desc_t) - 1 + 1745 lpt->ident_length; 1746 newkey->pgr_key_lpt_len = lpt_len; 1747 newkey->pgr_key_lpt_id = (scsi_devid_desc_t *) 1748 kmem_zalloc(lpt_len, KM_SLEEP); 1749 bcopy(lpt, newkey->pgr_key_lpt_id, lpt_len); 1750 } 1751 } else { 1752 newkey = sbd_pgr_do_register(slu, NULL, lpt, rpt, 0, svc_key); 1753 } 1754 1755 kmem_free(rpt, sizeof (scsi_devid_desc_t) - 1 + rpt->ident_length); 1756 kmem_free(lpt, sizeof (scsi_devid_desc_t) - 1 + lpt->ident_length); 1757 1758 /* Now reserve the key corresponding to the specified IT nexus */ 1759 pgr->pgr_rsvholder = newkey; 1760 1761 if (plist->unreg) { 1762 sbd_pgr_do_unregister(slu, it, key); 1763 } 1764 1765 /* Since we do not have IT nexus information, set PGR_CHEK flag */ 1766 sbd_pgr_set_pgr_check_flag(slu, B_TRUE); 1767 1768 /* Write to disk if currenty aptpl is set or given task is setting it */ 1769 if (pgr->pgr_flags & SBD_PGR_APTPL || plist->aptpl) { 1770 if (plist->aptpl) 1771 PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL); 1772 else 1773 PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_APTPL); 1774 1775 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) { 1776 stmf_scsilib_send_status(task, STATUS_CHECK, 1777 STMF_SAA_INSUFFICIENT_REG_RESOURCES); 1778 return; 1779 } 1780 } 1781 1782 pgr->pgr_PRgeneration++; 1783 stmf_scsilib_send_status(task, STATUS_GOOD, 0); 1784 } 1785 1786 void 1787 sbd_pgr_remove_it_handle(sbd_lu_t *sl, sbd_it_data_t *my_it) { 1788 sbd_it_data_t *it; 1789 1790 rw_enter(&sl->sl_pgr->pgr_lock, RW_WRITER); 1791 mutex_enter(&sl->sl_lock); 1792 for (it = sl->sl_it_list; it != NULL; it = it->sbd_it_next) { 1793 if (it == my_it) { 1794 if (it->pgr_key_ptr) { 1795 sbd_pgr_key_t *key = it->pgr_key_ptr; 1796 if (key->pgr_key_it == it) { 1797 key->pgr_key_it = NULL; 1798 sl->sl_pgr->pgr_flags &= 1799 ~SBD_PGR_ALL_KEYS_HAS_IT; 1800 } 1801 } 1802 break; 1803 } 1804 } 1805 mutex_exit(&sl->sl_lock); 1806 rw_exit(&sl->sl_pgr->pgr_lock); 1807 1808 } 1809 1810 scsi_devid_desc_t * 1811 sbd_tptid_to_devid_desc(scsi_transport_id_t *tptid, uint32_t *tptid_len) 1812 { 1813 1814 scsi_devid_desc_t *devid = NULL; 1815 uint16_t ident_len, sz; 1816 1817 struct scsi_fc_transport_id *fcid; 1818 struct iscsi_transport_id *iscsiid; 1819 struct scsi_srp_transport_id *srpid; 1820 char eui_str[20+1]; 1821 1822 switch (tptid->protocol_id) { 1823 1824 case PROTOCOL_FIBRE_CHANNEL: 1825 1826 if (*tptid_len < 24 || tptid->format_code != 0) { 1827 return (NULL); 1828 } 1829 *tptid_len -= 24; 1830 ident_len = 20; /* wwn.XXXXXXXXXXXXXXXX */ 1831 fcid = (scsi_fc_transport_id_t *)tptid; 1832 sz = sizeof (scsi_devid_desc_t) - 1 + ident_len; 1833 devid = (scsi_devid_desc_t *)kmem_zalloc(sz, KM_SLEEP); 1834 stmf_wwn_to_devid_desc(devid, fcid->port_name, 1835 PROTOCOL_FIBRE_CHANNEL); 1836 return (devid); 1837 1838 case PROTOCOL_iSCSI: 1839 1840 if (tptid->format_code != 0 && tptid->format_code != 1) { 1841 return (NULL); 1842 } 1843 iscsiid = (iscsi_transport_id_t *)tptid; 1844 ident_len = READ_SCSI16(iscsiid->add_len, uint16_t); 1845 if (*tptid_len < sizeof (iscsi_transport_id_t) + ident_len) { 1846 return (NULL); 1847 } 1848 *tptid_len -= (sizeof (iscsi_transport_id_t) + ident_len); 1849 sz = sizeof (scsi_devid_desc_t) - 1 + ident_len; 1850 devid = (scsi_devid_desc_t *)kmem_zalloc(sz, KM_SLEEP); 1851 (void) memcpy(devid->ident, iscsiid->iscsi_name, 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 case PROTOCOL_SRP: 1859 if (*tptid_len < 24 || tptid->format_code != 0) { 1860 return (NULL); 1861 } 1862 *tptid_len -= 24; 1863 srpid = (scsi_srp_transport_id_t *)tptid; 1864 ident_len = sizeof (eui_str) - 1; /* eui.XXXXXXXXXXXXXXXX */ 1865 sz = sizeof (scsi_devid_desc_t) - 1 + ident_len; 1866 devid = (scsi_devid_desc_t *)kmem_zalloc(sz, KM_SLEEP); 1867 /* ASSUME: initiator-extension of srp_name is zero */ 1868 (void) snprintf(eui_str, sizeof (eui_str), "eui.%016llX", 1869 (u_longlong_t)BE_IN64(srpid->srp_name)); 1870 bcopy(eui_str, devid->ident, ident_len); 1871 /* LINTED E_ASSIGN_NARROW_CONV */ 1872 devid->ident_length = ident_len; 1873 devid->protocol_id = tptid->protocol_id; 1874 devid->code_set = CODE_SET_ASCII; 1875 return (devid); 1876 1877 default: 1878 cmn_err(CE_NOTE, "sbd_tptid_to_devid_desc: received unknown" 1879 "protocol id 0x%x", tptid->protocol_id); 1880 return (NULL); 1881 } 1882 } 1883 1884 /* 1885 * Changes devid_desc to corresponding TransportID format 1886 * Returns : Total length used by TransportID 1887 * Note :- No buffer length checking 1888 */ 1889 uint32_t 1890 sbd_devid_desc_to_tptid(scsi_devid_desc_t *devid, scsi_transport_id_t *tptid) 1891 { 1892 struct scsi_fc_transport_id *fcid; 1893 struct iscsi_transport_id *iscsiid; 1894 struct scsi_srp_transport_id *srpid; 1895 uint32_t ident_len, sz = 0; 1896 1897 switch (devid->protocol_id) { 1898 case PROTOCOL_FIBRE_CHANNEL: 1899 fcid = (scsi_fc_transport_id_t *)tptid; 1900 tptid->format_code = 0; 1901 tptid->protocol_id = devid->protocol_id; 1902 /* convert from "wwn.XXXXXXXXXXXXXXXX" to 8-byte binary */ 1903 ASSERT(strncmp("wwn.", (char *)devid->ident, 4) == 0); 1904 sbd_base16_str_to_binary((char *)devid->ident + 4, 16, 1905 fcid->port_name); 1906 sz = 24; 1907 break; 1908 1909 case PROTOCOL_iSCSI: 1910 iscsiid = (iscsi_transport_id_t *)tptid; 1911 ident_len = devid->ident_length; 1912 tptid->format_code = 0; 1913 tptid->protocol_id = devid->protocol_id; 1914 SCSI_WRITE16(iscsiid->add_len, ident_len); 1915 (void) memcpy(iscsiid->iscsi_name, devid->ident, ident_len); 1916 sz = ALIGNED_TO_WORD_BOUNDARY(4 + ident_len); 1917 break; 1918 1919 case PROTOCOL_SRP: 1920 srpid = (scsi_srp_transport_id_t *)tptid; 1921 tptid->format_code = 0; 1922 tptid->protocol_id = devid->protocol_id; 1923 /* convert from "eui.XXXXXXXXXXXXXXXX" to 8-byte binary */ 1924 ASSERT(strncmp("eui.", (char *)devid->ident, 4) == 0); 1925 sbd_base16_str_to_binary((char *)devid->ident+4, 16, 1926 srpid->srp_name); 1927 /* ASSUME: initiator-extension part of srp_name is zero */ 1928 sz = 24; 1929 break; 1930 1931 default : 1932 cmn_err(CE_NOTE, "sbd_devid_desc_to_tptid: received unknown" 1933 " protocol id 0x%x", devid->protocol_id); 1934 break; 1935 } 1936 1937 return (sz); 1938 } 1939 1940 uint32_t 1941 sbd_get_tptid_length_for_devid(scsi_devid_desc_t *devid) 1942 { 1943 uint32_t sz = 0; 1944 switch (devid->protocol_id) { 1945 case PROTOCOL_SRP: 1946 case PROTOCOL_FIBRE_CHANNEL: 1947 sz = 24; 1948 break; 1949 case PROTOCOL_iSCSI: 1950 sz = 4 + devid->ident_length; 1951 break; 1952 } 1953 sz = ALIGNED_TO_WORD_BOUNDARY(sz); 1954 sz = (sz > 0 && sz < 24) ? 24 : sz; 1955 1956 return (sz); 1957 } 1958 1959 char * 1960 sbd_get_devid_string(sbd_lu_t *sl) 1961 { 1962 char *str = (char *)kmem_zalloc(33, KM_SLEEP); 1963 (void) snprintf(str, 33, 1964 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 1965 sl->sl_device_id[4], sl->sl_device_id[5], sl->sl_device_id[6], 1966 sl->sl_device_id[7], sl->sl_device_id[8], sl->sl_device_id[9], 1967 sl->sl_device_id[10], sl->sl_device_id[11], sl->sl_device_id[12], 1968 sl->sl_device_id[13], sl->sl_device_id[14], sl->sl_device_id[15], 1969 sl->sl_device_id[16], sl->sl_device_id[17], sl->sl_device_id[18], 1970 sl->sl_device_id[19]); 1971 return (str); 1972 } 1973 1974 /* Convert from Hex value in ASCII format to the equivalent bytes */ 1975 void 1976 sbd_base16_str_to_binary(char *c, int len, uint8_t *dp) 1977 { 1978 int ii; 1979 1980 ASSERT((len & 1) == 0); 1981 1982 for (ii = 0; ii < len / 2; ii++) { 1983 char nibble1, nibble2; 1984 char enc_char = *c++; 1985 nibble1 = sbd_ctoi(enc_char); 1986 1987 enc_char = *c++; 1988 nibble2 = sbd_ctoi(enc_char); 1989 1990 dp[ii] = (nibble1 << 4) | nibble2; 1991 } 1992 } 1993