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