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