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 /*
  26  * XXX TODO
  27  * #includes cribbed from stmf.c -- undoubtedly only a small subset of these
  28  * are actually needed.
  29  */
  30 #include <sys/conf.h>
  31 #include <sys/file.h>
  32 #include <sys/ddi.h>
  33 #include <sys/sunddi.h>
  34 #include <sys/scsi/scsi.h>
  35 #include <sys/scsi/generic/persist.h>
  36 #include <sys/byteorder.h>
  37 #include <sys/nvpair.h>
  38 #include <sys/door.h>
  39 
  40 #include <sys/stmf.h>
  41 #include <sys/lpif.h>
  42 #include <sys/stmf_ioctl.h>
  43 #include <sys/portif.h>
  44 #include <sys/pppt_ic_if.h>
  45 
  46 #include "pppt.h"
  47 
  48 /*
  49  * Macros
  50  */
  51 
  52 /* Free a struct if it was allocated */
  53 #define FREE_IF_ALLOC(m)                                        \
  54         do {                                                    \
  55                 if ((m)) kmem_free((m), sizeof (*(m)));         \
  56                 _NOTE(CONSTCOND)                                \
  57         } while (0)
  58 
  59 /*
  60  * Macros to simplify the addition of struct fields to an nvlist.
  61  * The name of the fields in the nvlist is the same as the name
  62  * of the struct field.
  63  *
  64  * These macros require an int rc and a "done:" return retval label;
  65  * they assume that the nvlist is named "nvl".
  66  */
  67 #define NVLIST_ADD_FIELD(type, structure, field)                        \
  68         do {                                                            \
  69                 rc = nvlist_add_##type(nvl, #field, structure->field);  \
  70                 if (rc) goto done;                                      \
  71                 _NOTE(CONSTCOND)                                        \
  72         } while (0)
  73 
  74 /* use this macro when the array is defined as part of the struct */
  75 #define NVLIST_ADD_ARRAY(type, structure, field)                        \
  76         do {                                                            \
  77                 rc = nvlist_add_##type##_array(nvl, #field,             \
  78                     structure->field, sizeof (structure->field)); \
  79                 if (rc) goto done;                                      \
  80                 _NOTE(CONSTCOND)                                        \
  81         } while (0)
  82 
  83 /*
  84  * use this macro when the array field is a ptr or you need to explictly
  85  * call out the size.
  86  */
  87 #define NVLIST_ADD_ARRAY_LEN(type, structure, field, len)               \
  88         do {                                                            \
  89                 rc = nvlist_add_##type##_array(nvl, #field,             \
  90                     structure->field, len);                          \
  91                 if (rc) goto done;                                      \
  92                 _NOTE(CONSTCOND)                                        \
  93         } while (0)
  94 
  95 #define NVLIST_ADD_DEVID(structure, field)                              \
  96         do {                                                            \
  97                 rc = stmf_ic_scsi_devid_desc_marshal(nvl, #field,       \
  98                     structure->field);                                       \
  99                 if (rc) goto done;                                      \
 100                 _NOTE(CONSTCOND)                                        \
 101         } while (0)
 102 
 103 #define NVLIST_ADD_RPORT(structure, field)                              \
 104         do {                                                            \
 105                 rc = stmf_ic_remote_port_marshal(nvl, #field,           \
 106                     structure->field);                                       \
 107                 if (rc) goto done;                                      \
 108                 _NOTE(CONSTCOND)                                        \
 109         } while (0)
 110 
 111 #define NVLIST_ADD_FIELD_UINT8(structure, field)                        \
 112         NVLIST_ADD_FIELD(structure, field, uint8)
 113 
 114 /*
 115  * Macros to simplify the extraction of struct fields from an nvlist.
 116  * The name of the fields in the nvlist is the same as the name
 117  * of the struct field.
 118  *
 119  * Requires an int rc and a "done:" return retval label.
 120  * Assumes that the nvlist is named "nvl".
 121  *
 122  * Sample usage: NVLIST_LOOKUP_FIELD(uint8, structname, fieldname);
 123  */
 124 #define NVLIST_LOOKUP_FIELD(type, structure, field)                     \
 125         do {                                                            \
 126                 rc = nvlist_lookup_##type(nvl, #field,                  \
 127                     &(structure->field));                                \
 128                 if (rc) {                                               \
 129                         stmf_ic_nvlookup_warn(__func__, #field);        \
 130                         goto done;                                      \
 131                 }                                                       \
 132                 _NOTE(CONSTCOND)                                        \
 133         } while (0)
 134 
 135 /*
 136  * Look up a field which gets stored into a structure bit field.
 137  * The type passed is a uint type which can hold the largest value
 138  * in the bit field.
 139  *
 140  * Requires an int rc and a "done:" return retval label.
 141  * Assumes that the nvlist is named "nvl".
 142  *
 143  * Sample usage: NVLIST_LOOKUP_BIT_FIELD(uint8, structname, fieldname);
 144  */
 145 #define NVLIST_LOOKUP_BIT_FIELD(type, structure, field)                 \
 146         do {                                                            \
 147                 type##_t tmp;                                           \
 148                 rc = nvlist_lookup_##type(nvl, #field, &tmp);               \
 149                 if (rc) {                                               \
 150                         stmf_ic_nvlookup_warn(__func__, #field);        \
 151                         goto done;                                      \
 152                 }                                                       \
 153                 structure->field = tmp;                                      \
 154                 _NOTE(CONSTCOND)                                        \
 155         } while (0)
 156 
 157 /*
 158  * Look up a boolean field which gets stored into a structure bit field.
 159  *
 160  * Requires an int rc and a "done:" return retval label.
 161  * Assumes that the nvlist is named "nvl".
 162  */
 163 #define NVLIST_LOOKUP_BIT_FIELD_BOOLEAN(structure, field)               \
 164         do {                                                            \
 165                 boolean_t tmp;                                          \
 166                 rc = nvlist_lookup_boolean_value(nvl, #field, &tmp);        \
 167                 if (rc) {                                               \
 168                         stmf_ic_nvlookup_warn(__func__, #field);        \
 169                         goto done;                                      \
 170                 }                                                       \
 171                 structure->field = (tmp ?  1 : 0);                   \
 172                 _NOTE(CONSTCOND)                                        \
 173         } while (0)
 174 
 175 /* shorthand  for nvlist_lookup_pairs() args */
 176 #define NV_PAIR(type, strct, field) #field, DATA_TYPE_##type, &(strct->field)
 177 
 178 /* number of times to retry the upcall to transmit */
 179 #define STMF_MSG_TRANSMIT_RETRY     3
 180 
 181 /*
 182  * How was the message constructed?
 183  *
 184  * We need to know this when we free the message in order to
 185  * determine what to do with pointers in the message:
 186  *
 187  * - messages which were unmarshaled from an nvlist may point to
 188  *   memory within that nvlist; this memory should not be freed since
 189  *   it will be deallocated when we free the nvlist.
 190  *
 191  * - messages which built using a constructor (alloc) function may
 192  *   point to memory which was explicitly allocated by the constructor;
 193  *   it should be freed when the message is freed.
 194  *
 195  */
 196 typedef enum {
 197         STMF_CONSTRUCTOR = 0,
 198         STMF_UNMARSHAL
 199 } stmf_ic_msg_construction_method_t;
 200 
 201 
 202 /*
 203  * Function prototypes.
 204  */
 205 
 206 /*
 207  * Helpers for msg_alloc routines, used when the msg payload is
 208  * the same for multiple types of messages.
 209  */
 210 static stmf_ic_msg_t *stmf_ic_reg_dereg_lun_msg_alloc(
 211     stmf_ic_msg_type_t msg_type, uint8_t *lun_id,
 212     char *lu_provider_name, uint16_t cb_arg_len,
 213     uint8_t *cb_arg, stmf_ic_msgid_t msgid);
 214 
 215 static stmf_ic_msg_t *stmf_ic_session_create_destroy_msg_alloc(
 216     stmf_ic_msg_type_t msg_type,
 217     stmf_scsi_session_t *session,
 218     stmf_ic_msgid_t msgid);
 219 
 220 static stmf_ic_msg_t *stmf_ic_echo_request_reply_msg_alloc(
 221     stmf_ic_msg_type_t msg_type,
 222     uint32_t data_len,
 223     uint8_t *data,
 224     stmf_ic_msgid_t msgid);
 225 
 226 /*
 227  * Msg free routines.
 228  */
 229 static void stmf_ic_reg_port_msg_free(stmf_ic_reg_port_msg_t *m,
 230     stmf_ic_msg_construction_method_t cmethod);
 231 static void stmf_ic_dereg_port_msg_free(stmf_ic_dereg_port_msg_t *m,
 232     stmf_ic_msg_construction_method_t cmethod);
 233 static void stmf_ic_reg_dereg_lun_msg_free(stmf_ic_reg_dereg_lun_msg_t *m,
 234     stmf_ic_msg_construction_method_t cmethod);
 235 static void stmf_ic_scsi_cmd_msg_free(stmf_ic_scsi_cmd_msg_t *m,
 236     stmf_ic_msg_construction_method_t cmethod);
 237 static void stmf_ic_scsi_data_msg_free(stmf_ic_scsi_data_msg_t *m,
 238     stmf_ic_msg_construction_method_t cmethod);
 239 static void stmf_ic_scsi_data_xfer_done_msg_free(
 240     stmf_ic_scsi_data_xfer_done_msg_t *m,
 241     stmf_ic_msg_construction_method_t cmethod);
 242 static void stmf_ic_scsi_status_msg_free(stmf_ic_scsi_status_msg_t *m,
 243     stmf_ic_msg_construction_method_t cmethod);
 244 static void stmf_ic_r2t_msg_free(stmf_ic_r2t_msg_t *m,
 245     stmf_ic_msg_construction_method_t cmethod);
 246 static void stmf_ic_status_msg_free(stmf_ic_status_msg_t *m,
 247     stmf_ic_msg_construction_method_t cmethod);
 248 static void stmf_ic_session_create_destroy_msg_free(
 249     stmf_ic_session_create_destroy_msg_t *m,
 250     stmf_ic_msg_construction_method_t cmethod);
 251 static void stmf_ic_echo_request_reply_msg_free(
 252     stmf_ic_echo_request_reply_msg_t *m,
 253     stmf_ic_msg_construction_method_t cmethod);
 254 
 255 /*
 256  * Marshaling routines.
 257  */
 258 static nvlist_t *stmf_ic_msg_marshal(stmf_ic_msg_t *msg);
 259 static int stmf_ic_reg_port_msg_marshal(nvlist_t *nvl, void *msg);
 260 static int stmf_ic_dereg_port_msg_marshal(nvlist_t *nvl, void *msg);
 261 static int stmf_ic_reg_dereg_lun_msg_marshal(nvlist_t *nvl, void *msg);
 262 static int stmf_ic_scsi_cmd_msg_marshal(nvlist_t *nvl, void *msg);
 263 static int stmf_ic_scsi_data_msg_marshal(nvlist_t *nvl, void *msg);
 264 static int stmf_ic_scsi_data_xfer_done_msg_marshal(nvlist_t *nvl, void *msg);
 265 static int stmf_ic_scsi_status_msg_marshal(nvlist_t *nvl, void *msg);
 266 static int stmf_ic_r2t_msg_marshal(nvlist_t *nvl, void *msg);
 267 static int stmf_ic_status_msg_marshal(nvlist_t *nvl, void *msg);
 268 static int stmf_ic_session_create_destroy_msg_marshal(nvlist_t *nvl, void *msg);
 269 static int stmf_ic_echo_request_reply_msg_marshal(nvlist_t *nvl, void *msg);
 270 static int stmf_ic_scsi_devid_desc_marshal(nvlist_t *parent_nvl,
 271         char *sdid_name, scsi_devid_desc_t *sdid);
 272 static int stmf_ic_remote_port_marshal(nvlist_t *parent_nvl,
 273         char *rport_name, stmf_remote_port_t *rport);
 274 
 275 /*
 276  * Unmarshaling routines.
 277  */
 278 static stmf_ic_msg_t *stmf_ic_msg_unmarshal(nvlist_t *nvl);
 279 static void *stmf_ic_reg_port_msg_unmarshal(nvlist_t *nvl);
 280 static void *stmf_ic_dereg_port_msg_unmarshal(nvlist_t *nvl);
 281 static void *stmf_ic_reg_dereg_lun_msg_unmarshal(nvlist_t *nvl);
 282 static void *stmf_ic_scsi_cmd_msg_unmarshal(nvlist_t *nvl);
 283 static void *stmf_ic_scsi_data_msg_unmarshal(nvlist_t *nvl);
 284 static void *stmf_ic_scsi_data_xfer_done_msg_unmarshal(nvlist_t *nvl);
 285 static void *stmf_ic_scsi_status_msg_unmarshal(nvlist_t *nvl);
 286 static void *stmf_ic_r2t_msg_unmarshal(nvlist_t *nvl);
 287 static void *stmf_ic_status_msg_unmarshal(nvlist_t *nvl);
 288 static void *stmf_ic_session_create_destroy_msg_unmarshal(nvlist_t *nvl);
 289 static void *stmf_ic_echo_request_reply_msg_unmarshal(nvlist_t *nvl);
 290 static scsi_devid_desc_t *stmf_ic_lookup_scsi_devid_desc_and_unmarshal(
 291     nvlist_t *nvl, char *field_name);
 292 static scsi_devid_desc_t *stmf_ic_scsi_devid_desc_unmarshal(
 293     nvlist_t *nvl_devid);
 294 static uint8_t *stmf_ic_uint8_array_unmarshal(nvlist_t *nvl, char *field_name,
 295         uint64_t len, uint8_t *buf);
 296 static char *stmf_ic_string_unmarshal(nvlist_t *nvl, char *field_name);
 297 static stmf_remote_port_t *stmf_ic_lookup_remote_port_and_unmarshal(
 298         nvlist_t *nvl, char *field_name);
 299 static stmf_remote_port_t *stmf_ic_remote_port_unmarshal(nvlist_t *nvl);
 300 
 301 /*
 302  * Transmit and recieve routines.
 303  */
 304 stmf_ic_msg_status_t stmf_ic_transmit(char *buf, size_t size);
 305 
 306 /*
 307  * Utilities.
 308  */
 309 static stmf_ic_msg_t *stmf_ic_alloc_msg_header(stmf_ic_msg_type_t msg_type,
 310         stmf_ic_msgid_t msgid);
 311 static size_t sizeof_scsi_devid_desc(int ident_length);
 312 static char *stmf_ic_strdup(char *str);
 313 static scsi_devid_desc_t *scsi_devid_desc_dup(scsi_devid_desc_t *did);
 314 static stmf_remote_port_t *remote_port_dup(stmf_remote_port_t *rport);
 315 static void scsi_devid_desc_free(scsi_devid_desc_t *did);
 316 static inline void stmf_ic_nvlookup_warn(const char *func, char *field);
 317 
 318 /*
 319  * Send a message out over the interconnect, in the process marshalling
 320  * the arguments.
 321  *
 322  * After being sent, the message is freed.
 323  */
 324 stmf_ic_msg_status_t
 325 stmf_ic_tx_msg(stmf_ic_msg_t *msg)
 326 {
 327         size_t size = 0;
 328         nvlist_t *nvl = NULL;
 329         char *buf = NULL;
 330         int err = 0;
 331         stmf_ic_msg_status_t status = STMF_IC_MSG_SUCCESS;
 332 
 333         nvl = stmf_ic_msg_marshal(msg);
 334         if (!nvl) {
 335                 cmn_err(CE_WARN, "stmf_ic_tx_msg: marshal failed");
 336                 status = STMF_IC_MSG_INTERNAL_ERROR;
 337                 goto done;
 338         }
 339 
 340         err = nvlist_size(nvl, &size, NV_ENCODE_XDR);
 341         if (err) {
 342                 status = STMF_IC_MSG_INTERNAL_ERROR;
 343                 goto done;
 344         }
 345 
 346         buf = kmem_alloc(size, KM_SLEEP);
 347         err = nvlist_pack(nvl, &buf, &size, NV_ENCODE_XDR, 0);
 348         if (err) {
 349                 status = STMF_IC_MSG_INTERNAL_ERROR;
 350                 goto done;
 351         }
 352 
 353         /* push the bits out on the wire */
 354 
 355         status = stmf_ic_transmit(buf, size);
 356 
 357 done:
 358         if (nvl)
 359                 nvlist_free(nvl);
 360 
 361         if (buf)
 362                 kmem_free(buf, size);
 363 
 364         stmf_ic_msg_free(msg);
 365 
 366 
 367         return (status);
 368 }
 369 
 370 /*
 371  * Pass the command to the daemon for transmission to the other node.
 372  */
 373 stmf_ic_msg_status_t
 374 stmf_ic_transmit(char *buf, size_t size)
 375 {
 376         int i;
 377         int rc;
 378         door_arg_t arg;
 379         door_handle_t door;
 380         uint32_t result;
 381 
 382         mutex_enter(&pppt_global.global_door_lock);
 383         if (pppt_global.global_door == NULL) {
 384                 /* daemon not listening */
 385                 mutex_exit(&pppt_global.global_door_lock);
 386                 return (STMF_IC_MSG_INTERNAL_ERROR);
 387         }
 388         door = pppt_global.global_door;
 389         door_ki_hold(door);
 390         mutex_exit(&pppt_global.global_door_lock);
 391 
 392         arg.data_ptr = buf;
 393         arg.data_size = size;
 394         arg.desc_ptr = NULL;
 395         arg.desc_num = 0;
 396         arg.rbuf = (char *)&result;
 397         arg.rsize = sizeof (result);
 398         /*
 399          * Retry a few times if there is a shortage of threads to
 400          * service the upcall. This shouldn't happen unless a large
 401          * number of initiators issue commands at once.
 402          */
 403         for (i = 0; i < STMF_MSG_TRANSMIT_RETRY; i++) {
 404                 rc = door_ki_upcall(door, &arg);
 405                 if (rc != EAGAIN)
 406                         break;
 407                 delay(hz);
 408         }
 409         door_ki_rele(door);
 410         if (rc != 0) {
 411                 cmn_err(CE_WARN,
 412                     "stmf_ic_transmit door_ki_upcall failed %d", rc);
 413                 return (STMF_IC_MSG_INTERNAL_ERROR);
 414         }
 415         if (result != 0) {
 416                 /* XXX Just warn for now */
 417                 cmn_err(CE_WARN,
 418                     "stmf_ic_transmit bad result from daemon %d", result);
 419         }
 420 
 421         return (STMF_IC_MSG_SUCCESS);
 422 }
 423 
 424 /*
 425  * This is a low-level upcall which is called when a message has
 426  * been received on the interconnect.
 427  *
 428  * The caller is responsible for freeing the buffer which is passed in.
 429  */
 430 /*ARGSUSED*/
 431 void
 432 stmf_ic_rx_msg(char *buf, size_t len)
 433 {
 434         nvlist_t *nvl = NULL;
 435         stmf_ic_msg_t *m = NULL;
 436         stmf_ic_echo_request_reply_msg_t *icerr;
 437         stmf_ic_msg_t *echo_msg;
 438         int rc = 0;
 439 
 440         rc = nvlist_unpack(buf, len, &nvl, 0);
 441         if (rc) {
 442                 cmn_err(CE_WARN, "stmf_ic_rx_msg: unpack failed");
 443                 return;
 444         }
 445 
 446         m = stmf_ic_msg_unmarshal(nvl);
 447         if (m == NULL) {
 448                 cmn_err(CE_WARN, "stmf_ic_rx_msg: unmarshal failed");
 449                 nvlist_free(nvl);
 450                 return;
 451         }
 452 
 453         switch (m->icm_msg_type) {
 454 
 455         case STMF_ICM_REGISTER_PROXY_PORT:
 456         case STMF_ICM_DEREGISTER_PROXY_PORT:
 457         case STMF_ICM_SCSI_CMD:
 458         case STMF_ICM_SCSI_DATA_XFER_DONE:
 459         case STMF_ICM_SESSION_CREATE:
 460         case STMF_ICM_SESSION_DESTROY:
 461                 /*
 462                  * These messages are all received by pppt.
 463                  * Currently, pppt will parse the message for type
 464                  */
 465                 (void) pppt_msg_rx(m);
 466                 break;
 467 
 468         case STMF_ICM_LUN_ACTIVE:
 469         case STMF_ICM_REGISTER_LUN:
 470         case STMF_ICM_DEREGISTER_LUN:
 471         case STMF_ICM_SCSI_DATA:
 472         case STMF_ICM_SCSI_STATUS:
 473                 /*
 474                  * These messages are all received by stmf.
 475                  * Currently, stmf will parse the message for type
 476                  */
 477                 (void) stmf_msg_rx(m);
 478                 break;
 479 
 480         case STMF_ICM_ECHO_REQUEST:
 481                 icerr = m->icm_msg;
 482                 echo_msg = stmf_ic_echo_reply_msg_alloc(icerr->icerr_datalen,
 483                     icerr->icerr_data, 0);
 484                 if (echo_msg != NULL) {
 485                         (void) stmf_ic_tx_msg(echo_msg);
 486                 }
 487                 stmf_ic_msg_free(m);
 488                 break;
 489 
 490         case STMF_ICM_ECHO_REPLY:
 491                 stmf_ic_msg_free(m);
 492                 break;
 493 
 494         case STMF_ICM_R2T:
 495                 /*
 496                  * XXX currently not supported
 497                  */
 498                 stmf_ic_msg_free(m);
 499                 break;
 500 
 501         case STMF_ICM_STATUS:
 502                 (void) stmf_msg_rx(m);
 503                 break;
 504 
 505         default:
 506                 ASSERT(0);
 507         }
 508 }
 509 
 510 /*
 511  * IC message allocation routines.
 512  */
 513 
 514 stmf_ic_msg_t *
 515 stmf_ic_reg_port_msg_alloc(
 516     scsi_devid_desc_t *port_id,
 517     uint16_t relative_port_id,
 518     uint16_t cb_arg_len,
 519     uint8_t *cb_arg,
 520     stmf_ic_msgid_t msgid)
 521 {
 522         stmf_ic_msg_t *icm = NULL;
 523         stmf_ic_reg_port_msg_t *icrp = NULL;
 524 
 525         icm = stmf_ic_alloc_msg_header(STMF_ICM_REGISTER_PROXY_PORT, msgid);
 526         icrp = (stmf_ic_reg_port_msg_t *)kmem_zalloc(sizeof (*icrp), KM_SLEEP);
 527         icm->icm_msg = (void *)icrp;
 528 
 529         icrp->icrp_port_id = scsi_devid_desc_dup(port_id);
 530         icrp->icrp_relative_port_id = relative_port_id;
 531 
 532         if (cb_arg_len) {
 533                 icrp->icrp_cb_arg_len = cb_arg_len;
 534                 icrp->icrp_cb_arg = cb_arg;
 535         }
 536 
 537         return (icm);
 538 }
 539 
 540 stmf_ic_msg_t *
 541 stmf_ic_dereg_port_msg_alloc(
 542     scsi_devid_desc_t *port_id,
 543     uint16_t cb_arg_len,
 544     uint8_t *cb_arg,
 545     stmf_ic_msgid_t msgid)
 546 {
 547         stmf_ic_msg_t *icm = NULL;
 548         stmf_ic_dereg_port_msg_t *icdp = NULL;
 549 
 550         icm = stmf_ic_alloc_msg_header(STMF_ICM_DEREGISTER_PROXY_PORT, msgid);
 551         icdp = (stmf_ic_dereg_port_msg_t *)kmem_zalloc(sizeof (*icdp),
 552             KM_SLEEP);
 553         icm->icm_msg = (void *)icdp;
 554 
 555         icdp->icdp_port_id = scsi_devid_desc_dup(port_id);
 556 
 557         if (cb_arg_len) {
 558                 icdp->icdp_cb_arg_len = cb_arg_len;
 559                 icdp->icdp_cb_arg = cb_arg;
 560         }
 561 
 562         return (icm);
 563 }
 564 
 565 
 566 stmf_ic_msg_t *
 567 stmf_ic_reg_lun_msg_alloc(
 568     uint8_t *lun_id,
 569     char *lu_provider_name,
 570     uint16_t cb_arg_len,
 571     uint8_t *cb_arg,
 572     stmf_ic_msgid_t msgid)
 573 {
 574         return (stmf_ic_reg_dereg_lun_msg_alloc(STMF_ICM_REGISTER_LUN, lun_id,
 575             lu_provider_name, cb_arg_len, cb_arg, msgid));
 576 }
 577 
 578 stmf_ic_msg_t *
 579 stmf_ic_lun_active_msg_alloc(
 580     uint8_t *lun_id,
 581     char *lu_provider_name,
 582     uint16_t cb_arg_len,
 583     uint8_t *cb_arg,
 584     stmf_ic_msgid_t msgid)
 585 {
 586         return (stmf_ic_reg_dereg_lun_msg_alloc(STMF_ICM_LUN_ACTIVE, lun_id,
 587             lu_provider_name, cb_arg_len, cb_arg, msgid));
 588 }
 589 
 590 stmf_ic_msg_t *
 591 stmf_ic_dereg_lun_msg_alloc(
 592     uint8_t *lun_id,
 593     char *lu_provider_name,
 594     uint16_t cb_arg_len,
 595     uint8_t *cb_arg,
 596     stmf_ic_msgid_t msgid)
 597 {
 598         return (stmf_ic_reg_dereg_lun_msg_alloc(STMF_ICM_DEREGISTER_LUN, lun_id,
 599             lu_provider_name, cb_arg_len, cb_arg, msgid));
 600 }
 601 
 602 /*
 603  * Guts of lun register/deregister/active alloc routines.
 604  */
 605 static stmf_ic_msg_t *
 606 stmf_ic_reg_dereg_lun_msg_alloc(
 607     stmf_ic_msg_type_t msg_type,
 608     uint8_t *lun_id,
 609     char *lu_provider_name,
 610     uint16_t cb_arg_len,
 611     uint8_t *cb_arg,
 612     stmf_ic_msgid_t msgid)
 613 {
 614         stmf_ic_msg_t *icm = NULL;
 615         stmf_ic_reg_dereg_lun_msg_t *icrl = NULL;
 616 
 617         icm = stmf_ic_alloc_msg_header(msg_type, msgid);
 618         icrl = (stmf_ic_reg_dereg_lun_msg_t *)
 619             kmem_zalloc(sizeof (*icrl), KM_SLEEP);
 620         icm->icm_msg = (void *)icrl;
 621 
 622         icrl->icrl_lu_provider_name = stmf_ic_strdup(lu_provider_name);
 623 
 624         bcopy(lun_id, icrl->icrl_lun_id, sizeof (icrl->icrl_lun_id));
 625 
 626         if (cb_arg_len) {
 627                 icrl->icrl_cb_arg_len = cb_arg_len;
 628                 icrl->icrl_cb_arg = cb_arg;
 629         }
 630 
 631         return (icm);
 632 }
 633 
 634 stmf_ic_msg_t *
 635 stmf_ic_scsi_cmd_msg_alloc(
 636     stmf_ic_msgid_t task_msgid,
 637     scsi_task_t *task,
 638     uint32_t immed_data_len,
 639     uint8_t *immed_data,
 640     stmf_ic_msgid_t msgid)
 641 {
 642         stmf_ic_msg_t *icm = NULL;
 643         stmf_ic_scsi_cmd_msg_t *icsc = NULL;
 644         scsi_devid_desc_t *ini_devid = task->task_session->ss_rport_id;
 645         scsi_devid_desc_t *tgt_devid = task->task_lport->lport_id;
 646         stmf_remote_port_t *rport = task->task_session->ss_rport;
 647 
 648         icm = stmf_ic_alloc_msg_header(STMF_ICM_SCSI_CMD, msgid);
 649         icsc = (stmf_ic_scsi_cmd_msg_t *)kmem_zalloc(sizeof (*icsc), KM_SLEEP);
 650         icm->icm_msg = (void *)icsc;
 651 
 652         icsc->icsc_task_msgid = task_msgid;
 653         icsc->icsc_ini_devid = scsi_devid_desc_dup(ini_devid);
 654         icsc->icsc_tgt_devid = scsi_devid_desc_dup(tgt_devid);
 655         icsc->icsc_rport = remote_port_dup(rport);
 656         icsc->icsc_session_id = task->task_session->ss_session_id;
 657 
 658         if (!task->task_mgmt_function && task->task_lu->lu_id) {
 659                 bcopy(task->task_lu->lu_id->ident,
 660                     icsc->icsc_lun_id, sizeof (icsc->icsc_lun_id));
 661         }
 662 
 663         bcopy(task->task_lun_no, icsc->icsc_task_lun_no,
 664             sizeof (icsc->icsc_task_lun_no));
 665 
 666         icsc->icsc_task_expected_xfer_length = task->task_expected_xfer_length;
 667         if (task->task_cdb_length) {
 668                 ASSERT(task->task_mgmt_function == TM_NONE);
 669                 icsc->icsc_task_cdb_length = task->task_cdb_length;
 670                 icsc->icsc_task_cdb =
 671                     (uint8_t *)kmem_zalloc(task->task_cdb_length, KM_SLEEP);
 672                 bcopy(task->task_cdb, icsc->icsc_task_cdb,
 673                     task->task_cdb_length);
 674         }
 675 
 676         icsc->icsc_task_flags = task->task_flags;
 677         icsc->icsc_task_priority = task->task_priority;
 678         icsc->icsc_task_mgmt_function = task->task_mgmt_function;
 679 
 680         icsc->icsc_immed_data_len = immed_data_len;
 681         icsc->icsc_immed_data = immed_data;
 682 
 683         return (icm);
 684 }
 685 
 686 stmf_ic_msg_t *
 687 stmf_ic_scsi_data_msg_alloc(
 688     stmf_ic_msgid_t task_msgid,
 689     uint64_t session_id,
 690     uint8_t *lun_id,
 691     uint64_t data_len,
 692     uint8_t *data,
 693     stmf_ic_msgid_t msgid)
 694 {
 695         stmf_ic_msg_t *icm = NULL;
 696         stmf_ic_scsi_data_msg_t *icsd = NULL;
 697 
 698         icm = stmf_ic_alloc_msg_header(STMF_ICM_SCSI_DATA, msgid);
 699         icsd = (stmf_ic_scsi_data_msg_t *)kmem_zalloc(sizeof (*icsd), KM_SLEEP);
 700         icm->icm_msg = (void *)icsd;
 701 
 702         icsd->icsd_task_msgid = task_msgid;
 703         icsd->icsd_session_id = session_id;
 704         bcopy(lun_id, icsd->icsd_lun_id, sizeof (icsd->icsd_lun_id));
 705         icsd->icsd_data_len = data_len;
 706         icsd->icsd_data = data;
 707 
 708         return (icm);
 709 }
 710 
 711 stmf_ic_msg_t *
 712 stmf_ic_scsi_data_xfer_done_msg_alloc(
 713     stmf_ic_msgid_t task_msgid,
 714     uint64_t session_id,
 715     stmf_status_t status,
 716     stmf_ic_msgid_t msgid)
 717 {
 718         stmf_ic_msg_t *icm = NULL;
 719         stmf_ic_scsi_data_xfer_done_msg_t *icsx = NULL;
 720 
 721         icm = stmf_ic_alloc_msg_header(STMF_ICM_SCSI_DATA_XFER_DONE, msgid);
 722         icsx = (stmf_ic_scsi_data_xfer_done_msg_t *)kmem_zalloc(
 723             sizeof (*icsx), KM_SLEEP);
 724         icm->icm_msg = (void *)icsx;
 725 
 726         icsx->icsx_task_msgid = task_msgid;
 727         icsx->icsx_session_id = session_id;
 728         icsx->icsx_status = status;
 729 
 730         return (icm);
 731 }
 732 
 733 stmf_ic_msg_t *
 734 stmf_ic_scsi_status_msg_alloc(
 735     stmf_ic_msgid_t task_msgid,
 736     uint64_t session_id,
 737     uint8_t *lun_id,
 738     uint8_t response,
 739     uint8_t status,
 740     uint8_t flags,
 741     uint32_t resid,
 742     uint8_t sense_len,
 743     uint8_t *sense,
 744     stmf_ic_msgid_t msgid)
 745 {
 746         stmf_ic_msg_t *icm = NULL;
 747         stmf_ic_scsi_status_msg_t *icss = NULL;
 748 
 749         icm = stmf_ic_alloc_msg_header(STMF_ICM_SCSI_STATUS, msgid);
 750         icss = (stmf_ic_scsi_status_msg_t *)kmem_zalloc(sizeof (*icss),
 751             KM_SLEEP);
 752         icm->icm_msg = (void *)icss;
 753 
 754         icss->icss_task_msgid = task_msgid;
 755         icss->icss_session_id = session_id;
 756         bcopy(lun_id, icss->icss_lun_id, sizeof (icss->icss_lun_id));
 757         icss->icss_response = response;
 758         icss->icss_status = status;
 759         icss->icss_flags = flags;
 760         icss->icss_resid = resid;
 761         icss->icss_sense_len = sense_len;
 762         icss->icss_sense = sense;
 763 
 764         return (icm);
 765 }
 766 
 767 stmf_ic_msg_t *
 768 stmf_ic_r2t_msg_alloc(
 769     stmf_ic_msgid_t task_msgid,
 770     uint64_t session_id,
 771     uint32_t offset,
 772     uint32_t length,
 773     stmf_ic_msgid_t msgid)
 774 {
 775         stmf_ic_msg_t *icm = NULL;
 776         stmf_ic_r2t_msg_t *icrt = NULL;
 777 
 778         icm = stmf_ic_alloc_msg_header(STMF_ICM_R2T, msgid);
 779         icrt = (stmf_ic_r2t_msg_t *)kmem_zalloc(sizeof (*icrt), KM_SLEEP);
 780         icm->icm_msg = (void *)icrt;
 781 
 782         icrt->icrt_task_msgid = task_msgid;
 783         icrt->icrt_session_id = session_id;
 784         icrt->icrt_offset = offset;
 785         icrt->icrt_length = length;
 786 
 787         return (icm);
 788 }
 789 
 790 stmf_ic_msg_t *
 791 stmf_ic_status_msg_alloc(
 792     stmf_status_t status,
 793     stmf_ic_msg_type_t msg_type,
 794     stmf_ic_msgid_t msgid)
 795 {
 796         stmf_ic_msg_t *icm = NULL;
 797         stmf_ic_status_msg_t *ics = NULL;
 798 
 799         icm = stmf_ic_alloc_msg_header(STMF_ICM_STATUS, msgid);
 800         ics = (stmf_ic_status_msg_t *)kmem_zalloc(sizeof (*ics), KM_SLEEP);
 801         icm->icm_msg = (void *)ics;
 802 
 803         ics->ics_status = status;
 804         ics->ics_msg_type = msg_type;
 805         ics->ics_msgid = msgid;              /* XXX same as msgid in header */
 806 
 807         return (icm);
 808 }
 809 
 810 stmf_ic_msg_t *
 811 stmf_ic_session_create_msg_alloc(
 812     stmf_scsi_session_t *session,
 813     stmf_ic_msgid_t msgid)
 814 {
 815         return (stmf_ic_session_create_destroy_msg_alloc(
 816             STMF_ICM_SESSION_CREATE, session, msgid));
 817 }
 818 
 819 stmf_ic_msg_t *
 820 stmf_ic_session_destroy_msg_alloc(
 821     stmf_scsi_session_t *session,
 822     stmf_ic_msgid_t msgid)
 823 {
 824         return (stmf_ic_session_create_destroy_msg_alloc(
 825             STMF_ICM_SESSION_DESTROY, session, msgid));
 826 }
 827 
 828 /*
 829  * Guts of session create/destroy routines.
 830  */
 831 static stmf_ic_msg_t *
 832 stmf_ic_session_create_destroy_msg_alloc(
 833     stmf_ic_msg_type_t msg_type,
 834     stmf_scsi_session_t *session,
 835     stmf_ic_msgid_t msgid)
 836 {
 837         stmf_ic_msg_t *icm = NULL;
 838         stmf_ic_session_create_destroy_msg_t *icscd = NULL;
 839         scsi_devid_desc_t *ini_devid = session->ss_rport_id;
 840         scsi_devid_desc_t *tgt_devid = session->ss_lport->lport_id;
 841 
 842         icm = stmf_ic_alloc_msg_header(msg_type, msgid);
 843         icscd = (stmf_ic_session_create_destroy_msg_t *)
 844             kmem_zalloc(sizeof (*icscd), KM_SLEEP);
 845         icm->icm_msg = (void *)icscd;
 846 
 847         icscd->icscd_session_id = session->ss_session_id;
 848         icscd->icscd_ini_devid = scsi_devid_desc_dup(ini_devid);
 849         icscd->icscd_tgt_devid = scsi_devid_desc_dup(tgt_devid);
 850         icscd->icscd_rport = remote_port_dup(session->ss_rport);
 851 
 852         return (icm);
 853 }
 854 
 855 stmf_ic_msg_t *
 856 stmf_ic_echo_request_msg_alloc(
 857     uint32_t data_len,
 858     uint8_t *data,
 859     stmf_ic_msgid_t msgid)
 860 {
 861         return (stmf_ic_echo_request_reply_msg_alloc(
 862             STMF_ICM_ECHO_REQUEST, data_len, data, msgid));
 863 }
 864 
 865 stmf_ic_msg_t *
 866 stmf_ic_echo_reply_msg_alloc(
 867     uint32_t data_len,
 868     uint8_t *data,
 869     stmf_ic_msgid_t msgid)
 870 {
 871         return (stmf_ic_echo_request_reply_msg_alloc(
 872             STMF_ICM_ECHO_REPLY, data_len, data, msgid));
 873 }
 874 
 875 
 876 static stmf_ic_msg_t *
 877 stmf_ic_echo_request_reply_msg_alloc(
 878     stmf_ic_msg_type_t msg_type,
 879     uint32_t data_len,
 880     uint8_t *data,
 881     stmf_ic_msgid_t msgid)
 882 {
 883         stmf_ic_msg_t *icm = NULL;
 884         stmf_ic_echo_request_reply_msg_t *icerr = NULL;
 885 
 886         icm = stmf_ic_alloc_msg_header(msg_type, msgid);
 887         icerr = kmem_zalloc(sizeof (*icerr), KM_SLEEP);
 888         icm->icm_msg = (void *)icerr;
 889 
 890         icerr->icerr_data = data;
 891         icerr->icerr_datalen = data_len;
 892 
 893         return (icm);
 894 }
 895 
 896 /*
 897  * msg free routines.
 898  */
 899 void
 900 stmf_ic_msg_free(stmf_ic_msg_t *msg)
 901 {
 902         stmf_ic_msg_construction_method_t cmethod =
 903             (msg->icm_nvlist ? STMF_UNMARSHAL : STMF_CONSTRUCTOR);
 904 
 905         switch (msg->icm_msg_type) {
 906         case STMF_ICM_REGISTER_PROXY_PORT:
 907                 stmf_ic_reg_port_msg_free(
 908                     (stmf_ic_reg_port_msg_t *)msg->icm_msg, cmethod);
 909                 break;
 910 
 911         case STMF_ICM_DEREGISTER_PROXY_PORT:
 912                 stmf_ic_dereg_port_msg_free(
 913                     (stmf_ic_dereg_port_msg_t *)msg->icm_msg, cmethod);
 914                 break;
 915 
 916         case STMF_ICM_LUN_ACTIVE:
 917         case STMF_ICM_REGISTER_LUN:
 918         case STMF_ICM_DEREGISTER_LUN:
 919                 stmf_ic_reg_dereg_lun_msg_free(
 920                     (stmf_ic_reg_dereg_lun_msg_t *)msg->icm_msg, cmethod);
 921                 break;
 922 
 923         case STMF_ICM_SCSI_CMD:
 924                 stmf_ic_scsi_cmd_msg_free(
 925                     (stmf_ic_scsi_cmd_msg_t *)msg->icm_msg, cmethod);
 926                 break;
 927 
 928         case STMF_ICM_SCSI_DATA:
 929                 stmf_ic_scsi_data_msg_free(
 930                     (stmf_ic_scsi_data_msg_t *)msg->icm_msg, cmethod);
 931                 break;
 932 
 933         case STMF_ICM_SCSI_DATA_XFER_DONE:
 934                 stmf_ic_scsi_data_xfer_done_msg_free(
 935                     (stmf_ic_scsi_data_xfer_done_msg_t *)msg->icm_msg, cmethod);
 936                 break;
 937 
 938         case STMF_ICM_SCSI_STATUS:
 939                 stmf_ic_scsi_status_msg_free(
 940                     (stmf_ic_scsi_status_msg_t *)msg->icm_msg, cmethod);
 941                 break;
 942 
 943         case STMF_ICM_R2T:
 944                 stmf_ic_r2t_msg_free(
 945                     (stmf_ic_r2t_msg_t *)msg->icm_msg, cmethod);
 946                 break;
 947 
 948         case STMF_ICM_STATUS:
 949                 stmf_ic_status_msg_free(
 950                     (stmf_ic_status_msg_t *)msg->icm_msg, cmethod);
 951                 break;
 952 
 953         case STMF_ICM_SESSION_CREATE:
 954         case STMF_ICM_SESSION_DESTROY:
 955                 stmf_ic_session_create_destroy_msg_free(
 956                     (stmf_ic_session_create_destroy_msg_t *)msg->icm_msg,
 957                     cmethod);
 958                 break;
 959 
 960         case STMF_ICM_ECHO_REQUEST:
 961         case STMF_ICM_ECHO_REPLY:
 962                 stmf_ic_echo_request_reply_msg_free(
 963                     (stmf_ic_echo_request_reply_msg_t *)msg->icm_msg, cmethod);
 964                 break;
 965 
 966         case STMF_ICM_MAX_MSG_TYPE:
 967                 ASSERT(0);
 968                 break;
 969 
 970         default:
 971                 ASSERT(0);
 972         }
 973 
 974         if (msg->icm_nvlist)
 975                 nvlist_free(msg->icm_nvlist);
 976 
 977         kmem_free(msg, sizeof (*msg));
 978 }
 979 
 980 /*ARGSUSED*/
 981 static void
 982 stmf_ic_reg_port_msg_free(stmf_ic_reg_port_msg_t *m,
 983     stmf_ic_msg_construction_method_t cmethod)
 984 {
 985         scsi_devid_desc_free(m->icrp_port_id);
 986 
 987         kmem_free(m, sizeof (*m));
 988 }
 989 
 990 
 991 /*ARGSUSED*/
 992 static void
 993 stmf_ic_dereg_port_msg_free(stmf_ic_dereg_port_msg_t *m,
 994     stmf_ic_msg_construction_method_t cmethod)
 995 {
 996         scsi_devid_desc_free(m->icdp_port_id);
 997 
 998         kmem_free(m, sizeof (*m));
 999 }
1000 
1001 
1002 /*
1003  * Works for both reg_lun_msg and dereg_lun_msg, since the message
1004  * payload is the same.
1005  */
1006 static void
1007 stmf_ic_reg_dereg_lun_msg_free(stmf_ic_reg_dereg_lun_msg_t *m,
1008     stmf_ic_msg_construction_method_t cmethod)
1009 {
1010         if (cmethod == STMF_CONSTRUCTOR) {
1011                 kmem_free(m->icrl_lu_provider_name,
1012                     strlen(m->icrl_lu_provider_name) + 1);
1013         }
1014 
1015         kmem_free(m, sizeof (*m));
1016 }
1017 
1018 static void
1019 stmf_ic_scsi_cmd_msg_free(stmf_ic_scsi_cmd_msg_t *m,
1020     stmf_ic_msg_construction_method_t cmethod)
1021 {
1022         scsi_devid_desc_free(m->icsc_ini_devid);
1023         scsi_devid_desc_free(m->icsc_tgt_devid);
1024         stmf_remote_port_free(m->icsc_rport);
1025         if ((cmethod == STMF_CONSTRUCTOR) && m->icsc_task_cdb) {
1026                 kmem_free(m->icsc_task_cdb, m->icsc_task_cdb_length);
1027         }
1028 
1029         kmem_free(m, sizeof (*m));
1030 
1031 }
1032 
1033 /*ARGSUSED*/
1034 static void
1035 stmf_ic_scsi_data_msg_free(stmf_ic_scsi_data_msg_t *m,
1036     stmf_ic_msg_construction_method_t cmethod)
1037 {
1038         kmem_free(m, sizeof (*m));
1039 }
1040 
1041 /*ARGSUSED*/
1042 static void
1043 stmf_ic_scsi_data_xfer_done_msg_free(stmf_ic_scsi_data_xfer_done_msg_t *m,
1044     stmf_ic_msg_construction_method_t cmethod)
1045 {
1046         kmem_free(m, sizeof (*m));
1047 }
1048 
1049 /*ARGSUSED*/
1050 static void
1051 stmf_ic_scsi_status_msg_free(stmf_ic_scsi_status_msg_t *m,
1052     stmf_ic_msg_construction_method_t cmethod)
1053 {
1054         kmem_free(m, sizeof (*m));
1055 }
1056 
1057 /*ARGSUSED*/
1058 static void
1059 stmf_ic_r2t_msg_free(stmf_ic_r2t_msg_t *m,
1060     stmf_ic_msg_construction_method_t cmethod)
1061 {
1062         kmem_free(m, sizeof (*m));
1063 }
1064 
1065 /*ARGSUSED*/
1066 static void
1067 stmf_ic_status_msg_free(stmf_ic_status_msg_t *m,
1068     stmf_ic_msg_construction_method_t cmethod)
1069 {
1070         kmem_free(m, sizeof (*m));
1071 }
1072 
1073 /*
1074  * Works for both session_create and session_destroy msgs, since the message
1075  * payload is the same.
1076  */
1077 /*ARGSUSED*/
1078 static void
1079 stmf_ic_session_create_destroy_msg_free(stmf_ic_session_create_destroy_msg_t *m,
1080     stmf_ic_msg_construction_method_t cmethod)
1081 {
1082         scsi_devid_desc_free(m->icscd_ini_devid);
1083         scsi_devid_desc_free(m->icscd_tgt_devid);
1084         stmf_remote_port_free(m->icscd_rport);
1085 
1086         kmem_free(m, sizeof (*m));
1087 }
1088 
1089 /*ARGSUSED*/
1090 static void
1091 stmf_ic_echo_request_reply_msg_free(stmf_ic_echo_request_reply_msg_t *m,
1092     stmf_ic_msg_construction_method_t cmethod)
1093 {
1094         kmem_free(m, sizeof (*m));
1095 }
1096 
1097 
1098 /*
1099  * Marshaling routines.
1100  */
1101 
1102 static nvlist_t *
1103 stmf_ic_msg_marshal(stmf_ic_msg_t *msg)
1104 {
1105         nvlist_t *nvl = NULL;
1106         int rc = 0;
1107 
1108         rc = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
1109         if (rc)
1110                 goto done;
1111 
1112         NVLIST_ADD_FIELD(uint8, msg, icm_msg_type);
1113         NVLIST_ADD_FIELD(uint64, msg, icm_msgid);
1114 
1115         switch (msg->icm_msg_type) {
1116         case STMF_ICM_REGISTER_PROXY_PORT:
1117                 rc = stmf_ic_reg_port_msg_marshal(nvl, msg->icm_msg);
1118                 break;
1119 
1120 
1121         case STMF_ICM_DEREGISTER_PROXY_PORT:
1122                 rc = stmf_ic_dereg_port_msg_marshal(nvl, msg->icm_msg);
1123                 break;
1124 
1125         case STMF_ICM_LUN_ACTIVE:
1126         case STMF_ICM_REGISTER_LUN:
1127         case STMF_ICM_DEREGISTER_LUN:
1128                 rc = stmf_ic_reg_dereg_lun_msg_marshal(nvl, msg->icm_msg);
1129                 break;
1130 
1131         case STMF_ICM_SCSI_CMD:
1132                 rc = stmf_ic_scsi_cmd_msg_marshal(nvl, msg->icm_msg);
1133                 break;
1134 
1135         case STMF_ICM_SCSI_DATA:
1136                 rc = stmf_ic_scsi_data_msg_marshal(nvl, msg->icm_msg);
1137                 break;
1138 
1139         case STMF_ICM_SCSI_DATA_XFER_DONE:
1140                 rc = stmf_ic_scsi_data_xfer_done_msg_marshal(nvl, msg->icm_msg);
1141                 break;
1142 
1143         case STMF_ICM_SCSI_STATUS:
1144                 rc = stmf_ic_scsi_status_msg_marshal(nvl, msg->icm_msg);
1145                 break;
1146 
1147         case STMF_ICM_R2T:
1148                 rc = stmf_ic_r2t_msg_marshal(nvl, msg->icm_msg);
1149                 break;
1150 
1151         case STMF_ICM_STATUS:
1152                 rc = stmf_ic_status_msg_marshal(nvl, msg->icm_msg);
1153                 break;
1154 
1155         case STMF_ICM_SESSION_CREATE:
1156         case STMF_ICM_SESSION_DESTROY:
1157                 rc = stmf_ic_session_create_destroy_msg_marshal(nvl,
1158                     msg->icm_msg);
1159                 break;
1160 
1161         case STMF_ICM_ECHO_REQUEST:
1162         case STMF_ICM_ECHO_REPLY:
1163                 rc = stmf_ic_echo_request_reply_msg_marshal(nvl,
1164                     msg->icm_msg);
1165                 break;
1166 
1167         case STMF_ICM_MAX_MSG_TYPE:
1168                 ASSERT(0);
1169                 break;
1170 
1171         default:
1172                 ASSERT(0);
1173         }
1174 
1175 done:
1176         if (!rc)
1177                 return (nvl);
1178 
1179         if (nvl)
1180                 nvlist_free(nvl);
1181 
1182         return (NULL);
1183 }
1184 
1185 
1186 static int
1187 stmf_ic_reg_port_msg_marshal(nvlist_t *nvl, void *msg)
1188 {
1189         stmf_ic_reg_port_msg_t *m = (stmf_ic_reg_port_msg_t *)msg;
1190         int rc = 0;
1191 
1192         NVLIST_ADD_DEVID(m, icrp_port_id);
1193         NVLIST_ADD_FIELD(uint16, m, icrp_relative_port_id);
1194 
1195         NVLIST_ADD_FIELD(uint16, m, icrp_cb_arg_len);
1196         /* only add the callback arg if necessary */
1197         if (m->icrp_cb_arg_len) {
1198                 NVLIST_ADD_ARRAY_LEN(uint8, m, icrp_cb_arg, m->icrp_cb_arg_len);
1199         }
1200 
1201 done:
1202         return (rc);
1203 }
1204 
1205 static int
1206 stmf_ic_dereg_port_msg_marshal(nvlist_t *nvl, void *msg)
1207 {
1208         stmf_ic_dereg_port_msg_t *m = (stmf_ic_dereg_port_msg_t *)msg;
1209         int rc = 0;
1210 
1211         NVLIST_ADD_DEVID(m, icdp_port_id);
1212         NVLIST_ADD_FIELD(uint16, m, icdp_cb_arg_len);
1213 
1214         /* only add the callback arg if necessary */
1215         if (m->icdp_cb_arg_len) {
1216                 NVLIST_ADD_ARRAY_LEN(uint8, m, icdp_cb_arg, m->icdp_cb_arg_len);
1217         }
1218 
1219 done:
1220         return (rc);
1221 }
1222 
1223 /*
1224  * Handles STMF_ICM_LUN_ACTIVE, STMF_ICM_REGISTER_LUN and
1225  * STMF_ICM_DEREGISTER_LUN;
1226  * msg payload is the same for all.
1227  */
1228 static int
1229 stmf_ic_reg_dereg_lun_msg_marshal(nvlist_t *nvl, void *msg)
1230 {
1231         stmf_ic_reg_dereg_lun_msg_t *m = (stmf_ic_reg_dereg_lun_msg_t *)msg;
1232         int rc = 0;
1233 
1234         NVLIST_ADD_ARRAY(uint8, m, icrl_lun_id);
1235         NVLIST_ADD_FIELD(string, m, icrl_lu_provider_name);
1236         NVLIST_ADD_FIELD(uint16, m, icrl_cb_arg_len);
1237 
1238         /* only add the callback arg if necessary */
1239         if (m->icrl_cb_arg_len) {
1240                 NVLIST_ADD_ARRAY_LEN(uint8, m, icrl_cb_arg, m->icrl_cb_arg_len);
1241         }
1242 
1243 done:
1244         return (rc);
1245 }
1246 
1247 static int
1248 stmf_ic_scsi_cmd_msg_marshal(nvlist_t *nvl, void *msg)
1249 {
1250         stmf_ic_scsi_cmd_msg_t *m = (stmf_ic_scsi_cmd_msg_t *)msg;
1251         int rc = 0;
1252 
1253         NVLIST_ADD_FIELD(uint64, m, icsc_task_msgid);
1254         NVLIST_ADD_DEVID(m, icsc_ini_devid);
1255         NVLIST_ADD_DEVID(m, icsc_tgt_devid);
1256         NVLIST_ADD_RPORT(m, icsc_rport);
1257         NVLIST_ADD_ARRAY(uint8, m, icsc_lun_id);
1258         NVLIST_ADD_FIELD(uint64, m, icsc_session_id);
1259         NVLIST_ADD_ARRAY_LEN(uint8, m, icsc_task_lun_no, 8);
1260         NVLIST_ADD_FIELD(uint32, m, icsc_task_expected_xfer_length);
1261         NVLIST_ADD_FIELD(uint16, m, icsc_task_cdb_length);
1262         /*
1263          * icsc_task_cdb_length may be zero in the case of a task
1264          * management function.
1265          */
1266         NVLIST_ADD_ARRAY_LEN(uint8, m, icsc_task_cdb, m->icsc_task_cdb_length);
1267         NVLIST_ADD_FIELD(uint8, m, icsc_task_flags);
1268         NVLIST_ADD_FIELD(uint8, m, icsc_task_priority);
1269         NVLIST_ADD_FIELD(uint8, m, icsc_task_mgmt_function);
1270 
1271         NVLIST_ADD_FIELD(uint32, m, icsc_immed_data_len);
1272         /* only add immediate data if necessary */
1273         if (m->icsc_immed_data_len) {
1274                 NVLIST_ADD_ARRAY_LEN(uint8, m, icsc_immed_data,
1275                     m->icsc_immed_data_len);
1276         }
1277 
1278 done:
1279         return (rc);
1280 }
1281 
1282 static int
1283 stmf_ic_scsi_data_msg_marshal(nvlist_t *nvl, void *msg)
1284 {
1285         stmf_ic_scsi_data_msg_t *m = (stmf_ic_scsi_data_msg_t *)msg;
1286         int rc = 0;
1287 
1288         NVLIST_ADD_FIELD(uint64, m, icsd_task_msgid);
1289         NVLIST_ADD_FIELD(uint64, m, icsd_session_id);
1290         NVLIST_ADD_ARRAY(uint8, m, icsd_lun_id);
1291         NVLIST_ADD_FIELD(uint64, m, icsd_data_len);
1292         NVLIST_ADD_ARRAY_LEN(uint8, m, icsd_data, m->icsd_data_len);
1293 
1294 done:
1295         return (rc);
1296 }
1297 
1298 static int
1299 stmf_ic_scsi_data_xfer_done_msg_marshal(nvlist_t *nvl, void *msg)
1300 {
1301         stmf_ic_scsi_data_xfer_done_msg_t *m =
1302             (stmf_ic_scsi_data_xfer_done_msg_t *)msg;
1303         int rc = 0;
1304 
1305         NVLIST_ADD_FIELD(uint64, m, icsx_task_msgid);
1306         NVLIST_ADD_FIELD(uint64, m, icsx_session_id);
1307         NVLIST_ADD_FIELD(uint64, m, icsx_status);
1308 
1309 done:
1310         return (rc);
1311 }
1312 
1313 static int
1314 stmf_ic_scsi_status_msg_marshal(nvlist_t *nvl, void *msg)
1315 {
1316         stmf_ic_scsi_status_msg_t *m = (stmf_ic_scsi_status_msg_t *)msg;
1317         int rc = 0;
1318 
1319         NVLIST_ADD_FIELD(uint64, m, icss_task_msgid);
1320         NVLIST_ADD_FIELD(uint64, m, icss_session_id);
1321         NVLIST_ADD_ARRAY(uint8, m, icss_lun_id);
1322         NVLIST_ADD_FIELD(uint8, m, icss_response);
1323         NVLIST_ADD_FIELD(uint8, m, icss_status);
1324         NVLIST_ADD_FIELD(uint8, m, icss_flags);
1325         NVLIST_ADD_FIELD(uint32, m, icss_resid);
1326 
1327         NVLIST_ADD_FIELD(uint8, m, icss_sense_len);
1328 
1329         if (m->icss_sense_len)
1330                 NVLIST_ADD_ARRAY_LEN(uint8, m, icss_sense, m->icss_sense_len);
1331 
1332 done:
1333         return (rc);
1334 }
1335 
1336 static int
1337 stmf_ic_r2t_msg_marshal(nvlist_t *nvl, void *msg)
1338 {
1339         stmf_ic_r2t_msg_t *m = (stmf_ic_r2t_msg_t *)msg;
1340         int rc = 0;
1341 
1342         NVLIST_ADD_FIELD(uint64, m, icrt_task_msgid);
1343         NVLIST_ADD_FIELD(uint64, m, icrt_session_id);
1344         NVLIST_ADD_FIELD(uint32, m, icrt_offset);
1345         NVLIST_ADD_FIELD(uint32, m, icrt_length);
1346 
1347 done:
1348         return (rc);
1349 }
1350 
1351 static int
1352 stmf_ic_status_msg_marshal(nvlist_t *nvl, void *msg)
1353 {
1354         stmf_ic_status_msg_t *m = (stmf_ic_status_msg_t *)msg;
1355         int rc = 0;
1356 
1357         NVLIST_ADD_FIELD(uint8, m, ics_msg_type);
1358         NVLIST_ADD_FIELD(uint64, m, ics_msgid);
1359         NVLIST_ADD_FIELD(uint8, m, ics_status);
1360 
1361 done:
1362         return (rc);
1363 }
1364 
1365 static int
1366 stmf_ic_session_create_destroy_msg_marshal(nvlist_t *nvl, void *msg)
1367 {
1368         stmf_ic_session_create_destroy_msg_t *m =
1369             (stmf_ic_session_create_destroy_msg_t *)msg;
1370         int rc = 0;
1371 
1372         NVLIST_ADD_DEVID(m, icscd_ini_devid);
1373         NVLIST_ADD_DEVID(m, icscd_tgt_devid);
1374         NVLIST_ADD_RPORT(m, icscd_rport);
1375         NVLIST_ADD_FIELD(uint64, m, icscd_session_id);
1376 
1377 done:
1378         return (rc);
1379 }
1380 
1381 static int
1382 stmf_ic_echo_request_reply_msg_marshal(nvlist_t *nvl, void *msg)
1383 {
1384         stmf_ic_echo_request_reply_msg_t *m = msg;
1385         int rc = 0;
1386 
1387         NVLIST_ADD_FIELD(uint32, m, icerr_datalen);
1388         if (m->icerr_datalen)
1389                 NVLIST_ADD_ARRAY_LEN(uint8, m, icerr_data, m->icerr_datalen);
1390 
1391 done:
1392         return (rc);
1393 }
1394 
1395 /*
1396  * Allocate a new nvlist representing the scsi_devid_desc and add it
1397  * to the nvlist.
1398  */
1399 static int
1400 stmf_ic_scsi_devid_desc_marshal(nvlist_t *parent_nvl,
1401         char *sdid_name,
1402         scsi_devid_desc_t *sdid)
1403 {
1404         int rc = 0;
1405         nvlist_t *nvl = NULL;
1406 
1407         rc = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
1408         if (rc)
1409                 goto done;
1410 
1411         NVLIST_ADD_FIELD(uint8, sdid, protocol_id);
1412         NVLIST_ADD_FIELD(uint8, sdid, code_set);
1413         NVLIST_ADD_FIELD(uint8, sdid, piv);
1414         NVLIST_ADD_FIELD(uint8, sdid, association);
1415         NVLIST_ADD_FIELD(uint8, sdid, ident_type);
1416         NVLIST_ADD_FIELD(uint8, sdid, ident_length);
1417 
1418         rc = nvlist_add_uint8_array(nvl, "ident", sdid->ident,
1419             sdid->ident_length);
1420         if (rc)
1421                 goto done;
1422 
1423         rc = nvlist_add_nvlist(parent_nvl, sdid_name, nvl);
1424 done:
1425         if (nvl) {
1426                 nvlist_free(nvl);
1427         }
1428         return (rc);
1429 }
1430 
1431 /*
1432  * Allocate a new nvlist representing the stmf_remote_port and add it
1433  * to the nvlist.
1434  */
1435 static int
1436 stmf_ic_remote_port_marshal(nvlist_t *parent_nvl, char *rport_name,
1437         stmf_remote_port_t *rport) {
1438 
1439         int rc = 0;
1440         nvlist_t *nvl = NULL;
1441 
1442         rc = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
1443         if (rc)
1444                 goto done;
1445 
1446         NVLIST_ADD_FIELD(uint16, rport, rport_tptid_sz);
1447         rc = nvlist_add_uint8_array(nvl, "rport_tptid",
1448             (uint8_t *)rport->rport_tptid, rport->rport_tptid_sz);
1449         if (rc)
1450                 goto done;
1451 
1452         rc = nvlist_add_nvlist(parent_nvl, rport_name, nvl);
1453 done:
1454         if (nvl) {
1455                 nvlist_free(nvl);
1456         }
1457         return (rc);
1458 }
1459 
1460 /*
1461  * Unmarshaling routines.
1462  */
1463 
1464 static stmf_ic_msg_t *
1465 stmf_ic_msg_unmarshal(nvlist_t *nvl)
1466 {
1467         stmf_ic_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1468         uint8_t msg_type;
1469         int rc = 0;
1470 
1471         /*
1472          * We'd like to do this:
1473          *
1474          *   NVLIST_LOOKUP_FIELD(uint8, m, icm_msg_type);
1475          *
1476          * but the fact that msg type is an enum causes type problems.
1477          */
1478         rc = nvlist_lookup_uint8(nvl, "icm_msg_type", &msg_type);
1479         if (rc) {
1480                 stmf_ic_nvlookup_warn(__func__, "icm_msg_type");
1481                 goto done;
1482         }
1483 
1484         m->icm_msg_type = msg_type;
1485         m->icm_nvlist = nvl;
1486 
1487         NVLIST_LOOKUP_FIELD(uint64, m, icm_msgid);
1488 
1489         switch (m->icm_msg_type) {
1490 
1491         case STMF_ICM_REGISTER_PROXY_PORT:
1492                 m->icm_msg = stmf_ic_reg_port_msg_unmarshal(nvl);
1493                 break;
1494 
1495 
1496         case STMF_ICM_DEREGISTER_PROXY_PORT:
1497                 m->icm_msg = stmf_ic_dereg_port_msg_unmarshal(nvl);
1498                 break;
1499 
1500         case STMF_ICM_LUN_ACTIVE:
1501         case STMF_ICM_REGISTER_LUN:
1502         case STMF_ICM_DEREGISTER_LUN:
1503                 m->icm_msg = stmf_ic_reg_dereg_lun_msg_unmarshal(nvl);
1504                 break;
1505 
1506         case STMF_ICM_SCSI_CMD:
1507                 m->icm_msg = stmf_ic_scsi_cmd_msg_unmarshal(nvl);
1508                 break;
1509 
1510         case STMF_ICM_SCSI_DATA:
1511                 m->icm_msg = stmf_ic_scsi_data_msg_unmarshal(nvl);
1512                 break;
1513 
1514         case STMF_ICM_SCSI_DATA_XFER_DONE:
1515                 m->icm_msg = stmf_ic_scsi_data_xfer_done_msg_unmarshal(nvl);
1516                 break;
1517 
1518         case STMF_ICM_SCSI_STATUS:
1519                 m->icm_msg = stmf_ic_scsi_status_msg_unmarshal(nvl);
1520                 break;
1521 
1522         case STMF_ICM_R2T:
1523                 m->icm_msg = stmf_ic_r2t_msg_unmarshal(nvl);
1524                 break;
1525 
1526         case STMF_ICM_STATUS:
1527                 m->icm_msg = stmf_ic_status_msg_unmarshal(nvl);
1528                 break;
1529 
1530         case STMF_ICM_SESSION_CREATE:
1531         case STMF_ICM_SESSION_DESTROY:
1532                 m->icm_msg = stmf_ic_session_create_destroy_msg_unmarshal(nvl);
1533                 break;
1534 
1535         case STMF_ICM_ECHO_REQUEST:
1536         case STMF_ICM_ECHO_REPLY:
1537                 m->icm_msg = stmf_ic_echo_request_reply_msg_unmarshal(nvl);
1538                 break;
1539 
1540         case STMF_ICM_MAX_MSG_TYPE:
1541                 ASSERT(0);
1542                 break;
1543 
1544         default:
1545                 ASSERT(0);
1546         }
1547 
1548 done:
1549 
1550         if (!m->icm_msg) {
1551                 kmem_free(m, sizeof (*m));
1552                 return (NULL);
1553         }
1554 
1555         return (m);
1556 }
1557 
1558 static void *
1559 stmf_ic_reg_port_msg_unmarshal(nvlist_t *nvl)
1560 {
1561         nvlist_t *nvl_port_id = NULL;
1562         int rc = 0;
1563         stmf_ic_reg_port_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1564 
1565         rc = nvlist_lookup_nvlist(nvl, "icrp_port_id", &nvl_port_id);
1566         if (rc) {
1567                 stmf_ic_nvlookup_warn(__func__, "icrp_port_id nvl");
1568                 rc = ENOMEM; /* XXX */
1569                 goto done;
1570         }
1571 
1572         m->icrp_port_id = stmf_ic_scsi_devid_desc_unmarshal(nvl_port_id);
1573         if (m->icrp_port_id == NULL) {
1574                 stmf_ic_nvlookup_warn(__func__, "icrp_port_id");
1575                 rc = ENOMEM; /* XXX */
1576                 goto done;
1577         }
1578 
1579         NVLIST_LOOKUP_FIELD(uint16, m, icrp_relative_port_id);
1580         NVLIST_LOOKUP_FIELD(uint16, m, icrp_cb_arg_len);
1581 
1582         if (m->icrp_cb_arg_len) {
1583                 m->icrp_cb_arg = stmf_ic_uint8_array_unmarshal(nvl,
1584                     "icrp_cb_arg", m->icrp_cb_arg_len, NULL);
1585                 if (m->icrp_cb_arg == NULL) {
1586                         stmf_ic_nvlookup_warn(__func__, "icrp_cb_arg");
1587                         rc = ENOMEM; /* XXX */
1588                         goto done;
1589                 }
1590         }
1591 
1592 done:
1593         if (!rc)
1594                 return (m);
1595 
1596         stmf_ic_reg_port_msg_free(m, STMF_UNMARSHAL);
1597 
1598         return (NULL);
1599 }
1600 
1601 /*
1602  * XXX largely the same as stmf_ic_reg_port_msg_unmarshal()
1603  * Common stuff should be factored out.  Type issues may make this
1604  * painful.
1605  */
1606 static void *
1607 stmf_ic_dereg_port_msg_unmarshal(nvlist_t *nvl)
1608 {
1609         nvlist_t *nvl_port_id = NULL;
1610         int rc = 0;
1611         stmf_ic_dereg_port_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1612 
1613         rc = nvlist_lookup_nvlist(nvl, "icdp_port_id", &nvl_port_id);
1614         if (rc) {
1615                 stmf_ic_nvlookup_warn(__func__, "icdp_port_id nvl");
1616                 goto done;
1617         }
1618 
1619         m->icdp_port_id = stmf_ic_scsi_devid_desc_unmarshal(nvl_port_id);
1620         if (m->icdp_port_id == NULL) {
1621                 stmf_ic_nvlookup_warn(__func__, "icdp_port_id");
1622                 rc = ENOMEM; /* XXX */
1623                 goto done;
1624         }
1625 
1626         NVLIST_LOOKUP_FIELD(uint16, m, icdp_cb_arg_len);
1627 
1628         if (m->icdp_cb_arg_len) {
1629                 m->icdp_cb_arg = stmf_ic_uint8_array_unmarshal(nvl,
1630                     "icdp_cb_arg", m->icdp_cb_arg_len, NULL);
1631                 if (m->icdp_cb_arg == NULL) {
1632                         stmf_ic_nvlookup_warn(__func__, "icdp_cb_arg");
1633                         rc = ENOMEM; /* XXX */
1634                         goto done;
1635                 }
1636         }
1637 
1638 done:
1639         if (!rc)
1640                 return (m);
1641 
1642         stmf_ic_dereg_port_msg_free(m, STMF_UNMARSHAL);
1643 
1644         return (NULL);
1645 }
1646 
1647 static void *
1648 stmf_ic_reg_dereg_lun_msg_unmarshal(nvlist_t *nvl)
1649 {
1650         int rc = 0;
1651         stmf_ic_reg_dereg_lun_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1652 
1653         if (! stmf_ic_uint8_array_unmarshal(nvl, "icrl_lun_id",
1654             sizeof (m->icrl_lun_id), m->icrl_lun_id)) {
1655                 stmf_ic_nvlookup_warn(__func__, "icrl_lun_id");
1656                 rc = ENOMEM; /* XXX */
1657                 goto done;
1658         }
1659 
1660         m->icrl_lu_provider_name = stmf_ic_string_unmarshal(nvl,
1661             "icrl_lu_provider_name");
1662 
1663         if (!m->icrl_lu_provider_name) {
1664                 stmf_ic_nvlookup_warn(__func__, "icrl_lu_provider_name");
1665                 rc = ENOMEM; /* XXX */
1666                 goto done;
1667         }
1668 
1669         NVLIST_LOOKUP_FIELD(uint16, m, icrl_cb_arg_len);
1670 
1671         if (m->icrl_cb_arg_len) {
1672                 m->icrl_cb_arg = stmf_ic_uint8_array_unmarshal(nvl,
1673                     "icrl_cb_arg", m->icrl_cb_arg_len, NULL);
1674                 if (m->icrl_cb_arg == NULL) {
1675                         stmf_ic_nvlookup_warn(__func__, "icrl_cb_arg");
1676                         rc = ENOMEM; /* XXX */
1677                         goto done;
1678                 }
1679         }
1680 
1681 done:
1682         if (!rc)
1683                 return (m);
1684 
1685         stmf_ic_reg_dereg_lun_msg_free(m, STMF_UNMARSHAL);
1686 
1687         return (NULL);
1688 }
1689 
1690 static void *
1691 stmf_ic_scsi_cmd_msg_unmarshal(nvlist_t *nvl)
1692 {
1693         int rc = 0;
1694         stmf_ic_scsi_cmd_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1695 
1696         if (nvlist_lookup_pairs(nvl, 0,
1697             NV_PAIR(UINT64, m, icsc_task_msgid),
1698             NV_PAIR(UINT64, m, icsc_session_id),
1699             NV_PAIR(UINT32, m, icsc_task_expected_xfer_length),
1700             NV_PAIR(UINT16, m, icsc_task_cdb_length),
1701             NV_PAIR(UINT8, m, icsc_task_flags),
1702             NV_PAIR(UINT8, m, icsc_task_mgmt_function),
1703             NV_PAIR(UINT32, m, icsc_immed_data_len),
1704             NULL) != 0) {
1705                 stmf_ic_nvlookup_warn(__func__, "icsc_task_msgid and friends");
1706                 rc = ENOMEM; /* XXX need something better */
1707                 goto done;
1708         }
1709 
1710         m->icsc_ini_devid = stmf_ic_lookup_scsi_devid_desc_and_unmarshal(
1711             nvl, "icsc_ini_devid");
1712         if (m->icsc_ini_devid == NULL) {
1713                 stmf_ic_nvlookup_warn(__func__, "icsc_ini_devid");
1714                 rc = ENOMEM;
1715                 goto done;
1716         }
1717 
1718         m->icsc_tgt_devid = stmf_ic_lookup_scsi_devid_desc_and_unmarshal(
1719             nvl, "icsc_tgt_devid");
1720         if (m->icsc_tgt_devid == NULL) {
1721                 stmf_ic_nvlookup_warn(__func__, "icsc_tgt_devid");
1722                 rc = ENOMEM;
1723                 goto done;
1724         }
1725 
1726         m->icsc_rport = stmf_ic_lookup_remote_port_and_unmarshal(
1727             nvl, "icsc_rport");
1728         if (m->icsc_rport == NULL) {
1729                 stmf_ic_nvlookup_warn(__func__, "icsc_rport");
1730                 rc = ENOMEM;
1731                 goto done;
1732         }
1733 
1734         /* icsc_lun_id */
1735         if (!stmf_ic_uint8_array_unmarshal(nvl, "icsc_lun_id",
1736             sizeof (m->icsc_lun_id), m->icsc_lun_id)) {
1737                 stmf_ic_nvlookup_warn(__func__, "icsc_lun_id");
1738                 rc = ENOMEM;
1739                 goto done;
1740         }
1741 
1742         /* icsc_task_lun_no */
1743         if (!stmf_ic_uint8_array_unmarshal(nvl, "icsc_task_lun_no",
1744             sizeof (m->icsc_task_lun_no), m->icsc_task_lun_no)) {
1745                 stmf_ic_nvlookup_warn(__func__, "icsc_task_lun_no");
1746                 rc = ENOMEM;
1747                 goto done;
1748         }
1749 
1750         /* icsc_task_cdb */
1751         if (m->icsc_task_cdb_length) {
1752                 m->icsc_task_cdb = stmf_ic_uint8_array_unmarshal(nvl,
1753                     "icsc_task_cdb", m->icsc_task_cdb_length, NULL);
1754                 if (!m->icsc_task_cdb) {
1755                         stmf_ic_nvlookup_warn(__func__, "icsc_task_cdb");
1756                         rc = ENOMEM;
1757                         goto done;
1758                 }
1759         }
1760 
1761         /* immediate data, if there is any */
1762         if (m->icsc_immed_data_len) {
1763                 m->icsc_immed_data = stmf_ic_uint8_array_unmarshal(nvl,
1764                     "icsc_immed_data", m->icsc_immed_data_len, NULL);
1765                 if (!m->icsc_immed_data) {
1766                         stmf_ic_nvlookup_warn(__func__, "icsc_immed_data");
1767                         rc = ENOMEM;
1768                         goto done;
1769                 }
1770         }
1771 
1772 done:
1773         if (!rc)
1774                 return (m);
1775 
1776         stmf_ic_scsi_cmd_msg_free(m, STMF_UNMARSHAL);
1777 
1778         return (NULL);
1779 }
1780 
1781 static void *
1782 stmf_ic_scsi_data_msg_unmarshal(nvlist_t *nvl)
1783 {
1784         int rc = 0;
1785         stmf_ic_scsi_data_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1786 
1787         if (nvlist_lookup_pairs(nvl, 0,
1788             NV_PAIR(UINT64, m, icsd_task_msgid),
1789             NV_PAIR(UINT64, m, icsd_session_id),
1790             NV_PAIR(UINT64, m, icsd_data_len),
1791             NULL) != 0) {
1792                 stmf_ic_nvlookup_warn(__func__, "icsd_task_msgid and friends");
1793                 rc = ENOMEM; /* XXX need something better */
1794                 goto done;
1795         }
1796 
1797         if (!stmf_ic_uint8_array_unmarshal(nvl, "icsd_lun_id",
1798             sizeof (m->icsd_lun_id), m->icsd_lun_id)) {
1799                 stmf_ic_nvlookup_warn(__func__, "icsd_lun_id");
1800                 rc = ENOMEM;
1801                 goto done;
1802         }
1803 
1804         m->icsd_data = stmf_ic_uint8_array_unmarshal(nvl, "icsd_data",
1805             m->icsd_data_len, NULL);
1806         if (!m->icsd_data) {
1807                 stmf_ic_nvlookup_warn(__func__, "icsd_data");
1808                 rc = ENOMEM;
1809                 goto done;
1810         }
1811 
1812 done:
1813         if (!rc)
1814                 return (m);
1815 
1816         stmf_ic_scsi_data_msg_free(m, STMF_UNMARSHAL);
1817 
1818         return (NULL);
1819 }
1820 
1821 static void *
1822 stmf_ic_scsi_data_xfer_done_msg_unmarshal(nvlist_t *nvl)
1823 {
1824         int rc = 0;
1825         stmf_ic_scsi_data_xfer_done_msg_t *m =
1826             kmem_zalloc(sizeof (*m), KM_SLEEP);
1827 
1828         if (nvlist_lookup_pairs(nvl, 0,
1829             NV_PAIR(UINT64, m, icsx_task_msgid),
1830             NV_PAIR(UINT64, m, icsx_session_id),
1831             NV_PAIR(UINT64, m, icsx_status),
1832             NULL) != 0) {
1833                 stmf_ic_nvlookup_warn(__func__, "icsx_task_msgid and friends");
1834                 rc = ENOMEM; /* XXX need something better */
1835                 goto done;
1836         }
1837 
1838 done:
1839         if (!rc)
1840                 return (m);
1841 
1842         stmf_ic_scsi_data_xfer_done_msg_free(m, STMF_UNMARSHAL);
1843 
1844         return (NULL);
1845 }
1846 
1847 static void *
1848 stmf_ic_scsi_status_msg_unmarshal(nvlist_t *nvl)
1849 {
1850         int rc = 0;
1851         stmf_ic_scsi_status_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1852 
1853         if (nvlist_lookup_pairs(nvl, 0,
1854             NV_PAIR(UINT64, m, icss_task_msgid),
1855             NV_PAIR(UINT64, m, icss_session_id),
1856             NV_PAIR(UINT8, m, icss_response),
1857             NV_PAIR(UINT8, m, icss_status),
1858             NV_PAIR(UINT8, m, icss_flags),
1859             NV_PAIR(UINT32, m, icss_resid),
1860             NV_PAIR(UINT8, m, icss_sense_len),
1861             NULL) != 0) {
1862                 stmf_ic_nvlookup_warn(__func__, "icss_task_msgid and friends");
1863                 rc = ENOMEM; /* XXX need something better */
1864                 goto done;
1865         }
1866 
1867         if (!stmf_ic_uint8_array_unmarshal(nvl, "icss_lun_id",
1868             sizeof (m->icss_lun_id), m->icss_lun_id)) {
1869                 stmf_ic_nvlookup_warn(__func__, "icss_lun_id");
1870                 rc = ENOMEM;
1871                 goto done;
1872         }
1873 
1874         if (m->icss_sense_len) {
1875                 m->icss_sense = stmf_ic_uint8_array_unmarshal(nvl, "icss_sense",
1876                     m->icss_sense_len, NULL);
1877                 if (!m->icss_sense) {
1878                         stmf_ic_nvlookup_warn(__func__, "icss_sense");
1879                         rc = ENOMEM;
1880                         goto done;
1881                 }
1882         }
1883 done:
1884         if (!rc)
1885                 return (m);
1886 
1887         stmf_ic_scsi_status_msg_free(m, STMF_UNMARSHAL);
1888 
1889         return (NULL);
1890 }
1891 
1892 static void *
1893 stmf_ic_r2t_msg_unmarshal(nvlist_t *nvl)
1894 {
1895         int rc = 0;
1896         stmf_ic_r2t_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1897 
1898         if (nvlist_lookup_pairs(nvl, 0,
1899             NV_PAIR(UINT64, m, icrt_task_msgid),
1900             NV_PAIR(UINT64, m, icrt_session_id),
1901             NV_PAIR(UINT32, m, icrt_offset),
1902             NV_PAIR(UINT32, m, icrt_length),
1903             NULL) != 0) {
1904                 stmf_ic_nvlookup_warn(__func__, "icrt_task_msgid and friends");
1905                 rc = ENOMEM; /* XXX need something better */
1906                 goto done;
1907         }
1908 
1909 done:
1910         if (!rc)
1911                 return (m);
1912 
1913         stmf_ic_r2t_msg_free(m, STMF_UNMARSHAL);
1914 
1915         return (NULL);
1916 }
1917 
1918 static void *
1919 stmf_ic_session_create_destroy_msg_unmarshal(nvlist_t *nvl)
1920 {
1921         int rc = 0;
1922         stmf_ic_session_create_destroy_msg_t *m = kmem_zalloc(sizeof (*m),
1923             KM_SLEEP);
1924 
1925         if (nvlist_lookup_pairs(nvl, 0,
1926             NV_PAIR(UINT64, m, icscd_session_id),
1927             NULL) != 0) {
1928                 stmf_ic_nvlookup_warn(__func__, "icsd_session_id");
1929                 rc = ENOMEM; /* XXX need something better */
1930                 goto done;
1931         }
1932 
1933         m->icscd_ini_devid = stmf_ic_lookup_scsi_devid_desc_and_unmarshal(
1934             nvl, "icscd_ini_devid");
1935         if (m->icscd_ini_devid == NULL) {
1936                 stmf_ic_nvlookup_warn(__func__, "icsd_ini_devid");
1937                 rc = ENOMEM;
1938                 goto done;
1939         }
1940 
1941         m->icscd_tgt_devid = stmf_ic_lookup_scsi_devid_desc_and_unmarshal(
1942             nvl, "icscd_tgt_devid");
1943         if (m->icscd_tgt_devid == NULL) {
1944                 stmf_ic_nvlookup_warn(__func__, "icsd_tgt_devid");
1945                 rc = ENOMEM;
1946                 goto done;
1947         }
1948 
1949         m->icscd_rport = stmf_ic_lookup_remote_port_and_unmarshal(
1950             nvl, "icscd_rport");
1951         if (m->icscd_rport == NULL) {
1952                 stmf_ic_nvlookup_warn(__func__, "icscd_rport");
1953                 rc = ENOMEM;
1954                 goto done;
1955         }
1956 
1957 done:
1958         if (!rc)
1959                 return (m);
1960 
1961         stmf_ic_session_create_destroy_msg_free(m, STMF_UNMARSHAL);
1962 
1963         return (NULL);
1964 }
1965 
1966 static void *
1967 stmf_ic_echo_request_reply_msg_unmarshal(nvlist_t *nvl)
1968 {
1969         int rc = 0;
1970         stmf_ic_echo_request_reply_msg_t *m = kmem_zalloc(sizeof (*m),
1971             KM_SLEEP);
1972 
1973         if (nvlist_lookup_pairs(nvl, 0,
1974             NV_PAIR(UINT32, m, icerr_datalen),
1975             NULL) != 0) {
1976                 stmf_ic_nvlookup_warn(__func__, "icerr_datalen");
1977                 rc = ENOMEM; /* XXX need something better */
1978                 goto done;
1979         }
1980 
1981         /* immediate data, if there is any */
1982         if (m->icerr_datalen) {
1983                 m->icerr_data = stmf_ic_uint8_array_unmarshal(nvl,
1984                     "icerr_data", m->icerr_datalen, NULL);
1985                 if (!m->icerr_data) {
1986                         stmf_ic_nvlookup_warn(__func__, "icerr_data");
1987                         rc = ENOMEM;
1988                         goto done;
1989                 }
1990         }
1991 
1992 done:
1993         if (!rc)
1994                 return (m);
1995 
1996         stmf_ic_echo_request_reply_msg_free(m, STMF_UNMARSHAL);
1997 
1998         return (NULL);
1999 }
2000 
2001 static void *
2002 stmf_ic_status_msg_unmarshal(nvlist_t *nvl)
2003 {
2004         int rc = 0;
2005         stmf_ic_status_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
2006 
2007         if (nvlist_lookup_pairs(nvl, 0,
2008             NV_PAIR(UINT8, m, ics_msg_type),
2009             NV_PAIR(UINT64, m, ics_msgid),
2010             NV_PAIR(UINT8, m, ics_status),
2011             NULL) != 0) {
2012                 stmf_ic_nvlookup_warn(__func__, "ics_msg_type and friends");
2013                 rc = ENOMEM; /* XXX need something better */
2014                 goto done;
2015         }
2016 
2017 done:
2018         if (!rc)
2019                 return (m);
2020 
2021         kmem_free(m, sizeof (*m));
2022         return (NULL);
2023 }
2024 
2025 
2026 static scsi_devid_desc_t *
2027 stmf_ic_lookup_scsi_devid_desc_and_unmarshal(nvlist_t *nvl, char *field_name)
2028 {
2029         nvlist_t *nvl_devid = NULL;
2030         scsi_devid_desc_t *did = NULL;
2031         int rc;
2032 
2033         rc = nvlist_lookup_nvlist(nvl, field_name, &nvl_devid);
2034         if (rc) {
2035                 goto done;
2036         }
2037 
2038         did = stmf_ic_scsi_devid_desc_unmarshal(nvl_devid);
2039 
2040 done:
2041         return (did);
2042 }
2043 
2044 
2045 static scsi_devid_desc_t *
2046 stmf_ic_scsi_devid_desc_unmarshal(nvlist_t *nvl)
2047 {
2048         scsi_devid_desc_t *sdid = NULL;
2049         uint8_t ident_length = 0;
2050         size_t sdid_size;
2051         int rc = 0;
2052 
2053         /*
2054          * we get the ident_length first, since that's the only
2055          * variable-sized field in the struct.
2056          */
2057         rc = nvlist_lookup_uint8(nvl, "ident_length", &ident_length);
2058         if (rc)
2059                 goto done;
2060 
2061         sdid_size = sizeof_scsi_devid_desc(ident_length);
2062         sdid = kmem_zalloc(sdid_size, KM_SLEEP);
2063 
2064         NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, protocol_id);
2065         NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, code_set);
2066         NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, piv);
2067         NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, association);
2068         NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, ident_type);
2069 
2070         sdid->ident_length = ident_length;
2071 
2072         if (!stmf_ic_uint8_array_unmarshal(nvl, "ident",
2073             sdid->ident_length, sdid->ident)) {
2074                 rc = ENOMEM; /* XXX */
2075                 goto done;
2076         }
2077 
2078 done:
2079         if (!rc)
2080                 return (sdid);
2081 
2082         kmem_free(sdid, sdid_size);
2083 
2084         return (NULL);
2085 }
2086 
2087 static stmf_remote_port_t *
2088 stmf_ic_lookup_remote_port_and_unmarshal(nvlist_t *nvl, char *field_name)
2089 {
2090         nvlist_t *nvl_rport = NULL;
2091 
2092         if (nvlist_lookup_nvlist(nvl, field_name, &nvl_rport) != 0)
2093                 return (NULL);
2094 
2095         return (stmf_ic_remote_port_unmarshal(nvl_rport));
2096 }
2097 
2098 static stmf_remote_port_t *
2099 stmf_ic_remote_port_unmarshal(nvlist_t *nvl)
2100 {
2101         stmf_remote_port_t *rport = NULL;
2102         uint16_t rport_tptid_sz = 0;
2103         int rc = 0;
2104 
2105         rc = nvlist_lookup_uint16(nvl, "rport_tptid_sz", &rport_tptid_sz);
2106         if (rc || rport_tptid_sz < sizeof (scsi_transport_id_t))
2107                 return (NULL);
2108 
2109         rport = stmf_remote_port_alloc(rport_tptid_sz);
2110         if (!stmf_ic_uint8_array_unmarshal(nvl, "rport_tptid", rport_tptid_sz,
2111             (uint8_t *)rport->rport_tptid)) {
2112                 stmf_remote_port_free(rport);
2113                 rport = NULL;
2114         }
2115         return (rport);
2116 }
2117 
2118 /*
2119  * Unmarshal a uint8_t array.
2120  *
2121  * Takes a buf argument:
2122  *
2123  * - if non-null, the array contents are copied into the buf,
2124  *   and we return a pointer to the buffer.
2125  *
2126  * - if null, we return a pointer to the unmarshaled data, which
2127  *   resides in the nvlist.
2128  *
2129  * Returns NULL on failure.
2130  */
2131 static uint8_t *
2132 stmf_ic_uint8_array_unmarshal(
2133     nvlist_t *nvl,
2134     char *field_name,
2135     uint64_t len,
2136     uint8_t *buf)       /* non-NULL: copy array into buf */
2137 {
2138         uint8_t *array = NULL;
2139         uint_t actual_len;
2140         int rc = 0;
2141 
2142         rc = nvlist_lookup_uint8_array(nvl, field_name, &array, &actual_len);
2143         if (rc) {
2144                 return (NULL);
2145         }
2146 
2147         if (len != actual_len) {
2148                 cmn_err(CE_WARN,
2149                     "stmf_ic_uint8_array_unmarshal: wrong len (%d != %d)",
2150                     (int)len, actual_len);
2151                 return (NULL);
2152         }
2153 
2154         if (buf) {
2155                 /* preallocated buf, copy in */
2156                 bcopy(array, buf, len);
2157         } else {
2158                 /* return a pointer to the underlying array in the nvlist */
2159                 buf = array;
2160         }
2161 
2162         return (buf);
2163 }
2164 
2165 /*
2166  * Unmarshal a string.
2167  *
2168  * Returns NULL on failure.
2169  */
2170 static char *
2171 stmf_ic_string_unmarshal(
2172     nvlist_t *nvl,
2173     char *field_name)
2174 {
2175         char *s = NULL;
2176         int rc = 0;
2177 
2178         rc = nvlist_lookup_string(nvl, field_name, &s);
2179         if (rc) {
2180                 return (NULL);
2181         }
2182 
2183         return (s);
2184 }
2185 
2186 /*
2187  * Utility routines.
2188  */
2189 
2190 static stmf_ic_msg_t *
2191 stmf_ic_alloc_msg_header(
2192     stmf_ic_msg_type_t msg_type,
2193     stmf_ic_msgid_t msgid)
2194 {
2195         stmf_ic_msg_t *icm;
2196 
2197         icm = (stmf_ic_msg_t *)kmem_zalloc(sizeof (*icm), KM_SLEEP);
2198         icm->icm_msg_type = msg_type;
2199         icm->icm_msgid = msgid;
2200 
2201         return (icm);
2202 }
2203 
2204 static size_t
2205 sizeof_scsi_devid_desc(int ident_length)
2206 {
2207         int num_ident_elems;
2208         size_t size;
2209 
2210         ASSERT(ident_length > 0);
2211 
2212         /*
2213          * Need to account for the fact that there's
2214          * already a single element in scsi_devid_desc_t.
2215          *
2216          * XXX would really like to have a way to determine the
2217          * sizeof (struct scsi_devid_desc.ident[0]), but
2218          * it's not clear that can be done.
2219          * Thus, this code relies on the knowledge of the type of
2220          * that field.
2221          */
2222         num_ident_elems = ident_length - 1;
2223         size = sizeof (scsi_devid_desc_t) +
2224             (num_ident_elems * sizeof (uint8_t));
2225 
2226         return (size);
2227 }
2228 
2229 
2230 /*
2231  * Duplicate the scsi_devid_desc_t.
2232  */
2233 static scsi_devid_desc_t *
2234 scsi_devid_desc_dup(scsi_devid_desc_t *did)
2235 {
2236         scsi_devid_desc_t *dup;
2237         size_t dup_size;
2238 
2239         ASSERT(did->ident_length > 0);
2240 
2241         dup_size = sizeof_scsi_devid_desc(did->ident_length);
2242         dup = (scsi_devid_desc_t *)kmem_zalloc(dup_size, KM_SLEEP);
2243         bcopy(did, dup, dup_size);
2244         return (dup);
2245 }
2246 
2247 /*
2248  * May be called with a null pointer.
2249  */
2250 static void
2251 scsi_devid_desc_free(scsi_devid_desc_t *did)
2252 {
2253         if (!did)
2254                 return;
2255 
2256         kmem_free(did, sizeof_scsi_devid_desc(did->ident_length));
2257 }
2258 
2259 /*
2260  * Duplicate the stmf_remote_port_t.
2261  */
2262 static stmf_remote_port_t *
2263 remote_port_dup(stmf_remote_port_t *rport)
2264 {
2265         stmf_remote_port_t *dup = NULL;
2266         if (rport) {
2267                 dup = stmf_remote_port_alloc(rport->rport_tptid_sz);
2268                 bcopy(rport->rport_tptid, dup->rport_tptid,
2269                     rport->rport_tptid_sz);
2270         }
2271         return (dup);
2272 }
2273 
2274 /*
2275  * Helper functions, returns NULL if no memory.
2276  */
2277 static char *
2278 stmf_ic_strdup(char *str)
2279 {
2280         char *copy;
2281 
2282         ASSERT(str);
2283 
2284         copy = kmem_zalloc(strlen(str) + 1, KM_SLEEP);
2285         (void) strcpy(copy, str);
2286         return (copy);
2287 }
2288 
2289 static inline void
2290 stmf_ic_nvlookup_warn(const char *func, char *field)
2291 {
2292         cmn_err(CE_WARN, "%s: nvlist lookup of %s failed", func, field);
2293 }