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