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