xref: /titanic_51/usr/src/uts/common/io/scsi/adapters/iscsi/isns_client.c (revision 2a910fbb92dbaed71db5d7843518f08d02ebb922)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * iSNS Client
26  */
27 
28 #include "iscsi.h"		/* For ISCSI_MAX_IOVEC */
29 #include "isns_protocol.h"
30 #include "isns_client.h"
31 #include "persistent.h"
32 
33 #ifdef _KERNEL
34 #include <sys/sunddi.h>
35 #else
36 #include <stdlib.h>
37 #endif
38 #include <netinet/tcp.h>
39 #include <sys/types.h>
40 
41 /* For local use */
42 #define	ISNS_MAX_IOVEC		5
43 #define	MAX_XID			(2^16)
44 #define	MAX_RCV_RSP_COUNT	10	/* Maximum number of unmatched xid */
45 #define	ISNS_RCV_TIMEOUT	5
46 #define	ISNS_RCV_RETRY_MAX	2
47 #define	IPV4_RSVD_BYTES		10
48 
49 typedef struct isns_reg_arg {
50 	iscsi_addr_t *isns_server_addr;
51 	uint8_t *node_name;
52 	size_t node_name_len;
53 	uint8_t *node_alias;
54 	size_t node_alias_len;
55 	uint32_t node_type;
56 	uint8_t *lhba_handle;
57 } isns_reg_arg_t;
58 
59 typedef struct isns_async_thread_arg {
60 	uint8_t *lhba_handle;
61 	void *listening_so;
62 } isns_async_thread_arg_t;
63 
64 /* One global queue to serve all LHBA instances. */
65 static ddi_taskq_t *reg_query_taskq;
66 static kmutex_t reg_query_taskq_mutex;
67 
68 /* One global queue to serve all LHBA instances. */
69 static ddi_taskq_t *scn_taskq;
70 static kmutex_t scn_taskq_mutex;
71 
72 /* One globally maintained transaction ID. */
73 static uint16_t xid = 0;
74 
75 /*
76  * One SCN callback registration per LHBA instance. For now, since we
77  * support only one instance, we create one place holder for the
78  * callback.
79  */
80 void (*scn_callback_p)(void *);
81 
82 /*
83  * One thread, port, local address, and listening socket per LHBA instance.
84  * For now, since we support only one instance, we create one set of place
85  * holder for these data.
86  */
87 static boolean_t esi_scn_thr_to_shutdown = B_FALSE;
88 static iscsi_thread_t *esi_scn_thr_id = NULL;
89 static void *instance_listening_so = NULL;
90 /*
91  * This mutex protects all the per LHBA instance variables, i.e.,
92  * esi_scn_thr_to_shutdown, esi_scn_thr_id, and instance_listening_so.
93  */
94 static kmutex_t esi_scn_thr_mutex;
95 
96 /* iSNS related helpers */
97 /* Return status */
98 #define	ISNS_OK				0
99 #define	ISNS_BAD_SVR_ADDR		1
100 #define	ISNS_INTERNAL_ERR		2
101 #define	ISNS_CANNOT_FIND_LOCAL_ADDR	3
102 static int discover_isns_server(uint8_t *lhba_handle,
103     iscsi_addr_list_t **isns_server_addrs);
104 static int create_esi_scn_thr(uint8_t *lhba_handle,
105     iscsi_addr_t *isns_server_addr);
106 static void esi_scn_thr_cleanup(void);
107 static void register_isns_client(void *arg);
108 static isns_status_t do_isns_dev_attr_reg(iscsi_addr_t *isns_server_addr,
109     uint8_t *node_name, uint8_t *node_alias, uint32_t node_type);
110 static isns_status_t do_isns_dev_dereg(iscsi_addr_t *isns_server_addr,
111     uint8_t *node_name);
112 
113 /*
114  * Make query to all iSNS servers visible to the specified LHBA.
115  * The query could be made for all target nodes or for a specific target
116  * node.
117  */
118 static isns_status_t do_isns_query(boolean_t is_query_all_nodes_b,
119     uint8_t *lhba_handle, uint8_t *target_node_name,
120     uint8_t *source_node_name, uint8_t *source_node_alias,
121     uint32_t source_node_type, isns_portal_group_list_t **pg_list);
122 
123 /*
124  * Create DevAttrQuery message requesting portal group information for all
125  * target nodes. Send it to the specified iSNS server. Parse the
126  * DevAttrQueryRsp PDU and translate the results into a portal group list
127  * object.
128  */
129 static isns_status_t do_isns_dev_attr_query_all_nodes(
130     iscsi_addr_t *isns_server_addr, uint8_t *node_name,
131     uint8_t *node_alias, isns_portal_group_list_t **pg_list);
132 
133 /*
134  * Create DevAttrQuery message requesting portal group information for the
135  * specified target node. Send it to the specified iSNS server. Parse the
136  * DevAttrQueryRsp PDU and translate the results into a portal group list
137  * object.
138  */
139 static isns_status_t do_isns_dev_attr_query_one_node(
140     iscsi_addr_t *isns_server_addr, uint8_t *target_node_name,
141     uint8_t *source_node_name, uint8_t *source_node_alias,
142     uint32_t source_node_type, isns_portal_group_list_t **pg_list);
143 
144 static void isns_service_esi_scn(iscsi_thread_t *thread, void* arg);
145 static void (*scn_callback_lookup(uint8_t *lhba_handle))(void *);
146 
147 /* Transport related helpers */
148 static void *isns_open(iscsi_addr_t *isns_server_addr);
149 static ssize_t isns_send_pdu(void *socket, isns_pdu_t *pdu);
150 static size_t isns_rcv_pdu(void *so, isns_pdu_t **pdu, size_t *pdu_size);
151 static boolean_t find_listening_addr(iscsi_addr_t *local_addr,
152     void *listening_so);
153 static boolean_t find_local_portal(iscsi_addr_t *isns_server_addr,
154     iscsi_addr_t **local_addr, void **listening_so);
155 
156 /* iSNS protocol related helpers */
157 static size_t isns_create_pdu_header(uint16_t func_id,
158     uint16_t flags, isns_pdu_t **pdu);
159 static int isns_add_attr(isns_pdu_t *pdu,
160     size_t max_pdu_size, uint32_t attr_id, uint32_t attr_len,
161     void *attr_data, uint32_t attr_numeric_data);
162 static uint16_t create_xid(void);
163 static size_t isns_create_dev_attr_reg_pdu(
164     uint8_t *node_name, uint8_t *node_alias, uint32_t node_type,
165     uint16_t *xid, isns_pdu_t **out_pdu);
166 static size_t isns_create_dev_dereg_pdu(uint8_t *node_name,
167     uint16_t *xid_p, isns_pdu_t **out_pdu);
168 static size_t isns_create_dev_attr_qry_target_nodes_pdu(
169     uint8_t *node_name, uint8_t *node_alias, uint16_t *xid,
170     isns_pdu_t **out_pdu);
171 static size_t isns_create_dev_attr_qry_one_pg_pdu(
172     uint8_t *target_node_name, uint8_t *source_node_name,
173     uint16_t *xid, isns_pdu_t **out_pdu);
174 static size_t isns_create_esi_rsp_pdu(uint32_t rsp_status_code,
175     isns_pdu_t *pdu, uint16_t *xid, isns_pdu_t **out_pdu);
176 static size_t isns_create_scn_reg_pdu(uint8_t *node_name,
177     uint8_t *node_alias, uint16_t *xid, isns_pdu_t **out_pdu);
178 static size_t isns_create_scn_dereg_pdu(uint8_t *node_name,
179     uint16_t *xid_p, isns_pdu_t **out_pdu);
180 static size_t isns_create_scn_rsp_pdu(uint32_t rsp_status_code,
181     isns_pdu_t *pdu, uint16_t *xid, isns_pdu_t **out_pdu);
182 static uint32_t isns_process_dev_attr_reg_rsp(isns_pdu_t *resp_pdu_p);
183 static uint32_t isns_process_dev_attr_dereg_rsp(isns_pdu_t *resp_pdu_p);
184 
185 /*
186  * Process and parse a DevAttrQryRsp message. The routine creates a list
187  * of Portal Group objects if the message is parasable without any issue.
188  * If the parsing is not successful, the pg_list will be set to NULL.
189  */
190 static uint32_t isns_process_dev_attr_qry_target_nodes_pdu(
191     iscsi_addr_t *isns_server_addr, uint16_t payload_funcId,
192     isns_resp_t *resp_p, size_t resp_len,
193     isns_portal_group_list_t **pg_list);
194 static uint32_t isns_process_scn_reg_rsp(isns_pdu_t *resp_pdu_p);
195 static uint32_t isns_process_scn_dereg_rsp(isns_pdu_t *resp_pdu_p);
196 static uint32_t isns_process_esi(isns_pdu_t *esi_pdu_p);
197 static uint32_t isns_process_scn(isns_pdu_t *scn_pdu_p, uint8_t *lhba_handle);
198 
199 void
200 isns_client_init()
201 {
202 	mutex_init(&reg_query_taskq_mutex, NULL, MUTEX_DRIVER, NULL);
203 	mutex_enter(&reg_query_taskq_mutex);
204 	reg_query_taskq = ddi_taskq_create(NULL, "isns_reg_query_taskq",
205 	    1, TASKQ_DEFAULTPRI, 0);
206 	mutex_exit(&reg_query_taskq_mutex);
207 
208 	mutex_init(&scn_taskq_mutex, NULL, MUTEX_DRIVER, NULL);
209 	mutex_enter(&scn_taskq_mutex);
210 	scn_taskq = ddi_taskq_create(NULL, "isns_scn_taskq",
211 	    1, TASKQ_DEFAULTPRI, 0);
212 	mutex_exit(&scn_taskq_mutex);
213 
214 	mutex_init(&esi_scn_thr_mutex, NULL, MUTEX_DRIVER, NULL);
215 
216 	/* MISC initializations. */
217 	scn_callback_p = NULL;
218 	esi_scn_thr_id = NULL;
219 	instance_listening_so = NULL;
220 	esi_scn_thr_to_shutdown = B_FALSE;
221 	xid = 0;
222 }
223 
224 void
225 isns_client_cleanup()
226 {
227 	ddi_taskq_t *tmp_taskq_p;
228 
229 	mutex_enter(&scn_taskq_mutex);
230 	tmp_taskq_p = scn_taskq;
231 	scn_taskq = NULL;
232 	mutex_exit(&scn_taskq_mutex);
233 	ddi_taskq_destroy(tmp_taskq_p);
234 
235 	mutex_enter(&reg_query_taskq_mutex);
236 	tmp_taskq_p = reg_query_taskq;
237 	reg_query_taskq = NULL;
238 	mutex_exit(&reg_query_taskq_mutex);
239 	ddi_taskq_destroy(tmp_taskq_p);
240 
241 	mutex_destroy(&reg_query_taskq_mutex);
242 	mutex_destroy(&scn_taskq_mutex);
243 
244 	esi_scn_thr_cleanup();
245 
246 	mutex_destroy(&esi_scn_thr_mutex);
247 }
248 
249 isns_status_t
250 isns_reg(uint8_t *lhba_handle,
251 	uint8_t *node_name,
252 	size_t node_name_len,
253 	uint8_t *node_alias,
254 	size_t node_alias_len,
255 	uint32_t node_type,
256 	void (*scn_callback)(void *))
257 {
258 	int i;
259 	int list_space;
260 	iscsi_addr_list_t *isns_server_addr_list;
261 	isns_reg_arg_t *reg_args_p;
262 
263 	/* Look up the iSNS Server address(es) based on the specified ISID */
264 	if (discover_isns_server(lhba_handle, &isns_server_addr_list) !=
265 	    ISNS_OK) {
266 		return (isns_no_svr_found);
267 	}
268 
269 	/* No iSNS server discovered - no registration needed. */
270 	if (isns_server_addr_list->al_out_cnt == 0) {
271 		list_space = sizeof (iscsi_addr_list_t);
272 		kmem_free(isns_server_addr_list, list_space);
273 		isns_server_addr_list = NULL;
274 		return (isns_no_svr_found);
275 	}
276 
277 	/* Check and create ESI/SCN threads and populate local address */
278 	for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
279 		if (create_esi_scn_thr(lhba_handle,
280 		    &(isns_server_addr_list->al_addrs[i])) == ISNS_OK) {
281 			break;
282 		}
283 	}
284 	if (i == isns_server_addr_list->al_out_cnt) {
285 		/*
286 		 * Problem creating ESI/SCN thread
287 		 * Free the server list
288 		 */
289 		list_space = sizeof (iscsi_addr_list_t);
290 		if (isns_server_addr_list->al_out_cnt > 0) {
291 			list_space += (sizeof (iscsi_addr_t) *
292 			    (isns_server_addr_list->al_out_cnt - 1));
293 		}
294 		kmem_free(isns_server_addr_list, list_space);
295 		isns_server_addr_list = NULL;
296 		return (isns_internal_err);
297 	}
298 
299 	/* Register against all iSNS servers discovered. */
300 	for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
301 		reg_args_p = kmem_zalloc(sizeof (isns_reg_arg_t), KM_SLEEP);
302 		reg_args_p->isns_server_addr =
303 		    kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP);
304 		bcopy(&isns_server_addr_list->al_addrs[i],
305 		    reg_args_p->isns_server_addr, sizeof (iscsi_addr_t));
306 		reg_args_p->node_name = kmem_zalloc(node_name_len, KM_SLEEP);
307 		bcopy(node_name, reg_args_p->node_name, node_name_len);
308 		reg_args_p->node_name_len = node_name_len;
309 		reg_args_p->node_alias = kmem_zalloc(node_alias_len, KM_SLEEP);
310 		bcopy(node_alias, reg_args_p->node_alias, node_alias_len);
311 		reg_args_p->node_alias_len = node_alias_len;
312 		reg_args_p->node_type = node_type;
313 
314 		/* Dispatch the registration request */
315 		register_isns_client(reg_args_p);
316 	}
317 
318 	/* Free the server list */
319 	list_space = sizeof (iscsi_addr_list_t);
320 	if (isns_server_addr_list->al_out_cnt > 0) {
321 		list_space += (sizeof (iscsi_addr_t) *
322 		    (isns_server_addr_list->al_out_cnt - 1));
323 	}
324 	kmem_free(isns_server_addr_list, list_space);
325 	isns_server_addr_list = NULL;
326 
327 	/* Register the scn_callback. */
328 	scn_callback_p = scn_callback;
329 
330 	return (isns_ok);
331 }
332 
333 isns_status_t
334 isns_reg_one_server(entry_t *isns_server,
335 	uint8_t *lhba_handle,
336 	uint8_t *node_name,
337 	size_t node_name_len,
338 	uint8_t *node_alias,
339 	size_t node_alias_len,
340 	uint32_t node_type,
341 	void (*scn_callback)(void *))
342 {
343 	int status;
344 	iscsi_addr_t *ap;
345 	isns_reg_arg_t *reg_args_p;
346 
347 	ap = (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP);
348 	ap->a_port = isns_server->e_port;
349 	ap->a_addr.i_insize = isns_server->e_insize;
350 	if (isns_server->e_insize == sizeof (struct in_addr)) {
351 		ap->a_addr.i_addr.in4.s_addr = (isns_server->e_u.u_in4.s_addr);
352 	} else if (isns_server->e_insize == sizeof (struct in6_addr)) {
353 		bcopy(&(isns_server->e_u.u_in6.s6_addr),
354 		    ap->a_addr.i_addr.in6.s6_addr,
355 		    sizeof (struct in6_addr));
356 	} else {
357 		kmem_free(ap, sizeof (iscsi_addr_t));
358 		return (isns_op_failed);
359 	}
360 
361 	/* Check and create ESI/SCN threads and populate local address */
362 	if ((status = create_esi_scn_thr(lhba_handle, ap))
363 	    != ISNS_OK) {
364 		/* Problem creating ESI/SCN thread */
365 		DTRACE_PROBE1(isns_reg_one_server_create_esi_scn_thr,
366 		    int, status);
367 		kmem_free(ap, sizeof (iscsi_addr_t));
368 		return (isns_internal_err);
369 	}
370 
371 	reg_args_p = kmem_zalloc(sizeof (isns_reg_arg_t), KM_SLEEP);
372 	reg_args_p->isns_server_addr =
373 	    kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP);
374 	bcopy(ap, reg_args_p->isns_server_addr, sizeof (iscsi_addr_t));
375 	reg_args_p->node_name = kmem_zalloc(node_name_len, KM_SLEEP);
376 	bcopy(node_name, reg_args_p->node_name, node_name_len);
377 	reg_args_p->node_name_len = node_name_len;
378 	reg_args_p->node_alias = kmem_zalloc(node_alias_len, KM_SLEEP);
379 	bcopy(node_alias, reg_args_p->node_alias, node_alias_len);
380 	reg_args_p->node_alias_len = node_alias_len;
381 	reg_args_p->node_type = node_type;
382 
383 	/* Dispatch the registration request */
384 	register_isns_client(reg_args_p);
385 
386 	/* Register the scn_callback. */
387 	scn_callback_p = scn_callback;
388 
389 	kmem_free(ap, sizeof (iscsi_addr_t));
390 	return (isns_ok);
391 }
392 
393 isns_status_t
394 isns_dereg(uint8_t *lhba_handle,
395 	uint8_t *node_name)
396 {
397 	int i;
398 	int isns_svr_lst_sz;
399 	int list_space;
400 	iscsi_addr_list_t *isns_server_addr_list = NULL;
401 	isns_status_t dereg_stat, combined_dereg_stat;
402 
403 	/* Look up the iSNS Server address(es) based on the specified ISID */
404 	if (discover_isns_server(lhba_handle, &isns_server_addr_list) !=
405 	    ISNS_OK) {
406 		return (isns_no_svr_found);
407 	}
408 	ASSERT(isns_server_addr_list != NULL);
409 	if (isns_server_addr_list->al_out_cnt == 0) {
410 		isns_svr_lst_sz = sizeof (iscsi_addr_list_t);
411 		kmem_free(isns_server_addr_list, isns_svr_lst_sz);
412 		isns_server_addr_list = NULL;
413 		return (isns_no_svr_found);
414 	}
415 
416 	combined_dereg_stat = isns_ok;
417 	for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
418 		dereg_stat = do_isns_dev_dereg(
419 		    &isns_server_addr_list->al_addrs[i],
420 		    node_name);
421 		if (dereg_stat == isns_ok) {
422 			if (combined_dereg_stat != isns_ok) {
423 				combined_dereg_stat = isns_op_partially_failed;
424 			}
425 		} else {
426 			if (combined_dereg_stat == isns_ok) {
427 				combined_dereg_stat = isns_op_partially_failed;
428 			}
429 		}
430 	}
431 
432 	/* Free the server list. */
433 	list_space = sizeof (iscsi_addr_list_t);
434 	if (isns_server_addr_list->al_out_cnt > 0) {
435 		list_space += (sizeof (iscsi_addr_t) *
436 		    (isns_server_addr_list->al_out_cnt - 1));
437 	}
438 	kmem_free(isns_server_addr_list, list_space);
439 	isns_server_addr_list = NULL;
440 
441 	/* Cleanup ESI/SCN thread. */
442 	esi_scn_thr_cleanup();
443 
444 	return (combined_dereg_stat);
445 }
446 
447 isns_status_t
448 isns_dereg_one_server(entry_t *isns_server,
449 	uint8_t *node_name,
450 	boolean_t is_last_isns_server_b)
451 {
452 	iscsi_addr_t *ap;
453 	isns_status_t dereg_stat;
454 
455 	ap = (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP);
456 	ap->a_port = isns_server->e_port;
457 	ap->a_addr.i_insize = isns_server->e_insize;
458 	if (isns_server->e_insize == sizeof (struct in_addr)) {
459 		ap->a_addr.i_addr.in4.s_addr = (isns_server->e_u.u_in4.s_addr);
460 	} else if (isns_server->e_insize == sizeof (struct in6_addr)) {
461 		bcopy(&(isns_server->e_u.u_in6.s6_addr),
462 		    ap->a_addr.i_addr.in6.s6_addr,
463 		    sizeof (struct in6_addr));
464 	} else {
465 		kmem_free(ap, sizeof (iscsi_addr_t));
466 		return (isns_op_failed);
467 	}
468 
469 	dereg_stat = do_isns_dev_dereg(ap, node_name);
470 
471 	kmem_free(ap, sizeof (iscsi_addr_t));
472 
473 	if (is_last_isns_server_b == B_TRUE) {
474 		/*
475 		 * Clean up ESI/SCN thread resource if it is the
476 		 * last known iSNS server.
477 		 */
478 		esi_scn_thr_cleanup();
479 	}
480 
481 	return (dereg_stat);
482 }
483 
484 isns_status_t
485 isns_query(uint8_t *lhba_handle,
486 	uint8_t *node_name,
487 	uint8_t *node_alias,
488 	uint32_t node_type,
489 	isns_portal_group_list_t **pg_list)
490 {
491 	return (do_isns_query(B_TRUE,
492 	    lhba_handle,
493 	    (uint8_t *)"",
494 	    node_name,
495 	    node_alias,
496 	    node_type,
497 	    pg_list));
498 }
499 
500 /* ARGSUSED */
501 isns_status_t
502 isns_query_one_server(iscsi_addr_t *isns_server_addr,
503 	uint8_t *lhba_handle,
504 	uint8_t *node_name,
505 	uint8_t *node_alias,
506 	uint32_t node_type,
507 	isns_portal_group_list_t **pg_list)
508 {
509 	return (do_isns_dev_attr_query_all_nodes(isns_server_addr,
510 	    node_name,
511 	    node_alias,
512 	    pg_list));
513 }
514 
515 isns_status_t
516 isns_query_one_node(uint8_t *target_node_name,
517 	uint8_t *lhba_handle,
518 	uint8_t *source_node_name,
519 	uint8_t *source_node_alias,
520 	uint32_t source_node_type,
521 	isns_portal_group_list_t **pg_list)
522 {
523 	return (do_isns_query(B_FALSE,
524 	    lhba_handle,
525 	    target_node_name,
526 	    source_node_name,
527 	    source_node_alias,
528 	    source_node_type,
529 	    pg_list));
530 }
531 
532 /* ARGSUSED */
533 isns_status_t
534 isns_query_one_server_one_node(iscsi_addr_t *isns_server_addr,
535 	uint8_t *target_node_name,
536 	uint8_t *lhba_handle,
537 	uint8_t *source_node_name,
538 	uint8_t *source_node_alias,
539 	uint32_t source_node_type,
540 	isns_portal_group_list_t **pg_list) {
541 	/* Not supported yet. */
542 	*pg_list = NULL;
543 	return (isns_op_failed);
544 }
545 
546 /* ARGSUSED */
547 static
548 int
549 discover_isns_server(uint8_t *lhba_handle,
550 	iscsi_addr_list_t **isns_server_addrs)
551 {
552 	entry_t e;
553 	int i;
554 	int isns_server_count = 1;
555 	int list_space;
556 	void *void_p;
557 
558 	/*
559 	 * Use supported iSNS server discovery method to find out all the
560 	 * iSNS servers. For now, only static configuration method is
561 	 * supported.
562 	 */
563 	isns_server_count = 0;
564 	void_p = NULL;
565 	persistent_isns_addr_lock();
566 	while (persistent_isns_addr_next(&void_p, &e) == B_TRUE) {
567 		isns_server_count++;
568 	}
569 	persistent_isns_addr_unlock();
570 
571 	list_space = sizeof (iscsi_addr_list_t);
572 	if (isns_server_count > 0) {
573 		list_space += (sizeof (iscsi_addr_t) * (isns_server_count - 1));
574 	}
575 	*isns_server_addrs = (iscsi_addr_list_t *)kmem_zalloc(list_space,
576 	    KM_SLEEP);
577 	(*isns_server_addrs)->al_out_cnt = isns_server_count;
578 
579 	persistent_isns_addr_lock();
580 	i = 0;
581 	void_p = NULL;
582 	while (persistent_isns_addr_next(&void_p, &e) == B_TRUE) {
583 		iscsi_addr_t *ap;
584 
585 		ap = &((*isns_server_addrs)->al_addrs[i]);
586 		ap->a_port = e.e_port;
587 		ap->a_addr.i_insize = e.e_insize;
588 		if (e.e_insize == sizeof (struct in_addr)) {
589 			ap->a_addr.i_addr.in4.s_addr = (e.e_u.u_in4.s_addr);
590 		} else if (e.e_insize == sizeof (struct in6_addr)) {
591 			bcopy(&e.e_u.u_in6.s6_addr,
592 			    ap->a_addr.i_addr.in6.s6_addr,
593 			    sizeof (struct in6_addr));
594 		} else {
595 			kmem_free(*isns_server_addrs, list_space);
596 			*isns_server_addrs = NULL;
597 			return (ISNS_BAD_SVR_ADDR);
598 		}
599 		i++;
600 	}
601 	persistent_isns_addr_unlock();
602 
603 	return (ISNS_OK);
604 }
605 
606 static
607 int
608 create_esi_scn_thr(uint8_t *lhba_handle, iscsi_addr_t *isns_server_address)
609 {
610 	void *listening_so  = NULL;
611 	boolean_t found	    = B_FALSE;
612 
613 	ASSERT(lhba_handle != NULL);
614 	ASSERT(isns_server_address != NULL);
615 
616 	/*
617 	 * Bringing up of the thread should happen regardless of the
618 	 * subsequent registration status. That means, do not destroy the
619 	 * ESI/SCN thread already created.
620 	 */
621 	/* Check and create ESI/SCN thread. */
622 	mutex_enter(&esi_scn_thr_mutex);
623 
624 	/* Determine local port and address. */
625 	found = find_local_portal(isns_server_address,
626 	    NULL, &listening_so);
627 	if (found == B_FALSE) {
628 		if (listening_so != NULL) {
629 			iscsi_net->close(listening_so);
630 		}
631 		mutex_exit(&esi_scn_thr_mutex);
632 		return (ISNS_CANNOT_FIND_LOCAL_ADDR);
633 	}
634 
635 	if (esi_scn_thr_id == NULL) {
636 		char thr_name[ISCSI_TH_MAX_NAME_LEN];
637 		int rval;
638 		isns_async_thread_arg_t *larg;
639 
640 		/* Assume the LHBA handle has a length of 4 */
641 		if (snprintf(thr_name, sizeof (thr_name) - 1,
642 		    "isns_client_esi_%x%x%x%x",
643 		    lhba_handle[0],
644 		    lhba_handle[1],
645 		    lhba_handle[2],
646 		    lhba_handle[3]) >=
647 		    sizeof (thr_name)) {
648 			esi_scn_thr_id = NULL;
649 			if (listening_so != NULL) {
650 				iscsi_net->close(listening_so);
651 				listening_so = NULL;
652 			}
653 			mutex_exit(&esi_scn_thr_mutex);
654 			return (ISNS_INTERNAL_ERR);
655 		}
656 
657 		larg = kmem_zalloc(sizeof (isns_async_thread_arg_t), KM_SLEEP);
658 		larg->lhba_handle = lhba_handle;
659 		larg->listening_so = listening_so;
660 		instance_listening_so = listening_so;
661 		esi_scn_thr_to_shutdown = B_FALSE;
662 		esi_scn_thr_id = iscsi_thread_create(NULL,
663 		    thr_name, isns_service_esi_scn, (void *)larg);
664 		if (esi_scn_thr_id == NULL) {
665 			if (listening_so != NULL) {
666 				iscsi_net->close(listening_so);
667 				listening_so = NULL;
668 				instance_listening_so = NULL;
669 			}
670 			mutex_exit(&esi_scn_thr_mutex);
671 			return (ISNS_INTERNAL_ERR);
672 		}
673 
674 		rval = iscsi_thread_start(esi_scn_thr_id);
675 		if (rval == B_FALSE) {
676 			iscsi_thread_destroy(esi_scn_thr_id);
677 			esi_scn_thr_id = NULL;
678 			if (listening_so != NULL) {
679 				iscsi_net->close(listening_so);
680 				listening_so = NULL;
681 				instance_listening_so = NULL;
682 			}
683 			mutex_exit(&esi_scn_thr_mutex);
684 			return (ISNS_INTERNAL_ERR);
685 		}
686 		(void) iscsi_thread_send_wakeup(esi_scn_thr_id);
687 	}
688 	mutex_exit(&esi_scn_thr_mutex);
689 
690 	return (ISNS_OK);
691 }
692 
693 static
694 void
695 register_isns_client(void *arg)
696 {
697 	isns_reg_arg_t *reg_args;
698 	isns_status_t status;
699 
700 	reg_args = (isns_reg_arg_t *)arg;
701 
702 	/* Deregister stale registration (if any). */
703 	status = do_isns_dev_dereg(reg_args->isns_server_addr,
704 	    reg_args->node_name);
705 
706 	if (status == isns_open_conn_err) {
707 		/* Cannot open connection to the server. Stop proceeding. */
708 		kmem_free(reg_args->isns_server_addr, sizeof (iscsi_addr_t));
709 		reg_args->isns_server_addr = NULL;
710 		kmem_free(reg_args->node_name, reg_args->node_name_len);
711 		reg_args->node_name = NULL;
712 		kmem_free(reg_args->node_alias, reg_args->node_alias_len);
713 		reg_args->node_alias = NULL;
714 		kmem_free(reg_args, sizeof (isns_reg_arg_t));
715 		return;
716 	}
717 
718 	DTRACE_PROBE1(register_isns_client_dereg, isns_status_t, status);
719 
720 	/* New registration. */
721 	status =  do_isns_dev_attr_reg(reg_args->isns_server_addr,
722 	    reg_args->node_name, reg_args->node_alias, reg_args->node_type);
723 
724 	DTRACE_PROBE1(register_isns_client_reg, isns_status_t, status);
725 
726 	/* Cleanup */
727 	kmem_free(reg_args->isns_server_addr, sizeof (iscsi_addr_t));
728 	reg_args->isns_server_addr = NULL;
729 	kmem_free(reg_args->node_name, reg_args->node_name_len);
730 	reg_args->node_name = NULL;
731 	kmem_free(reg_args->node_alias, reg_args->node_alias_len);
732 	reg_args->node_alias = NULL;
733 	kmem_free(reg_args, sizeof (isns_reg_arg_t));
734 }
735 
736 static
737 isns_status_t
738 do_isns_dev_attr_reg(iscsi_addr_t *isns_server_addr,
739 	uint8_t *node_name, uint8_t *node_alias, uint32_t node_type)
740 {
741 	int rcv_rsp_cnt = 0;
742 	int rsp_status;
743 	isns_pdu_t *in_pdu, *out_pdu;
744 	isns_status_t rval;
745 	size_t bytes_received, in_pdu_size = 0, out_pdu_size = 0;
746 	uint16_t xid;
747 	void *so = NULL;
748 
749 	out_pdu_size = isns_create_dev_attr_reg_pdu(
750 	    node_name,
751 	    node_alias,
752 	    node_type,
753 	    &xid, &out_pdu);
754 	if (out_pdu_size == 0) {
755 		return (isns_create_msg_err);
756 	}
757 
758 	ASSERT(out_pdu != NULL);
759 	ASSERT(out_pdu_size > 0);
760 
761 	so = isns_open(isns_server_addr);
762 	if (so == NULL) {
763 		/* Log a message and return */
764 		kmem_free(out_pdu, out_pdu_size);
765 		out_pdu = NULL;
766 		return (isns_open_conn_err);
767 	}
768 
769 	if (isns_send_pdu(so, out_pdu) != 0) {
770 		iscsi_net->close(so);
771 		kmem_free(out_pdu, out_pdu_size);
772 		out_pdu = NULL;
773 		return (isns_send_msg_err);
774 	}
775 
776 	/* Done with the out PDU - free it */
777 	kmem_free(out_pdu, out_pdu_size);
778 	out_pdu = NULL;
779 
780 	rcv_rsp_cnt = 0;
781 	rval = isns_ok;
782 	for (;;) {
783 		bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
784 		ASSERT(bytes_received >= (size_t)0);
785 		if (bytes_received == 0) {
786 			ASSERT(in_pdu == NULL);
787 			ASSERT(in_pdu_size == 0);
788 			rval = isns_rcv_msg_err;
789 			break;
790 		}
791 
792 		ASSERT(in_pdu != NULL);
793 		ASSERT(in_pdu_size > 0);
794 
795 		if (ntohs(in_pdu->xid) != xid) {
796 			rcv_rsp_cnt++;
797 			if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
798 				continue;
799 			} else {
800 				/* Exceed maximum receive count. */
801 				kmem_free(in_pdu, in_pdu_size);
802 				in_pdu = NULL;
803 				rval = isns_no_rsp_rcvd;
804 				break;
805 			}
806 		}
807 
808 		rsp_status = isns_process_dev_attr_reg_rsp(in_pdu);
809 		if (rsp_status != ISNS_RSP_SUCCESSFUL) {
810 			if (rsp_status == ISNS_RSP_SRC_UNAUTHORIZED) {
811 				rval = isns_op_partially_failed;
812 			} else {
813 				rval = isns_op_failed;
814 			}
815 		}
816 		kmem_free(in_pdu, in_pdu_size);
817 		in_pdu = NULL;
818 		break;
819 	}
820 
821 	if (rval != isns_ok) {
822 		iscsi_net->close(so);
823 		return (rval);
824 	}
825 
826 	/* Always register SCN */
827 	out_pdu_size = isns_create_scn_reg_pdu(
828 	    node_name, node_alias,
829 	    &xid, &out_pdu);
830 	if (out_pdu_size == 0) {
831 		iscsi_net->close(so);
832 		return (isns_create_msg_err);
833 	}
834 
835 	ASSERT(out_pdu != NULL);
836 	ASSERT(out_pdu_size > 0);
837 
838 	if (isns_send_pdu(so, out_pdu) != 0) {
839 		iscsi_net->close(so);
840 		kmem_free(out_pdu, out_pdu_size);
841 		out_pdu = NULL;
842 		return (isns_send_msg_err);
843 	}
844 
845 	/* Done with the out PDU - free it */
846 	kmem_free(out_pdu, out_pdu_size);
847 	out_pdu = NULL;
848 
849 	rcv_rsp_cnt = 0;
850 	for (;;) {
851 		bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
852 		ASSERT(bytes_received >= (size_t)0);
853 		if (bytes_received == 0) {
854 			ASSERT(in_pdu == NULL);
855 			ASSERT(in_pdu_size == 0);
856 			rval = isns_rcv_msg_err;
857 			break;
858 		}
859 
860 		ASSERT(in_pdu != NULL);
861 		ASSERT(in_pdu_size > 0);
862 
863 		if (ntohs(in_pdu->xid) != xid) {
864 			rcv_rsp_cnt++;
865 			if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
866 				continue;
867 			} else {
868 				/* Exceed maximum receive count. */
869 				kmem_free(in_pdu, in_pdu_size);
870 				in_pdu = NULL;
871 				rval = isns_no_rsp_rcvd;
872 				break;
873 			}
874 		}
875 
876 		rsp_status = isns_process_scn_reg_rsp(in_pdu);
877 		if (rsp_status != ISNS_RSP_SUCCESSFUL) {
878 			rval = isns_op_failed;
879 		}
880 		kmem_free(in_pdu, in_pdu_size);
881 		in_pdu = NULL;
882 		break;
883 	}
884 
885 	iscsi_net->close(so);
886 
887 	return (rval);
888 }
889 
890 static
891 isns_status_t
892 do_isns_dev_dereg(iscsi_addr_t *isns_server_addr,
893 	uint8_t *node_name)
894 {
895 	int rcv_rsp_cnt = 0;
896 	int rsp_status;
897 	isns_pdu_t *in_pdu, *out_pdu;
898 	isns_status_t rval;
899 	size_t bytes_received, in_pdu_size = 0, out_pdu_size = 0;
900 	uint16_t xid;
901 	void *so = NULL;
902 
903 	out_pdu_size = isns_create_dev_dereg_pdu(
904 	    node_name,
905 	    &xid, &out_pdu);
906 	if (out_pdu_size == 0) {
907 		return (isns_create_msg_err);
908 	}
909 
910 	ASSERT(out_pdu != NULL);
911 	ASSERT(out_pdu_size > 0);
912 
913 	so = isns_open(isns_server_addr);
914 	if (so == NULL) {
915 		/* Log a message and return */
916 		kmem_free(out_pdu, out_pdu_size);
917 		out_pdu = NULL;
918 		return (isns_open_conn_err);
919 	}
920 
921 	if (isns_send_pdu(so, out_pdu) != 0) {
922 		iscsi_net->close(so);
923 		kmem_free(out_pdu, out_pdu_size);
924 		out_pdu = NULL;
925 		return (isns_send_msg_err);
926 	}
927 
928 	/* Done with the out PDU - free it */
929 	kmem_free(out_pdu, out_pdu_size);
930 	out_pdu = NULL;
931 
932 	rcv_rsp_cnt = 0;
933 	rval = isns_ok;
934 	for (;;) {
935 		bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
936 		ASSERT(bytes_received >= (size_t)0);
937 		if (bytes_received == 0) {
938 			ASSERT(in_pdu == NULL);
939 			ASSERT(in_pdu_size == 0);
940 			rval = isns_rcv_msg_err;
941 			break;
942 		}
943 
944 		ASSERT(in_pdu != NULL);
945 		ASSERT(in_pdu_size > 0);
946 
947 		if (ntohs(in_pdu->xid) != xid) {
948 			rcv_rsp_cnt++;
949 			if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
950 				continue;
951 			} else {
952 				/* Exceed maximum receive count. */
953 				kmem_free(in_pdu, in_pdu_size);
954 				in_pdu = NULL;
955 				rval = isns_no_rsp_rcvd;
956 				break;
957 			}
958 		}
959 
960 		rsp_status = isns_process_dev_attr_dereg_rsp(in_pdu);
961 		if (rsp_status != ISNS_RSP_SUCCESSFUL) {
962 			rval = isns_op_failed;
963 		}
964 		kmem_free(in_pdu, in_pdu_size);
965 		in_pdu = NULL;
966 		break;
967 	}
968 
969 	if (rval != isns_ok) {
970 		iscsi_net->close(so);
971 		return (rval);
972 	}
973 
974 	/* Always deregister SCN */
975 	out_pdu_size = isns_create_scn_dereg_pdu(
976 	    node_name,
977 	    &xid, &out_pdu);
978 	if (out_pdu_size == 0) {
979 		iscsi_net->close(so);
980 		return (isns_create_msg_err);
981 	}
982 
983 	ASSERT(out_pdu != NULL);
984 	ASSERT(out_pdu_size > 0);
985 
986 	if (isns_send_pdu(so, out_pdu) != 0) {
987 		iscsi_net->close(so);
988 		kmem_free(out_pdu, out_pdu_size);
989 		out_pdu = NULL;
990 		return (isns_send_msg_err);
991 	}
992 
993 	/* Done with the out PDU - free it */
994 	kmem_free(out_pdu, out_pdu_size);
995 	out_pdu = NULL;
996 
997 	rcv_rsp_cnt = 0;
998 	for (;;) {
999 		bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
1000 		ASSERT(bytes_received >= (size_t)0);
1001 		if (bytes_received == 0) {
1002 			ASSERT(in_pdu == NULL);
1003 			ASSERT(in_pdu_size == 0);
1004 			rval = isns_rcv_msg_err;
1005 			break;
1006 		}
1007 
1008 		ASSERT(in_pdu != NULL);
1009 		ASSERT(in_pdu_size > 0);
1010 
1011 		if (ntohs(in_pdu->xid) != xid) {
1012 			rcv_rsp_cnt++;
1013 			if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
1014 				continue;
1015 			} else {
1016 				/* Exceed maximum receive count. */
1017 				kmem_free(in_pdu, in_pdu_size);
1018 				in_pdu = NULL;
1019 				rval = isns_no_rsp_rcvd;
1020 				break;
1021 			}
1022 		}
1023 
1024 		rsp_status = isns_process_scn_dereg_rsp(in_pdu);
1025 		if (rsp_status != ISNS_RSP_SUCCESSFUL) {
1026 			rval = isns_op_failed;
1027 		}
1028 		kmem_free(in_pdu, in_pdu_size);
1029 		in_pdu = NULL;
1030 		break;
1031 	}
1032 
1033 	iscsi_net->close(so);
1034 
1035 	return (rval);
1036 }
1037 
1038 static
1039 isns_status_t
1040 do_isns_query(boolean_t is_query_all_nodes_b,
1041 	uint8_t *lhba_handle,
1042 	uint8_t *target_node_name,
1043 	uint8_t *source_node_name,
1044 	uint8_t *source_node_alias,
1045 	uint32_t source_node_type,
1046 	isns_portal_group_list_t **pg_list)
1047 {
1048 	int i, j, k;
1049 	int combined_num_of_pgs, combined_pg_lst_sz,
1050 	    isns_svr_lst_sz,
1051 	    tmp_pg_list_sz,
1052 	    tmp_pg_lists_sz;
1053 	iscsi_addr_list_t *isns_server_addr_list = NULL;
1054 	isns_portal_group_t *pg;
1055 	isns_portal_group_list_t *combined_pg_list,
1056 	    *tmp_pg_list, **tmp_pg_lists;
1057 	isns_status_t qry_stat, combined_qry_stat;
1058 
1059 	/* Look up the iSNS Server address(es) based on the specified ISID */
1060 	if (discover_isns_server(lhba_handle, &isns_server_addr_list) !=
1061 	    ISNS_OK) {
1062 		*pg_list = NULL;
1063 		return (isns_no_svr_found);
1064 	}
1065 	if (isns_server_addr_list->al_out_cnt == 0) {
1066 		isns_svr_lst_sz = sizeof (iscsi_addr_list_t);
1067 		kmem_free(isns_server_addr_list, isns_svr_lst_sz);
1068 		isns_server_addr_list = NULL;
1069 		*pg_list = NULL;
1070 		return (isns_no_svr_found);
1071 	}
1072 
1073 	/*
1074 	 * isns_server_addr_list->al_out_cnt should not be zero by the
1075 	 * time it comes to this point.
1076 	 */
1077 	tmp_pg_lists_sz = isns_server_addr_list->al_out_cnt *
1078 	    sizeof (isns_portal_group_list_t *);
1079 	tmp_pg_lists = (isns_portal_group_list_t **)kmem_zalloc(
1080 	    tmp_pg_lists_sz, KM_SLEEP);
1081 	combined_num_of_pgs = 0;
1082 	combined_qry_stat = isns_ok;
1083 	for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
1084 		if (is_query_all_nodes_b) {
1085 			qry_stat = do_isns_dev_attr_query_all_nodes(
1086 			    &isns_server_addr_list->al_addrs[i],
1087 			    source_node_name,
1088 			    source_node_alias,
1089 			    &tmp_pg_list);
1090 		} else {
1091 			qry_stat = do_isns_dev_attr_query_one_node(
1092 			    &isns_server_addr_list->al_addrs[i],
1093 			    target_node_name,
1094 			    source_node_name,
1095 			    source_node_alias,
1096 			    source_node_type,
1097 			    &tmp_pg_list);
1098 		}
1099 
1100 		/* Record the portal group list retrieved from this server. */
1101 		tmp_pg_lists[i] = tmp_pg_list;
1102 		if (tmp_pg_list != NULL) {
1103 			combined_num_of_pgs += tmp_pg_list->pg_out_cnt;
1104 		}
1105 
1106 		if (qry_stat == isns_ok) {
1107 			if (combined_qry_stat != isns_ok) {
1108 				combined_qry_stat = isns_op_partially_failed;
1109 			}
1110 		} else {
1111 			if (combined_qry_stat != isns_op_partially_failed) {
1112 				if (combined_qry_stat == isns_ok && i > 0) {
1113 					combined_qry_stat =
1114 					    isns_op_partially_failed;
1115 				} else {
1116 					combined_qry_stat = qry_stat;
1117 				}
1118 			}
1119 		}
1120 
1121 		if (is_query_all_nodes_b == B_FALSE) {
1122 			if (qry_stat == isns_ok) {
1123 				/*
1124 				 * Break out of the loop if we already got
1125 				 * the node information for one node.
1126 				 */
1127 				break;
1128 			}
1129 		}
1130 	}
1131 
1132 	/* Merge the retrieved portal lists */
1133 	combined_pg_lst_sz = sizeof (isns_portal_group_list_t);
1134 	if (combined_num_of_pgs > 0) {
1135 		combined_pg_lst_sz += (combined_num_of_pgs - 1) *
1136 		    sizeof (isns_portal_group_t);
1137 	}
1138 	combined_pg_list = (isns_portal_group_list_t *)kmem_zalloc(
1139 	    combined_pg_lst_sz, KM_SLEEP);
1140 
1141 	combined_pg_list->pg_out_cnt = combined_num_of_pgs;
1142 	k = 0;
1143 	for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
1144 		if (tmp_pg_lists[i] == NULL) {
1145 			continue;
1146 		}
1147 		for (j = 0; j < tmp_pg_lists[i]->pg_out_cnt; j++) {
1148 			pg = &(combined_pg_list->pg_list[k]);
1149 			bcopy(&(tmp_pg_lists[i]->pg_list[j]),
1150 			    pg, sizeof (isns_portal_group_t));
1151 			k++;
1152 		}
1153 		tmp_pg_list_sz = sizeof (isns_portal_group_list_t);
1154 		if (tmp_pg_lists[i]->pg_out_cnt > 0) {
1155 			tmp_pg_list_sz += (tmp_pg_lists[i]->pg_out_cnt - 1) *
1156 			    sizeof (isns_portal_group_t);
1157 		}
1158 		kmem_free(tmp_pg_lists[i], tmp_pg_list_sz);
1159 		tmp_pg_lists[i] = NULL;
1160 	}
1161 	kmem_free(tmp_pg_lists, tmp_pg_lists_sz);
1162 	tmp_pg_lists = NULL;
1163 
1164 	isns_svr_lst_sz = sizeof (iscsi_addr_list_t);
1165 	if (isns_server_addr_list->al_out_cnt > 0) {
1166 		isns_svr_lst_sz += (sizeof (iscsi_addr_t) *
1167 		    (isns_server_addr_list->al_out_cnt - 1));
1168 	}
1169 	kmem_free(isns_server_addr_list, isns_svr_lst_sz);
1170 	isns_server_addr_list = NULL;
1171 
1172 	DTRACE_PROBE1(list, isns_portal_group_list_t *, combined_pg_list);
1173 
1174 	*pg_list = combined_pg_list;
1175 	return (combined_qry_stat);
1176 }
1177 
1178 static
1179 isns_status_t
1180 do_isns_dev_attr_query_all_nodes(iscsi_addr_t *isns_server_addr,
1181 	uint8_t *node_name,
1182 	uint8_t *node_alias,
1183 	isns_portal_group_list_t **pg_list)
1184 {
1185 	int bytes_received;
1186 	int rcv_rsp_cnt = 0;
1187 	int rsp_status;
1188 	uint16_t xid, seq_id = 0, func_id;
1189 	isns_pdu_t *in_pdu, *out_pdu;
1190 	isns_pdu_mult_payload_t *combined_pdu = NULL, *old_combined_pdu = NULL;
1191 	isns_status_t qry_stat;
1192 	size_t out_pdu_size = 0, in_pdu_size = 0;
1193 	size_t old_combined_pdu_size = 0, combined_pdu_size = 0;
1194 	void *so = NULL;
1195 	uint8_t *payload_ptr;
1196 
1197 	/* Initialize */
1198 	*pg_list = NULL;
1199 
1200 	so = isns_open(isns_server_addr);
1201 	if (so == NULL) {
1202 		/* Log a message and return */
1203 		return (isns_open_conn_err);
1204 	}
1205 
1206 	/*
1207 	 * Then, ask for all PG attributes. Filter the non-target nodes.
1208 	 */
1209 	out_pdu_size = isns_create_dev_attr_qry_target_nodes_pdu(
1210 	    node_name, node_alias, &xid, &out_pdu);
1211 	if (out_pdu_size == 0) {
1212 		iscsi_net->close(so);
1213 		return (isns_create_msg_err);
1214 	}
1215 
1216 	ASSERT(out_pdu != NULL);
1217 	ASSERT(out_pdu_size > 0);
1218 
1219 	if (isns_send_pdu(so, out_pdu) != 0) {
1220 		iscsi_net->close(so);
1221 		kmem_free(out_pdu, out_pdu_size);
1222 		out_pdu = NULL;
1223 		return (isns_send_msg_err);
1224 	}
1225 
1226 	/* Done with the out PDU - free it */
1227 	kmem_free(out_pdu, out_pdu_size);
1228 	out_pdu = NULL;
1229 
1230 	rcv_rsp_cnt = 0;
1231 	qry_stat = isns_ok;
1232 	for (;;) {
1233 		uint16_t flags;
1234 
1235 		bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
1236 		ASSERT(bytes_received >= 0);
1237 		if (bytes_received == 0) {
1238 			ASSERT(in_pdu == NULL);
1239 			ASSERT(in_pdu_size == 0);
1240 			qry_stat = isns_rcv_msg_err;
1241 			break;
1242 		}
1243 
1244 		ASSERT(in_pdu != NULL);
1245 		ASSERT(in_pdu_size > 0);
1246 
1247 		/*
1248 		 * make sure we are processing the right transaction id
1249 		 */
1250 		if (ntohs(in_pdu->xid) != xid) {
1251 			rcv_rsp_cnt++;
1252 			if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
1253 				kmem_free(in_pdu, in_pdu_size);
1254 				in_pdu = NULL;
1255 				continue;
1256 			} else {
1257 				/* Exceed maximum receive count. */
1258 				kmem_free(in_pdu, in_pdu_size);
1259 				in_pdu = NULL;
1260 				qry_stat = isns_no_rsp_rcvd;
1261 				break;
1262 			}
1263 		}
1264 
1265 		/*
1266 		 * check to see if FIRST and LAST PDU flag is set
1267 		 * if they are both set, then this response only has one
1268 		 * pdu and we can process the pdu
1269 		 */
1270 		flags = in_pdu->flags;
1271 		if (((flags & ISNS_FLAG_FIRST_PDU) == ISNS_FLAG_FIRST_PDU) &&
1272 		    ((flags & ISNS_FLAG_LAST_PDU) == ISNS_FLAG_LAST_PDU)) {
1273 			rsp_status =
1274 			    isns_process_dev_attr_qry_target_nodes_pdu(
1275 			    isns_server_addr,
1276 			    in_pdu->func_id,
1277 			    (isns_resp_t *)in_pdu->payload,
1278 			    (size_t)in_pdu->payload_len,
1279 			    pg_list);
1280 			kmem_free(in_pdu, in_pdu_size);
1281 			in_pdu = NULL;
1282 			break;
1283 		}
1284 		/*
1285 		 * this pdu is part of a multi-pdu response.  save off the
1286 		 * the payload of this pdu and continue processing
1287 		 */
1288 		if ((flags & ISNS_FLAG_FIRST_PDU) == ISNS_FLAG_FIRST_PDU) {
1289 			/* This is the first pdu, make sure sequence ID is 0 */
1290 			if (in_pdu->seq != 0) {
1291 				cmn_err(CE_NOTE, "isns query response invalid: "
1292 				    "first pdu is not sequence ID 0");
1293 				kmem_free(in_pdu, in_pdu_size);
1294 				in_pdu = NULL;
1295 				return (isns_op_failed);
1296 			}
1297 			seq_id = 0;
1298 
1299 			/* create new pdu and copy in data from old pdu */
1300 			combined_pdu_size = ISNSP_MULT_PAYLOAD_HEADER_SIZE +
1301 			    in_pdu->payload_len;
1302 			combined_pdu = (isns_pdu_mult_payload_t *)kmem_zalloc(
1303 			    combined_pdu_size, KM_SLEEP);
1304 			func_id = in_pdu->func_id;
1305 			combined_pdu->payload_len = in_pdu->payload_len;
1306 			bcopy(in_pdu->payload, combined_pdu->payload,
1307 			    in_pdu->payload_len);
1308 
1309 			/* done with in_pdu, free it */
1310 			kmem_free(in_pdu, in_pdu_size);
1311 			in_pdu = NULL;
1312 		} else {
1313 			seq_id++;
1314 			if (in_pdu->seq != seq_id) {
1315 				cmn_err(CE_NOTE, "isns query response invalid: "
1316 				    "Missing sequence ID %d from isns query "
1317 				    "response.", seq_id);
1318 				kmem_free(in_pdu, in_pdu_size);
1319 				in_pdu = NULL;
1320 				if (combined_pdu != NULL) {
1321 					kmem_free(combined_pdu,
1322 					    combined_pdu_size);
1323 					combined_pdu = NULL;
1324 				}
1325 				return (isns_op_failed);
1326 			}
1327 			/*
1328 			 * if conbined_pdu_size is still zero, then we never
1329 			 * processed the first pdu
1330 			 */
1331 			if (combined_pdu_size == 0) {
1332 				cmn_err(CE_NOTE, "isns query response invalid: "
1333 				    "Did not receive first pdu.\n");
1334 				kmem_free(in_pdu, in_pdu_size);
1335 				in_pdu = NULL;
1336 				return (isns_op_failed);
1337 			}
1338 			/* save off the old combined pdu */
1339 			old_combined_pdu_size = combined_pdu_size;
1340 			old_combined_pdu = combined_pdu;
1341 
1342 			/*
1343 			 * alloc a new pdu big enough to also hold the new
1344 			 * pdu payload
1345 			 */
1346 			combined_pdu_size += in_pdu->payload_len;
1347 			combined_pdu = (isns_pdu_mult_payload_t *)kmem_zalloc(
1348 			    combined_pdu_size, KM_SLEEP);
1349 
1350 			/*
1351 			 * copy the old pdu into the new allocated pdu buffer
1352 			 * and append on the new pdu payload that we just
1353 			 * received
1354 			 */
1355 			bcopy(old_combined_pdu, combined_pdu,
1356 			    old_combined_pdu_size);
1357 
1358 			payload_ptr = combined_pdu->payload +
1359 			    combined_pdu->payload_len;
1360 			combined_pdu->payload_len += in_pdu->payload_len;
1361 			bcopy(in_pdu->payload, payload_ptr,
1362 			    in_pdu->payload_len);
1363 
1364 			/* free in_pdu and old_combined_pdu */
1365 			kmem_free(in_pdu, in_pdu_size);
1366 			kmem_free(old_combined_pdu, old_combined_pdu_size);
1367 			in_pdu = NULL;
1368 			old_combined_pdu = NULL;
1369 		}
1370 		/*
1371 		 * check to see if this is the LAST pdu.
1372 		 * if it is, we can process it and move on
1373 		 * otherwise continue to wait for the next pdu
1374 		 */
1375 		if ((flags & ISNS_FLAG_LAST_PDU) == ISNS_FLAG_LAST_PDU) {
1376 			rsp_status =
1377 			    isns_process_dev_attr_qry_target_nodes_pdu(
1378 			    isns_server_addr,
1379 			    func_id,
1380 			    (isns_resp_t *)combined_pdu->payload,
1381 			    combined_pdu->payload_len,
1382 			    pg_list);
1383 			kmem_free(combined_pdu, combined_pdu_size);
1384 			combined_pdu = NULL;
1385 			break;
1386 		}
1387 	}
1388 	if (rsp_status != ISNS_RSP_SUCCESSFUL) {
1389 		qry_stat = isns_op_failed;
1390 	}
1391 
1392 	iscsi_net->close(so);
1393 
1394 	return (qry_stat);
1395 }
1396 
1397 /* ARGSUSED */
1398 static
1399 isns_status_t
1400 do_isns_dev_attr_query_one_node(iscsi_addr_t *isns_server_addr,
1401 	uint8_t *target_node_name,
1402 	uint8_t *source_node_name,
1403 	uint8_t *source_node_alias,
1404 	uint32_t source_node_type,
1405 	isns_portal_group_list_t **pg_list)
1406 {
1407 	int bytes_received;
1408 	int rcv_rsp_cnt;
1409 	int rsp_status;
1410 	isns_pdu_t *in_pdu, *out_pdu;
1411 	isns_status_t rval;
1412 	size_t out_pdu_size = 0, in_pdu_size = 0;
1413 	uint16_t xid;
1414 	void *so = NULL;
1415 
1416 	/* Obtain the list of target type storage nodes first */
1417 	out_pdu_size = isns_create_dev_attr_qry_one_pg_pdu(
1418 	    target_node_name, source_node_name, &xid, &out_pdu);
1419 	if (out_pdu_size == 0) {
1420 		return (isns_create_msg_err);
1421 	}
1422 
1423 	ASSERT(out_pdu != NULL);
1424 	ASSERT(out_pdu_size > 0);
1425 
1426 	so = isns_open(isns_server_addr);
1427 	if (so == NULL) {
1428 		/* Log a message and return */
1429 		kmem_free(out_pdu, out_pdu_size);
1430 		out_pdu = NULL;
1431 		return (isns_open_conn_err);
1432 	}
1433 
1434 	if (isns_send_pdu(so, out_pdu) != 0) {
1435 		iscsi_net->close(so);
1436 		kmem_free(out_pdu, out_pdu_size);
1437 		out_pdu = NULL;
1438 		return (isns_send_msg_err);
1439 	}
1440 
1441 	/* Done with the out PDU - free it */
1442 	kmem_free(out_pdu, out_pdu_size);
1443 	out_pdu = NULL;
1444 
1445 	rcv_rsp_cnt = 0;
1446 	rval = isns_ok;
1447 	for (;;) {
1448 		bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
1449 		ASSERT(bytes_received >= 0);
1450 		if (bytes_received == 0) {
1451 			ASSERT(in_pdu == NULL);
1452 			ASSERT(in_pdu_size == 0);
1453 			rval = isns_rcv_msg_err;
1454 			break;
1455 		}
1456 
1457 		ASSERT(in_pdu != NULL);
1458 		ASSERT(in_pdu_size > 0);
1459 
1460 		if (ntohs(in_pdu->xid) != xid) {
1461 			rcv_rsp_cnt++;
1462 			if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
1463 				continue;
1464 			} else {
1465 				/* Exceed maximum receive count. */
1466 				kmem_free(in_pdu, in_pdu_size);
1467 				in_pdu = NULL;
1468 				rval = isns_no_rsp_rcvd;
1469 				break;
1470 			}
1471 		}
1472 
1473 		rsp_status = isns_process_dev_attr_qry_target_nodes_pdu(
1474 		    isns_server_addr, in_pdu->func_id,
1475 		    (isns_resp_t *)in_pdu->payload, (size_t)in_pdu->payload_len,
1476 		    pg_list);
1477 		if (rsp_status != ISNS_RSP_SUCCESSFUL) {
1478 			rval = isns_op_failed;
1479 		}
1480 		kmem_free(in_pdu, in_pdu_size);
1481 		in_pdu = NULL;
1482 		break;
1483 	}
1484 
1485 	iscsi_net->close(so);
1486 
1487 	return (rval);
1488 }
1489 
1490 static
1491 void
1492 *isns_open(iscsi_addr_t *isns_server_addr)
1493 {
1494 	int rval = 0;
1495 	union {
1496 		struct sockaddr sin;
1497 		struct sockaddr_in s_in4;
1498 		struct sockaddr_in6 s_in6;
1499 	} sa_rsvr = { 0 };
1500 	void *so;
1501 	struct sockaddr_in6	t_addr;
1502 	socklen_t		t_addrlen;
1503 
1504 	bzero(&t_addr, sizeof (struct sockaddr_in6));
1505 	t_addrlen = sizeof (struct sockaddr_in6);
1506 	if (isns_server_addr->a_addr.i_insize == sizeof (struct in_addr)) {
1507 		/* IPv4 */
1508 		sa_rsvr.s_in4.sin_family = AF_INET;
1509 		sa_rsvr.s_in4.sin_port = htons(isns_server_addr->a_port);
1510 		sa_rsvr.s_in4.sin_addr.s_addr =
1511 		    isns_server_addr->a_addr.i_addr.in4.s_addr;
1512 
1513 		/* Create socket */
1514 		so = iscsi_net->socket(AF_INET, SOCK_STREAM, 0);
1515 	} else {
1516 		/* IPv6 */
1517 		sa_rsvr.s_in6.sin6_family = AF_INET6;
1518 		bcopy(&(isns_server_addr->a_addr.i_addr.in6),
1519 		    sa_rsvr.s_in6.sin6_addr.s6_addr,
1520 		    sizeof (struct in6_addr));
1521 		sa_rsvr.s_in6.sin6_port = htons(isns_server_addr->a_port);
1522 		/* Create socket */
1523 		so = iscsi_net->socket(AF_INET6, SOCK_STREAM, 0);
1524 	}
1525 
1526 	if (so == NULL) {
1527 		return (NULL);
1528 	}
1529 
1530 	rval = iscsi_net->connect(so, &sa_rsvr.sin,
1531 	    (isns_server_addr->a_addr.i_insize == sizeof (struct in_addr)) ?
1532 	    sizeof (struct sockaddr_in) :
1533 	    sizeof (struct sockaddr_in6), 0, 0);
1534 
1535 	if (rval != 0) {
1536 		/* Flag value 2 indicates both cantsend and cantrecv */
1537 		iscsi_net->shutdown(so, 2);
1538 		iscsi_net->close(so);
1539 		return (NULL);
1540 	}
1541 
1542 	(void) iscsi_net->getsockname(so, (struct sockaddr *)&t_addr,
1543 	    &t_addrlen);
1544 
1545 	return (so);
1546 }
1547 
1548 static ssize_t
1549 isns_send_pdu(void *socket, isns_pdu_t *pdu)
1550 {
1551 	int		iovlen = 0;
1552 	iovec_t		iovec[ISNS_MAX_IOVEC];
1553 	struct msghdr	msg;
1554 	size_t		send_len;
1555 	size_t		total_len = 0;
1556 
1557 	ASSERT(iovlen < ISNS_MAX_IOVEC);
1558 	iovec[iovlen].iov_base = (void *)pdu;
1559 	iovec[iovlen].iov_len = (ISNSP_HEADER_SIZE);
1560 	total_len += (ISNSP_HEADER_SIZE);
1561 	iovlen++;
1562 
1563 	ASSERT(iovlen < ISNS_MAX_IOVEC);
1564 	iovec[iovlen].iov_base = (void *)pdu->payload;
1565 	iovec[iovlen].iov_len = ntohs(pdu->payload_len);
1566 	total_len += ntohs(pdu->payload_len);
1567 	iovlen++;
1568 
1569 	/* Initialization of the message header. */
1570 	bzero(&msg, sizeof (msg));
1571 	msg.msg_iov = &iovec[0];
1572 	msg.msg_flags   = MSG_WAITALL;
1573 	msg.msg_iovlen  = iovlen;
1574 
1575 	send_len = iscsi_net->sendmsg(socket, &msg);
1576 	return (send_len == total_len ? 0 : -1);
1577 }
1578 
1579 static
1580 size_t
1581 isns_rcv_pdu(void *socket, isns_pdu_t **pdu, size_t *pdu_size)
1582 {
1583 	int poll_cnt;
1584 	iovec_t iovec[ISNS_MAX_IOVEC];
1585 	isns_pdu_t *tmp_pdu_hdr;
1586 	size_t bytes_received, total_bytes_received = 0, payload_len = 0;
1587 	struct msghdr msg;
1588 	uint8_t *tmp_pdu_data;
1589 
1590 	/* Receive the header first */
1591 	tmp_pdu_hdr = (isns_pdu_t *)kmem_zalloc(ISNSP_HEADER_SIZE, KM_SLEEP);
1592 	(void) memset((char *)&iovec[0], 0, sizeof (iovec_t));
1593 	iovec[0].iov_base = (void *)tmp_pdu_hdr;
1594 	iovec[0].iov_len = ISNSP_HEADER_SIZE;
1595 
1596 	/* Initialization of the message header. */
1597 	bzero(&msg, sizeof (msg));
1598 	msg.msg_iov = &iovec[0];
1599 	msg.msg_flags = MSG_WAITALL;
1600 	msg.msg_iovlen = 1;
1601 
1602 	/* Poll and receive the packets. */
1603 	poll_cnt = 0;
1604 	do {
1605 		bytes_received = iscsi_net->recvmsg(socket, &msg,
1606 		    ISNS_RCV_TIMEOUT);
1607 		if (bytes_received == 0) {
1608 			/* Not yet. Increase poll count and try again. */
1609 			poll_cnt++;
1610 			continue;
1611 		} else {
1612 			/* OK data received. */
1613 			break;
1614 		}
1615 	} while (poll_cnt < ISNS_RCV_RETRY_MAX);
1616 
1617 	DTRACE_PROBE2(isns_rcv_pdu_hdr_summary,
1618 	    int, poll_cnt, int, bytes_received);
1619 	if (poll_cnt >= ISNS_RCV_RETRY_MAX) {
1620 		kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1621 		*pdu = NULL;
1622 		*pdu_size = 0;
1623 		return (0);
1624 	}
1625 	if (bytes_received == 0 || bytes_received != ISNSP_HEADER_SIZE) {
1626 		kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1627 		*pdu = NULL;
1628 		*pdu_size = 0;
1629 		return (0);
1630 	}
1631 	total_bytes_received += bytes_received;
1632 
1633 	payload_len = ntohs(tmp_pdu_hdr->payload_len);
1634 	DTRACE_PROBE1(isns_rcv_pdu_probe1, int, payload_len);
1635 	/* Verify the received payload len is within limit */
1636 	if (payload_len > ISNSP_MAX_PAYLOAD_SIZE) {
1637 		kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1638 		*pdu = NULL;
1639 		*pdu_size = 0;
1640 		return (0);
1641 	}
1642 
1643 	/* Proceed to receive additional data. */
1644 	tmp_pdu_data = kmem_zalloc(payload_len, KM_SLEEP);
1645 	(void) memset((char *)&iovec[0], 0, sizeof (iovec_t));
1646 	iovec[0].iov_base = (void *)tmp_pdu_data;
1647 	iovec[0].iov_len = payload_len;
1648 
1649 	/* Initialization of the message header. */
1650 	bzero(&msg, sizeof (msg));
1651 	msg.msg_iov = &iovec[0];
1652 	msg.msg_flags   = MSG_WAITALL;
1653 	msg.msg_iovlen  = 1;
1654 
1655 	/* Poll and receive the rest of the PDU. */
1656 	poll_cnt = 0;
1657 	do {
1658 		bytes_received = iscsi_net->recvmsg(socket, &msg,
1659 		    ISNS_RCV_TIMEOUT);
1660 		if (bytes_received == 0) {
1661 			/* Not yet. Increase poll count and try again. */
1662 			poll_cnt++;
1663 			continue;
1664 		} else {
1665 			/* OK data received. */
1666 			break;
1667 		}
1668 	} while (poll_cnt < ISNS_RCV_RETRY_MAX);
1669 
1670 	DTRACE_PROBE2(isns_rcv_pdu_data_summary,
1671 	    int, poll_cnt, int, bytes_received);
1672 
1673 	if (poll_cnt >= ISNS_RCV_RETRY_MAX) {
1674 		kmem_free(tmp_pdu_data, payload_len);
1675 		kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1676 		*pdu = NULL;
1677 		*pdu_size = 0;
1678 		return (0);
1679 	}
1680 	if (bytes_received == 0 || bytes_received != payload_len) {
1681 		kmem_free(tmp_pdu_data, payload_len);
1682 		kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1683 		*pdu = NULL;
1684 		*pdu_size = 0;
1685 		return (0);
1686 	}
1687 	total_bytes_received += bytes_received;
1688 
1689 	*pdu_size = ISNSP_HEADER_SIZE + payload_len;
1690 	(*pdu) = (isns_pdu_t *)kmem_zalloc((*pdu_size), KM_SLEEP);
1691 	(*pdu)->version = ntohs(tmp_pdu_hdr->version);
1692 	(*pdu)->func_id = ntohs(tmp_pdu_hdr->func_id);
1693 	(*pdu)->payload_len = payload_len;
1694 	(*pdu)->flags = ntohs(tmp_pdu_hdr->flags);
1695 	(*pdu)->xid = ntohs(tmp_pdu_hdr->xid);
1696 	(*pdu)->seq = ntohs(tmp_pdu_hdr->seq);
1697 	bcopy(tmp_pdu_data, &((*pdu)->payload), payload_len);
1698 
1699 	kmem_free(tmp_pdu_data, payload_len);
1700 	tmp_pdu_data = NULL;
1701 	kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1702 	tmp_pdu_hdr = NULL;
1703 
1704 	return (total_bytes_received);
1705 }
1706 
1707 
1708 /*
1709  * isns_create_dev_attr_reg_pdu - isns client registration pdu
1710  */
1711 static size_t
1712 isns_create_dev_attr_reg_pdu(
1713 	uint8_t *node_name,
1714 	uint8_t *node_alias,
1715 	uint32_t node_type,
1716 	uint16_t *xid_p,
1717 	isns_pdu_t **out_pdu)
1718 {
1719 	in_port_t local_port;
1720 	isns_pdu_t *pdu;
1721 	size_t pdu_size, node_name_len, node_alias_len;
1722 	uint16_t flags;
1723 	boolean_t	rval	    = B_FALSE;
1724 	iscsi_addr_t	local_addr;
1725 
1726 	ASSERT(node_name != NULL);
1727 	ASSERT(node_alias != NULL);
1728 
1729 	/* RFC 4171 section 6.1 - NULLs included in the length. */
1730 	node_name_len = strlen((char *)node_name) + 1;
1731 	node_alias_len = strlen((char *)node_alias) + 1;
1732 
1733 	if (node_name_len == 1) {
1734 		*out_pdu = NULL;
1735 		return (0);
1736 	}
1737 
1738 	/*
1739 	 * Create DevAttrReg Message
1740 	 *
1741 	 * Enable the replace bit so that we can update
1742 	 * existing registration
1743 	 */
1744 	flags = ISNS_FLAG_FIRST_PDU |
1745 	    ISNS_FLAG_LAST_PDU |
1746 	    ISNS_FLAG_REPLACE_REG;
1747 	pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_REG, flags, &pdu);
1748 	*xid_p = pdu->xid;
1749 
1750 	/* Source attribute */
1751 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1752 	    node_name_len, node_name, 0) != 0) {
1753 		kmem_free(pdu, pdu_size);
1754 		*out_pdu = NULL;
1755 		return (0);
1756 	}
1757 
1758 	/*
1759 	 * Message Key Attributes
1760 	 *
1761 	 * EID attribute - Section 6.2.1
1762 	 * This is required for re-registrations or Replace
1763 	 * Bit is ignored - Section 5.6.5.1
1764 	 */
1765 	if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID,
1766 	    node_name_len, node_name, 0) != 0) {
1767 		kmem_free(pdu, pdu_size);
1768 		*out_pdu = NULL;
1769 		return (0);
1770 	}
1771 
1772 	/* Delimiter */
1773 	if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
1774 	    != 0) {
1775 		kmem_free(pdu, pdu_size);
1776 		*out_pdu = NULL;
1777 		return (0);
1778 	}
1779 
1780 	/* EID attribute - Section 6.2.1 */
1781 	if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID,
1782 	    node_name_len, node_name, 0) != 0) {
1783 		kmem_free(pdu, pdu_size);
1784 		*out_pdu = NULL;
1785 		return (0);
1786 	}
1787 
1788 	/* ENTITY Protocol - Section 6.2.2 */
1789 	if (isns_add_attr(pdu, pdu_size, ISNS_ENTITY_PROTOCOL_ATTR_ID, 4,
1790 	    0, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) {
1791 		kmem_free(pdu, pdu_size);
1792 		*out_pdu = NULL;
1793 		return (0);
1794 	}
1795 
1796 	/* iSCSI Name - Section 6.4.1 */
1797 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1798 	    node_name_len, node_name, 0) != 0) {
1799 		kmem_free(pdu, pdu_size);
1800 		*out_pdu = NULL;
1801 		return (0);
1802 	}
1803 
1804 	/* iSCSI Alias - Section 6.4.3 Optional */
1805 	if (node_alias_len > 1) {
1806 		if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_ALIAS_ATTR_ID,
1807 		    node_alias_len, node_alias, 0) != 0) {
1808 			kmem_free(pdu, pdu_size);
1809 			*out_pdu = NULL;
1810 			return (0);
1811 		}
1812 	}
1813 
1814 	/* iSCSI Node Type - Section 6.4.2 */
1815 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NODE_TYPE_ATTR_ID, 4,
1816 	    0, node_type) != 0) {
1817 		kmem_free(pdu, pdu_size);
1818 		*out_pdu = NULL;
1819 		return (0);
1820 	}
1821 
1822 	mutex_enter(&esi_scn_thr_mutex);
1823 	if (instance_listening_so != NULL) {
1824 		rval = find_listening_addr(&local_addr, instance_listening_so);
1825 		if (rval == B_FALSE) {
1826 			kmem_free(pdu, pdu_size);
1827 			*out_pdu = NULL;
1828 			mutex_exit(&esi_scn_thr_mutex);
1829 			return (0);
1830 		}
1831 	} else {
1832 		kmem_free(pdu, pdu_size);
1833 		*out_pdu = NULL;
1834 		mutex_exit(&esi_scn_thr_mutex);
1835 		return (0);
1836 	}
1837 	local_port = local_addr.a_port;
1838 	/* Portal IP Address - Section 6.5.2 */
1839 	if (isns_add_attr(pdu, pdu_size, ISNS_PORTAL_IP_ADDR_ATTR_ID, 16,
1840 	    &(local_addr.a_addr.i_addr.in4),
1841 	    local_addr.a_addr.i_insize) != 0) {
1842 		kmem_free(pdu, pdu_size);
1843 		*out_pdu = NULL;
1844 		mutex_exit(&esi_scn_thr_mutex);
1845 		return (0);
1846 	}
1847 	mutex_exit(&esi_scn_thr_mutex);
1848 
1849 	/* Portal Port  - Section 6.5.3 */
1850 	if (isns_add_attr(pdu, pdu_size, ISNS_PORTAL_PORT_ATTR_ID, 4, 0,
1851 	    local_port) != 0) {
1852 		kmem_free(pdu, pdu_size);
1853 		*out_pdu = NULL;
1854 		return (0);
1855 	}
1856 
1857 	/* SCN Port  - Section 6.3.7 */
1858 	if (isns_add_attr(pdu, pdu_size, ISNS_SCN_PORT_ATTR_ID, 4, 0,
1859 	    local_port) != 0) {
1860 		kmem_free(pdu, pdu_size);
1861 		*out_pdu = NULL;
1862 		return (0);
1863 	}
1864 
1865 	/* ESI Port - Section 6.3.5 */
1866 	if (isns_add_attr(pdu, pdu_size, ISNS_ESI_PORT_ATTR_ID, 4, 0,
1867 	    local_port) != 0) {
1868 		kmem_free(pdu, pdu_size);
1869 		*out_pdu = NULL;
1870 		return (0);
1871 	}
1872 
1873 	*out_pdu = pdu;
1874 	return (pdu_size);
1875 }
1876 
1877 /*
1878  * isns_create_dev_dereg_pdu - Create an iSNS PDU for deregistration.
1879  */
1880 static size_t
1881 isns_create_dev_dereg_pdu(
1882 	uint8_t *node_name,
1883 	uint16_t *xid_p,
1884 	isns_pdu_t **out_pdu)
1885 {
1886 	isns_pdu_t *pdu;
1887 	size_t pdu_size, node_name_len;
1888 	uint16_t flags;
1889 
1890 	ASSERT(node_name != NULL);
1891 
1892 	/* RFC 4171 section 6.1 - NULLs included in the length. */
1893 	node_name_len = strlen((char *)node_name) + 1;
1894 
1895 	if (node_name_len == 1) {
1896 		*out_pdu = NULL;
1897 		return (0);
1898 	}
1899 
1900 	/*
1901 	 * Create DevDeReg Message
1902 	 */
1903 	flags = ISNS_FLAG_FIRST_PDU |
1904 	    ISNS_FLAG_LAST_PDU;
1905 	pdu_size = isns_create_pdu_header(ISNS_DEV_DEREG, flags, &pdu);
1906 	*xid_p = pdu->xid;
1907 
1908 	/* Source attribute */
1909 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1910 	    node_name_len, node_name, 0) != 0) {
1911 		kmem_free(pdu, pdu_size);
1912 		*out_pdu = NULL;
1913 		return (0);
1914 	}
1915 
1916 	/* Delimiter */
1917 	if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
1918 	    != 0) {
1919 		kmem_free(pdu, pdu_size);
1920 		*out_pdu = NULL;
1921 		return (0);
1922 	}
1923 
1924 	/* Entity Identifier */
1925 	if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID,
1926 	    node_name_len, node_name, 0) != 0) {
1927 		kmem_free(pdu, pdu_size);
1928 		*out_pdu = NULL;
1929 		return (0);
1930 	}
1931 
1932 	*out_pdu = pdu;
1933 	return (pdu_size);
1934 }
1935 
1936 /*
1937  * isns_create_dev_attr_target_nodes_pdu - get all accessible targets
1938  *
1939  * Querys for a list of all accessible target nodes for this
1940  * initiator.  Requests all required login information (name,
1941  * ip, port, tpgt).
1942  */
1943 static size_t
1944 isns_create_dev_attr_qry_target_nodes_pdu(
1945 	uint8_t *node_name,
1946 	uint8_t *node_alias,
1947 	uint16_t *xid_p, isns_pdu_t **out_pdu)
1948 {
1949 	isns_pdu_t *pdu_p;
1950 	uint16_t flags;
1951 	size_t pdu_size, node_name_len;
1952 
1953 	ASSERT(node_name != NULL);
1954 	ASSERT(node_alias != NULL);
1955 
1956 	/* RFC 4171 section 6.1 - NULLs included in the length. */
1957 	node_name_len = strlen((char *)node_name) + 1;
1958 
1959 	if (node_name_len == 1) {
1960 		*out_pdu = NULL;
1961 		return (0);
1962 	}
1963 
1964 	/* Create DevAttrQry Message */
1965 	flags = ISNS_FLAG_FIRST_PDU |
1966 	    ISNS_FLAG_LAST_PDU;
1967 	pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_QRY, flags, &pdu_p);
1968 	*xid_p = pdu_p->xid;
1969 
1970 	/* Source attribute */
1971 	if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1972 	    node_name_len, node_name, 0) != 0) {
1973 		kmem_free(pdu_p, pdu_size);
1974 		*out_pdu = NULL;
1975 		return (0);
1976 	}
1977 
1978 	/*
1979 	 * Message Key Attribute
1980 	 *
1981 	 * iSCSI Node Type
1982 	 * Query target nodes only
1983 	 */
1984 	if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NODE_TYPE_ATTR_ID,
1985 	    4, 0, ISNS_TARGET_NODE_TYPE) != 0) {
1986 		kmem_free(pdu_p, pdu_size);
1987 		*out_pdu = NULL;
1988 		return (0);
1989 	}
1990 
1991 	/* Delimiter */
1992 	if (isns_add_attr(pdu_p, pdu_size,
1993 	    ISNS_DELIMITER_ATTR_ID, 0, 0, 0) != 0) {
1994 		kmem_free(pdu_p, pdu_size);
1995 		*out_pdu = NULL;
1996 		return (0);
1997 	}
1998 
1999 	/* PG iSCSI Name - Zero length TLV */
2000 	if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_ISCSI_NAME_ATTR_ID,
2001 	    0, 0, 0) != 0) {
2002 		kmem_free(pdu_p, pdu_size);
2003 		*out_pdu = NULL;
2004 		return (0);
2005 	}
2006 
2007 	/* PG Portal IP Address - Zero length TLV */
2008 	if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
2009 	    0, 0, 0) != 0) {
2010 		kmem_free(pdu_p, pdu_size);
2011 		*out_pdu = NULL;
2012 		return (0);
2013 	}
2014 
2015 	/* PG Portal Port - Zero length TLV */
2016 	if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_PORT_ATTR_ID,
2017 	    0, 0, 0) != 0) {
2018 		kmem_free(pdu_p, pdu_size);
2019 		*out_pdu = NULL;
2020 		return (0);
2021 	}
2022 
2023 	/* PG Portal Group Tag - Zero length TLV */
2024 	if (isns_add_attr(pdu_p, pdu_size,
2025 	    ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) {
2026 		kmem_free(pdu_p, pdu_size);
2027 		*out_pdu = NULL;
2028 		return (0);
2029 	}
2030 
2031 	*out_pdu = pdu_p;
2032 	return (pdu_size);
2033 }
2034 
2035 static
2036 size_t
2037 isns_create_dev_attr_qry_one_pg_pdu(
2038 	uint8_t *target_node_name,
2039 	uint8_t *source_node_name,
2040 	uint16_t *xid_p,
2041 	isns_pdu_t **out_pdu)
2042 {
2043 	isns_pdu_t *pdu_p;
2044 	uint16_t flags;
2045 	size_t pdu_size, source_node_name_len, target_node_name_len;
2046 
2047 	ASSERT(target_node_name != NULL);
2048 	ASSERT(source_node_name != NULL);
2049 
2050 	/* RFC 4171 section 6.1 - NULLs included in the length. */
2051 	source_node_name_len = strlen((char *)source_node_name) + 1;
2052 	target_node_name_len = strlen((char *)target_node_name) + 1;
2053 
2054 	if (source_node_name_len == 1) {
2055 		*out_pdu = NULL;
2056 		return (0);
2057 	}
2058 
2059 	/* Create DevAttrQry message scoped to target_node_name */
2060 	flags = ISNS_FLAG_FIRST_PDU |
2061 	    ISNS_FLAG_LAST_PDU;
2062 	pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_QRY, flags, &pdu_p);
2063 	*xid_p = pdu_p->xid;
2064 
2065 	/* Source attribute */
2066 	if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2067 	    source_node_name_len, source_node_name, 0) != 0) {
2068 		kmem_free(pdu_p, pdu_size);
2069 		*out_pdu = NULL;
2070 		return (0);
2071 	}
2072 
2073 	/* Message key attribute */
2074 	/* iSCSI Node Name */
2075 	if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2076 	    target_node_name_len,
2077 	    target_node_name, 0) != 0) {
2078 		kmem_free(pdu_p, pdu_size);
2079 		*out_pdu = NULL;
2080 		return (0);
2081 	}
2082 
2083 	/* Delimiter */
2084 	if (isns_add_attr(pdu_p, pdu_size,
2085 	    ISNS_DELIMITER_ATTR_ID, 0, 0, 0) != 0) {
2086 		kmem_free(pdu_p, pdu_size);
2087 		*out_pdu = NULL;
2088 		return (0);
2089 	}
2090 
2091 	/* PG iSCSI Name - Zero length TLV */
2092 	if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_ISCSI_NAME_ATTR_ID,
2093 	    0, 0, 0) != 0) {
2094 		kmem_free(pdu_p, pdu_size);
2095 		*out_pdu = NULL;
2096 		return (0);
2097 	}
2098 
2099 	/* PG Portal IP Address - Zero length TLV */
2100 	if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
2101 	    0, 0, 0) != 0) {
2102 		kmem_free(pdu_p, pdu_size);
2103 		*out_pdu = NULL;
2104 		return (0);
2105 	}
2106 
2107 	/* PG Portal Port - Zero length TLV */
2108 	if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_PORT_ATTR_ID,
2109 	    0, 0, 0) != 0) {
2110 		kmem_free(pdu_p, pdu_size);
2111 		*out_pdu = NULL;
2112 		return (0);
2113 	}
2114 
2115 	/* PG Portal Group Tag - Zero length TLV */
2116 	if (isns_add_attr(pdu_p, pdu_size,
2117 	    ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) {
2118 		kmem_free(pdu_p, pdu_size);
2119 		*out_pdu = NULL;
2120 		return (0);
2121 	}
2122 
2123 	*out_pdu = pdu_p;
2124 	return (pdu_size);
2125 }
2126 
2127 static
2128 size_t
2129 isns_create_scn_reg_pdu(
2130 	uint8_t *node_name,
2131 	uint8_t *node_alias,
2132 	uint16_t *xid_p,
2133 	isns_pdu_t **out_pdu)
2134 {
2135 	isns_pdu_t *pdu;
2136 	size_t pdu_size, node_name_len;
2137 	uint16_t flags;
2138 
2139 	ASSERT(node_name != NULL);
2140 	ASSERT(node_alias != NULL);
2141 
2142 	/* RFC 4171 section 6.1 - NULLs included in the length. */
2143 	node_name_len = strlen((char *)node_name) + 1;
2144 
2145 	if (node_name_len == 1) {
2146 		*out_pdu = NULL;
2147 		return (0);
2148 	}
2149 
2150 	/* Create SCNReg Message */
2151 	flags = ISNS_FLAG_FIRST_PDU |
2152 	    ISNS_FLAG_LAST_PDU;
2153 	pdu_size = isns_create_pdu_header(ISNS_SCN_REG, flags, &pdu);
2154 	*xid_p = pdu->xid;
2155 
2156 	/* Source attribute */
2157 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2158 	    node_name_len, node_name, 0) != 0) {
2159 		kmem_free(pdu, pdu_size);
2160 		*out_pdu = NULL;
2161 		return (0);
2162 	}
2163 
2164 	/* Message attribute */
2165 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2166 	    node_name_len, node_name, 0) != 0) {
2167 		kmem_free(pdu, pdu_size);
2168 		*out_pdu = NULL;
2169 		return (0);
2170 	}
2171 
2172 	/* Delimiter */
2173 	if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
2174 	    != 0) {
2175 		kmem_free(pdu, pdu_size);
2176 		*out_pdu = NULL;
2177 		return (0);
2178 	}
2179 
2180 	/* Operating attribute */
2181 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_SCN_BITMAP_ATTR_ID,
2182 	    4,
2183 	    0,
2184 	/*
2185 	 * Microsoft seems to not differentiate between init and
2186 	 * target. Hence, it makes no difference to turn on/off
2187 	 * the initiator/target bit.
2188 	 */
2189 	    ISNS_TARGET_SELF_INFO_ONLY |
2190 	    ISNS_OBJ_REMOVED |
2191 	    ISNS_OBJ_ADDED |
2192 	    ISNS_OBJ_UPDATED) != 0) {
2193 		kmem_free(pdu, pdu_size);
2194 		*out_pdu = NULL;
2195 		return (0);
2196 	}
2197 
2198 	*out_pdu = pdu;
2199 	return (pdu_size);
2200 }
2201 
2202 static
2203 size_t
2204 isns_create_scn_dereg_pdu(
2205 	uint8_t *node_name,
2206 	uint16_t *xid_p,
2207 	isns_pdu_t **out_pdu)
2208 {
2209 	isns_pdu_t *pdu;
2210 	size_t pdu_size, node_name_len;
2211 	uint16_t flags;
2212 
2213 	ASSERT(node_name != NULL);
2214 
2215 	/* RFC 4171 section 6.1 - NULLs included in the length. */
2216 	node_name_len = strlen((char *)node_name) + 1;
2217 
2218 	if (node_name_len == 1) {
2219 		*out_pdu = NULL;
2220 		return (0);
2221 	}
2222 
2223 	/* Create SCNReg Message */
2224 	flags = ISNS_FLAG_FIRST_PDU |
2225 	    ISNS_FLAG_LAST_PDU;
2226 	pdu_size = isns_create_pdu_header(ISNS_SCN_DEREG, flags, &pdu);
2227 	*xid_p = pdu->xid;
2228 
2229 	/* Source attribute */
2230 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2231 	    node_name_len, node_name, 0) != 0) {
2232 		kmem_free(pdu, pdu_size);
2233 		*out_pdu = NULL;
2234 		return (0);
2235 	}
2236 
2237 	/* Message attribute */
2238 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2239 	    node_name_len, node_name, 0) != 0) {
2240 		kmem_free(pdu, pdu_size);
2241 		*out_pdu = NULL;
2242 		return (0);
2243 	}
2244 
2245 	/* Delimiter */
2246 	if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
2247 	    != 0) {
2248 		kmem_free(pdu, pdu_size);
2249 		*out_pdu = NULL;
2250 		return (0);
2251 	}
2252 
2253 	/* No operating attribute */
2254 
2255 	*out_pdu = pdu;
2256 	return (pdu_size);
2257 }
2258 
2259 static
2260 size_t
2261 isns_create_esi_rsp_pdu(uint32_t rsp_status_code,
2262 	isns_pdu_t *esi_pdu,
2263 	uint16_t *xid_p,
2264 	isns_pdu_t **out_pdu)
2265 {
2266 	isns_pdu_t *pdu_p;
2267 	uint16_t flags;
2268 	uint8_t *payload_ptr;
2269 	uint32_t swapped_status_code = htonl(rsp_status_code);
2270 	size_t pdu_size, payload_len = 0;
2271 
2272 	/* Create ESIRsp Message */
2273 	flags = ISNS_FLAG_FIRST_PDU |
2274 	    ISNS_FLAG_LAST_PDU;
2275 	pdu_size = isns_create_pdu_header(ISNS_ESI_RSP, flags, &pdu_p);
2276 	*xid_p = pdu_p->xid;
2277 
2278 	payload_len = ntohs(pdu_p->payload_len);
2279 
2280 	/* Status Code */
2281 	payload_ptr = pdu_p->payload + payload_len;
2282 	bcopy(&swapped_status_code, payload_ptr, 4);
2283 	payload_len += 4;
2284 
2285 	payload_ptr = pdu_p->payload + payload_len;
2286 	if ((esi_pdu->payload_len) < ISNSP_MAX_PAYLOAD_SIZE) {
2287 		bcopy(esi_pdu->payload, payload_ptr,
2288 		    (esi_pdu->payload_len));
2289 		payload_len += (esi_pdu->payload_len);
2290 	} else {
2291 		bcopy(esi_pdu->payload, payload_ptr, ISNSP_MAX_PAYLOAD_SIZE);
2292 		payload_len += ISNSP_MAX_PAYLOAD_SIZE;
2293 	}
2294 	pdu_p->payload_len = htons(payload_len);
2295 
2296 	/* Delimiter */
2297 	if (isns_add_attr(pdu_p, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
2298 	    != 0) {
2299 		kmem_free(pdu_p, pdu_size);
2300 		*out_pdu = NULL;
2301 		return (0);
2302 	}
2303 
2304 	*out_pdu = pdu_p;
2305 	return (pdu_size);
2306 }
2307 
2308 static
2309 size_t
2310 isns_create_scn_rsp_pdu(uint32_t rsp_status_code,
2311 	isns_pdu_t *scn_pdu,
2312 	uint16_t *xid_p,
2313 	isns_pdu_t **out_pdu)
2314 {
2315 	isns_pdu_t *pdu_p;
2316 	uint16_t flags;
2317 	uint8_t *payload_ptr;
2318 	uint32_t swapped_status_code = htonl(rsp_status_code);
2319 	size_t pdu_size, payload_len = 0;
2320 
2321 	/* Create SCNRsp Message */
2322 	flags = ISNS_FLAG_FIRST_PDU |
2323 	    ISNS_FLAG_LAST_PDU;
2324 	pdu_size = isns_create_pdu_header(ISNS_SCN_RSP, flags, &pdu_p);
2325 	*xid_p = pdu_p->xid;
2326 
2327 	payload_len = ntohs(pdu_p->payload_len);
2328 
2329 	/* Status Code */
2330 	payload_ptr = pdu_p->payload + payload_len;
2331 	bcopy(&swapped_status_code, payload_ptr, 4);
2332 	payload_len += 4;
2333 
2334 	payload_ptr = pdu_p->payload + payload_len;
2335 	if ((scn_pdu->payload_len) < ISNSP_MAX_PAYLOAD_SIZE) {
2336 		bcopy(scn_pdu->payload, payload_ptr,
2337 		    (scn_pdu->payload_len));
2338 		payload_len += (scn_pdu->payload_len);
2339 	} else {
2340 		bcopy(scn_pdu->payload, payload_ptr, ISNSP_MAX_PAYLOAD_SIZE);
2341 		payload_len += ISNSP_MAX_PAYLOAD_SIZE;
2342 	}
2343 	pdu_p->payload_len = htons(payload_len);
2344 
2345 	/* Delimiter */
2346 	if (isns_add_attr(pdu_p, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
2347 	    != 0) {
2348 		kmem_free(pdu_p, pdu_size);
2349 		*out_pdu = NULL;
2350 		return (0);
2351 	}
2352 
2353 	*out_pdu = pdu_p;
2354 	return (pdu_size);
2355 }
2356 
2357 static
2358 uint32_t
2359 isns_process_dev_attr_reg_rsp(isns_pdu_t *resp_pdu_p)
2360 {
2361 	isns_resp_t *resp_p;
2362 
2363 	if (resp_pdu_p->func_id != ISNS_DEV_ATTR_REG_RSP) {
2364 		/* If this happens the iSNS server may have a problem. */
2365 		return (ISNS_RSP_MSG_FORMAT_ERROR);
2366 	}
2367 
2368 	/* Check response's status code */
2369 	resp_p = (isns_resp_t *)resp_pdu_p->payload;
2370 	if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2371 		return (ntohl(resp_p->status));
2372 	}
2373 
2374 	return (ISNS_RSP_SUCCESSFUL);
2375 }
2376 
2377 static
2378 uint32_t
2379 isns_process_dev_attr_dereg_rsp(isns_pdu_t *resp_pdu_p)
2380 {
2381 	isns_resp_t *resp_p;
2382 
2383 	if (resp_pdu_p->func_id != ISNS_DEV_DEREG_RSP) {
2384 		/* If this happens the iSNS server may have a problem. */
2385 		return (ISNS_RSP_MSG_FORMAT_ERROR);
2386 	}
2387 
2388 	/* Check response's status code */
2389 	resp_p = (isns_resp_t *)resp_pdu_p->payload;
2390 	if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2391 		return (ntohl(resp_p->status));
2392 	}
2393 
2394 	return (ISNS_RSP_SUCCESSFUL);
2395 }
2396 
2397 static
2398 uint32_t
2399 isns_process_scn_reg_rsp(isns_pdu_t *resp_pdu_p)
2400 {
2401 	isns_resp_t *resp_p;
2402 
2403 	ASSERT(resp_pdu_p != NULL);
2404 	if (resp_pdu_p->func_id != ISNS_SCN_REG_RSP) {
2405 		/* If this happens the iSNS server may have a problem. */
2406 		return (ISNS_RSP_MSG_FORMAT_ERROR);
2407 	}
2408 
2409 	/* Check response's status code */
2410 	resp_p = (isns_resp_t *)resp_pdu_p->payload;
2411 	if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2412 		return (ntohl(resp_p->status));
2413 	}
2414 	return (ISNS_RSP_SUCCESSFUL);
2415 }
2416 
2417 static
2418 uint32_t
2419 isns_process_scn_dereg_rsp(isns_pdu_t *resp_pdu_p)
2420 {
2421 	isns_resp_t *resp_p;
2422 
2423 	ASSERT(resp_pdu_p != NULL);
2424 	if (resp_pdu_p->func_id != ISNS_SCN_DEREG_RSP) {
2425 		/* If this happens the iSNS server may have a problem. */
2426 		return (ISNS_RSP_MSG_FORMAT_ERROR);
2427 	}
2428 
2429 	/* Check response's status code */
2430 	resp_p = (isns_resp_t *)resp_pdu_p->payload;
2431 	if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2432 		return (ntohl(resp_p->status));
2433 	}
2434 	return (ISNS_RSP_SUCCESSFUL);
2435 }
2436 
2437 static
2438 uint32_t
2439 isns_process_dev_attr_qry_target_nodes_pdu(
2440 	iscsi_addr_t *isns_server_addr, uint16_t payload_funcId,
2441 	isns_resp_t *resp_p, size_t resp_len,
2442 	isns_portal_group_list_t **pg_list)
2443 {
2444 	boolean_t done_b, found_delimiter_b, target_node_type_b;
2445 	int num_of_pgs = 0, pg_sz, idx;
2446 	isns_tlv_t *attr_tlv_p;
2447 	uint8_t *data_p;
2448 	uint32_t len, total_payload_len = 0;
2449 	isns_portal_group_t *pg;
2450 	uint8_t	junk[IPV4_RSVD_BYTES];
2451 
2452 	*pg_list = NULL;
2453 	bzero(junk, IPV4_RSVD_BYTES);
2454 
2455 	if (payload_funcId != ISNS_DEV_ATTR_QRY_RSP) {
2456 		/* If this happens the iSNS server may have a problem. */
2457 		return (ISNS_RSP_MSG_FORMAT_ERROR);
2458 	}
2459 
2460 	if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2461 		return (ntohl(resp_p->status));
2462 	}
2463 
2464 	/*
2465 	 * If payload is smaller than the length of even 1 attribute
2466 	 * there is something wrong with the PDU.
2467 	 */
2468 	if (resp_len < (ISNS_TLV_ATTR_ID_LEN +
2469 	    ISNS_TLV_ATTR_LEN_LEN)) {
2470 		return (ISNS_RSP_MSG_FORMAT_ERROR);
2471 	}
2472 
2473 	/*
2474 	 * Expected DevAttrQryRsp message format:
2475 	 *
2476 	 * Status Code
2477 	 * iSCSI Node Type
2478 	 * Delimiter
2479 	 * PG iSCSI Name		[Optional]
2480 	 * PG Portal IP Address		[Optional]
2481 	 * PG Portal Port		[Optional]
2482 	 * PG Tag			[Optional]
2483 	 * PG iSCSI Name		[Optional]
2484 	 * PG Portal IP Address		[Optional]
2485 	 * PG Portal Port		[Optional]
2486 	 * PG Tag			[Optional]
2487 	 * .
2488 	 * .
2489 	 * .
2490 	 */
2491 	data_p = resp_p->data;
2492 	done_b = B_FALSE;
2493 	found_delimiter_b = B_FALSE;
2494 	num_of_pgs = 0;
2495 	total_payload_len = sizeof (resp_p->status);
2496 	/* Find out the number of entries retrieved */
2497 	while (!done_b) {
2498 		attr_tlv_p = (isns_tlv_t *)data_p;
2499 		if (ntohl(attr_tlv_p->attr_id) == ISNS_DELIMITER_ATTR_ID) {
2500 			if (found_delimiter_b) {
2501 				done_b = B_TRUE;
2502 			} else {
2503 				found_delimiter_b = B_TRUE;
2504 			}
2505 		} else if (ntohl(attr_tlv_p->attr_id) ==
2506 		    ISNS_PG_TAG_ATTR_ID) {
2507 			if (ntohl(attr_tlv_p->attr_len) > 0) {
2508 				/*
2509 				 * Count only those iSCSI node that have a
2510 				 * non-NULL PGT value as valid Entity.
2511 				 * Per rfc4171 section 3.4 - If the PGT value
2512 				 * registered for a specified Portal and iSCSI
2513 				 * Node is NULL, or if no PGT value is
2514 				 * registered, then the Portal does not provide
2515 				 * access to that iSCSI Node in the Entity.
2516 				 */
2517 				num_of_pgs++;
2518 			}
2519 		}
2520 		len = ntohl(attr_tlv_p->attr_len);
2521 
2522 		total_payload_len += (ISNS_TLV_ATTR_ID_LEN +
2523 		    ISNS_TLV_ATTR_LEN_LEN + len);
2524 		if (total_payload_len >= resp_len) {
2525 			done_b = B_TRUE;
2526 		} else {
2527 			data_p += (ISNS_TLV_ATTR_ID_LEN +
2528 			    ISNS_TLV_ATTR_LEN_LEN + len);
2529 		}
2530 	}
2531 
2532 	pg_sz = sizeof (isns_portal_group_list_t);
2533 	if (num_of_pgs > 0) {
2534 		pg_sz += (num_of_pgs - 1) * sizeof (isns_portal_group_t);
2535 	}
2536 	DTRACE_PROBE1(isns_process_dev_attr_qry_target_nodes_pdu_pg_size,
2537 	    int, pg_sz);
2538 	/*
2539 	 * Once we passed this point, if for any reason we need to return
2540 	 * because of a failure, we need to free the memory allocated for
2541 	 * the pg_list and nullify it.
2542 	 */
2543 	*pg_list = (isns_portal_group_list_t *)kmem_zalloc(pg_sz, KM_SLEEP);
2544 	(*pg_list)->pg_out_cnt = 0;
2545 
2546 	/* Assign the isns_server information to all portal groups */
2547 	for (idx = 0; idx < num_of_pgs; idx++) {
2548 		pg = &((*pg_list)->pg_list[idx]);
2549 		bcopy(&isns_server_addr->a_addr, &pg->isns_server_ip,
2550 		    sizeof (iscsi_ipaddr_t));
2551 		pg->isns_server_port = isns_server_addr->a_port;
2552 	}
2553 
2554 	data_p = resp_p->data;
2555 	done_b = B_FALSE;
2556 	found_delimiter_b = B_FALSE;
2557 	total_payload_len = sizeof (resp_p->status);
2558 	while (!done_b) {
2559 		attr_tlv_p = (isns_tlv_t *)data_p;
2560 		pg = &((*pg_list)->pg_list[(*pg_list)->pg_out_cnt]);
2561 		switch (ntohl(attr_tlv_p->attr_id)) {
2562 			case ISNS_DELIMITER_ATTR_ID:
2563 				if (found_delimiter_b) {
2564 					done_b = B_TRUE;
2565 				} else {
2566 					found_delimiter_b = B_TRUE;
2567 				}
2568 				break;
2569 
2570 			case ISNS_PG_ISCSI_NAME_ATTR_ID:
2571 				target_node_type_b = B_TRUE;
2572 				bcopy(attr_tlv_p->attr_value,
2573 				    (char *)pg->pg_iscsi_name,
2574 				    ntohl(attr_tlv_p->attr_len) <
2575 				    ISCSI_MAX_NAME_LEN ?
2576 				    ntohl(attr_tlv_p->attr_len) :
2577 				    ISCSI_MAX_NAME_LEN);
2578 
2579 				DTRACE_PROBE1(isns_dev_attr_qry_process1,
2580 				    char *, (char *)pg->pg_iscsi_name);
2581 				break;
2582 
2583 			case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
2584 				if (target_node_type_b) {
2585 					/*
2586 					 * Section 6.3.1 - The Portal IP Address
2587 					 * is a 16-byte field that may contain
2588 					 * an IPv4 or IPv6 address. When this
2589 					 * field contains an IPv4 address, it
2590 					 * is stored as an IPv4-mapped IPv6
2591 					 * address
2592 					 */
2593 					if (ntohl(attr_tlv_p->attr_len) != 16) {
2594 #define	STRING_AALR "address attribute length received "
2595 #define	STRING_FISE16 "from iSNS server, Expected = 16, "
2596 						cmn_err(CE_NOTE, "Wrong IP "
2597 						    STRING_AALR
2598 						    STRING_FISE16
2599 						    "Received = %d",
2600 						    ntohl(
2601 						    attr_tlv_p->attr_len));
2602 						return (
2603 						    ISNS_RSP_MSG_FORMAT_ERROR);
2604 #undef STRING_AALR
2605 #undef STRING_FISE16
2606 					}
2607 
2608 					/*
2609 					 * Section 6.3.1 and RFC 2373 state
2610 					 * that an IPv4 address will be denoted
2611 					 * by the 10 top bytes as all zero
2612 					 * followed by either 2 bytes of
2613 					 * 0x0000 or 0xFFFF The 0x0000 states
2614 					 * that the address is is IPv6 capable
2615 					 * and 0xFFFF states its not capable.
2616 					 */
2617 					if ((bcmp(attr_tlv_p->attr_value, junk,
2618 					    IPV4_RSVD_BYTES) == 0) &&
2619 					    (((attr_tlv_p->attr_value[10] ==
2620 					    0x00) &&
2621 					    (attr_tlv_p->attr_value[11] ==
2622 					    0x00)) ||
2623 					    ((attr_tlv_p->attr_value[10] ==
2624 					    0xFF) &&
2625 					    (attr_tlv_p->attr_value[11] ==
2626 					    0xFF)))) {
2627 
2628 						/* IPv4 */
2629 						bcopy(attr_tlv_p->attr_value +
2630 						    12, &pg->pg_ip_addr.u_ip4,
2631 						    sizeof (struct in_addr));
2632 						pg->insize =
2633 						    sizeof (struct in_addr);
2634 					} else {
2635 						/* IPv6 */
2636 						bcopy(attr_tlv_p->attr_value,
2637 						    &pg->pg_ip_addr.u_ip6,
2638 						    sizeof (struct in6_addr));
2639 						pg->insize =
2640 						    sizeof (struct in6_addr);
2641 					}
2642 				}
2643 				break;
2644 
2645 			case ISNS_PG_PORTAL_PORT_ATTR_ID:
2646 				if (target_node_type_b) {
2647 					pg->pg_port =
2648 					    ntohl(*(uint32_t *)
2649 					    (*attr_tlv_p).
2650 					    attr_value);
2651 				}
2652 
2653 				break;
2654 
2655 			case ISNS_PG_TAG_ATTR_ID:
2656 				if (target_node_type_b) {
2657 					pg->pg_tag =
2658 					    ntohl(*(uint32_t *)
2659 					    (*attr_tlv_p).
2660 					    attr_value);
2661 				}
2662 				target_node_type_b = B_FALSE;
2663 				if (ntohl(attr_tlv_p->attr_len) > 0) {
2664 					/*
2665 					 * Only the iSCSI node that has a
2666 					 * non-NULL PGT value is an valid
2667 					 * Entity.
2668 					 */
2669 					(*pg_list)->pg_out_cnt++;
2670 				}
2671 				break;
2672 
2673 			default:
2674 				break;
2675 		}
2676 
2677 		len = ntohl(attr_tlv_p->attr_len);
2678 		total_payload_len += (ISNS_TLV_ATTR_ID_LEN +
2679 		    ISNS_TLV_ATTR_LEN_LEN + len);
2680 		if ((total_payload_len >= resp_len) ||
2681 		    ((*pg_list)->pg_out_cnt == num_of_pgs)) {
2682 			done_b = B_TRUE;
2683 		} else {
2684 			data_p += (ISNS_TLV_ATTR_ID_LEN +
2685 			    ISNS_TLV_ATTR_LEN_LEN + len);
2686 		}
2687 	}
2688 
2689 	return (ISNS_RSP_SUCCESSFUL);
2690 }
2691 
2692 /* ARGSUSED */
2693 static
2694 uint32_t
2695 isns_process_esi(isns_pdu_t *esi_pdu_p)
2696 {
2697 	/* There's nothing particular to process for ESI. */
2698 	return (ISNS_RSP_SUCCESSFUL);
2699 }
2700 
2701 static
2702 uint32_t
2703 isns_process_scn(isns_pdu_t *scn_pdu_p, uint8_t *lhba_handle)
2704 {
2705 	boolean_t dest_attr_found_b;
2706 	boolean_t done_b;
2707 	boolean_t scn_type_found_b;
2708 	isns_scn_callback_arg_t *scn_args_p;
2709 	isns_tlv_t *attr_tlv_p;
2710 	uint8_t *data_p;
2711 	uint8_t *src_attr;
2712 	uint32_t attr_eff_len, normalized_attr_len;
2713 	uint32_t scn_type;
2714 	uint32_t total_payload_len;
2715 	void (*scn_callback_to_use)(void *);
2716 
2717 	/* get the lhba_handle to use for the call back */
2718 	scn_callback_to_use = scn_callback_lookup(lhba_handle);
2719 	if (scn_callback_to_use == NULL) {
2720 		return (ISNS_RSP_INTERNAL_ERROR);
2721 	}
2722 
2723 	dest_attr_found_b = B_FALSE;
2724 	scn_type = 0;
2725 	scn_type_found_b = B_FALSE;
2726 	data_p = scn_pdu_p->payload;
2727 	done_b = B_FALSE;
2728 	total_payload_len = 0;
2729 	src_attr = (uint8_t *)kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
2730 	/*
2731 	 * Section 5.6.5.8 states an SCN can have more than one
2732 	 * source attribute.  Process all attributes until we
2733 	 * each process all the data or encounter the delimiter.
2734 	 */
2735 	while (!done_b) {
2736 		attr_tlv_p = (isns_tlv_t *)data_p;
2737 
2738 		switch (ntohl(attr_tlv_p->attr_id)) {
2739 		/* ISNS_ISCSI_NAME_ATTR_ID - attribute name */
2740 		case ISNS_ISCSI_NAME_ATTR_ID:
2741 			attr_eff_len = strlen(
2742 			    (char *)attr_tlv_p->attr_value) + 1;
2743 			/*
2744 			 * The attribute length must be 4-byte aligned.
2745 			 * Section 5.1.3, RFC 4171.
2746 			 */
2747 			normalized_attr_len = (attr_eff_len % 4) == 0 ?
2748 			    (attr_eff_len) :
2749 			    (attr_eff_len + (4 - (attr_eff_len % 4)));
2750 			if (normalized_attr_len !=
2751 			    ntohl(attr_tlv_p->attr_len)) {
2752 				/* This SCN is bad. */
2753 				kmem_free(src_attr, ISCSI_MAX_NAME_LEN);
2754 				return (ISNS_RSP_MSG_FORMAT_ERROR);
2755 			}
2756 
2757 			/* Check if this was the Destination Attribute */
2758 			if ((dest_attr_found_b == B_TRUE) &&
2759 			    (scn_type_found_b == B_TRUE)) {
2760 				bzero(src_attr, ISCSI_MAX_NAME_LEN);
2761 				bcopy(attr_tlv_p->attr_value,
2762 				    (char *)src_attr,
2763 				    ntohl(attr_tlv_p->attr_len) <
2764 				    ISCSI_MAX_NAME_LEN ?
2765 				    ntohl(attr_tlv_p->attr_len) :
2766 				    ISCSI_MAX_NAME_LEN);
2767 
2768 				/* allocate new callback structure */
2769 				scn_args_p =
2770 				    (isns_scn_callback_arg_t *)kmem_zalloc(
2771 				    sizeof (isns_scn_callback_arg_t),
2772 				    KM_SLEEP);
2773 				scn_args_p->scn_type = ntohl(scn_type);
2774 				bcopy(src_attr, scn_args_p->source_key_attr,
2775 				    sizeof (scn_args_p->source_key_attr));
2776 
2777 				/* Dispatch the callback to process the SCN */
2778 				mutex_enter(&scn_taskq_mutex);
2779 				if (scn_taskq != NULL) {
2780 					(void) ddi_taskq_dispatch(scn_taskq,
2781 					    scn_callback_to_use,
2782 					    scn_args_p, DDI_SLEEP);
2783 				}
2784 				mutex_exit(&scn_taskq_mutex);
2785 			} else {
2786 				/* Skip Destination Attribute */
2787 				dest_attr_found_b = B_TRUE;
2788 			}
2789 			break;
2790 
2791 		/* ISNS_ISCSI_SCN_BITMAP_ATTR_ID - change type */
2792 		case ISNS_ISCSI_SCN_BITMAP_ATTR_ID:
2793 			/*
2794 			 * Determine the type of action to take for this SCN.
2795 			 */
2796 			scn_type_found_b = B_TRUE;
2797 			bcopy(&(attr_tlv_p->attr_value), &scn_type, 4);
2798 			break;
2799 
2800 		/* ISNS_DELIMITER_ATTR_ID - end of the payload of a message */
2801 		case ISNS_DELIMITER_ATTR_ID:
2802 			done_b = B_TRUE;
2803 			break;
2804 		}
2805 
2806 		if (done_b == B_FALSE) {
2807 			total_payload_len += ntohl(attr_tlv_p->attr_len) +
2808 			    ISNS_TLV_ATTR_ID_LEN + ISNS_TLV_ATTR_LEN_LEN;
2809 			if ((total_payload_len >= scn_pdu_p->payload_len) ||
2810 			    (total_payload_len > ISNSP_MAX_PAYLOAD_SIZE)) {
2811 				/* No more Attributes to process */
2812 				done_b = B_TRUE;
2813 			} else {
2814 				if (scn_pdu_p->payload_len -
2815 				    total_payload_len <=
2816 				    ISNS_TLV_ATTR_ID_LEN +
2817 				    ISNS_TLV_ATTR_LEN_LEN) {
2818 					/*
2819 					 * The rest of the data in the PDU
2820 					 * is less than the size of a valid
2821 					 * iSNS TLV. This next attribute
2822 					 * probably spans across the PDU
2823 					 * boundary. For now, do not
2824 					 * process it further.
2825 					 */
2826 					done_b = B_TRUE;
2827 				} else {
2828 					/* Advance to the next Attribute */
2829 					data_p += (ISNS_TLV_ATTR_ID_LEN +
2830 					    ISNS_TLV_ATTR_LEN_LEN +
2831 					    ntohl(attr_tlv_p->attr_len));
2832 				}
2833 			}
2834 		}
2835 	}
2836 
2837 	kmem_free(src_attr, ISCSI_MAX_NAME_LEN);
2838 	return (ISNS_RSP_SUCCESSFUL);
2839 }
2840 
2841 static
2842 size_t
2843 isns_create_pdu_header(uint16_t func_id, uint16_t flags, isns_pdu_t **pdu)
2844 {
2845 	/*
2846 	 * It should be ok to assume ISNSP_MAX_PDU_SIZE is large enough
2847 	 * since we are creating our own PDU which is fully under our control.
2848 	 */
2849 	size_t pdu_size = ISNSP_MAX_PDU_SIZE;
2850 
2851 	*pdu = (isns_pdu_t *)kmem_zalloc(pdu_size, KM_SLEEP);
2852 	(void) memset((*pdu), 0, pdu_size);
2853 	(*pdu)->version = htons((uint16_t)ISNSP_VERSION);
2854 	(*pdu)->func_id = htons((uint16_t)func_id);
2855 	(*pdu)->payload_len = htons(0);
2856 	(*pdu)->flags = htons((uint16_t)(flags | ISNS_FLAG_CLIENT));
2857 	(*pdu)->xid = htons(create_xid());
2858 	(*pdu)->seq = htons(0);
2859 
2860 	return (pdu_size);
2861 }
2862 
2863 static
2864 int
2865 isns_add_attr(isns_pdu_t *pdu,
2866 	size_t max_pdu_size,
2867 	uint32_t attr_id,
2868 	uint32_t attr_len,
2869 	void *attr_data,
2870 	uint32_t attr_numeric_data)
2871 {
2872 	isns_tlv_t *attr_tlv;
2873 	uint8_t *payload_ptr;
2874 	uint16_t payload_len;
2875 	uint32_t normalized_attr_len;
2876 	uint64_t attr_tlv_len;
2877 
2878 	/* The attribute length must be 4-byte aligned. Section 5.1.3. */
2879 	normalized_attr_len = (attr_len % 4) == 0 ? (attr_len) :
2880 	    (attr_len + (4 - (attr_len % 4)));
2881 	attr_tlv_len = ISNS_TLV_ATTR_ID_LEN
2882 	    + ISNS_TLV_ATTR_LEN_LEN
2883 	    + normalized_attr_len;
2884 	/* Check if we are going to exceed the maximum PDU length. */
2885 	payload_len = ntohs(pdu->payload_len);
2886 	if ((payload_len + attr_tlv_len) > max_pdu_size) {
2887 		return (1);
2888 	}
2889 
2890 	attr_tlv = (isns_tlv_t *)kmem_zalloc(attr_tlv_len, KM_SLEEP);
2891 
2892 	attr_tlv->attr_id = htonl(attr_id);
2893 
2894 	switch (attr_id) {
2895 		case ISNS_DELIMITER_ATTR_ID:
2896 		break;
2897 
2898 		case ISNS_PORTAL_IP_ADDR_ATTR_ID:
2899 		case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
2900 			if (attr_numeric_data == sizeof (in_addr_t)) {
2901 				/* IPv4 */
2902 				attr_tlv->attr_value[10] = 0xFF;
2903 				attr_tlv->attr_value[11] = 0xFF;
2904 				bcopy(attr_data, ((attr_tlv->attr_value) + 12),
2905 				    sizeof (in_addr_t));
2906 			} else if (attr_numeric_data == sizeof (in6_addr_t)) {
2907 				/* IPv6 */
2908 				bcopy(attr_data, attr_tlv->attr_value,
2909 				    sizeof (in6_addr_t));
2910 			} else if (attr_numeric_data == 0) {
2911 				/* EMPTY */
2912 				/* Do nothing */
2913 			} else {
2914 				kmem_free(attr_tlv, attr_tlv_len);
2915 				attr_tlv = NULL;
2916 				return (1);
2917 			}
2918 		break;
2919 
2920 		case ISNS_EID_ATTR_ID:
2921 		case ISNS_ISCSI_NAME_ATTR_ID:
2922 		case ISNS_ISCSI_ALIAS_ATTR_ID:
2923 		case ISNS_PG_ISCSI_NAME_ATTR_ID:
2924 			bcopy((char *)attr_data,
2925 			    attr_tlv->attr_value,
2926 			    attr_len);
2927 		break;
2928 
2929 		default:
2930 			switch (normalized_attr_len) {
2931 				case 0:
2932 				break;
2933 
2934 				case 4:
2935 					*(uint32_t *)attr_tlv->attr_value =
2936 					    htonl(attr_numeric_data);
2937 				break;
2938 
2939 				case 8:
2940 					*(uint64_t *)attr_tlv->attr_value =
2941 					    BE_64((uint64_t)
2942 					    attr_numeric_data);
2943 				break;
2944 			}
2945 	}
2946 
2947 	attr_tlv->attr_len = htonl(normalized_attr_len);
2948 	/*
2949 	 * Convert the network byte ordered payload length to host byte
2950 	 * ordered for local address calculation.
2951 	 */
2952 	payload_len = ntohs(pdu->payload_len);
2953 	payload_ptr = pdu->payload + payload_len;
2954 	bcopy(attr_tlv, payload_ptr, attr_tlv_len);
2955 	payload_len += attr_tlv_len;
2956 
2957 	/*
2958 	 * Convert the host byte ordered payload length back to network
2959 	 * byte ordered - it's now ready to be sent on the wire.
2960 	 */
2961 	pdu->payload_len = htons(payload_len);
2962 
2963 	kmem_free(attr_tlv, attr_tlv_len);
2964 	attr_tlv = NULL;
2965 
2966 	return (0);
2967 }
2968 
2969 /* ARGSUSED */
2970 static
2971 void
2972 isns_service_esi_scn(iscsi_thread_t *thread, void *arg)
2973 {
2974 	int clnt_len;
2975 	isns_async_thread_arg_t *larg;
2976 	isns_pdu_t *in_pdu;
2977 	size_t bytes_received, in_pdu_size = 0;
2978 	uint8_t *lhba_handle;
2979 	struct sockaddr_in6	 t_addr;
2980 	socklen_t		t_addrlen;
2981 	union {
2982 		struct sockaddr sin;
2983 		struct sockaddr_in s_in4;
2984 		struct sockaddr_in6 s_in6;
2985 	} clnt_addr = { 0 };
2986 	union {
2987 		struct sockaddr_in	soa4;
2988 		struct sockaddr_in6	soa6;
2989 	} local_conn_prop;
2990 	void *listening_so, *connecting_so;
2991 
2992 	larg = (isns_async_thread_arg_t *)arg;
2993 	listening_so = larg->listening_so;
2994 	lhba_handle = larg->lhba_handle;
2995 
2996 	/* Done using the argument - free it */
2997 	kmem_free(larg, sizeof (*larg));
2998 	bzero(&t_addr, sizeof (struct sockaddr_in6));
2999 	t_addrlen = sizeof (struct sockaddr_in6);
3000 
3001 	(void) iscsi_net->getsockname(listening_so,
3002 	    (struct sockaddr *)&t_addr, &t_addrlen);
3003 	if (t_addrlen <= sizeof (local_conn_prop)) {
3004 		bcopy(&t_addr, &local_conn_prop, t_addrlen);
3005 	}
3006 
3007 	if (iscsi_net->listen(listening_so, 5) < 0) {
3008 		iscsi_net->close(listening_so);
3009 	}
3010 
3011 	for (;;) {
3012 		int rval;
3013 		isns_pdu_t *out_pdu;
3014 		size_t out_pdu_size;
3015 
3016 		clnt_len = sizeof (clnt_addr);
3017 
3018 		/* Blocking call */
3019 		connecting_so = iscsi_net->accept(
3020 		    listening_so, &clnt_addr.sin, &clnt_len);
3021 
3022 		mutex_enter(&esi_scn_thr_mutex);
3023 		if (esi_scn_thr_to_shutdown == B_TRUE) {
3024 			/* Terminate the thread if instructed to do so. */
3025 			mutex_exit(&esi_scn_thr_mutex);
3026 			return;
3027 		}
3028 		mutex_exit(&esi_scn_thr_mutex);
3029 
3030 		if (connecting_so == NULL) {
3031 			iscsi_net->close(listening_so);
3032 			continue;
3033 		}
3034 
3035 		bytes_received = isns_rcv_pdu(connecting_so, &in_pdu,
3036 		    &in_pdu_size);
3037 		if (in_pdu == NULL) {
3038 			continue;
3039 		}
3040 		if (bytes_received == 0) {
3041 			continue;
3042 		}
3043 
3044 		switch (in_pdu->func_id) {
3045 		case ISNS_ESI:
3046 		case ISNS_SCN:
3047 			if (in_pdu->func_id == ISNS_ESI) {
3048 				rval = isns_process_esi(in_pdu);
3049 				out_pdu_size = isns_create_esi_rsp_pdu(
3050 				    rval,
3051 				    in_pdu,
3052 				    &xid,
3053 				    &out_pdu);
3054 			} else if (in_pdu->func_id == ISNS_SCN) {
3055 				rval = isns_process_scn(in_pdu,
3056 				    lhba_handle);
3057 				out_pdu_size = isns_create_scn_rsp_pdu(
3058 				    rval,
3059 				    in_pdu,
3060 				    &xid,
3061 				    &out_pdu);
3062 			} else {
3063 				/*
3064 				 * Ignore all traffics other than
3065 				 * ESI and SCN.
3066 				 */
3067 				kmem_free(in_pdu, in_pdu_size);
3068 				in_pdu = NULL;
3069 				continue;
3070 			}
3071 
3072 			if (out_pdu_size == 0) {
3073 				kmem_free(in_pdu, in_pdu_size);
3074 				in_pdu = NULL;
3075 				continue;
3076 			}
3077 
3078 			(void) isns_send_pdu(connecting_so, out_pdu);
3079 
3080 			kmem_free(out_pdu, out_pdu_size);
3081 			out_pdu = NULL;
3082 			kmem_free(in_pdu, in_pdu_size);
3083 			in_pdu = NULL;
3084 
3085 			iscsi_net->close(connecting_so);
3086 			break;
3087 
3088 		default:
3089 			kmem_free(in_pdu, in_pdu_size);
3090 			in_pdu = NULL;
3091 			continue;
3092 		}
3093 	}
3094 }
3095 
3096 static
3097 boolean_t
3098 find_listening_addr(iscsi_addr_t *local_addr, void *listening_so)
3099 {
3100 	union {
3101 		struct sockaddr_in	soa4;
3102 		struct sockaddr_in6	soa6;
3103 	} local_conn_prop = { 0 };
3104 
3105 	struct sockaddr_in6	t_addr;
3106 	socklen_t		t_addrlen;
3107 
3108 	if (local_addr == NULL || listening_so == NULL) {
3109 		return (B_FALSE);
3110 	}
3111 
3112 	bzero(&t_addr, sizeof (struct sockaddr_in6));
3113 	t_addrlen = sizeof (struct sockaddr_in6);
3114 
3115 	(void) iscsi_net->getsockname(listening_so, (struct sockaddr *)&t_addr,
3116 	    &t_addrlen);
3117 	if (t_addrlen > sizeof (local_conn_prop)) {
3118 		return (B_FALSE);
3119 	}
3120 	bcopy(&t_addr, &local_conn_prop, t_addrlen);
3121 	if (local_conn_prop.soa4.sin_family == AF_INET) {
3122 		local_addr->a_addr.i_addr.in4.s_addr =
3123 		    local_conn_prop.soa4.sin_addr.s_addr;
3124 		local_addr->a_addr.i_insize = sizeof (in_addr_t);
3125 	} else if (local_conn_prop.soa4.sin_family == AF_INET6) {
3126 		/* Currently, IPv6 is not supported */
3127 		return (B_FALSE);
3128 	} else {
3129 		return (B_FALSE);
3130 	}
3131 
3132 	local_addr->a_port = ntohs(local_conn_prop.soa4.sin_port);
3133 
3134 	return (B_TRUE);
3135 }
3136 
3137 static
3138 boolean_t
3139 find_local_portal(iscsi_addr_t *isns_server_addr,
3140     iscsi_addr_t **local_addr, void **listening_so)
3141 {
3142 	union {
3143 		struct sockaddr_in	soa4;
3144 		struct sockaddr_in6	soa6;
3145 	} local_conn_prop = { 0 };
3146 	union {
3147 		struct sockaddr sin;
3148 		struct sockaddr_in s_in4;
3149 		struct sockaddr_in6 s_in6;
3150 	} serv_addr = { 0 };
3151 	void *so;
3152 	struct sockaddr_in6	t_addr;
3153 	socklen_t		t_addrlen;
3154 
3155 	if (listening_so == NULL) {
3156 		return (B_FALSE);
3157 	}
3158 
3159 	if (local_addr != NULL) {
3160 		*local_addr = NULL;
3161 	}
3162 
3163 	*listening_so = NULL;
3164 	bzero(&t_addr, sizeof (struct sockaddr_in6));
3165 	t_addrlen = sizeof (struct sockaddr_in6);
3166 
3167 	/*
3168 	 * Determine the local IP address.
3169 	 */
3170 	if (local_addr != NULL) {
3171 		so = isns_open(isns_server_addr);
3172 		if (so == NULL) {
3173 			return (B_FALSE);
3174 		}
3175 
3176 		iscsi_net->getsockname(so,
3177 		    (struct sockaddr *)&t_addr, &t_addrlen);
3178 		if (t_addrlen > sizeof (local_conn_prop)) {
3179 			iscsi_net->close(so);
3180 			return (B_FALSE);
3181 		}
3182 
3183 		bcopy(&t_addr, &local_conn_prop, t_addrlen);
3184 		t_addrlen = sizeof (struct sockaddr_in6);
3185 		if (local_conn_prop.soa4.sin_family == AF_INET) {
3186 			*local_addr =
3187 			    (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t),
3188 			    KM_SLEEP);
3189 			(*local_addr)->a_addr.i_addr.in4.s_addr =
3190 			    local_conn_prop.soa4.sin_addr.s_addr;
3191 			(*local_addr)->a_addr.i_insize = sizeof (in_addr_t);
3192 		} else if (local_conn_prop.soa4.sin_family == AF_INET6) {
3193 			/* Currently, IPv6 is not supported */
3194 			return (B_FALSE);
3195 		} else {
3196 			iscsi_net->close(so);
3197 			return (B_FALSE);
3198 		}
3199 
3200 		iscsi_net->close(so);
3201 	}
3202 	/*
3203 	 * Determine the local IP address. (End)
3204 	 */
3205 
3206 	serv_addr.s_in4.sin_family = AF_INET;
3207 	/*
3208 	 * Use INADDR_ANY to accept connections from any of the connected
3209 	 * networks.
3210 	 */
3211 	serv_addr.s_in4.sin_addr.s_addr = htonl(INADDR_ANY);
3212 	/*
3213 	 * Use port number 0 to allow the system to assign a unique unused
3214 	 * port.
3215 	 */
3216 	serv_addr.s_in4.sin_port = htons(0);
3217 
3218 	so = iscsi_net->socket(AF_INET, SOCK_STREAM, 0);
3219 	if (so == NULL) {
3220 		if (local_addr != NULL && (*local_addr != NULL)) {
3221 			kmem_free((*local_addr), sizeof (iscsi_addr_t));
3222 			*local_addr = NULL;
3223 		}
3224 		return (B_FALSE);
3225 	}
3226 
3227 	if (iscsi_net->bind(so, &serv_addr.sin,
3228 		sizeof (struct sockaddr), 0, 0) < 0) {
3229 		if (local_addr != NULL && (*local_addr != NULL)) {
3230 			kmem_free((*local_addr), sizeof (iscsi_addr_t));
3231 			*local_addr = NULL;
3232 		}
3233 		iscsi_net->close(so);
3234 		return (B_FALSE);
3235 	}
3236 
3237 	if (local_addr != NULL && (*local_addr != NULL)) {
3238 		(void) iscsi_net->getsockname(so, (struct sockaddr *)&t_addr,
3239 		    &t_addrlen);
3240 		if (t_addrlen <= sizeof (local_conn_prop)) {
3241 			bcopy(&t_addr, &local_conn_prop, t_addrlen);
3242 			(*local_addr)->a_port =
3243 			    ntohs(local_conn_prop.soa4.sin_port);
3244 		} else {
3245 			(*local_addr)->a_port = ISNS_DEFAULT_ESI_SCN_PORT;
3246 		}
3247 	}
3248 
3249 	*listening_so = so;
3250 
3251 	return (B_TRUE);
3252 }
3253 
3254 /* ARGSUSED */
3255 static
3256 void
3257 (*scn_callback_lookup(uint8_t *lhba_handle))(void *)
3258 {
3259 	/*
3260 	 * When we support multiple HBA instance we will use lhba_handle
3261 	 * to look up the associated SCN callback. For now, we only support
3262 	 * one HBA instance therefore we always return the same SCN callback.
3263 	 */
3264 	return (scn_callback_p);
3265 }
3266 
3267 static
3268 uint16_t
3269 create_xid()
3270 {
3271 	return (xid++ % MAX_XID);
3272 }
3273 
3274 static
3275 void
3276 esi_scn_thr_cleanup()
3277 {
3278 	boolean_t	unblock_esi_scn_thr_b		= B_FALSE;
3279 	iscsi_addr_t	local_addr;
3280 
3281 	mutex_enter(&esi_scn_thr_mutex);
3282 	if (esi_scn_thr_to_shutdown == B_FALSE) {
3283 
3284 		/* Instruct the ESI/SCN to shut itself down. */
3285 		esi_scn_thr_to_shutdown = B_TRUE;
3286 		if (instance_listening_so != NULL &&
3287 		    (find_listening_addr(&local_addr,
3288 		    instance_listening_so) == B_TRUE)) {
3289 			isns_pdu_t *out_pdu;
3290 			size_t out_pdu_size;
3291 			void *connecting_so;
3292 
3293 			/*
3294 			 * Open a connection to the local address and send
3295 			 * a dummy header to unblock the accept call so that
3296 			 * the ESI/SCN thread has a chance to terminate
3297 			 * itself.
3298 			 */
3299 			connecting_so = isns_open(&local_addr);
3300 			if (connecting_so == NULL) {
3301 				unblock_esi_scn_thr_b = B_FALSE;
3302 				esi_scn_thr_to_shutdown = B_FALSE;
3303 			} else {
3304 				out_pdu_size = isns_create_pdu_header(0,
3305 				    ISNS_FLAG_FIRST_PDU |
3306 				    ISNS_FLAG_LAST_PDU,
3307 				    &out_pdu);
3308 				if (isns_send_pdu(connecting_so,
3309 				    out_pdu) != 0) {
3310 					unblock_esi_scn_thr_b = B_FALSE;
3311 					esi_scn_thr_to_shutdown = B_FALSE;
3312 				} else {
3313 					unblock_esi_scn_thr_b = B_TRUE;
3314 				}
3315 				iscsi_net->close(connecting_so);
3316 				kmem_free(out_pdu, out_pdu_size);
3317 				out_pdu = NULL;
3318 			}
3319 		}
3320 
3321 		if (unblock_esi_scn_thr_b == B_TRUE) {
3322 			mutex_exit(&esi_scn_thr_mutex);
3323 			(void) iscsi_thread_stop(esi_scn_thr_id);
3324 			iscsi_thread_destroy(esi_scn_thr_id);
3325 			mutex_enter(&esi_scn_thr_mutex);
3326 			esi_scn_thr_id = NULL;
3327 
3328 			/*
3329 			 * Shutdown and close the listening socket.
3330 			 */
3331 			iscsi_net->shutdown(instance_listening_so, 2);
3332 			iscsi_net->close(instance_listening_so);
3333 			instance_listening_so = NULL;
3334 		}
3335 	}
3336 	mutex_exit(&esi_scn_thr_mutex);
3337 }
3338