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