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