xref: /illumos-gate/usr/src/uts/common/io/comstar/port/pppt/alua_ic_if.c (revision 5bbb4db2c3f208d12bf0fd11769728f9e5ba66a2)
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 	uint8_t *lun_id = task->task_lu->lu_id->ident;
633 
634 	icm = stmf_ic_alloc_msg_header(STMF_ICM_SCSI_CMD, msgid);
635 	icsc = (stmf_ic_scsi_cmd_msg_t *)kmem_zalloc(sizeof (*icsc), KM_SLEEP);
636 	icm->icm_msg = (void *)icsc;
637 
638 	icsc->icsc_task_msgid = task_msgid;
639 	icsc->icsc_ini_devid = scsi_devid_desc_dup(ini_devid);
640 	icsc->icsc_tgt_devid = scsi_devid_desc_dup(tgt_devid);
641 	icsc->icsc_session_id = task->task_session->ss_session_id;
642 
643 	bcopy(lun_id, icsc->icsc_lun_id, sizeof (icsc->icsc_lun_id));
644 
645 	bcopy(task->task_lun_no, icsc->icsc_task_lun_no,
646 	    sizeof (icsc->icsc_task_lun_no));
647 
648 	icsc->icsc_task_expected_xfer_length = task->task_expected_xfer_length;
649 	icsc->icsc_task_cdb_length = task->task_cdb_length;
650 
651 	icsc->icsc_task_cdb = (uint8_t *)kmem_zalloc(task->task_cdb_length,
652 	    KM_SLEEP);
653 	bcopy(task->task_cdb, icsc->icsc_task_cdb, task->task_cdb_length);
654 
655 	icsc->icsc_task_flags = task->task_flags;
656 	icsc->icsc_task_priority = task->task_priority;
657 	icsc->icsc_task_mgmt_function = task->task_mgmt_function;
658 
659 	icsc->icsc_immed_data_len = immed_data_len;
660 	icsc->icsc_immed_data = immed_data;
661 
662 	return (icm);
663 }
664 
665 stmf_ic_msg_t *
666 stmf_ic_scsi_data_msg_alloc(
667     stmf_ic_msgid_t task_msgid,
668     uint64_t session_id,
669     uint8_t *lun_id,
670     uint64_t data_len,
671     uint8_t *data,
672     stmf_ic_msgid_t msgid)
673 {
674 	stmf_ic_msg_t *icm = NULL;
675 	stmf_ic_scsi_data_msg_t *icsd = NULL;
676 
677 	icm = stmf_ic_alloc_msg_header(STMF_ICM_SCSI_DATA, msgid);
678 	icsd = (stmf_ic_scsi_data_msg_t *)kmem_zalloc(sizeof (*icsd), KM_SLEEP);
679 	icm->icm_msg = (void *)icsd;
680 
681 	icsd->icsd_task_msgid = task_msgid;
682 	icsd->icsd_session_id = session_id;
683 	bcopy(lun_id, icsd->icsd_lun_id, sizeof (icsd->icsd_lun_id));
684 	icsd->icsd_data_len = data_len;
685 	icsd->icsd_data = data;
686 
687 	return (icm);
688 }
689 
690 stmf_ic_msg_t *
691 stmf_ic_scsi_data_xfer_done_msg_alloc(
692     stmf_ic_msgid_t task_msgid,
693     uint64_t session_id,
694     stmf_status_t status,
695     stmf_ic_msgid_t msgid)
696 {
697 	stmf_ic_msg_t *icm = NULL;
698 	stmf_ic_scsi_data_xfer_done_msg_t *icsx = NULL;
699 
700 	icm = stmf_ic_alloc_msg_header(STMF_ICM_SCSI_DATA_XFER_DONE, msgid);
701 	icsx = (stmf_ic_scsi_data_xfer_done_msg_t *)kmem_zalloc(
702 	    sizeof (*icsx), KM_SLEEP);
703 	icm->icm_msg = (void *)icsx;
704 
705 	icsx->icsx_task_msgid = task_msgid;
706 	icsx->icsx_session_id = session_id;
707 	icsx->icsx_status = status;
708 
709 	return (icm);
710 }
711 
712 stmf_ic_msg_t *
713 stmf_ic_scsi_status_msg_alloc(
714     stmf_ic_msgid_t task_msgid,
715     uint64_t session_id,
716     uint8_t *lun_id,
717     uint8_t response,
718     uint8_t status,
719     uint8_t flags,
720     uint32_t resid,
721     uint8_t sense_len,
722     uint8_t *sense,
723     stmf_ic_msgid_t msgid)
724 {
725 	stmf_ic_msg_t *icm = NULL;
726 	stmf_ic_scsi_status_msg_t *icss = NULL;
727 
728 	icm = stmf_ic_alloc_msg_header(STMF_ICM_SCSI_STATUS, msgid);
729 	icss = (stmf_ic_scsi_status_msg_t *)kmem_zalloc(sizeof (*icss),
730 	    KM_SLEEP);
731 	icm->icm_msg = (void *)icss;
732 
733 	icss->icss_task_msgid = task_msgid;
734 	icss->icss_session_id = session_id;
735 	bcopy(lun_id, icss->icss_lun_id, sizeof (icss->icss_lun_id));
736 	icss->icss_response = response;
737 	icss->icss_status = status;
738 	icss->icss_flags = flags;
739 	icss->icss_resid = resid;
740 	icss->icss_sense_len = sense_len;
741 	icss->icss_sense = sense;
742 
743 	return (icm);
744 }
745 
746 stmf_ic_msg_t *
747 stmf_ic_r2t_msg_alloc(
748     stmf_ic_msgid_t task_msgid,
749     uint64_t session_id,
750     uint32_t offset,
751     uint32_t length,
752     stmf_ic_msgid_t msgid)
753 {
754 	stmf_ic_msg_t *icm = NULL;
755 	stmf_ic_r2t_msg_t *icrt = NULL;
756 
757 	icm = stmf_ic_alloc_msg_header(STMF_ICM_R2T, msgid);
758 	icrt = (stmf_ic_r2t_msg_t *)kmem_zalloc(sizeof (*icrt), KM_SLEEP);
759 	icm->icm_msg = (void *)icrt;
760 
761 	icrt->icrt_task_msgid = task_msgid;
762 	icrt->icrt_session_id = session_id;
763 	icrt->icrt_offset = offset;
764 	icrt->icrt_length = length;
765 
766 	return (icm);
767 }
768 
769 stmf_ic_msg_t *
770 stmf_ic_status_msg_alloc(
771     stmf_status_t status,
772     stmf_ic_msg_type_t msg_type,
773     stmf_ic_msgid_t msgid)
774 {
775 	stmf_ic_msg_t *icm = NULL;
776 	stmf_ic_status_msg_t *ics = NULL;
777 
778 	icm = stmf_ic_alloc_msg_header(STMF_ICM_STATUS, msgid);
779 	ics = (stmf_ic_status_msg_t *)kmem_zalloc(sizeof (*ics), KM_SLEEP);
780 	icm->icm_msg = (void *)ics;
781 
782 	ics->ics_status = status;
783 	ics->ics_msg_type = msg_type;
784 	ics->ics_msgid = msgid;		/* XXX same as msgid in header */
785 
786 	return (icm);
787 }
788 
789 stmf_ic_msg_t *
790 stmf_ic_session_create_msg_alloc(
791     stmf_scsi_session_t *session,
792     stmf_ic_msgid_t msgid)
793 {
794 	return (stmf_ic_session_create_destroy_msg_alloc(
795 	    STMF_ICM_SESSION_CREATE, session, msgid));
796 }
797 
798 stmf_ic_msg_t *
799 stmf_ic_session_destroy_msg_alloc(
800     stmf_scsi_session_t *session,
801     stmf_ic_msgid_t msgid)
802 {
803 	return (stmf_ic_session_create_destroy_msg_alloc(
804 	    STMF_ICM_SESSION_DESTROY, session, msgid));
805 }
806 
807 /*
808  * Guts of session create/destroy routines.
809  */
810 static stmf_ic_msg_t *
811 stmf_ic_session_create_destroy_msg_alloc(
812     stmf_ic_msg_type_t msg_type,
813     stmf_scsi_session_t *session,
814     stmf_ic_msgid_t msgid)
815 {
816 	stmf_ic_msg_t *icm = NULL;
817 	stmf_ic_session_create_destroy_msg_t *icscd = NULL;
818 	scsi_devid_desc_t *ini_devid = session->ss_rport_id;
819 	scsi_devid_desc_t *tgt_devid = session->ss_lport->lport_id;
820 
821 	icm = stmf_ic_alloc_msg_header(msg_type, msgid);
822 	icscd = (stmf_ic_session_create_destroy_msg_t *)
823 	    kmem_zalloc(sizeof (*icscd), KM_SLEEP);
824 	icm->icm_msg = (void *)icscd;
825 
826 	icscd->icscd_session_id = session->ss_session_id;
827 	icscd->icscd_ini_devid = scsi_devid_desc_dup(ini_devid);
828 	icscd->icscd_tgt_devid = scsi_devid_desc_dup(tgt_devid);
829 
830 	return (icm);
831 }
832 
833 stmf_ic_msg_t *
834 stmf_ic_echo_request_msg_alloc(
835     uint32_t data_len,
836     uint8_t *data,
837     stmf_ic_msgid_t msgid)
838 {
839 	return (stmf_ic_echo_request_reply_msg_alloc(
840 	    STMF_ICM_ECHO_REQUEST, data_len, data, msgid));
841 }
842 
843 stmf_ic_msg_t *
844 stmf_ic_echo_reply_msg_alloc(
845     uint32_t data_len,
846     uint8_t *data,
847     stmf_ic_msgid_t msgid)
848 {
849 	return (stmf_ic_echo_request_reply_msg_alloc(
850 	    STMF_ICM_ECHO_REPLY, data_len, data, msgid));
851 }
852 
853 
854 static stmf_ic_msg_t *
855 stmf_ic_echo_request_reply_msg_alloc(
856     stmf_ic_msg_type_t msg_type,
857     uint32_t data_len,
858     uint8_t *data,
859     stmf_ic_msgid_t msgid)
860 {
861 	stmf_ic_msg_t *icm = NULL;
862 	stmf_ic_echo_request_reply_msg_t *icerr = NULL;
863 
864 	icm = stmf_ic_alloc_msg_header(msg_type, msgid);
865 	icerr = kmem_zalloc(sizeof (*icerr), KM_SLEEP);
866 	icm->icm_msg = (void *)icerr;
867 
868 	icerr->icerr_data = data;
869 	icerr->icerr_datalen = data_len;
870 
871 	return (icm);
872 }
873 
874 /*
875  * msg free routines.
876  */
877 void
878 stmf_ic_msg_free(stmf_ic_msg_t *msg)
879 {
880 	stmf_ic_msg_construction_method_t cmethod =
881 	    (msg->icm_nvlist ? STMF_UNMARSHAL : STMF_CONSTRUCTOR);
882 
883 	switch (msg->icm_msg_type) {
884 	case STMF_ICM_REGISTER_PROXY_PORT:
885 		stmf_ic_reg_port_msg_free(
886 		    (stmf_ic_reg_port_msg_t *)msg->icm_msg, cmethod);
887 		break;
888 
889 	case STMF_ICM_DEREGISTER_PROXY_PORT:
890 		stmf_ic_dereg_port_msg_free(
891 		    (stmf_ic_dereg_port_msg_t *)msg->icm_msg, cmethod);
892 		break;
893 
894 	case STMF_ICM_LUN_ACTIVE:
895 	case STMF_ICM_REGISTER_LUN:
896 	case STMF_ICM_DEREGISTER_LUN:
897 		stmf_ic_reg_dereg_lun_msg_free(
898 		    (stmf_ic_reg_dereg_lun_msg_t *)msg->icm_msg, cmethod);
899 		break;
900 
901 	case STMF_ICM_SCSI_CMD:
902 		stmf_ic_scsi_cmd_msg_free(
903 		    (stmf_ic_scsi_cmd_msg_t *)msg->icm_msg, cmethod);
904 		break;
905 
906 	case STMF_ICM_SCSI_DATA:
907 		stmf_ic_scsi_data_msg_free(
908 		    (stmf_ic_scsi_data_msg_t *)msg->icm_msg, cmethod);
909 		break;
910 
911 	case STMF_ICM_SCSI_DATA_XFER_DONE:
912 		stmf_ic_scsi_data_xfer_done_msg_free(
913 		    (stmf_ic_scsi_data_xfer_done_msg_t *)msg->icm_msg, cmethod);
914 		break;
915 
916 	case STMF_ICM_SCSI_STATUS:
917 		stmf_ic_scsi_status_msg_free(
918 		    (stmf_ic_scsi_status_msg_t *)msg->icm_msg, cmethod);
919 		break;
920 
921 	case STMF_ICM_R2T:
922 		stmf_ic_r2t_msg_free(
923 		    (stmf_ic_r2t_msg_t *)msg->icm_msg, cmethod);
924 		break;
925 
926 	case STMF_ICM_STATUS:
927 		stmf_ic_status_msg_free(
928 		    (stmf_ic_status_msg_t *)msg->icm_msg, cmethod);
929 		break;
930 
931 	case STMF_ICM_SESSION_CREATE:
932 	case STMF_ICM_SESSION_DESTROY:
933 		stmf_ic_session_create_destroy_msg_free(
934 		    (stmf_ic_session_create_destroy_msg_t *)msg->icm_msg,
935 		    cmethod);
936 		break;
937 
938 	case STMF_ICM_ECHO_REQUEST:
939 	case STMF_ICM_ECHO_REPLY:
940 		stmf_ic_echo_request_reply_msg_free(
941 		    (stmf_ic_echo_request_reply_msg_t *)msg->icm_msg, cmethod);
942 		break;
943 
944 	case STMF_ICM_MAX_MSG_TYPE:
945 		ASSERT(0);
946 		break;
947 
948 	default:
949 		ASSERT(0);
950 	}
951 
952 	if (msg->icm_nvlist)
953 		nvlist_free(msg->icm_nvlist);
954 
955 	kmem_free(msg, sizeof (*msg));
956 }
957 
958 /*ARGSUSED*/
959 static void
960 stmf_ic_reg_port_msg_free(stmf_ic_reg_port_msg_t *m,
961     stmf_ic_msg_construction_method_t cmethod)
962 {
963 	scsi_devid_desc_free(m->icrp_port_id);
964 
965 	kmem_free(m, sizeof (*m));
966 }
967 
968 
969 /*ARGSUSED*/
970 static void
971 stmf_ic_dereg_port_msg_free(stmf_ic_dereg_port_msg_t *m,
972     stmf_ic_msg_construction_method_t cmethod)
973 {
974 	scsi_devid_desc_free(m->icdp_port_id);
975 
976 	kmem_free(m, sizeof (*m));
977 }
978 
979 
980 /*
981  * Works for both reg_lun_msg and dereg_lun_msg, since the message
982  * payload is the same.
983  */
984 static void
985 stmf_ic_reg_dereg_lun_msg_free(stmf_ic_reg_dereg_lun_msg_t *m,
986     stmf_ic_msg_construction_method_t cmethod)
987 {
988 	if (cmethod == STMF_CONSTRUCTOR) {
989 		kmem_free(m->icrl_lu_provider_name,
990 		    strlen(m->icrl_lu_provider_name) + 1);
991 	}
992 
993 	kmem_free(m, sizeof (*m));
994 }
995 
996 static void
997 stmf_ic_scsi_cmd_msg_free(stmf_ic_scsi_cmd_msg_t *m,
998     stmf_ic_msg_construction_method_t cmethod)
999 {
1000 	scsi_devid_desc_free(m->icsc_ini_devid);
1001 	scsi_devid_desc_free(m->icsc_tgt_devid);
1002 	if (cmethod == STMF_CONSTRUCTOR) {
1003 		kmem_free(m->icsc_task_cdb, m->icsc_task_cdb_length);
1004 	}
1005 
1006 	kmem_free(m, sizeof (*m));
1007 
1008 }
1009 
1010 /*ARGSUSED*/
1011 static void
1012 stmf_ic_scsi_data_msg_free(stmf_ic_scsi_data_msg_t *m,
1013     stmf_ic_msg_construction_method_t cmethod)
1014 {
1015 	kmem_free(m, sizeof (*m));
1016 }
1017 
1018 /*ARGSUSED*/
1019 static void
1020 stmf_ic_scsi_data_xfer_done_msg_free(stmf_ic_scsi_data_xfer_done_msg_t *m,
1021     stmf_ic_msg_construction_method_t cmethod)
1022 {
1023 	kmem_free(m, sizeof (*m));
1024 }
1025 
1026 /*ARGSUSED*/
1027 static void
1028 stmf_ic_scsi_status_msg_free(stmf_ic_scsi_status_msg_t *m,
1029     stmf_ic_msg_construction_method_t cmethod)
1030 {
1031 	kmem_free(m, sizeof (*m));
1032 }
1033 
1034 /*ARGSUSED*/
1035 static void
1036 stmf_ic_r2t_msg_free(stmf_ic_r2t_msg_t *m,
1037     stmf_ic_msg_construction_method_t cmethod)
1038 {
1039 	kmem_free(m, sizeof (*m));
1040 }
1041 
1042 /*ARGSUSED*/
1043 static void
1044 stmf_ic_status_msg_free(stmf_ic_status_msg_t *m,
1045     stmf_ic_msg_construction_method_t cmethod)
1046 {
1047 	kmem_free(m, sizeof (*m));
1048 }
1049 
1050 /*
1051  * Works for both session_create and session_destroy msgs, since the message
1052  * payload is the same.
1053  */
1054 /*ARGSUSED*/
1055 static void
1056 stmf_ic_session_create_destroy_msg_free(stmf_ic_session_create_destroy_msg_t *m,
1057     stmf_ic_msg_construction_method_t cmethod)
1058 {
1059 	scsi_devid_desc_free(m->icscd_ini_devid);
1060 	scsi_devid_desc_free(m->icscd_tgt_devid);
1061 
1062 	kmem_free(m, sizeof (*m));
1063 }
1064 
1065 /*ARGSUSED*/
1066 static void
1067 stmf_ic_echo_request_reply_msg_free(stmf_ic_echo_request_reply_msg_t *m,
1068     stmf_ic_msg_construction_method_t cmethod)
1069 {
1070 	kmem_free(m, sizeof (*m));
1071 }
1072 
1073 
1074 /*
1075  * Marshaling routines.
1076  */
1077 
1078 static nvlist_t *
1079 stmf_ic_msg_marshal(stmf_ic_msg_t *msg)
1080 {
1081 	nvlist_t *nvl = NULL;
1082 	int rc = 0;
1083 
1084 	rc = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
1085 	if (rc)
1086 		goto done;
1087 
1088 	NVLIST_ADD_FIELD(uint8, msg, icm_msg_type);
1089 	NVLIST_ADD_FIELD(uint64, msg, icm_msgid);
1090 
1091 	switch (msg->icm_msg_type) {
1092 	case STMF_ICM_REGISTER_PROXY_PORT:
1093 		rc = stmf_ic_reg_port_msg_marshal(nvl, msg->icm_msg);
1094 		break;
1095 
1096 
1097 	case STMF_ICM_DEREGISTER_PROXY_PORT:
1098 		rc = stmf_ic_dereg_port_msg_marshal(nvl, msg->icm_msg);
1099 		break;
1100 
1101 	case STMF_ICM_LUN_ACTIVE:
1102 	case STMF_ICM_REGISTER_LUN:
1103 	case STMF_ICM_DEREGISTER_LUN:
1104 		rc = stmf_ic_reg_dereg_lun_msg_marshal(nvl, msg->icm_msg);
1105 		break;
1106 
1107 	case STMF_ICM_SCSI_CMD:
1108 		rc = stmf_ic_scsi_cmd_msg_marshal(nvl, msg->icm_msg);
1109 		break;
1110 
1111 	case STMF_ICM_SCSI_DATA:
1112 		rc = stmf_ic_scsi_data_msg_marshal(nvl, msg->icm_msg);
1113 		break;
1114 
1115 	case STMF_ICM_SCSI_DATA_XFER_DONE:
1116 		rc = stmf_ic_scsi_data_xfer_done_msg_marshal(nvl, msg->icm_msg);
1117 		break;
1118 
1119 	case STMF_ICM_SCSI_STATUS:
1120 		rc = stmf_ic_scsi_status_msg_marshal(nvl, msg->icm_msg);
1121 		break;
1122 
1123 	case STMF_ICM_R2T:
1124 		rc = stmf_ic_r2t_msg_marshal(nvl, msg->icm_msg);
1125 		break;
1126 
1127 	case STMF_ICM_STATUS:
1128 		rc = stmf_ic_status_msg_marshal(nvl, msg->icm_msg);
1129 		break;
1130 
1131 	case STMF_ICM_SESSION_CREATE:
1132 	case STMF_ICM_SESSION_DESTROY:
1133 		rc = stmf_ic_session_create_destroy_msg_marshal(nvl,
1134 		    msg->icm_msg);
1135 		break;
1136 
1137 	case STMF_ICM_ECHO_REQUEST:
1138 	case STMF_ICM_ECHO_REPLY:
1139 		rc = stmf_ic_echo_request_reply_msg_marshal(nvl,
1140 		    msg->icm_msg);
1141 		break;
1142 
1143 	case STMF_ICM_MAX_MSG_TYPE:
1144 		ASSERT(0);
1145 		break;
1146 
1147 	default:
1148 		ASSERT(0);
1149 	}
1150 
1151 done:
1152 	if (!rc)
1153 		return (nvl);
1154 
1155 	if (nvl)
1156 		nvlist_free(nvl);
1157 
1158 	return (NULL);
1159 }
1160 
1161 
1162 static int
1163 stmf_ic_reg_port_msg_marshal(nvlist_t *nvl, void *msg)
1164 {
1165 	stmf_ic_reg_port_msg_t *m = (stmf_ic_reg_port_msg_t *)msg;
1166 	int rc = 0;
1167 
1168 	NVLIST_ADD_DEVID(m, icrp_port_id);
1169 	NVLIST_ADD_FIELD(uint16, m, icrp_relative_port_id);
1170 
1171 	NVLIST_ADD_FIELD(uint16, m, icrp_cb_arg_len);
1172 	/* only add the callback arg if necessary */
1173 	if (m->icrp_cb_arg_len) {
1174 		NVLIST_ADD_ARRAY_LEN(uint8, m, icrp_cb_arg, m->icrp_cb_arg_len);
1175 	}
1176 
1177 done:
1178 	return (rc);
1179 }
1180 
1181 static int
1182 stmf_ic_dereg_port_msg_marshal(nvlist_t *nvl, void *msg)
1183 {
1184 	stmf_ic_dereg_port_msg_t *m = (stmf_ic_dereg_port_msg_t *)msg;
1185 	int rc = 0;
1186 
1187 	NVLIST_ADD_DEVID(m, icdp_port_id);
1188 	NVLIST_ADD_FIELD(uint16, m, icdp_cb_arg_len);
1189 
1190 	/* only add the callback arg if necessary */
1191 	if (m->icdp_cb_arg_len) {
1192 		NVLIST_ADD_ARRAY_LEN(uint8, m, icdp_cb_arg, m->icdp_cb_arg_len);
1193 	}
1194 
1195 done:
1196 	return (rc);
1197 }
1198 
1199 /*
1200  * Handles STMF_ICM_LUN_ACTIVE, STMF_ICM_REGISTER_LUN and
1201  * STMF_ICM_DEREGISTER_LUN;
1202  * msg payload is the same for all.
1203  */
1204 static int
1205 stmf_ic_reg_dereg_lun_msg_marshal(nvlist_t *nvl, void *msg)
1206 {
1207 	stmf_ic_reg_dereg_lun_msg_t *m = (stmf_ic_reg_dereg_lun_msg_t *)msg;
1208 	int rc = 0;
1209 
1210 	NVLIST_ADD_ARRAY(uint8, m, icrl_lun_id);
1211 	NVLIST_ADD_FIELD(string, m, icrl_lu_provider_name);
1212 	NVLIST_ADD_FIELD(uint16, m, icrl_cb_arg_len);
1213 
1214 	/* only add the callback arg if necessary */
1215 	if (m->icrl_cb_arg_len) {
1216 		NVLIST_ADD_ARRAY_LEN(uint8, m, icrl_cb_arg, m->icrl_cb_arg_len);
1217 	}
1218 
1219 done:
1220 	return (rc);
1221 }
1222 
1223 static int
1224 stmf_ic_scsi_cmd_msg_marshal(nvlist_t *nvl, void *msg)
1225 {
1226 	stmf_ic_scsi_cmd_msg_t *m = (stmf_ic_scsi_cmd_msg_t *)msg;
1227 	int rc = 0;
1228 
1229 	NVLIST_ADD_FIELD(uint64, m, icsc_task_msgid);
1230 	NVLIST_ADD_DEVID(m, icsc_ini_devid);
1231 	NVLIST_ADD_DEVID(m, icsc_tgt_devid);
1232 	NVLIST_ADD_ARRAY(uint8, m, icsc_lun_id);
1233 	NVLIST_ADD_FIELD(uint64, m, icsc_session_id);
1234 	NVLIST_ADD_ARRAY_LEN(uint8, m, icsc_task_lun_no, 8);
1235 	NVLIST_ADD_FIELD(uint32, m, icsc_task_expected_xfer_length);
1236 	NVLIST_ADD_FIELD(uint16, m, icsc_task_cdb_length);
1237 	NVLIST_ADD_ARRAY_LEN(uint8, m, icsc_task_cdb, m->icsc_task_cdb_length);
1238 	NVLIST_ADD_FIELD(uint8, m, icsc_task_flags);
1239 	NVLIST_ADD_FIELD(uint8, m, icsc_task_priority);
1240 	NVLIST_ADD_FIELD(uint8, m, icsc_task_mgmt_function);
1241 
1242 	NVLIST_ADD_FIELD(uint32, m, icsc_immed_data_len);
1243 	/* only add immediate data if necessary */
1244 	if (m->icsc_immed_data_len) {
1245 		NVLIST_ADD_ARRAY_LEN(uint8, m, icsc_immed_data,
1246 		    m->icsc_immed_data_len);
1247 	}
1248 
1249 done:
1250 	return (rc);
1251 }
1252 
1253 static int
1254 stmf_ic_scsi_data_msg_marshal(nvlist_t *nvl, void *msg)
1255 {
1256 	stmf_ic_scsi_data_msg_t *m = (stmf_ic_scsi_data_msg_t *)msg;
1257 	int rc = 0;
1258 
1259 	NVLIST_ADD_FIELD(uint64, m, icsd_task_msgid);
1260 	NVLIST_ADD_FIELD(uint64, m, icsd_session_id);
1261 	NVLIST_ADD_ARRAY(uint8, m, icsd_lun_id);
1262 	NVLIST_ADD_FIELD(uint64, m, icsd_data_len);
1263 	NVLIST_ADD_ARRAY_LEN(uint8, m, icsd_data, m->icsd_data_len);
1264 
1265 done:
1266 	return (rc);
1267 }
1268 
1269 static int
1270 stmf_ic_scsi_data_xfer_done_msg_marshal(nvlist_t *nvl, void *msg)
1271 {
1272 	stmf_ic_scsi_data_xfer_done_msg_t *m =
1273 	    (stmf_ic_scsi_data_xfer_done_msg_t *)msg;
1274 	int rc = 0;
1275 
1276 	NVLIST_ADD_FIELD(uint64, m, icsx_task_msgid);
1277 	NVLIST_ADD_FIELD(uint64, m, icsx_session_id);
1278 	NVLIST_ADD_FIELD(uint64, m, icsx_status);
1279 
1280 done:
1281 	return (rc);
1282 }
1283 
1284 static int
1285 stmf_ic_scsi_status_msg_marshal(nvlist_t *nvl, void *msg)
1286 {
1287 	stmf_ic_scsi_status_msg_t *m = (stmf_ic_scsi_status_msg_t *)msg;
1288 	int rc = 0;
1289 
1290 	NVLIST_ADD_FIELD(uint64, m, icss_task_msgid);
1291 	NVLIST_ADD_FIELD(uint64, m, icss_session_id);
1292 	NVLIST_ADD_ARRAY(uint8, m, icss_lun_id);
1293 	NVLIST_ADD_FIELD(uint8, m, icss_response);
1294 	NVLIST_ADD_FIELD(uint8, m, icss_status);
1295 	NVLIST_ADD_FIELD(uint8, m, icss_flags);
1296 	NVLIST_ADD_FIELD(uint32, m, icss_resid);
1297 
1298 	NVLIST_ADD_FIELD(uint8, m, icss_sense_len);
1299 
1300 	if (m->icss_sense_len)
1301 		NVLIST_ADD_ARRAY_LEN(uint8, m, icss_sense, m->icss_sense_len);
1302 
1303 done:
1304 	return (rc);
1305 }
1306 
1307 static int
1308 stmf_ic_r2t_msg_marshal(nvlist_t *nvl, void *msg)
1309 {
1310 	stmf_ic_r2t_msg_t *m = (stmf_ic_r2t_msg_t *)msg;
1311 	int rc = 0;
1312 
1313 	NVLIST_ADD_FIELD(uint64, m, icrt_task_msgid);
1314 	NVLIST_ADD_FIELD(uint64, m, icrt_session_id);
1315 	NVLIST_ADD_FIELD(uint32, m, icrt_offset);
1316 	NVLIST_ADD_FIELD(uint32, m, icrt_length);
1317 
1318 done:
1319 	return (rc);
1320 }
1321 
1322 static int
1323 stmf_ic_status_msg_marshal(nvlist_t *nvl, void *msg)
1324 {
1325 	stmf_ic_status_msg_t *m = (stmf_ic_status_msg_t *)msg;
1326 	int rc = 0;
1327 
1328 	NVLIST_ADD_FIELD(uint8, m, ics_msg_type);
1329 	NVLIST_ADD_FIELD(uint64, m, ics_msgid);
1330 	NVLIST_ADD_FIELD(uint8, m, ics_status);
1331 
1332 done:
1333 	return (rc);
1334 }
1335 
1336 static int
1337 stmf_ic_session_create_destroy_msg_marshal(nvlist_t *nvl, void *msg)
1338 {
1339 	stmf_ic_session_create_destroy_msg_t *m =
1340 	    (stmf_ic_session_create_destroy_msg_t *)msg;
1341 	int rc = 0;
1342 
1343 	NVLIST_ADD_DEVID(m, icscd_ini_devid);
1344 	NVLIST_ADD_DEVID(m, icscd_tgt_devid);
1345 	NVLIST_ADD_FIELD(uint64, m, icscd_session_id);
1346 
1347 done:
1348 	return (rc);
1349 }
1350 
1351 static int
1352 stmf_ic_echo_request_reply_msg_marshal(nvlist_t *nvl, void *msg)
1353 {
1354 	stmf_ic_echo_request_reply_msg_t *m = msg;
1355 	int rc = 0;
1356 
1357 	NVLIST_ADD_FIELD(uint32, m, icerr_datalen);
1358 	if (m->icerr_datalen)
1359 		NVLIST_ADD_ARRAY_LEN(uint8, m, icerr_data, m->icerr_datalen);
1360 
1361 done:
1362 	return (rc);
1363 }
1364 
1365 /*
1366  * Allocate a new nvlist representing the scsi_devid_desc and add it
1367  * to the nvlist.
1368  */
1369 static int
1370 stmf_ic_scsi_devid_desc_marshal(nvlist_t *parent_nvl,
1371 	char *sdid_name,
1372 	scsi_devid_desc_t *sdid)
1373 {
1374 	int rc = 0;
1375 	nvlist_t *nvl = NULL;
1376 
1377 	rc = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
1378 	if (rc)
1379 		goto done;
1380 
1381 	NVLIST_ADD_FIELD(uint8, sdid, protocol_id);
1382 	NVLIST_ADD_FIELD(uint8, sdid, code_set);
1383 	NVLIST_ADD_FIELD(uint8, sdid, piv);
1384 	NVLIST_ADD_FIELD(uint8, sdid, association);
1385 	NVLIST_ADD_FIELD(uint8, sdid, ident_type);
1386 	NVLIST_ADD_FIELD(uint8, sdid, ident_length);
1387 
1388 	rc = nvlist_add_uint8_array(nvl, "ident", sdid->ident,
1389 	    sdid->ident_length);
1390 	if (rc)
1391 		goto done;
1392 
1393 	rc = nvlist_add_nvlist(parent_nvl, sdid_name, nvl);
1394 
1395 done:
1396 	if (nvl) {
1397 		nvlist_free(nvl);
1398 	}
1399 	return (rc);
1400 }
1401 
1402 /*
1403  * Unmarshaling routines.
1404  */
1405 
1406 static stmf_ic_msg_t *
1407 stmf_ic_msg_unmarshal(nvlist_t *nvl)
1408 {
1409 	stmf_ic_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1410 	uint8_t msg_type;
1411 	int rc = 0;
1412 
1413 	/*
1414 	 * We'd like to do this:
1415 	 *
1416 	 *   NVLIST_LOOKUP_FIELD(uint8, m, icm_msg_type);
1417 	 *
1418 	 * but the fact that msg type is an enum causes type problems.
1419 	 */
1420 	rc = nvlist_lookup_uint8(nvl, "icm_msg_type", &msg_type);
1421 	if (rc) {
1422 		stmf_ic_nvlookup_warn(__func__, "icm_msg_type");
1423 		goto done;
1424 	}
1425 
1426 	m->icm_msg_type = msg_type;
1427 	m->icm_nvlist = nvl;
1428 
1429 	NVLIST_LOOKUP_FIELD(uint64, m, icm_msgid);
1430 
1431 	switch (m->icm_msg_type) {
1432 
1433 	case STMF_ICM_REGISTER_PROXY_PORT:
1434 		m->icm_msg = stmf_ic_reg_port_msg_unmarshal(nvl);
1435 		break;
1436 
1437 
1438 	case STMF_ICM_DEREGISTER_PROXY_PORT:
1439 		m->icm_msg = stmf_ic_dereg_port_msg_unmarshal(nvl);
1440 		break;
1441 
1442 	case STMF_ICM_LUN_ACTIVE:
1443 	case STMF_ICM_REGISTER_LUN:
1444 	case STMF_ICM_DEREGISTER_LUN:
1445 		m->icm_msg = stmf_ic_reg_dereg_lun_msg_unmarshal(nvl);
1446 		break;
1447 
1448 	case STMF_ICM_SCSI_CMD:
1449 		m->icm_msg = stmf_ic_scsi_cmd_msg_unmarshal(nvl);
1450 		break;
1451 
1452 	case STMF_ICM_SCSI_DATA:
1453 		m->icm_msg = stmf_ic_scsi_data_msg_unmarshal(nvl);
1454 		break;
1455 
1456 	case STMF_ICM_SCSI_DATA_XFER_DONE:
1457 		m->icm_msg = stmf_ic_scsi_data_xfer_done_msg_unmarshal(nvl);
1458 		break;
1459 
1460 	case STMF_ICM_SCSI_STATUS:
1461 		m->icm_msg = stmf_ic_scsi_status_msg_unmarshal(nvl);
1462 		break;
1463 
1464 	case STMF_ICM_R2T:
1465 		m->icm_msg = stmf_ic_r2t_msg_unmarshal(nvl);
1466 		break;
1467 
1468 	case STMF_ICM_STATUS:
1469 		m->icm_msg = stmf_ic_status_msg_unmarshal(nvl);
1470 		break;
1471 
1472 	case STMF_ICM_SESSION_CREATE:
1473 	case STMF_ICM_SESSION_DESTROY:
1474 		m->icm_msg = stmf_ic_session_create_destroy_msg_unmarshal(nvl);
1475 		break;
1476 
1477 	case STMF_ICM_ECHO_REQUEST:
1478 	case STMF_ICM_ECHO_REPLY:
1479 		m->icm_msg = stmf_ic_echo_request_reply_msg_unmarshal(nvl);
1480 		break;
1481 
1482 	case STMF_ICM_MAX_MSG_TYPE:
1483 		ASSERT(0);
1484 		break;
1485 
1486 	default:
1487 		ASSERT(0);
1488 	}
1489 
1490 done:
1491 
1492 	if (!m->icm_msg) {
1493 		kmem_free(m, sizeof (*m));
1494 		return (NULL);
1495 	}
1496 
1497 	return (m);
1498 }
1499 
1500 static void *
1501 stmf_ic_reg_port_msg_unmarshal(nvlist_t *nvl)
1502 {
1503 	nvlist_t *nvl_port_id = NULL;
1504 	int rc = 0;
1505 	stmf_ic_reg_port_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1506 
1507 	rc = nvlist_lookup_nvlist(nvl, "icrp_port_id", &nvl_port_id);
1508 	if (rc) {
1509 		stmf_ic_nvlookup_warn(__func__, "icrp_port_id nvl");
1510 		rc = ENOMEM; /* XXX */
1511 		goto done;
1512 	}
1513 
1514 	m->icrp_port_id = stmf_ic_scsi_devid_desc_unmarshal(nvl_port_id);
1515 	if (m->icrp_port_id == NULL) {
1516 		stmf_ic_nvlookup_warn(__func__, "icrp_port_id");
1517 		rc = ENOMEM; /* XXX */
1518 		goto done;
1519 	}
1520 
1521 	NVLIST_LOOKUP_FIELD(uint16, m, icrp_relative_port_id);
1522 	NVLIST_LOOKUP_FIELD(uint16, m, icrp_cb_arg_len);
1523 
1524 	if (m->icrp_cb_arg_len) {
1525 		m->icrp_cb_arg = stmf_ic_uint8_array_unmarshal(nvl,
1526 		    "icrp_cb_arg", m->icrp_cb_arg_len, NULL);
1527 		if (m->icrp_cb_arg == NULL) {
1528 			stmf_ic_nvlookup_warn(__func__, "icrp_cb_arg");
1529 			rc = ENOMEM; /* XXX */
1530 			goto done;
1531 		}
1532 	}
1533 
1534 done:
1535 	if (!rc)
1536 		return (m);
1537 
1538 	stmf_ic_reg_port_msg_free(m, STMF_UNMARSHAL);
1539 
1540 	return (NULL);
1541 }
1542 
1543 /*
1544  * XXX largely the same as stmf_ic_reg_port_msg_unmarshal()
1545  * Common stuff should be factored out.  Type issues may make this
1546  * painful.
1547  */
1548 static void *
1549 stmf_ic_dereg_port_msg_unmarshal(nvlist_t *nvl)
1550 {
1551 	nvlist_t *nvl_port_id = NULL;
1552 	int rc = 0;
1553 	stmf_ic_dereg_port_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1554 
1555 	rc = nvlist_lookup_nvlist(nvl, "icdp_port_id", &nvl_port_id);
1556 	if (rc) {
1557 		stmf_ic_nvlookup_warn(__func__, "icdp_port_id nvl");
1558 		goto done;
1559 	}
1560 
1561 	m->icdp_port_id = stmf_ic_scsi_devid_desc_unmarshal(nvl_port_id);
1562 	if (m->icdp_port_id == NULL) {
1563 		stmf_ic_nvlookup_warn(__func__, "icdp_port_id");
1564 		rc = ENOMEM; /* XXX */
1565 		goto done;
1566 	}
1567 
1568 	NVLIST_LOOKUP_FIELD(uint16, m, icdp_cb_arg_len);
1569 
1570 	if (m->icdp_cb_arg_len) {
1571 		m->icdp_cb_arg = stmf_ic_uint8_array_unmarshal(nvl,
1572 		    "icdp_cb_arg", m->icdp_cb_arg_len, NULL);
1573 		if (m->icdp_cb_arg == NULL) {
1574 			stmf_ic_nvlookup_warn(__func__, "icdp_cb_arg");
1575 			rc = ENOMEM; /* XXX */
1576 			goto done;
1577 		}
1578 	}
1579 
1580 done:
1581 	if (!rc)
1582 		return (m);
1583 
1584 	stmf_ic_dereg_port_msg_free(m, STMF_UNMARSHAL);
1585 
1586 	return (NULL);
1587 }
1588 
1589 static void *
1590 stmf_ic_reg_dereg_lun_msg_unmarshal(nvlist_t *nvl)
1591 {
1592 	int rc = 0;
1593 	stmf_ic_reg_dereg_lun_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1594 
1595 	if (! stmf_ic_uint8_array_unmarshal(nvl, "icrl_lun_id",
1596 	    sizeof (m->icrl_lun_id), m->icrl_lun_id)) {
1597 		stmf_ic_nvlookup_warn(__func__, "icrl_lun_id");
1598 		rc = ENOMEM; /* XXX */
1599 		goto done;
1600 	}
1601 
1602 	m->icrl_lu_provider_name = stmf_ic_string_unmarshal(nvl,
1603 	    "icrl_lu_provider_name");
1604 
1605 	if (!m->icrl_lu_provider_name) {
1606 		stmf_ic_nvlookup_warn(__func__, "icrl_lu_provider_name");
1607 		rc = ENOMEM; /* XXX */
1608 		goto done;
1609 	}
1610 
1611 	NVLIST_LOOKUP_FIELD(uint16, m, icrl_cb_arg_len);
1612 
1613 	if (m->icrl_cb_arg_len) {
1614 		m->icrl_cb_arg = stmf_ic_uint8_array_unmarshal(nvl,
1615 		    "icrl_cb_arg", m->icrl_cb_arg_len, NULL);
1616 		if (m->icrl_cb_arg == NULL) {
1617 			stmf_ic_nvlookup_warn(__func__, "icrl_cb_arg");
1618 			rc = ENOMEM; /* XXX */
1619 			goto done;
1620 		}
1621 	}
1622 
1623 done:
1624 	if (!rc)
1625 		return (m);
1626 
1627 	stmf_ic_reg_dereg_lun_msg_free(m, STMF_UNMARSHAL);
1628 
1629 	return (NULL);
1630 }
1631 
1632 static void *
1633 stmf_ic_scsi_cmd_msg_unmarshal(nvlist_t *nvl)
1634 {
1635 	int rc = 0;
1636 	stmf_ic_scsi_cmd_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1637 
1638 	if (nvlist_lookup_pairs(nvl, 0,
1639 	    NV_PAIR(UINT64, m, icsc_task_msgid),
1640 	    NV_PAIR(UINT64, m, icsc_session_id),
1641 	    NV_PAIR(UINT32, m, icsc_task_expected_xfer_length),
1642 	    NV_PAIR(UINT16, m, icsc_task_cdb_length),
1643 	    NV_PAIR(UINT8, m, icsc_task_flags),
1644 	    NV_PAIR(UINT8, m, icsc_task_mgmt_function),
1645 	    NV_PAIR(UINT32, m, icsc_immed_data_len),
1646 	    NULL) != 0) {
1647 		stmf_ic_nvlookup_warn(__func__, "icsc_task_msgid and friends");
1648 		rc = ENOMEM; /* XXX need something better */
1649 		goto done;
1650 	}
1651 
1652 	m->icsc_ini_devid = stmf_ic_lookup_scsi_devid_desc_and_unmarshal(
1653 	    nvl, "icsc_ini_devid");
1654 	if (m->icsc_ini_devid == NULL) {
1655 		stmf_ic_nvlookup_warn(__func__, "icsc_ini_devid");
1656 		rc = ENOMEM;
1657 		goto done;
1658 	}
1659 
1660 	m->icsc_tgt_devid = stmf_ic_lookup_scsi_devid_desc_and_unmarshal(
1661 	    nvl, "icsc_tgt_devid");
1662 	if (m->icsc_tgt_devid == NULL) {
1663 		stmf_ic_nvlookup_warn(__func__, "icsc_tgt_devid");
1664 		rc = ENOMEM;
1665 		goto done;
1666 	}
1667 
1668 	/* icsc_lun_id */
1669 	if (!stmf_ic_uint8_array_unmarshal(nvl, "icsc_lun_id",
1670 	    sizeof (m->icsc_lun_id), m->icsc_lun_id)) {
1671 		stmf_ic_nvlookup_warn(__func__, "icsc_lun_id");
1672 		rc = ENOMEM;
1673 		goto done;
1674 	}
1675 
1676 	/* icsc_task_lun_no */
1677 	if (!stmf_ic_uint8_array_unmarshal(nvl, "icsc_task_lun_no",
1678 	    sizeof (m->icsc_task_lun_no), m->icsc_task_lun_no)) {
1679 		stmf_ic_nvlookup_warn(__func__, "icsc_task_lun_no");
1680 		rc = ENOMEM;
1681 		goto done;
1682 	}
1683 
1684 	/* icsc_task_cdb */
1685 	m->icsc_task_cdb = stmf_ic_uint8_array_unmarshal(nvl, "icsc_task_cdb",
1686 	    m->icsc_task_cdb_length, NULL);
1687 	if (!m->icsc_task_cdb) {
1688 		stmf_ic_nvlookup_warn(__func__, "icsc_task_cdb");
1689 		rc = ENOMEM;
1690 		goto done;
1691 	}
1692 
1693 	/* immediate data, if there is any */
1694 	if (m->icsc_immed_data_len) {
1695 		m->icsc_immed_data = stmf_ic_uint8_array_unmarshal(nvl,
1696 		    "icsc_immed_data", m->icsc_immed_data_len, NULL);
1697 		if (!m->icsc_immed_data) {
1698 			stmf_ic_nvlookup_warn(__func__, "icsc_immed_data");
1699 			rc = ENOMEM;
1700 			goto done;
1701 		}
1702 	}
1703 
1704 done:
1705 	if (!rc)
1706 		return (m);
1707 
1708 	stmf_ic_scsi_cmd_msg_free(m, STMF_UNMARSHAL);
1709 
1710 	return (NULL);
1711 }
1712 
1713 static void *
1714 stmf_ic_scsi_data_msg_unmarshal(nvlist_t *nvl)
1715 {
1716 	int rc = 0;
1717 	stmf_ic_scsi_data_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1718 
1719 	if (nvlist_lookup_pairs(nvl, 0,
1720 	    NV_PAIR(UINT64, m, icsd_task_msgid),
1721 	    NV_PAIR(UINT64, m, icsd_session_id),
1722 	    NV_PAIR(UINT64, m, icsd_data_len),
1723 	    NULL) != 0) {
1724 		stmf_ic_nvlookup_warn(__func__, "icsd_task_msgid and friends");
1725 		rc = ENOMEM; /* XXX need something better */
1726 		goto done;
1727 	}
1728 
1729 	if (!stmf_ic_uint8_array_unmarshal(nvl, "icsd_lun_id",
1730 	    sizeof (m->icsd_lun_id), m->icsd_lun_id)) {
1731 		stmf_ic_nvlookup_warn(__func__, "icsd_lun_id");
1732 		rc = ENOMEM;
1733 		goto done;
1734 	}
1735 
1736 	m->icsd_data = stmf_ic_uint8_array_unmarshal(nvl, "icsd_data",
1737 	    m->icsd_data_len, NULL);
1738 	if (!m->icsd_data) {
1739 		stmf_ic_nvlookup_warn(__func__, "icsd_data");
1740 		rc = ENOMEM;
1741 		goto done;
1742 	}
1743 
1744 done:
1745 	if (!rc)
1746 		return (m);
1747 
1748 	stmf_ic_scsi_data_msg_free(m, STMF_UNMARSHAL);
1749 
1750 	return (NULL);
1751 }
1752 
1753 static void *
1754 stmf_ic_scsi_data_xfer_done_msg_unmarshal(nvlist_t *nvl)
1755 {
1756 	int rc = 0;
1757 	stmf_ic_scsi_data_xfer_done_msg_t *m =
1758 	    kmem_zalloc(sizeof (*m), KM_SLEEP);
1759 
1760 	if (nvlist_lookup_pairs(nvl, 0,
1761 	    NV_PAIR(UINT64, m, icsx_task_msgid),
1762 	    NV_PAIR(UINT64, m, icsx_session_id),
1763 	    NV_PAIR(UINT64, m, icsx_status),
1764 	    NULL) != 0) {
1765 		stmf_ic_nvlookup_warn(__func__, "icsx_task_msgid and friends");
1766 		rc = ENOMEM; /* XXX need something better */
1767 		goto done;
1768 	}
1769 
1770 done:
1771 	if (!rc)
1772 		return (m);
1773 
1774 	stmf_ic_scsi_data_xfer_done_msg_free(m, STMF_UNMARSHAL);
1775 
1776 	return (NULL);
1777 }
1778 
1779 static void *
1780 stmf_ic_scsi_status_msg_unmarshal(nvlist_t *nvl)
1781 {
1782 	int rc = 0;
1783 	stmf_ic_scsi_status_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1784 
1785 	if (nvlist_lookup_pairs(nvl, 0,
1786 	    NV_PAIR(UINT64, m, icss_task_msgid),
1787 	    NV_PAIR(UINT64, m, icss_session_id),
1788 	    NV_PAIR(UINT8, m, icss_response),
1789 	    NV_PAIR(UINT8, m, icss_status),
1790 	    NV_PAIR(UINT8, m, icss_flags),
1791 	    NV_PAIR(UINT32, m, icss_resid),
1792 	    NV_PAIR(UINT8, m, icss_sense_len),
1793 	    NULL) != 0) {
1794 		stmf_ic_nvlookup_warn(__func__, "icss_task_msgid and friends");
1795 		rc = ENOMEM; /* XXX need something better */
1796 		goto done;
1797 	}
1798 
1799 	if (!stmf_ic_uint8_array_unmarshal(nvl, "icss_lun_id",
1800 	    sizeof (m->icss_lun_id), m->icss_lun_id)) {
1801 		stmf_ic_nvlookup_warn(__func__, "icss_lun_id");
1802 		rc = ENOMEM;
1803 		goto done;
1804 	}
1805 
1806 	if (m->icss_sense_len) {
1807 		m->icss_sense = stmf_ic_uint8_array_unmarshal(nvl, "icss_sense",
1808 		    m->icss_sense_len, NULL);
1809 		if (!m->icss_sense) {
1810 			stmf_ic_nvlookup_warn(__func__, "icss_sense");
1811 			rc = ENOMEM;
1812 			goto done;
1813 		}
1814 	}
1815 done:
1816 	if (!rc)
1817 		return (m);
1818 
1819 	stmf_ic_scsi_status_msg_free(m, STMF_UNMARSHAL);
1820 
1821 	return (NULL);
1822 }
1823 
1824 static void *
1825 stmf_ic_r2t_msg_unmarshal(nvlist_t *nvl)
1826 {
1827 	int rc = 0;
1828 	stmf_ic_r2t_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1829 
1830 	if (nvlist_lookup_pairs(nvl, 0,
1831 	    NV_PAIR(UINT64, m, icrt_task_msgid),
1832 	    NV_PAIR(UINT64, m, icrt_session_id),
1833 	    NV_PAIR(UINT32, m, icrt_offset),
1834 	    NV_PAIR(UINT32, m, icrt_length),
1835 	    NULL) != 0) {
1836 		stmf_ic_nvlookup_warn(__func__, "icrt_task_msgid and friends");
1837 		rc = ENOMEM; /* XXX need something better */
1838 		goto done;
1839 	}
1840 
1841 done:
1842 	if (!rc)
1843 		return (m);
1844 
1845 	stmf_ic_r2t_msg_free(m, STMF_UNMARSHAL);
1846 
1847 	return (NULL);
1848 }
1849 
1850 static void *
1851 stmf_ic_session_create_destroy_msg_unmarshal(nvlist_t *nvl)
1852 {
1853 	int rc = 0;
1854 	stmf_ic_session_create_destroy_msg_t *m = kmem_zalloc(sizeof (*m),
1855 	    KM_SLEEP);
1856 
1857 	if (nvlist_lookup_pairs(nvl, 0,
1858 	    NV_PAIR(UINT64, m, icscd_session_id),
1859 	    NULL) != 0) {
1860 		stmf_ic_nvlookup_warn(__func__, "icsd_session_id");
1861 		rc = ENOMEM; /* XXX need something better */
1862 		goto done;
1863 	}
1864 
1865 	m->icscd_ini_devid = stmf_ic_lookup_scsi_devid_desc_and_unmarshal(
1866 	    nvl, "icscd_ini_devid");
1867 	if (m->icscd_ini_devid == NULL) {
1868 		stmf_ic_nvlookup_warn(__func__, "icsd_ini_devid");
1869 		rc = ENOMEM;
1870 		goto done;
1871 	}
1872 
1873 	m->icscd_tgt_devid = stmf_ic_lookup_scsi_devid_desc_and_unmarshal(
1874 	    nvl, "icscd_tgt_devid");
1875 	if (m->icscd_tgt_devid == NULL) {
1876 		stmf_ic_nvlookup_warn(__func__, "icsd_tgt_devid");
1877 		rc = ENOMEM;
1878 		goto done;
1879 	}
1880 
1881 done:
1882 	if (!rc)
1883 		return (m);
1884 
1885 	stmf_ic_session_create_destroy_msg_free(m, STMF_UNMARSHAL);
1886 
1887 	return (NULL);
1888 }
1889 
1890 static void *
1891 stmf_ic_echo_request_reply_msg_unmarshal(nvlist_t *nvl)
1892 {
1893 	int rc = 0;
1894 	stmf_ic_echo_request_reply_msg_t *m = kmem_zalloc(sizeof (*m),
1895 	    KM_SLEEP);
1896 
1897 	if (nvlist_lookup_pairs(nvl, 0,
1898 	    NV_PAIR(UINT32, m, icerr_datalen),
1899 	    NULL) != 0) {
1900 		stmf_ic_nvlookup_warn(__func__, "icerr_datalen");
1901 		rc = ENOMEM; /* XXX need something better */
1902 		goto done;
1903 	}
1904 
1905 	/* immediate data, if there is any */
1906 	if (m->icerr_datalen) {
1907 		m->icerr_data = stmf_ic_uint8_array_unmarshal(nvl,
1908 		    "icerr_data", m->icerr_datalen, NULL);
1909 		if (!m->icerr_data) {
1910 			stmf_ic_nvlookup_warn(__func__, "icerr_data");
1911 			rc = ENOMEM;
1912 			goto done;
1913 		}
1914 	}
1915 
1916 done:
1917 	if (!rc)
1918 		return (m);
1919 
1920 	stmf_ic_echo_request_reply_msg_free(m, STMF_UNMARSHAL);
1921 
1922 	return (NULL);
1923 }
1924 
1925 static void *
1926 stmf_ic_status_msg_unmarshal(nvlist_t *nvl)
1927 {
1928 	int rc = 0;
1929 	stmf_ic_status_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP);
1930 
1931 	if (nvlist_lookup_pairs(nvl, 0,
1932 	    NV_PAIR(UINT8, m, ics_msg_type),
1933 	    NV_PAIR(UINT64, m, ics_msgid),
1934 	    NV_PAIR(UINT8, m, ics_status),
1935 	    NULL) != 0) {
1936 		stmf_ic_nvlookup_warn(__func__, "ics_msg_type and friends");
1937 		rc = ENOMEM; /* XXX need something better */
1938 		goto done;
1939 	}
1940 
1941 done:
1942 	if (!rc)
1943 		return (m);
1944 
1945 	kmem_free(m, sizeof (*m));
1946 	return (NULL);
1947 }
1948 
1949 
1950 static scsi_devid_desc_t *
1951 stmf_ic_lookup_scsi_devid_desc_and_unmarshal(nvlist_t *nvl, char *field_name)
1952 {
1953 	nvlist_t *nvl_devid = NULL;
1954 	scsi_devid_desc_t *did = NULL;
1955 	int rc;
1956 
1957 	rc = nvlist_lookup_nvlist(nvl, field_name, &nvl_devid);
1958 	if (rc) {
1959 		goto done;
1960 	}
1961 
1962 	did = stmf_ic_scsi_devid_desc_unmarshal(nvl_devid);
1963 
1964 done:
1965 	return (did);
1966 }
1967 
1968 
1969 static scsi_devid_desc_t *
1970 stmf_ic_scsi_devid_desc_unmarshal(nvlist_t *nvl)
1971 {
1972 	scsi_devid_desc_t *sdid = NULL;
1973 	uint8_t ident_length = 0;
1974 	size_t sdid_size;
1975 	int rc = 0;
1976 
1977 	/*
1978 	 * we get the ident_length first, since that's the only
1979 	 * variable-sized field in the struct.
1980 	 */
1981 	rc = nvlist_lookup_uint8(nvl, "ident_length", &ident_length);
1982 	if (rc)
1983 		goto done;
1984 
1985 	sdid_size = sizeof_scsi_devid_desc(ident_length);
1986 	sdid = kmem_zalloc(sdid_size, KM_SLEEP);
1987 
1988 	NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, protocol_id);
1989 	NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, code_set);
1990 	NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, piv);
1991 	NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, association);
1992 	NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, ident_type);
1993 
1994 	sdid->ident_length = ident_length;
1995 
1996 	if (!stmf_ic_uint8_array_unmarshal(nvl, "ident",
1997 	    sdid->ident_length, sdid->ident)) {
1998 		rc = ENOMEM; /* XXX */
1999 		goto done;
2000 	}
2001 
2002 done:
2003 	if (!rc)
2004 		return (sdid);
2005 
2006 	kmem_free(sdid, sdid_size);
2007 
2008 	return (NULL);
2009 }
2010 
2011 /*
2012  * Unmarshal a uint8_t array.
2013  *
2014  * Takes a buf argument:
2015  *
2016  * - if non-null, the array contents are copied into the buf,
2017  *   and we return a pointer to the buffer.
2018  *
2019  * - if null, we return a pointer to the unmarshaled data, which
2020  *   resides in the nvlist.
2021  *
2022  * Returns NULL on failure.
2023  */
2024 static uint8_t *
2025 stmf_ic_uint8_array_unmarshal(
2026     nvlist_t *nvl,
2027     char *field_name,
2028     uint16_t len,
2029     uint8_t *buf)	/* non-NULL: copy array into buf */
2030 {
2031 	uint8_t *array = NULL;
2032 	uint_t actual_len;
2033 	int rc = 0;
2034 
2035 	rc = nvlist_lookup_uint8_array(nvl, field_name, &array, &actual_len);
2036 	if (rc) {
2037 		return (NULL);
2038 	}
2039 
2040 	if (len != actual_len) {
2041 		cmn_err(CE_WARN,
2042 		    "stmf_ic_uint8_array_unmarshal: wrong len (%d != %d)",
2043 		    len, actual_len);
2044 		return (NULL);
2045 	}
2046 
2047 	if (buf) {
2048 		/* preallocated buf, copy in */
2049 		bcopy(array, buf, len);
2050 	} else {
2051 		/* return a pointer to the underlying array in the nvlist */
2052 		buf = array;
2053 	}
2054 
2055 	return (buf);
2056 }
2057 
2058 /*
2059  * Unmarshal a string.
2060  *
2061  * Returns NULL on failure.
2062  */
2063 static char *
2064 stmf_ic_string_unmarshal(
2065     nvlist_t *nvl,
2066     char *field_name)
2067 {
2068 	char *s = NULL;
2069 	int rc = 0;
2070 
2071 	rc = nvlist_lookup_string(nvl, field_name, &s);
2072 	if (rc) {
2073 		return (NULL);
2074 	}
2075 
2076 	return (s);
2077 }
2078 
2079 /*
2080  * Utility routines.
2081  */
2082 
2083 static stmf_ic_msg_t *
2084 stmf_ic_alloc_msg_header(
2085     stmf_ic_msg_type_t msg_type,
2086     stmf_ic_msgid_t msgid)
2087 {
2088 	stmf_ic_msg_t *icm;
2089 
2090 	icm = (stmf_ic_msg_t *)kmem_zalloc(sizeof (*icm), KM_SLEEP);
2091 	icm->icm_msg_type = msg_type;
2092 	icm->icm_msgid = msgid;
2093 
2094 	return (icm);
2095 }
2096 
2097 static size_t
2098 sizeof_scsi_devid_desc(int ident_length)
2099 {
2100 	int num_ident_elems;
2101 	size_t size;
2102 
2103 	ASSERT(ident_length > 0);
2104 
2105 	/*
2106 	 * Need to account for the fact that there's
2107 	 * already a single element in scsi_devid_desc_t.
2108 	 *
2109 	 * XXX would really like to have a way to determine the
2110 	 * sizeof (struct scsi_devid_desc.ident[0]), but
2111 	 * it's not clear that can be done.
2112 	 * Thus, this code relies on the knowledge of the type of
2113 	 * that field.
2114 	 */
2115 	num_ident_elems = ident_length - 1;
2116 	size = sizeof (scsi_devid_desc_t) +
2117 	    (num_ident_elems * sizeof (uint8_t));
2118 
2119 	return (size);
2120 }
2121 
2122 
2123 /*
2124  * Duplicate the scsi_devid_desc_t.
2125  */
2126 static scsi_devid_desc_t *
2127 scsi_devid_desc_dup(scsi_devid_desc_t *did)
2128 {
2129 	scsi_devid_desc_t *dup;
2130 	size_t dup_size;
2131 
2132 	ASSERT(did->ident_length > 0);
2133 
2134 	dup_size = sizeof_scsi_devid_desc(did->ident_length);
2135 	dup = (scsi_devid_desc_t *)kmem_zalloc(dup_size, KM_SLEEP);
2136 	bcopy(did, dup, dup_size);
2137 	return (dup);
2138 }
2139 
2140 /*
2141  * May be called with a null pointer.
2142  */
2143 static void
2144 scsi_devid_desc_free(scsi_devid_desc_t *did)
2145 {
2146 	if (!did)
2147 		return;
2148 
2149 	kmem_free(did, sizeof_scsi_devid_desc(did->ident_length));
2150 }
2151 
2152 /*
2153  * Helper functions, returns NULL if no memory.
2154  */
2155 static char *
2156 stmf_ic_strdup(char *str)
2157 {
2158 	char *copy;
2159 
2160 	ASSERT(str);
2161 
2162 	copy = kmem_zalloc(strlen(str) + 1, KM_SLEEP);
2163 	(void) strcpy(copy, str);
2164 	return (copy);
2165 }
2166 
2167 static inline void
2168 stmf_ic_nvlookup_warn(const char *func, char *field)
2169 {
2170 	cmn_err(CE_WARN, "%s: nvlist lookup of %s failed", func, field);
2171 }
2172