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