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