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