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