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