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