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.,
926362598eSbing 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);
1516362598eSbing zhao - Sun Microsystems - Beijing China static boolean_t find_listening_addr(iscsi_addr_t *local_addr,
1526362598eSbing 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
isns_client_init()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
isns_client_cleanup()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
isns_reg(uint8_t * lhba_handle,uint8_t * node_name,size_t node_name_len,uint8_t * node_alias,size_t node_alias_len,uint32_t node_type,void (* scn_callback)(void *))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
isns_reg_one_server(entry_t * isns_server,uint8_t * lhba_handle,uint8_t * node_name,size_t node_name_len,uint8_t * node_alias,size_t node_alias_len,uint32_t node_type,void (* scn_callback)(void *))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
isns_dereg(uint8_t * lhba_handle,uint8_t * node_name)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
isns_dereg_one_server(entry_t * isns_server,uint8_t * node_name,boolean_t is_last_isns_server_b)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
isns_query(uint8_t * lhba_handle,uint8_t * node_name,uint8_t * node_alias,uint32_t node_type,isns_portal_group_list_t ** pg_list)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
isns_query_one_server(iscsi_addr_t * isns_server_addr,uint8_t * lhba_handle,uint8_t * node_name,uint8_t * node_alias,uint32_t node_type,isns_portal_group_list_t ** pg_list)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
isns_query_one_node(uint8_t * target_node_name,uint8_t * lhba_handle,uint8_t * source_node_name,uint8_t * source_node_alias,uint32_t source_node_type,isns_portal_group_list_t ** pg_list)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
isns_query_one_server_one_node(iscsi_addr_t * isns_server_addr,uint8_t * target_node_name,uint8_t * lhba_handle,uint8_t * source_node_name,uint8_t * source_node_alias,uint32_t source_node_type,isns_portal_group_list_t ** pg_list)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
discover_isns_server(uint8_t * lhba_handle,iscsi_addr_list_t ** isns_server_addrs)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 			return (ISNS_BAD_SVR_ADDR);
598fcf3ce44SJohn Forte 		}
599fcf3ce44SJohn Forte 		i++;
600fcf3ce44SJohn Forte 	}
601fcf3ce44SJohn Forte 	persistent_isns_addr_unlock();
602fcf3ce44SJohn Forte 
603fcf3ce44SJohn Forte 	return (ISNS_OK);
604fcf3ce44SJohn Forte }
605fcf3ce44SJohn Forte 
606fcf3ce44SJohn Forte static
607fcf3ce44SJohn Forte int
create_esi_scn_thr(uint8_t * lhba_handle,iscsi_addr_t * isns_server_address)608fcf3ce44SJohn Forte create_esi_scn_thr(uint8_t *lhba_handle, iscsi_addr_t *isns_server_address)
609fcf3ce44SJohn Forte {
6106362598eSbing zhao - Sun Microsystems - Beijing China 	void *listening_so  = NULL;
6116362598eSbing zhao - Sun Microsystems - Beijing China 	boolean_t found	    = B_FALSE;
612fcf3ce44SJohn Forte 
613fcf3ce44SJohn Forte 	ASSERT(lhba_handle != NULL);
614fcf3ce44SJohn Forte 	ASSERT(isns_server_address != NULL);
615fcf3ce44SJohn Forte 
616fcf3ce44SJohn Forte 	/*
617fcf3ce44SJohn Forte 	 * Bringing up of the thread should happen regardless of the
618fcf3ce44SJohn Forte 	 * subsequent registration status. That means, do not destroy the
619fcf3ce44SJohn Forte 	 * ESI/SCN thread already created.
620fcf3ce44SJohn Forte 	 */
621fcf3ce44SJohn Forte 	/* Check and create ESI/SCN thread. */
622fcf3ce44SJohn Forte 	mutex_enter(&esi_scn_thr_mutex);
6236362598eSbing zhao - Sun Microsystems - Beijing China 
6246362598eSbing zhao - Sun Microsystems - Beijing China 	/* Determine local port and address. */
6256362598eSbing zhao - Sun Microsystems - Beijing China 	found = find_local_portal(isns_server_address,
6266362598eSbing zhao - Sun Microsystems - Beijing China 	    NULL, &listening_so);
6276362598eSbing zhao - Sun Microsystems - Beijing China 	if (found == B_FALSE) {
6286362598eSbing zhao - Sun Microsystems - Beijing China 		if (listening_so != NULL) {
6296362598eSbing zhao - Sun Microsystems - Beijing China 			iscsi_net->close(listening_so);
6306362598eSbing zhao - Sun Microsystems - Beijing China 		}
6316362598eSbing zhao - Sun Microsystems - Beijing China 		mutex_exit(&esi_scn_thr_mutex);
6326362598eSbing zhao - Sun Microsystems - Beijing China 		return (ISNS_CANNOT_FIND_LOCAL_ADDR);
6336362598eSbing zhao - Sun Microsystems - Beijing China 	}
6346362598eSbing zhao - Sun Microsystems - Beijing China 
635fcf3ce44SJohn Forte 	if (esi_scn_thr_id == NULL) {
636fcf3ce44SJohn Forte 		char thr_name[ISCSI_TH_MAX_NAME_LEN];
637fcf3ce44SJohn Forte 		int rval;
638fcf3ce44SJohn Forte 		isns_async_thread_arg_t *larg;
639fcf3ce44SJohn Forte 
640fcf3ce44SJohn Forte 		/* Assume the LHBA handle has a length of 4 */
641fcf3ce44SJohn Forte 		if (snprintf(thr_name, sizeof (thr_name) - 1,
642fcf3ce44SJohn Forte 		    "isns_client_esi_%x%x%x%x",
643fcf3ce44SJohn Forte 		    lhba_handle[0],
644fcf3ce44SJohn Forte 		    lhba_handle[1],
645fcf3ce44SJohn Forte 		    lhba_handle[2],
646fcf3ce44SJohn Forte 		    lhba_handle[3]) >=
647fcf3ce44SJohn Forte 		    sizeof (thr_name)) {
648fcf3ce44SJohn Forte 			esi_scn_thr_id = NULL;
649fcf3ce44SJohn Forte 			if (listening_so != NULL) {
650fcf3ce44SJohn Forte 				iscsi_net->close(listening_so);
651fcf3ce44SJohn Forte 				listening_so = NULL;
652fcf3ce44SJohn Forte 			}
653fcf3ce44SJohn Forte 			mutex_exit(&esi_scn_thr_mutex);
654fcf3ce44SJohn Forte 			return (ISNS_INTERNAL_ERR);
655fcf3ce44SJohn Forte 		}
656fcf3ce44SJohn Forte 
657fcf3ce44SJohn Forte 		larg = kmem_zalloc(sizeof (isns_async_thread_arg_t), KM_SLEEP);
658fcf3ce44SJohn Forte 		larg->lhba_handle = lhba_handle;
659fcf3ce44SJohn Forte 		larg->listening_so = listening_so;
660fcf3ce44SJohn Forte 		instance_listening_so = listening_so;
661fcf3ce44SJohn Forte 		esi_scn_thr_to_shutdown = B_FALSE;
662fcf3ce44SJohn Forte 		esi_scn_thr_id = iscsi_thread_create(NULL,
663fcf3ce44SJohn Forte 		    thr_name, isns_service_esi_scn, (void *)larg);
664fcf3ce44SJohn Forte 		if (esi_scn_thr_id == NULL) {
665fcf3ce44SJohn Forte 			if (listening_so != NULL) {
666fcf3ce44SJohn Forte 				iscsi_net->close(listening_so);
667fcf3ce44SJohn Forte 				listening_so = NULL;
668fcf3ce44SJohn Forte 				instance_listening_so = NULL;
669fcf3ce44SJohn Forte 			}
670fcf3ce44SJohn Forte 			mutex_exit(&esi_scn_thr_mutex);
671fcf3ce44SJohn Forte 			return (ISNS_INTERNAL_ERR);
672fcf3ce44SJohn Forte 		}
673fcf3ce44SJohn Forte 
674fcf3ce44SJohn Forte 		rval = iscsi_thread_start(esi_scn_thr_id);
675fcf3ce44SJohn Forte 		if (rval == B_FALSE) {
676fcf3ce44SJohn Forte 			iscsi_thread_destroy(esi_scn_thr_id);
677fcf3ce44SJohn Forte 			esi_scn_thr_id = NULL;
678fcf3ce44SJohn Forte 			if (listening_so != NULL) {
679fcf3ce44SJohn Forte 				iscsi_net->close(listening_so);
680fcf3ce44SJohn Forte 				listening_so = NULL;
681fcf3ce44SJohn Forte 				instance_listening_so = NULL;
682fcf3ce44SJohn Forte 			}
683fcf3ce44SJohn Forte 			mutex_exit(&esi_scn_thr_mutex);
684fcf3ce44SJohn Forte 			return (ISNS_INTERNAL_ERR);
685fcf3ce44SJohn Forte 		}
68649311b35SJack Meng 		(void) iscsi_thread_send_wakeup(esi_scn_thr_id);
687fcf3ce44SJohn Forte 	}
688fcf3ce44SJohn Forte 	mutex_exit(&esi_scn_thr_mutex);
689fcf3ce44SJohn Forte 
690fcf3ce44SJohn Forte 	return (ISNS_OK);
691fcf3ce44SJohn Forte }
692fcf3ce44SJohn Forte 
693fcf3ce44SJohn Forte static
694fcf3ce44SJohn Forte void
register_isns_client(void * arg)695fcf3ce44SJohn Forte register_isns_client(void *arg)
696fcf3ce44SJohn Forte {
697fcf3ce44SJohn Forte 	isns_reg_arg_t *reg_args;
698fcf3ce44SJohn Forte 	isns_status_t status;
699fcf3ce44SJohn Forte 
700fcf3ce44SJohn Forte 	reg_args = (isns_reg_arg_t *)arg;
701fcf3ce44SJohn Forte 
702fcf3ce44SJohn Forte 	/* Deregister stale registration (if any). */
703fcf3ce44SJohn Forte 	status = do_isns_dev_dereg(reg_args->isns_server_addr,
704fcf3ce44SJohn Forte 	    reg_args->node_name);
705fcf3ce44SJohn Forte 
706fcf3ce44SJohn Forte 	if (status == isns_open_conn_err) {
707fcf3ce44SJohn Forte 		/* Cannot open connection to the server. Stop proceeding. */
708fcf3ce44SJohn Forte 		kmem_free(reg_args->isns_server_addr, sizeof (iscsi_addr_t));
709fcf3ce44SJohn Forte 		reg_args->isns_server_addr = NULL;
710fcf3ce44SJohn Forte 		kmem_free(reg_args->node_name, reg_args->node_name_len);
711fcf3ce44SJohn Forte 		reg_args->node_name = NULL;
712fcf3ce44SJohn Forte 		kmem_free(reg_args->node_alias, reg_args->node_alias_len);
713fcf3ce44SJohn Forte 		reg_args->node_alias = NULL;
714fcf3ce44SJohn Forte 		kmem_free(reg_args, sizeof (isns_reg_arg_t));
715fcf3ce44SJohn Forte 		return;
716fcf3ce44SJohn Forte 	}
717fcf3ce44SJohn Forte 
718fcf3ce44SJohn Forte 	DTRACE_PROBE1(register_isns_client_dereg, isns_status_t, status);
719fcf3ce44SJohn Forte 
720fcf3ce44SJohn Forte 	/* New registration. */
721fcf3ce44SJohn Forte 	status =  do_isns_dev_attr_reg(reg_args->isns_server_addr,
722fcf3ce44SJohn Forte 	    reg_args->node_name, reg_args->node_alias, reg_args->node_type);
723fcf3ce44SJohn Forte 
724fcf3ce44SJohn Forte 	DTRACE_PROBE1(register_isns_client_reg, isns_status_t, status);
725fcf3ce44SJohn Forte 
726fcf3ce44SJohn Forte 	/* Cleanup */
727fcf3ce44SJohn Forte 	kmem_free(reg_args->isns_server_addr, sizeof (iscsi_addr_t));
728fcf3ce44SJohn Forte 	reg_args->isns_server_addr = NULL;
729fcf3ce44SJohn Forte 	kmem_free(reg_args->node_name, reg_args->node_name_len);
730fcf3ce44SJohn Forte 	reg_args->node_name = NULL;
731fcf3ce44SJohn Forte 	kmem_free(reg_args->node_alias, reg_args->node_alias_len);
732fcf3ce44SJohn Forte 	reg_args->node_alias = NULL;
733fcf3ce44SJohn Forte 	kmem_free(reg_args, sizeof (isns_reg_arg_t));
734fcf3ce44SJohn Forte }
735fcf3ce44SJohn Forte 
736fcf3ce44SJohn Forte static
737fcf3ce44SJohn Forte isns_status_t
do_isns_dev_attr_reg(iscsi_addr_t * isns_server_addr,uint8_t * node_name,uint8_t * node_alias,uint32_t node_type)738fcf3ce44SJohn Forte do_isns_dev_attr_reg(iscsi_addr_t *isns_server_addr,
739fcf3ce44SJohn Forte 	uint8_t *node_name, uint8_t *node_alias, uint32_t node_type)
740fcf3ce44SJohn Forte {
741fcf3ce44SJohn Forte 	int rcv_rsp_cnt = 0;
742fcf3ce44SJohn Forte 	int rsp_status;
743fcf3ce44SJohn Forte 	isns_pdu_t *in_pdu, *out_pdu;
744fcf3ce44SJohn Forte 	isns_status_t rval;
745fcf3ce44SJohn Forte 	size_t bytes_received, in_pdu_size = 0, out_pdu_size = 0;
746fcf3ce44SJohn Forte 	uint16_t xid;
747fcf3ce44SJohn Forte 	void *so = NULL;
748fcf3ce44SJohn Forte 
749fcf3ce44SJohn Forte 	out_pdu_size = isns_create_dev_attr_reg_pdu(
750fcf3ce44SJohn Forte 	    node_name,
751fcf3ce44SJohn Forte 	    node_alias,
752fcf3ce44SJohn Forte 	    node_type,
753fcf3ce44SJohn Forte 	    &xid, &out_pdu);
754fcf3ce44SJohn Forte 	if (out_pdu_size == 0) {
755fcf3ce44SJohn Forte 		return (isns_create_msg_err);
756fcf3ce44SJohn Forte 	}
757fcf3ce44SJohn Forte 
758fcf3ce44SJohn Forte 	ASSERT(out_pdu != NULL);
759fcf3ce44SJohn Forte 	ASSERT(out_pdu_size > 0);
760fcf3ce44SJohn Forte 
761fcf3ce44SJohn Forte 	so = isns_open(isns_server_addr);
762fcf3ce44SJohn Forte 	if (so == NULL) {
763fcf3ce44SJohn Forte 		/* Log a message and return */
764fcf3ce44SJohn Forte 		kmem_free(out_pdu, out_pdu_size);
765fcf3ce44SJohn Forte 		out_pdu = NULL;
766fcf3ce44SJohn Forte 		return (isns_open_conn_err);
767fcf3ce44SJohn Forte 	}
768fcf3ce44SJohn Forte 
769fcf3ce44SJohn Forte 	if (isns_send_pdu(so, out_pdu) != 0) {
770fcf3ce44SJohn Forte 		iscsi_net->close(so);
771fcf3ce44SJohn Forte 		kmem_free(out_pdu, out_pdu_size);
772fcf3ce44SJohn Forte 		out_pdu = NULL;
773fcf3ce44SJohn Forte 		return (isns_send_msg_err);
774fcf3ce44SJohn Forte 	}
775fcf3ce44SJohn Forte 
776fcf3ce44SJohn Forte 	/* Done with the out PDU - free it */
777fcf3ce44SJohn Forte 	kmem_free(out_pdu, out_pdu_size);
778fcf3ce44SJohn Forte 	out_pdu = NULL;
779fcf3ce44SJohn Forte 
780fcf3ce44SJohn Forte 	rcv_rsp_cnt = 0;
781fcf3ce44SJohn Forte 	rval = isns_ok;
782fcf3ce44SJohn Forte 	for (;;) {
783fcf3ce44SJohn Forte 		bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
784fcf3ce44SJohn Forte 		ASSERT(bytes_received >= (size_t)0);
785fcf3ce44SJohn Forte 		if (bytes_received == 0) {
786fcf3ce44SJohn Forte 			ASSERT(in_pdu == NULL);
787fcf3ce44SJohn Forte 			ASSERT(in_pdu_size == 0);
788fcf3ce44SJohn Forte 			rval = isns_rcv_msg_err;
789fcf3ce44SJohn Forte 			break;
790fcf3ce44SJohn Forte 		}
791fcf3ce44SJohn Forte 
792fcf3ce44SJohn Forte 		ASSERT(in_pdu != NULL);
793fcf3ce44SJohn Forte 		ASSERT(in_pdu_size > 0);
794fcf3ce44SJohn Forte 
795fcf3ce44SJohn Forte 		if (ntohs(in_pdu->xid) != xid) {
796fcf3ce44SJohn Forte 			rcv_rsp_cnt++;
797fcf3ce44SJohn Forte 			if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
798fcf3ce44SJohn Forte 				continue;
799fcf3ce44SJohn Forte 			} else {
800fcf3ce44SJohn Forte 				/* Exceed maximum receive count. */
801fcf3ce44SJohn Forte 				kmem_free(in_pdu, in_pdu_size);
802fcf3ce44SJohn Forte 				in_pdu = NULL;
803fcf3ce44SJohn Forte 				rval = isns_no_rsp_rcvd;
804fcf3ce44SJohn Forte 				break;
805fcf3ce44SJohn Forte 			}
806fcf3ce44SJohn Forte 		}
807fcf3ce44SJohn Forte 
808fcf3ce44SJohn Forte 		rsp_status = isns_process_dev_attr_reg_rsp(in_pdu);
809fcf3ce44SJohn Forte 		if (rsp_status != ISNS_RSP_SUCCESSFUL) {
810fcf3ce44SJohn Forte 			if (rsp_status == ISNS_RSP_SRC_UNAUTHORIZED) {
811fcf3ce44SJohn Forte 				rval = isns_op_partially_failed;
812fcf3ce44SJohn Forte 			} else {
813fcf3ce44SJohn Forte 				rval = isns_op_failed;
814fcf3ce44SJohn Forte 			}
815fcf3ce44SJohn Forte 		}
816fcf3ce44SJohn Forte 		kmem_free(in_pdu, in_pdu_size);
817fcf3ce44SJohn Forte 		in_pdu = NULL;
818fcf3ce44SJohn Forte 		break;
819fcf3ce44SJohn Forte 	}
820fcf3ce44SJohn Forte 
821fcf3ce44SJohn Forte 	if (rval != isns_ok) {
822fcf3ce44SJohn Forte 		iscsi_net->close(so);
823fcf3ce44SJohn Forte 		return (rval);
824fcf3ce44SJohn Forte 	}
825fcf3ce44SJohn Forte 
826fcf3ce44SJohn Forte 	/* Always register SCN */
827fcf3ce44SJohn Forte 	out_pdu_size = isns_create_scn_reg_pdu(
828fcf3ce44SJohn Forte 	    node_name, node_alias,
829fcf3ce44SJohn Forte 	    &xid, &out_pdu);
830fcf3ce44SJohn Forte 	if (out_pdu_size == 0) {
831fcf3ce44SJohn Forte 		iscsi_net->close(so);
832fcf3ce44SJohn Forte 		return (isns_create_msg_err);
833fcf3ce44SJohn Forte 	}
834fcf3ce44SJohn Forte 
835fcf3ce44SJohn Forte 	ASSERT(out_pdu != NULL);
836fcf3ce44SJohn Forte 	ASSERT(out_pdu_size > 0);
837fcf3ce44SJohn Forte 
838fcf3ce44SJohn Forte 	if (isns_send_pdu(so, out_pdu) != 0) {
839fcf3ce44SJohn Forte 		iscsi_net->close(so);
840fcf3ce44SJohn Forte 		kmem_free(out_pdu, out_pdu_size);
841fcf3ce44SJohn Forte 		out_pdu = NULL;
842fcf3ce44SJohn Forte 		return (isns_send_msg_err);
843fcf3ce44SJohn Forte 	}
844fcf3ce44SJohn Forte 
845fcf3ce44SJohn Forte 	/* Done with the out PDU - free it */
846fcf3ce44SJohn Forte 	kmem_free(out_pdu, out_pdu_size);
847fcf3ce44SJohn Forte 	out_pdu = NULL;
848fcf3ce44SJohn Forte 
849fcf3ce44SJohn Forte 	rcv_rsp_cnt = 0;
850fcf3ce44SJohn Forte 	for (;;) {
851fcf3ce44SJohn Forte 		bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
852fcf3ce44SJohn Forte 		ASSERT(bytes_received >= (size_t)0);
853fcf3ce44SJohn Forte 		if (bytes_received == 0) {
854fcf3ce44SJohn Forte 			ASSERT(in_pdu == NULL);
855fcf3ce44SJohn Forte 			ASSERT(in_pdu_size == 0);
856fcf3ce44SJohn Forte 			rval = isns_rcv_msg_err;
857fcf3ce44SJohn Forte 			break;
858fcf3ce44SJohn Forte 		}
859fcf3ce44SJohn Forte 
860fcf3ce44SJohn Forte 		ASSERT(in_pdu != NULL);
861fcf3ce44SJohn Forte 		ASSERT(in_pdu_size > 0);
862fcf3ce44SJohn Forte 
863fcf3ce44SJohn Forte 		if (ntohs(in_pdu->xid) != xid) {
864fcf3ce44SJohn Forte 			rcv_rsp_cnt++;
865fcf3ce44SJohn Forte 			if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
866fcf3ce44SJohn Forte 				continue;
867fcf3ce44SJohn Forte 			} else {
868fcf3ce44SJohn Forte 				/* Exceed maximum receive count. */
869fcf3ce44SJohn Forte 				kmem_free(in_pdu, in_pdu_size);
870fcf3ce44SJohn Forte 				in_pdu = NULL;
871fcf3ce44SJohn Forte 				rval = isns_no_rsp_rcvd;
872fcf3ce44SJohn Forte 				break;
873fcf3ce44SJohn Forte 			}
874fcf3ce44SJohn Forte 		}
875fcf3ce44SJohn Forte 
876fcf3ce44SJohn Forte 		rsp_status = isns_process_scn_reg_rsp(in_pdu);
877fcf3ce44SJohn Forte 		if (rsp_status != ISNS_RSP_SUCCESSFUL) {
878fcf3ce44SJohn Forte 			rval = isns_op_failed;
879fcf3ce44SJohn Forte 		}
880fcf3ce44SJohn Forte 		kmem_free(in_pdu, in_pdu_size);
881fcf3ce44SJohn Forte 		in_pdu = NULL;
882fcf3ce44SJohn Forte 		break;
883fcf3ce44SJohn Forte 	}
884fcf3ce44SJohn Forte 
885fcf3ce44SJohn Forte 	iscsi_net->close(so);
886fcf3ce44SJohn Forte 
887fcf3ce44SJohn Forte 	return (rval);
888fcf3ce44SJohn Forte }
889fcf3ce44SJohn Forte 
890fcf3ce44SJohn Forte static
891fcf3ce44SJohn Forte isns_status_t
do_isns_dev_dereg(iscsi_addr_t * isns_server_addr,uint8_t * node_name)892fcf3ce44SJohn Forte do_isns_dev_dereg(iscsi_addr_t *isns_server_addr,
893fcf3ce44SJohn Forte 	uint8_t *node_name)
894fcf3ce44SJohn Forte {
895fcf3ce44SJohn Forte 	int rcv_rsp_cnt = 0;
896fcf3ce44SJohn Forte 	int rsp_status;
897fcf3ce44SJohn Forte 	isns_pdu_t *in_pdu, *out_pdu;
898fcf3ce44SJohn Forte 	isns_status_t rval;
899fcf3ce44SJohn Forte 	size_t bytes_received, in_pdu_size = 0, out_pdu_size = 0;
900fcf3ce44SJohn Forte 	uint16_t xid;
901fcf3ce44SJohn Forte 	void *so = NULL;
902fcf3ce44SJohn Forte 
903fcf3ce44SJohn Forte 	out_pdu_size = isns_create_dev_dereg_pdu(
904fcf3ce44SJohn Forte 	    node_name,
905fcf3ce44SJohn Forte 	    &xid, &out_pdu);
906fcf3ce44SJohn Forte 	if (out_pdu_size == 0) {
907fcf3ce44SJohn Forte 		return (isns_create_msg_err);
908fcf3ce44SJohn Forte 	}
909fcf3ce44SJohn Forte 
910fcf3ce44SJohn Forte 	ASSERT(out_pdu != NULL);
911fcf3ce44SJohn Forte 	ASSERT(out_pdu_size > 0);
912fcf3ce44SJohn Forte 
913fcf3ce44SJohn Forte 	so = isns_open(isns_server_addr);
914fcf3ce44SJohn Forte 	if (so == NULL) {
915fcf3ce44SJohn Forte 		/* Log a message and return */
916fcf3ce44SJohn Forte 		kmem_free(out_pdu, out_pdu_size);
917fcf3ce44SJohn Forte 		out_pdu = NULL;
918fcf3ce44SJohn Forte 		return (isns_open_conn_err);
919fcf3ce44SJohn Forte 	}
920fcf3ce44SJohn Forte 
921fcf3ce44SJohn Forte 	if (isns_send_pdu(so, out_pdu) != 0) {
922fcf3ce44SJohn Forte 		iscsi_net->close(so);
923fcf3ce44SJohn Forte 		kmem_free(out_pdu, out_pdu_size);
924fcf3ce44SJohn Forte 		out_pdu = NULL;
925fcf3ce44SJohn Forte 		return (isns_send_msg_err);
926fcf3ce44SJohn Forte 	}
927fcf3ce44SJohn Forte 
928fcf3ce44SJohn Forte 	/* Done with the out PDU - free it */
929fcf3ce44SJohn Forte 	kmem_free(out_pdu, out_pdu_size);
930fcf3ce44SJohn Forte 	out_pdu = NULL;
931fcf3ce44SJohn Forte 
932fcf3ce44SJohn Forte 	rcv_rsp_cnt = 0;
933fcf3ce44SJohn Forte 	rval = isns_ok;
934fcf3ce44SJohn Forte 	for (;;) {
935fcf3ce44SJohn Forte 		bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
936fcf3ce44SJohn Forte 		ASSERT(bytes_received >= (size_t)0);
937fcf3ce44SJohn Forte 		if (bytes_received == 0) {
938fcf3ce44SJohn Forte 			ASSERT(in_pdu == NULL);
939fcf3ce44SJohn Forte 			ASSERT(in_pdu_size == 0);
940fcf3ce44SJohn Forte 			rval = isns_rcv_msg_err;
941fcf3ce44SJohn Forte 			break;
942fcf3ce44SJohn Forte 		}
943fcf3ce44SJohn Forte 
944fcf3ce44SJohn Forte 		ASSERT(in_pdu != NULL);
945fcf3ce44SJohn Forte 		ASSERT(in_pdu_size > 0);
946fcf3ce44SJohn Forte 
947fcf3ce44SJohn Forte 		if (ntohs(in_pdu->xid) != xid) {
948fcf3ce44SJohn Forte 			rcv_rsp_cnt++;
949fcf3ce44SJohn Forte 			if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
950fcf3ce44SJohn Forte 				continue;
951fcf3ce44SJohn Forte 			} else {
952fcf3ce44SJohn Forte 				/* Exceed maximum receive count. */
953fcf3ce44SJohn Forte 				kmem_free(in_pdu, in_pdu_size);
954fcf3ce44SJohn Forte 				in_pdu = NULL;
955fcf3ce44SJohn Forte 				rval = isns_no_rsp_rcvd;
956fcf3ce44SJohn Forte 				break;
957fcf3ce44SJohn Forte 			}
958fcf3ce44SJohn Forte 		}
959fcf3ce44SJohn Forte 
960fcf3ce44SJohn Forte 		rsp_status = isns_process_dev_attr_dereg_rsp(in_pdu);
961fcf3ce44SJohn Forte 		if (rsp_status != ISNS_RSP_SUCCESSFUL) {
962fcf3ce44SJohn Forte 			rval = isns_op_failed;
963fcf3ce44SJohn Forte 		}
964fcf3ce44SJohn Forte 		kmem_free(in_pdu, in_pdu_size);
965fcf3ce44SJohn Forte 		in_pdu = NULL;
966fcf3ce44SJohn Forte 		break;
967fcf3ce44SJohn Forte 	}
968fcf3ce44SJohn Forte 
969fcf3ce44SJohn Forte 	if (rval != isns_ok) {
970fcf3ce44SJohn Forte 		iscsi_net->close(so);
971fcf3ce44SJohn Forte 		return (rval);
972fcf3ce44SJohn Forte 	}
973fcf3ce44SJohn Forte 
974fcf3ce44SJohn Forte 	/* Always deregister SCN */
975fcf3ce44SJohn Forte 	out_pdu_size = isns_create_scn_dereg_pdu(
976fcf3ce44SJohn Forte 	    node_name,
977fcf3ce44SJohn Forte 	    &xid, &out_pdu);
978fcf3ce44SJohn Forte 	if (out_pdu_size == 0) {
979fcf3ce44SJohn Forte 		iscsi_net->close(so);
980fcf3ce44SJohn Forte 		return (isns_create_msg_err);
981fcf3ce44SJohn Forte 	}
982fcf3ce44SJohn Forte 
983fcf3ce44SJohn Forte 	ASSERT(out_pdu != NULL);
984fcf3ce44SJohn Forte 	ASSERT(out_pdu_size > 0);
985fcf3ce44SJohn Forte 
986fcf3ce44SJohn Forte 	if (isns_send_pdu(so, out_pdu) != 0) {
987fcf3ce44SJohn Forte 		iscsi_net->close(so);
988fcf3ce44SJohn Forte 		kmem_free(out_pdu, out_pdu_size);
989fcf3ce44SJohn Forte 		out_pdu = NULL;
990fcf3ce44SJohn Forte 		return (isns_send_msg_err);
991fcf3ce44SJohn Forte 	}
992fcf3ce44SJohn Forte 
993fcf3ce44SJohn Forte 	/* Done with the out PDU - free it */
994fcf3ce44SJohn Forte 	kmem_free(out_pdu, out_pdu_size);
995fcf3ce44SJohn Forte 	out_pdu = NULL;
996fcf3ce44SJohn Forte 
997fcf3ce44SJohn Forte 	rcv_rsp_cnt = 0;
998fcf3ce44SJohn Forte 	for (;;) {
999fcf3ce44SJohn Forte 		bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
1000fcf3ce44SJohn Forte 		ASSERT(bytes_received >= (size_t)0);
1001fcf3ce44SJohn Forte 		if (bytes_received == 0) {
1002fcf3ce44SJohn Forte 			ASSERT(in_pdu == NULL);
1003fcf3ce44SJohn Forte 			ASSERT(in_pdu_size == 0);
1004fcf3ce44SJohn Forte 			rval = isns_rcv_msg_err;
1005fcf3ce44SJohn Forte 			break;
1006fcf3ce44SJohn Forte 		}
1007fcf3ce44SJohn Forte 
1008fcf3ce44SJohn Forte 		ASSERT(in_pdu != NULL);
1009fcf3ce44SJohn Forte 		ASSERT(in_pdu_size > 0);
1010fcf3ce44SJohn Forte 
1011fcf3ce44SJohn Forte 		if (ntohs(in_pdu->xid) != xid) {
1012fcf3ce44SJohn Forte 			rcv_rsp_cnt++;
1013fcf3ce44SJohn Forte 			if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
1014fcf3ce44SJohn Forte 				continue;
1015fcf3ce44SJohn Forte 			} else {
1016fcf3ce44SJohn Forte 				/* Exceed maximum receive count. */
1017fcf3ce44SJohn Forte 				kmem_free(in_pdu, in_pdu_size);
1018fcf3ce44SJohn Forte 				in_pdu = NULL;
1019fcf3ce44SJohn Forte 				rval = isns_no_rsp_rcvd;
1020fcf3ce44SJohn Forte 				break;
1021fcf3ce44SJohn Forte 			}
1022fcf3ce44SJohn Forte 		}
1023fcf3ce44SJohn Forte 
1024fcf3ce44SJohn Forte 		rsp_status = isns_process_scn_dereg_rsp(in_pdu);
1025fcf3ce44SJohn Forte 		if (rsp_status != ISNS_RSP_SUCCESSFUL) {
1026fcf3ce44SJohn Forte 			rval = isns_op_failed;
1027fcf3ce44SJohn Forte 		}
1028fcf3ce44SJohn Forte 		kmem_free(in_pdu, in_pdu_size);
1029fcf3ce44SJohn Forte 		in_pdu = NULL;
1030fcf3ce44SJohn Forte 		break;
1031fcf3ce44SJohn Forte 	}
1032fcf3ce44SJohn Forte 
1033fcf3ce44SJohn Forte 	iscsi_net->close(so);
1034fcf3ce44SJohn Forte 
1035fcf3ce44SJohn Forte 	return (rval);
1036fcf3ce44SJohn Forte }
1037fcf3ce44SJohn Forte 
1038fcf3ce44SJohn Forte static
1039fcf3ce44SJohn Forte isns_status_t
do_isns_query(boolean_t is_query_all_nodes_b,uint8_t * lhba_handle,uint8_t * target_node_name,uint8_t * source_node_name,uint8_t * source_node_alias,uint32_t source_node_type,isns_portal_group_list_t ** pg_list)1040fcf3ce44SJohn Forte do_isns_query(boolean_t is_query_all_nodes_b,
1041fcf3ce44SJohn Forte 	uint8_t *lhba_handle,
1042fcf3ce44SJohn Forte 	uint8_t *target_node_name,
1043fcf3ce44SJohn Forte 	uint8_t *source_node_name,
1044fcf3ce44SJohn Forte 	uint8_t *source_node_alias,
1045fcf3ce44SJohn Forte 	uint32_t source_node_type,
1046fcf3ce44SJohn Forte 	isns_portal_group_list_t **pg_list)
1047fcf3ce44SJohn Forte {
1048fcf3ce44SJohn Forte 	int i, j, k;
1049fcf3ce44SJohn Forte 	int combined_num_of_pgs, combined_pg_lst_sz,
1050fcf3ce44SJohn Forte 	    isns_svr_lst_sz,
1051fcf3ce44SJohn Forte 	    tmp_pg_list_sz,
1052fcf3ce44SJohn Forte 	    tmp_pg_lists_sz;
1053fcf3ce44SJohn Forte 	iscsi_addr_list_t *isns_server_addr_list = NULL;
1054fcf3ce44SJohn Forte 	isns_portal_group_t *pg;
1055fcf3ce44SJohn Forte 	isns_portal_group_list_t *combined_pg_list,
1056fcf3ce44SJohn Forte 	    *tmp_pg_list, **tmp_pg_lists;
1057fcf3ce44SJohn Forte 	isns_status_t qry_stat, combined_qry_stat;
1058fcf3ce44SJohn Forte 
1059fcf3ce44SJohn Forte 	/* Look up the iSNS Server address(es) based on the specified ISID */
1060fcf3ce44SJohn Forte 	if (discover_isns_server(lhba_handle, &isns_server_addr_list) !=
1061fcf3ce44SJohn Forte 	    ISNS_OK) {
1062fcf3ce44SJohn Forte 		*pg_list = NULL;
1063fcf3ce44SJohn Forte 		return (isns_no_svr_found);
1064fcf3ce44SJohn Forte 	}
1065fcf3ce44SJohn Forte 	if (isns_server_addr_list->al_out_cnt == 0) {
1066fcf3ce44SJohn Forte 		isns_svr_lst_sz = sizeof (iscsi_addr_list_t);
1067fcf3ce44SJohn Forte 		kmem_free(isns_server_addr_list, isns_svr_lst_sz);
1068fcf3ce44SJohn Forte 		isns_server_addr_list = NULL;
1069fcf3ce44SJohn Forte 		*pg_list = NULL;
1070fcf3ce44SJohn Forte 		return (isns_no_svr_found);
1071fcf3ce44SJohn Forte 	}
1072fcf3ce44SJohn Forte 
1073fcf3ce44SJohn Forte 	/*
1074fcf3ce44SJohn Forte 	 * isns_server_addr_list->al_out_cnt should not be zero by the
1075fcf3ce44SJohn Forte 	 * time it comes to this point.
1076fcf3ce44SJohn Forte 	 */
1077fcf3ce44SJohn Forte 	tmp_pg_lists_sz = isns_server_addr_list->al_out_cnt *
1078fcf3ce44SJohn Forte 	    sizeof (isns_portal_group_list_t *);
1079fcf3ce44SJohn Forte 	tmp_pg_lists = (isns_portal_group_list_t **)kmem_zalloc(
1080fcf3ce44SJohn Forte 	    tmp_pg_lists_sz, KM_SLEEP);
1081fcf3ce44SJohn Forte 	combined_num_of_pgs = 0;
1082fcf3ce44SJohn Forte 	combined_qry_stat = isns_ok;
1083fcf3ce44SJohn Forte 	for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
1084fcf3ce44SJohn Forte 		if (is_query_all_nodes_b) {
1085fcf3ce44SJohn Forte 			qry_stat = do_isns_dev_attr_query_all_nodes(
1086fcf3ce44SJohn Forte 			    &isns_server_addr_list->al_addrs[i],
1087fcf3ce44SJohn Forte 			    source_node_name,
1088fcf3ce44SJohn Forte 			    source_node_alias,
1089fcf3ce44SJohn Forte 			    &tmp_pg_list);
1090fcf3ce44SJohn Forte 		} else {
1091fcf3ce44SJohn Forte 			qry_stat = do_isns_dev_attr_query_one_node(
1092fcf3ce44SJohn Forte 			    &isns_server_addr_list->al_addrs[i],
1093fcf3ce44SJohn Forte 			    target_node_name,
1094fcf3ce44SJohn Forte 			    source_node_name,
1095fcf3ce44SJohn Forte 			    source_node_alias,
1096fcf3ce44SJohn Forte 			    source_node_type,
1097fcf3ce44SJohn Forte 			    &tmp_pg_list);
1098fcf3ce44SJohn Forte 		}
1099fcf3ce44SJohn Forte 
1100fcf3ce44SJohn Forte 		/* Record the portal group list retrieved from this server. */
1101fcf3ce44SJohn Forte 		tmp_pg_lists[i] = tmp_pg_list;
1102fcf3ce44SJohn Forte 		if (tmp_pg_list != NULL) {
1103fcf3ce44SJohn Forte 			combined_num_of_pgs += tmp_pg_list->pg_out_cnt;
1104fcf3ce44SJohn Forte 		}
1105fcf3ce44SJohn Forte 
1106fcf3ce44SJohn Forte 		if (qry_stat == isns_ok) {
1107fcf3ce44SJohn Forte 			if (combined_qry_stat != isns_ok) {
1108fcf3ce44SJohn Forte 				combined_qry_stat = isns_op_partially_failed;
1109fcf3ce44SJohn Forte 			}
1110fcf3ce44SJohn Forte 		} else {
1111fcf3ce44SJohn Forte 			if (combined_qry_stat != isns_op_partially_failed) {
1112fcf3ce44SJohn Forte 				if (combined_qry_stat == isns_ok && i > 0) {
1113fcf3ce44SJohn Forte 					combined_qry_stat =
1114fcf3ce44SJohn Forte 					    isns_op_partially_failed;
1115fcf3ce44SJohn Forte 				} else {
1116fcf3ce44SJohn Forte 					combined_qry_stat = qry_stat;
1117fcf3ce44SJohn Forte 				}
1118fcf3ce44SJohn Forte 			}
1119fcf3ce44SJohn Forte 		}
1120fcf3ce44SJohn Forte 
1121fcf3ce44SJohn Forte 		if (is_query_all_nodes_b == B_FALSE) {
1122fcf3ce44SJohn Forte 			if (qry_stat == isns_ok) {
1123fcf3ce44SJohn Forte 				/*
1124fcf3ce44SJohn Forte 				 * Break out of the loop if we already got
1125fcf3ce44SJohn Forte 				 * the node information for one node.
1126fcf3ce44SJohn Forte 				 */
1127fcf3ce44SJohn Forte 				break;
1128fcf3ce44SJohn Forte 			}
1129fcf3ce44SJohn Forte 		}
1130fcf3ce44SJohn Forte 	}
1131fcf3ce44SJohn Forte 
1132fcf3ce44SJohn Forte 	/* Merge the retrieved portal lists */
1133fcf3ce44SJohn Forte 	combined_pg_lst_sz = sizeof (isns_portal_group_list_t);
1134fcf3ce44SJohn Forte 	if (combined_num_of_pgs > 0) {
1135fcf3ce44SJohn Forte 		combined_pg_lst_sz += (combined_num_of_pgs - 1) *
1136fcf3ce44SJohn Forte 		    sizeof (isns_portal_group_t);
1137fcf3ce44SJohn Forte 	}
1138fcf3ce44SJohn Forte 	combined_pg_list = (isns_portal_group_list_t *)kmem_zalloc(
1139fcf3ce44SJohn Forte 	    combined_pg_lst_sz, KM_SLEEP);
1140fcf3ce44SJohn Forte 
1141fcf3ce44SJohn Forte 	combined_pg_list->pg_out_cnt = combined_num_of_pgs;
1142fcf3ce44SJohn Forte 	k = 0;
1143fcf3ce44SJohn Forte 	for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
1144fcf3ce44SJohn Forte 		if (tmp_pg_lists[i] == NULL) {
1145fcf3ce44SJohn Forte 			continue;
1146fcf3ce44SJohn Forte 		}
1147fcf3ce44SJohn Forte 		for (j = 0; j < tmp_pg_lists[i]->pg_out_cnt; j++) {
1148fcf3ce44SJohn Forte 			pg = &(combined_pg_list->pg_list[k]);
1149fcf3ce44SJohn Forte 			bcopy(&(tmp_pg_lists[i]->pg_list[j]),
1150fcf3ce44SJohn Forte 			    pg, sizeof (isns_portal_group_t));
1151fcf3ce44SJohn Forte 			k++;
1152fcf3ce44SJohn Forte 		}
1153fcf3ce44SJohn Forte 		tmp_pg_list_sz = sizeof (isns_portal_group_list_t);
1154fcf3ce44SJohn Forte 		if (tmp_pg_lists[i]->pg_out_cnt > 0) {
1155fcf3ce44SJohn Forte 			tmp_pg_list_sz += (tmp_pg_lists[i]->pg_out_cnt - 1) *
1156fcf3ce44SJohn Forte 			    sizeof (isns_portal_group_t);
1157fcf3ce44SJohn Forte 		}
1158fcf3ce44SJohn Forte 		kmem_free(tmp_pg_lists[i], tmp_pg_list_sz);
1159fcf3ce44SJohn Forte 		tmp_pg_lists[i] = NULL;
1160fcf3ce44SJohn Forte 	}
1161fcf3ce44SJohn Forte 	kmem_free(tmp_pg_lists, tmp_pg_lists_sz);
1162fcf3ce44SJohn Forte 	tmp_pg_lists = NULL;
1163fcf3ce44SJohn Forte 
1164fcf3ce44SJohn Forte 	isns_svr_lst_sz = sizeof (iscsi_addr_list_t);
1165fcf3ce44SJohn Forte 	if (isns_server_addr_list->al_out_cnt > 0) {
1166fcf3ce44SJohn Forte 		isns_svr_lst_sz += (sizeof (iscsi_addr_t) *
1167fcf3ce44SJohn Forte 		    (isns_server_addr_list->al_out_cnt - 1));
1168fcf3ce44SJohn Forte 	}
1169fcf3ce44SJohn Forte 	kmem_free(isns_server_addr_list, isns_svr_lst_sz);
1170fcf3ce44SJohn Forte 	isns_server_addr_list = NULL;
1171fcf3ce44SJohn Forte 
1172fcf3ce44SJohn Forte 	DTRACE_PROBE1(list, isns_portal_group_list_t *, combined_pg_list);
1173fcf3ce44SJohn Forte 
1174fcf3ce44SJohn Forte 	*pg_list = combined_pg_list;
1175fcf3ce44SJohn Forte 	return (combined_qry_stat);
1176fcf3ce44SJohn Forte }
1177fcf3ce44SJohn Forte 
1178fcf3ce44SJohn Forte static
1179fcf3ce44SJohn Forte isns_status_t
do_isns_dev_attr_query_all_nodes(iscsi_addr_t * isns_server_addr,uint8_t * node_name,uint8_t * node_alias,isns_portal_group_list_t ** pg_list)1180fcf3ce44SJohn Forte do_isns_dev_attr_query_all_nodes(iscsi_addr_t *isns_server_addr,
1181fcf3ce44SJohn Forte 	uint8_t *node_name,
1182fcf3ce44SJohn Forte 	uint8_t *node_alias,
1183fcf3ce44SJohn Forte 	isns_portal_group_list_t **pg_list)
1184fcf3ce44SJohn Forte {
1185fcf3ce44SJohn Forte 	int bytes_received;
1186fcf3ce44SJohn Forte 	int rcv_rsp_cnt = 0;
1187fcf3ce44SJohn Forte 	int rsp_status;
1188fcf3ce44SJohn Forte 	uint16_t xid, seq_id = 0, func_id;
1189fcf3ce44SJohn Forte 	isns_pdu_t *in_pdu, *out_pdu;
1190fcf3ce44SJohn Forte 	isns_pdu_mult_payload_t *combined_pdu = NULL, *old_combined_pdu = NULL;
1191fcf3ce44SJohn Forte 	isns_status_t qry_stat;
1192fcf3ce44SJohn Forte 	size_t out_pdu_size = 0, in_pdu_size = 0;
1193fcf3ce44SJohn Forte 	size_t old_combined_pdu_size = 0, combined_pdu_size = 0;
1194fcf3ce44SJohn Forte 	void *so = NULL;
1195fcf3ce44SJohn Forte 	uint8_t *payload_ptr;
1196fcf3ce44SJohn Forte 
1197fcf3ce44SJohn Forte 	/* Initialize */
1198fcf3ce44SJohn Forte 	*pg_list = NULL;
1199fcf3ce44SJohn Forte 
1200fcf3ce44SJohn Forte 	so = isns_open(isns_server_addr);
1201fcf3ce44SJohn Forte 	if (so == NULL) {
1202fcf3ce44SJohn Forte 		/* Log a message and return */
1203fcf3ce44SJohn Forte 		return (isns_open_conn_err);
1204fcf3ce44SJohn Forte 	}
1205fcf3ce44SJohn Forte 
1206fcf3ce44SJohn Forte 	/*
1207fcf3ce44SJohn Forte 	 * Then, ask for all PG attributes. Filter the non-target nodes.
1208fcf3ce44SJohn Forte 	 */
1209fcf3ce44SJohn Forte 	out_pdu_size = isns_create_dev_attr_qry_target_nodes_pdu(
1210fcf3ce44SJohn Forte 	    node_name, node_alias, &xid, &out_pdu);
1211fcf3ce44SJohn Forte 	if (out_pdu_size == 0) {
1212fcf3ce44SJohn Forte 		iscsi_net->close(so);
1213fcf3ce44SJohn Forte 		return (isns_create_msg_err);
1214fcf3ce44SJohn Forte 	}
1215fcf3ce44SJohn Forte 
1216fcf3ce44SJohn Forte 	ASSERT(out_pdu != NULL);
1217fcf3ce44SJohn Forte 	ASSERT(out_pdu_size > 0);
1218fcf3ce44SJohn Forte 
1219fcf3ce44SJohn Forte 	if (isns_send_pdu(so, out_pdu) != 0) {
1220fcf3ce44SJohn Forte 		iscsi_net->close(so);
1221fcf3ce44SJohn Forte 		kmem_free(out_pdu, out_pdu_size);
1222fcf3ce44SJohn Forte 		out_pdu = NULL;
1223fcf3ce44SJohn Forte 		return (isns_send_msg_err);
1224fcf3ce44SJohn Forte 	}
1225fcf3ce44SJohn Forte 
1226fcf3ce44SJohn Forte 	/* Done with the out PDU - free it */
1227fcf3ce44SJohn Forte 	kmem_free(out_pdu, out_pdu_size);
1228fcf3ce44SJohn Forte 	out_pdu = NULL;
1229fcf3ce44SJohn Forte 
1230fcf3ce44SJohn Forte 	rcv_rsp_cnt = 0;
1231fcf3ce44SJohn Forte 	qry_stat = isns_ok;
1232fcf3ce44SJohn Forte 	for (;;) {
1233fcf3ce44SJohn Forte 		uint16_t flags;
1234fcf3ce44SJohn Forte 
1235fcf3ce44SJohn Forte 		bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
1236fcf3ce44SJohn Forte 		ASSERT(bytes_received >= 0);
1237fcf3ce44SJohn Forte 		if (bytes_received == 0) {
1238fcf3ce44SJohn Forte 			ASSERT(in_pdu == NULL);
1239fcf3ce44SJohn Forte 			ASSERT(in_pdu_size == 0);
1240fcf3ce44SJohn Forte 			qry_stat = isns_rcv_msg_err;
1241fcf3ce44SJohn Forte 			break;
1242fcf3ce44SJohn Forte 		}
1243fcf3ce44SJohn Forte 
1244fcf3ce44SJohn Forte 		ASSERT(in_pdu != NULL);
1245fcf3ce44SJohn Forte 		ASSERT(in_pdu_size > 0);
1246fcf3ce44SJohn Forte 
1247fcf3ce44SJohn Forte 		/*
1248fcf3ce44SJohn Forte 		 * make sure we are processing the right transaction id
1249fcf3ce44SJohn Forte 		 */
1250fcf3ce44SJohn Forte 		if (ntohs(in_pdu->xid) != xid) {
1251fcf3ce44SJohn Forte 			rcv_rsp_cnt++;
1252fcf3ce44SJohn Forte 			if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
1253fcf3ce44SJohn Forte 				kmem_free(in_pdu, in_pdu_size);
1254fcf3ce44SJohn Forte 				in_pdu = NULL;
1255fcf3ce44SJohn Forte 				continue;
1256fcf3ce44SJohn Forte 			} else {
1257fcf3ce44SJohn Forte 				/* Exceed maximum receive count. */
1258fcf3ce44SJohn Forte 				kmem_free(in_pdu, in_pdu_size);
1259fcf3ce44SJohn Forte 				in_pdu = NULL;
1260fcf3ce44SJohn Forte 				qry_stat = isns_no_rsp_rcvd;
1261fcf3ce44SJohn Forte 				break;
1262fcf3ce44SJohn Forte 			}
1263fcf3ce44SJohn Forte 		}
1264fcf3ce44SJohn Forte 
1265fcf3ce44SJohn Forte 		/*
1266fcf3ce44SJohn Forte 		 * check to see if FIRST and LAST PDU flag is set
1267fcf3ce44SJohn Forte 		 * if they are both set, then this response only has one
1268fcf3ce44SJohn Forte 		 * pdu and we can process the pdu
1269fcf3ce44SJohn Forte 		 */
1270fcf3ce44SJohn Forte 		flags = in_pdu->flags;
1271fcf3ce44SJohn Forte 		if (((flags & ISNS_FLAG_FIRST_PDU) == ISNS_FLAG_FIRST_PDU) &&
1272fcf3ce44SJohn Forte 		    ((flags & ISNS_FLAG_LAST_PDU) == ISNS_FLAG_LAST_PDU)) {
1273fcf3ce44SJohn Forte 			rsp_status =
1274fcf3ce44SJohn Forte 			    isns_process_dev_attr_qry_target_nodes_pdu(
1275fcf3ce44SJohn Forte 			    isns_server_addr,
1276fcf3ce44SJohn Forte 			    in_pdu->func_id,
1277fcf3ce44SJohn Forte 			    (isns_resp_t *)in_pdu->payload,
1278fcf3ce44SJohn Forte 			    (size_t)in_pdu->payload_len,
1279fcf3ce44SJohn Forte 			    pg_list);
1280fcf3ce44SJohn Forte 			kmem_free(in_pdu, in_pdu_size);
1281fcf3ce44SJohn Forte 			in_pdu = NULL;
1282fcf3ce44SJohn Forte 			break;
1283fcf3ce44SJohn Forte 		}
1284fcf3ce44SJohn Forte 		/*
1285fcf3ce44SJohn Forte 		 * this pdu is part of a multi-pdu response.  save off the
1286fcf3ce44SJohn Forte 		 * the payload of this pdu and continue processing
1287fcf3ce44SJohn Forte 		 */
1288fcf3ce44SJohn Forte 		if ((flags & ISNS_FLAG_FIRST_PDU) == ISNS_FLAG_FIRST_PDU) {
1289fcf3ce44SJohn Forte 			/* This is the first pdu, make sure sequence ID is 0 */
1290fcf3ce44SJohn Forte 			if (in_pdu->seq != 0) {
1291fcf3ce44SJohn Forte 				cmn_err(CE_NOTE, "isns query response invalid: "
1292fcf3ce44SJohn Forte 				    "first pdu is not sequence ID 0");
1293fcf3ce44SJohn Forte 				kmem_free(in_pdu, in_pdu_size);
1294fcf3ce44SJohn Forte 				in_pdu = NULL;
1295fcf3ce44SJohn Forte 				return (isns_op_failed);
1296fcf3ce44SJohn Forte 			}
1297fcf3ce44SJohn Forte 			seq_id = 0;
1298fcf3ce44SJohn Forte 
1299fcf3ce44SJohn Forte 			/* create new pdu and copy in data from old pdu */
1300fcf3ce44SJohn Forte 			combined_pdu_size = ISNSP_MULT_PAYLOAD_HEADER_SIZE +
1301fcf3ce44SJohn Forte 			    in_pdu->payload_len;
1302fcf3ce44SJohn Forte 			combined_pdu = (isns_pdu_mult_payload_t *)kmem_zalloc(
1303fcf3ce44SJohn Forte 			    combined_pdu_size, KM_SLEEP);
1304fcf3ce44SJohn Forte 			func_id = in_pdu->func_id;
1305fcf3ce44SJohn Forte 			combined_pdu->payload_len = in_pdu->payload_len;
1306fcf3ce44SJohn Forte 			bcopy(in_pdu->payload, combined_pdu->payload,
1307fcf3ce44SJohn Forte 			    in_pdu->payload_len);
1308fcf3ce44SJohn Forte 
1309fcf3ce44SJohn Forte 			/* done with in_pdu, free it */
1310fcf3ce44SJohn Forte 			kmem_free(in_pdu, in_pdu_size);
1311fcf3ce44SJohn Forte 			in_pdu = NULL;
1312fcf3ce44SJohn Forte 		} else {
1313fcf3ce44SJohn Forte 			seq_id++;
1314fcf3ce44SJohn Forte 			if (in_pdu->seq != seq_id) {
1315fcf3ce44SJohn Forte 				cmn_err(CE_NOTE, "isns query response invalid: "
1316fcf3ce44SJohn Forte 				    "Missing sequence ID %d from isns query "
1317fcf3ce44SJohn Forte 				    "response.", seq_id);
1318fcf3ce44SJohn Forte 				kmem_free(in_pdu, in_pdu_size);
1319fcf3ce44SJohn Forte 				in_pdu = NULL;
1320fcf3ce44SJohn Forte 				if (combined_pdu != NULL) {
1321fcf3ce44SJohn Forte 					kmem_free(combined_pdu,
1322fcf3ce44SJohn Forte 					    combined_pdu_size);
1323fcf3ce44SJohn Forte 					combined_pdu = NULL;
1324fcf3ce44SJohn Forte 				}
1325fcf3ce44SJohn Forte 				return (isns_op_failed);
1326fcf3ce44SJohn Forte 			}
1327fcf3ce44SJohn Forte 			/*
1328fcf3ce44SJohn Forte 			 * if conbined_pdu_size is still zero, then we never
1329fcf3ce44SJohn Forte 			 * processed the first pdu
1330fcf3ce44SJohn Forte 			 */
1331fcf3ce44SJohn Forte 			if (combined_pdu_size == 0) {
1332fcf3ce44SJohn Forte 				cmn_err(CE_NOTE, "isns query response invalid: "
1333fcf3ce44SJohn Forte 				    "Did not receive first pdu.\n");
1334fcf3ce44SJohn Forte 				kmem_free(in_pdu, in_pdu_size);
1335fcf3ce44SJohn Forte 				in_pdu = NULL;
1336fcf3ce44SJohn Forte 				return (isns_op_failed);
1337fcf3ce44SJohn Forte 			}
1338fcf3ce44SJohn Forte 			/* save off the old combined pdu */
1339fcf3ce44SJohn Forte 			old_combined_pdu_size = combined_pdu_size;
1340fcf3ce44SJohn Forte 			old_combined_pdu = combined_pdu;
1341fcf3ce44SJohn Forte 
1342fcf3ce44SJohn Forte 			/*
1343fcf3ce44SJohn Forte 			 * alloc a new pdu big enough to also hold the new
1344fcf3ce44SJohn Forte 			 * pdu payload
1345fcf3ce44SJohn Forte 			 */
1346fcf3ce44SJohn Forte 			combined_pdu_size += in_pdu->payload_len;
1347fcf3ce44SJohn Forte 			combined_pdu = (isns_pdu_mult_payload_t *)kmem_zalloc(
1348fcf3ce44SJohn Forte 			    combined_pdu_size, KM_SLEEP);
1349fcf3ce44SJohn Forte 
1350fcf3ce44SJohn Forte 			/*
1351fcf3ce44SJohn Forte 			 * copy the old pdu into the new allocated pdu buffer
1352fcf3ce44SJohn Forte 			 * and append on the new pdu payload that we just
1353fcf3ce44SJohn Forte 			 * received
1354fcf3ce44SJohn Forte 			 */
1355fcf3ce44SJohn Forte 			bcopy(old_combined_pdu, combined_pdu,
1356fcf3ce44SJohn Forte 			    old_combined_pdu_size);
1357fcf3ce44SJohn Forte 
1358fcf3ce44SJohn Forte 			payload_ptr = combined_pdu->payload +
1359fcf3ce44SJohn Forte 			    combined_pdu->payload_len;
1360fcf3ce44SJohn Forte 			combined_pdu->payload_len += in_pdu->payload_len;
1361fcf3ce44SJohn Forte 			bcopy(in_pdu->payload, payload_ptr,
1362fcf3ce44SJohn Forte 			    in_pdu->payload_len);
1363fcf3ce44SJohn Forte 
1364fcf3ce44SJohn Forte 			/* free in_pdu and old_combined_pdu */
1365fcf3ce44SJohn Forte 			kmem_free(in_pdu, in_pdu_size);
1366fcf3ce44SJohn Forte 			kmem_free(old_combined_pdu, old_combined_pdu_size);
1367fcf3ce44SJohn Forte 			in_pdu = NULL;
1368fcf3ce44SJohn Forte 			old_combined_pdu = NULL;
1369fcf3ce44SJohn Forte 		}
1370fcf3ce44SJohn Forte 		/*
1371fcf3ce44SJohn Forte 		 * check to see if this is the LAST pdu.
1372fcf3ce44SJohn Forte 		 * if it is, we can process it and move on
1373fcf3ce44SJohn Forte 		 * otherwise continue to wait for the next pdu
1374fcf3ce44SJohn Forte 		 */
1375fcf3ce44SJohn Forte 		if ((flags & ISNS_FLAG_LAST_PDU) == ISNS_FLAG_LAST_PDU) {
1376fcf3ce44SJohn Forte 			rsp_status =
1377fcf3ce44SJohn Forte 			    isns_process_dev_attr_qry_target_nodes_pdu(
1378fcf3ce44SJohn Forte 			    isns_server_addr,
1379fcf3ce44SJohn Forte 			    func_id,
1380fcf3ce44SJohn Forte 			    (isns_resp_t *)combined_pdu->payload,
1381fcf3ce44SJohn Forte 			    combined_pdu->payload_len,
1382fcf3ce44SJohn Forte 			    pg_list);
1383fcf3ce44SJohn Forte 			kmem_free(combined_pdu, combined_pdu_size);
1384fcf3ce44SJohn Forte 			combined_pdu = NULL;
1385fcf3ce44SJohn Forte 			break;
1386fcf3ce44SJohn Forte 		}
1387fcf3ce44SJohn Forte 	}
1388fcf3ce44SJohn Forte 	if (rsp_status != ISNS_RSP_SUCCESSFUL) {
1389fcf3ce44SJohn Forte 		qry_stat = isns_op_failed;
1390fcf3ce44SJohn Forte 	}
1391fcf3ce44SJohn Forte 
1392fcf3ce44SJohn Forte 	iscsi_net->close(so);
1393fcf3ce44SJohn Forte 
1394fcf3ce44SJohn Forte 	return (qry_stat);
1395fcf3ce44SJohn Forte }
1396fcf3ce44SJohn Forte 
1397fcf3ce44SJohn Forte /* ARGSUSED */
1398fcf3ce44SJohn Forte static
1399fcf3ce44SJohn Forte isns_status_t
do_isns_dev_attr_query_one_node(iscsi_addr_t * isns_server_addr,uint8_t * target_node_name,uint8_t * source_node_name,uint8_t * source_node_alias,uint32_t source_node_type,isns_portal_group_list_t ** pg_list)1400fcf3ce44SJohn Forte do_isns_dev_attr_query_one_node(iscsi_addr_t *isns_server_addr,
1401fcf3ce44SJohn Forte 	uint8_t *target_node_name,
1402fcf3ce44SJohn Forte 	uint8_t *source_node_name,
1403fcf3ce44SJohn Forte 	uint8_t *source_node_alias,
1404fcf3ce44SJohn Forte 	uint32_t source_node_type,
1405fcf3ce44SJohn Forte 	isns_portal_group_list_t **pg_list)
1406fcf3ce44SJohn Forte {
1407fcf3ce44SJohn Forte 	int bytes_received;
1408fcf3ce44SJohn Forte 	int rcv_rsp_cnt;
1409fcf3ce44SJohn Forte 	int rsp_status;
1410fcf3ce44SJohn Forte 	isns_pdu_t *in_pdu, *out_pdu;
1411fcf3ce44SJohn Forte 	isns_status_t rval;
1412fcf3ce44SJohn Forte 	size_t out_pdu_size = 0, in_pdu_size = 0;
1413fcf3ce44SJohn Forte 	uint16_t xid;
1414fcf3ce44SJohn Forte 	void *so = NULL;
1415fcf3ce44SJohn Forte 
1416fcf3ce44SJohn Forte 	/* Obtain the list of target type storage nodes first */
1417fcf3ce44SJohn Forte 	out_pdu_size = isns_create_dev_attr_qry_one_pg_pdu(
1418fcf3ce44SJohn Forte 	    target_node_name, source_node_name, &xid, &out_pdu);
1419fcf3ce44SJohn Forte 	if (out_pdu_size == 0) {
1420fcf3ce44SJohn Forte 		return (isns_create_msg_err);
1421fcf3ce44SJohn Forte 	}
1422fcf3ce44SJohn Forte 
1423fcf3ce44SJohn Forte 	ASSERT(out_pdu != NULL);
1424fcf3ce44SJohn Forte 	ASSERT(out_pdu_size > 0);
1425fcf3ce44SJohn Forte 
1426fcf3ce44SJohn Forte 	so = isns_open(isns_server_addr);
1427fcf3ce44SJohn Forte 	if (so == NULL) {
1428fcf3ce44SJohn Forte 		/* Log a message and return */
1429fcf3ce44SJohn Forte 		kmem_free(out_pdu, out_pdu_size);
1430fcf3ce44SJohn Forte 		out_pdu = NULL;
1431fcf3ce44SJohn Forte 		return (isns_open_conn_err);
1432fcf3ce44SJohn Forte 	}
1433fcf3ce44SJohn Forte 
1434fcf3ce44SJohn Forte 	if (isns_send_pdu(so, out_pdu) != 0) {
1435fcf3ce44SJohn Forte 		iscsi_net->close(so);
1436fcf3ce44SJohn Forte 		kmem_free(out_pdu, out_pdu_size);
1437fcf3ce44SJohn Forte 		out_pdu = NULL;
1438fcf3ce44SJohn Forte 		return (isns_send_msg_err);
1439fcf3ce44SJohn Forte 	}
1440fcf3ce44SJohn Forte 
1441fcf3ce44SJohn Forte 	/* Done with the out PDU - free it */
1442fcf3ce44SJohn Forte 	kmem_free(out_pdu, out_pdu_size);
1443fcf3ce44SJohn Forte 	out_pdu = NULL;
1444fcf3ce44SJohn Forte 
1445fcf3ce44SJohn Forte 	rcv_rsp_cnt = 0;
1446fcf3ce44SJohn Forte 	rval = isns_ok;
1447fcf3ce44SJohn Forte 	for (;;) {
1448fcf3ce44SJohn Forte 		bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
1449fcf3ce44SJohn Forte 		ASSERT(bytes_received >= 0);
1450fcf3ce44SJohn Forte 		if (bytes_received == 0) {
1451fcf3ce44SJohn Forte 			ASSERT(in_pdu == NULL);
1452fcf3ce44SJohn Forte 			ASSERT(in_pdu_size == 0);
1453fcf3ce44SJohn Forte 			rval = isns_rcv_msg_err;
1454fcf3ce44SJohn Forte 			break;
1455fcf3ce44SJohn Forte 		}
1456fcf3ce44SJohn Forte 
1457fcf3ce44SJohn Forte 		ASSERT(in_pdu != NULL);
1458fcf3ce44SJohn Forte 		ASSERT(in_pdu_size > 0);
1459fcf3ce44SJohn Forte 
1460fcf3ce44SJohn Forte 		if (ntohs(in_pdu->xid) != xid) {
1461fcf3ce44SJohn Forte 			rcv_rsp_cnt++;
1462fcf3ce44SJohn Forte 			if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
1463fcf3ce44SJohn Forte 				continue;
1464fcf3ce44SJohn Forte 			} else {
1465fcf3ce44SJohn Forte 				/* Exceed maximum receive count. */
1466fcf3ce44SJohn Forte 				kmem_free(in_pdu, in_pdu_size);
1467fcf3ce44SJohn Forte 				in_pdu = NULL;
1468fcf3ce44SJohn Forte 				rval = isns_no_rsp_rcvd;
1469fcf3ce44SJohn Forte 				break;
1470fcf3ce44SJohn Forte 			}
1471fcf3ce44SJohn Forte 		}
1472fcf3ce44SJohn Forte 
1473fcf3ce44SJohn Forte 		rsp_status = isns_process_dev_attr_qry_target_nodes_pdu(
1474fcf3ce44SJohn Forte 		    isns_server_addr, in_pdu->func_id,
1475fcf3ce44SJohn Forte 		    (isns_resp_t *)in_pdu->payload, (size_t)in_pdu->payload_len,
1476fcf3ce44SJohn Forte 		    pg_list);
1477fcf3ce44SJohn Forte 		if (rsp_status != ISNS_RSP_SUCCESSFUL) {
1478fcf3ce44SJohn Forte 			rval = isns_op_failed;
1479fcf3ce44SJohn Forte 		}
1480fcf3ce44SJohn Forte 		kmem_free(in_pdu, in_pdu_size);
1481fcf3ce44SJohn Forte 		in_pdu = NULL;
1482fcf3ce44SJohn Forte 		break;
1483fcf3ce44SJohn Forte 	}
1484fcf3ce44SJohn Forte 
1485fcf3ce44SJohn Forte 	iscsi_net->close(so);
1486fcf3ce44SJohn Forte 
1487fcf3ce44SJohn Forte 	return (rval);
1488fcf3ce44SJohn Forte }
1489fcf3ce44SJohn Forte 
1490fcf3ce44SJohn Forte static
1491fcf3ce44SJohn Forte void
isns_open(iscsi_addr_t * isns_server_addr)1492fcf3ce44SJohn Forte *isns_open(iscsi_addr_t *isns_server_addr)
1493fcf3ce44SJohn Forte {
1494fcf3ce44SJohn Forte 	int rval = 0;
1495fcf3ce44SJohn Forte 	union {
1496fcf3ce44SJohn Forte 		struct sockaddr sin;
1497fcf3ce44SJohn Forte 		struct sockaddr_in s_in4;
1498fcf3ce44SJohn Forte 		struct sockaddr_in6 s_in6;
1499fcf3ce44SJohn Forte 	} sa_rsvr = { 0 };
1500fcf3ce44SJohn Forte 	void *so;
15010f1702c5SYu Xiangning 	struct sockaddr_in6	t_addr;
15020f1702c5SYu Xiangning 	socklen_t		t_addrlen;
1503fcf3ce44SJohn Forte 
15040f1702c5SYu Xiangning 	bzero(&t_addr, sizeof (struct sockaddr_in6));
15050f1702c5SYu Xiangning 	t_addrlen = sizeof (struct sockaddr_in6);
1506fcf3ce44SJohn Forte 	if (isns_server_addr->a_addr.i_insize == sizeof (struct in_addr)) {
1507fcf3ce44SJohn Forte 		/* IPv4 */
1508fcf3ce44SJohn Forte 		sa_rsvr.s_in4.sin_family = AF_INET;
1509fcf3ce44SJohn Forte 		sa_rsvr.s_in4.sin_port = htons(isns_server_addr->a_port);
1510fcf3ce44SJohn Forte 		sa_rsvr.s_in4.sin_addr.s_addr =
1511fcf3ce44SJohn Forte 		    isns_server_addr->a_addr.i_addr.in4.s_addr;
1512fcf3ce44SJohn Forte 
1513fcf3ce44SJohn Forte 		/* Create socket */
1514fcf3ce44SJohn Forte 		so = iscsi_net->socket(AF_INET, SOCK_STREAM, 0);
1515fcf3ce44SJohn Forte 	} else {
1516fcf3ce44SJohn Forte 		/* IPv6 */
1517fcf3ce44SJohn Forte 		sa_rsvr.s_in6.sin6_family = AF_INET6;
1518fcf3ce44SJohn Forte 		bcopy(&(isns_server_addr->a_addr.i_addr.in6),
1519fcf3ce44SJohn Forte 		    sa_rsvr.s_in6.sin6_addr.s6_addr,
1520fcf3ce44SJohn Forte 		    sizeof (struct in6_addr));
1521fcf3ce44SJohn Forte 		sa_rsvr.s_in6.sin6_port = htons(isns_server_addr->a_port);
1522fcf3ce44SJohn Forte 		/* Create socket */
1523fcf3ce44SJohn Forte 		so = iscsi_net->socket(AF_INET6, SOCK_STREAM, 0);
1524fcf3ce44SJohn Forte 	}
1525fcf3ce44SJohn Forte 
1526fcf3ce44SJohn Forte 	if (so == NULL) {
1527fcf3ce44SJohn Forte 		return (NULL);
1528fcf3ce44SJohn Forte 	}
1529fcf3ce44SJohn Forte 
1530fcf3ce44SJohn Forte 	rval = iscsi_net->connect(so, &sa_rsvr.sin,
1531fcf3ce44SJohn Forte 	    (isns_server_addr->a_addr.i_insize == sizeof (struct in_addr)) ?
1532fcf3ce44SJohn Forte 	    sizeof (struct sockaddr_in) :
1533fcf3ce44SJohn Forte 	    sizeof (struct sockaddr_in6), 0, 0);
1534fcf3ce44SJohn Forte 
1535fcf3ce44SJohn Forte 	if (rval != 0) {
1536fcf3ce44SJohn Forte 		/* Flag value 2 indicates both cantsend and cantrecv */
1537fcf3ce44SJohn Forte 		iscsi_net->shutdown(so, 2);
1538fcf3ce44SJohn Forte 		iscsi_net->close(so);
1539fcf3ce44SJohn Forte 		return (NULL);
1540fcf3ce44SJohn Forte 	}
1541fcf3ce44SJohn Forte 
15420f1702c5SYu Xiangning 	(void) iscsi_net->getsockname(so, (struct sockaddr *)&t_addr,
15430f1702c5SYu Xiangning 	    &t_addrlen);
1544fcf3ce44SJohn Forte 
1545fcf3ce44SJohn Forte 	return (so);
1546fcf3ce44SJohn Forte }
1547fcf3ce44SJohn Forte 
1548fcf3ce44SJohn Forte static ssize_t
isns_send_pdu(void * socket,isns_pdu_t * pdu)1549fcf3ce44SJohn Forte isns_send_pdu(void *socket, isns_pdu_t *pdu)
1550fcf3ce44SJohn Forte {
1551fcf3ce44SJohn Forte 	int		iovlen = 0;
1552fcf3ce44SJohn Forte 	iovec_t		iovec[ISNS_MAX_IOVEC];
1553fcf3ce44SJohn Forte 	struct msghdr	msg;
1554fcf3ce44SJohn Forte 	size_t		send_len;
1555fcf3ce44SJohn Forte 	size_t		total_len = 0;
1556fcf3ce44SJohn Forte 
1557fcf3ce44SJohn Forte 	ASSERT(iovlen < ISNS_MAX_IOVEC);
1558fcf3ce44SJohn Forte 	iovec[iovlen].iov_base = (void *)pdu;
1559fcf3ce44SJohn Forte 	iovec[iovlen].iov_len = (ISNSP_HEADER_SIZE);
1560fcf3ce44SJohn Forte 	total_len += (ISNSP_HEADER_SIZE);
1561fcf3ce44SJohn Forte 	iovlen++;
1562fcf3ce44SJohn Forte 
1563fcf3ce44SJohn Forte 	ASSERT(iovlen < ISNS_MAX_IOVEC);
1564fcf3ce44SJohn Forte 	iovec[iovlen].iov_base = (void *)pdu->payload;
1565fcf3ce44SJohn Forte 	iovec[iovlen].iov_len = ntohs(pdu->payload_len);
1566fcf3ce44SJohn Forte 	total_len += ntohs(pdu->payload_len);
1567fcf3ce44SJohn Forte 	iovlen++;
1568fcf3ce44SJohn Forte 
1569fcf3ce44SJohn Forte 	/* Initialization of the message header. */
1570fcf3ce44SJohn Forte 	bzero(&msg, sizeof (msg));
1571fcf3ce44SJohn Forte 	msg.msg_iov = &iovec[0];
1572fcf3ce44SJohn Forte 	msg.msg_flags   = MSG_WAITALL;
1573fcf3ce44SJohn Forte 	msg.msg_iovlen  = iovlen;
1574fcf3ce44SJohn Forte 
1575fcf3ce44SJohn Forte 	send_len = iscsi_net->sendmsg(socket, &msg);
1576fcf3ce44SJohn Forte 	return (send_len == total_len ? 0 : -1);
1577fcf3ce44SJohn Forte }
1578fcf3ce44SJohn Forte 
1579fcf3ce44SJohn Forte static
1580fcf3ce44SJohn Forte size_t
isns_rcv_pdu(void * socket,isns_pdu_t ** pdu,size_t * pdu_size)1581fcf3ce44SJohn Forte isns_rcv_pdu(void *socket, isns_pdu_t **pdu, size_t *pdu_size)
1582fcf3ce44SJohn Forte {
1583fcf3ce44SJohn Forte 	int poll_cnt;
1584fcf3ce44SJohn Forte 	iovec_t iovec[ISNS_MAX_IOVEC];
1585fcf3ce44SJohn Forte 	isns_pdu_t *tmp_pdu_hdr;
1586fcf3ce44SJohn Forte 	size_t bytes_received, total_bytes_received = 0, payload_len = 0;
1587fcf3ce44SJohn Forte 	struct msghdr msg;
1588fcf3ce44SJohn Forte 	uint8_t *tmp_pdu_data;
1589fcf3ce44SJohn Forte 
1590fcf3ce44SJohn Forte 	/* Receive the header first */
1591fcf3ce44SJohn Forte 	tmp_pdu_hdr = (isns_pdu_t *)kmem_zalloc(ISNSP_HEADER_SIZE, KM_SLEEP);
1592fcf3ce44SJohn Forte 	(void) memset((char *)&iovec[0], 0, sizeof (iovec_t));
1593fcf3ce44SJohn Forte 	iovec[0].iov_base = (void *)tmp_pdu_hdr;
1594fcf3ce44SJohn Forte 	iovec[0].iov_len = ISNSP_HEADER_SIZE;
1595fcf3ce44SJohn Forte 
1596fcf3ce44SJohn Forte 	/* Initialization of the message header. */
1597fcf3ce44SJohn Forte 	bzero(&msg, sizeof (msg));
1598fcf3ce44SJohn Forte 	msg.msg_iov = &iovec[0];
1599fcf3ce44SJohn Forte 	msg.msg_flags = MSG_WAITALL;
1600fcf3ce44SJohn Forte 	msg.msg_iovlen = 1;
1601fcf3ce44SJohn Forte 
1602fcf3ce44SJohn Forte 	/* Poll and receive the packets. */
1603fcf3ce44SJohn Forte 	poll_cnt = 0;
1604fcf3ce44SJohn Forte 	do {
1605fcf3ce44SJohn Forte 		bytes_received = iscsi_net->recvmsg(socket, &msg,
1606fcf3ce44SJohn Forte 		    ISNS_RCV_TIMEOUT);
1607fcf3ce44SJohn Forte 		if (bytes_received == 0) {
1608fcf3ce44SJohn Forte 			/* Not yet. Increase poll count and try again. */
1609fcf3ce44SJohn Forte 			poll_cnt++;
1610fcf3ce44SJohn Forte 			continue;
1611fcf3ce44SJohn Forte 		} else {
1612fcf3ce44SJohn Forte 			/* OK data received. */
1613fcf3ce44SJohn Forte 			break;
1614fcf3ce44SJohn Forte 		}
1615fcf3ce44SJohn Forte 	} while (poll_cnt < ISNS_RCV_RETRY_MAX);
1616fcf3ce44SJohn Forte 
1617fcf3ce44SJohn Forte 	DTRACE_PROBE2(isns_rcv_pdu_hdr_summary,
1618fcf3ce44SJohn Forte 	    int, poll_cnt, int, bytes_received);
1619fcf3ce44SJohn Forte 	if (poll_cnt >= ISNS_RCV_RETRY_MAX) {
1620fcf3ce44SJohn Forte 		kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1621fcf3ce44SJohn Forte 		*pdu = NULL;
1622fcf3ce44SJohn Forte 		*pdu_size = 0;
1623fcf3ce44SJohn Forte 		return (0);
1624fcf3ce44SJohn Forte 	}
1625fcf3ce44SJohn Forte 	if (bytes_received == 0 || bytes_received != ISNSP_HEADER_SIZE) {
1626fcf3ce44SJohn Forte 		kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1627fcf3ce44SJohn Forte 		*pdu = NULL;
1628fcf3ce44SJohn Forte 		*pdu_size = 0;
1629fcf3ce44SJohn Forte 		return (0);
1630fcf3ce44SJohn Forte 	}
1631fcf3ce44SJohn Forte 	total_bytes_received += bytes_received;
1632fcf3ce44SJohn Forte 
1633fcf3ce44SJohn Forte 	payload_len = ntohs(tmp_pdu_hdr->payload_len);
1634fcf3ce44SJohn Forte 	DTRACE_PROBE1(isns_rcv_pdu_probe1, int, payload_len);
1635fcf3ce44SJohn Forte 	/* Verify the received payload len is within limit */
1636fcf3ce44SJohn Forte 	if (payload_len > ISNSP_MAX_PAYLOAD_SIZE) {
1637fcf3ce44SJohn Forte 		kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1638fcf3ce44SJohn Forte 		*pdu = NULL;
1639fcf3ce44SJohn Forte 		*pdu_size = 0;
1640fcf3ce44SJohn Forte 		return (0);
1641fcf3ce44SJohn Forte 	}
1642fcf3ce44SJohn Forte 
1643fcf3ce44SJohn Forte 	/* Proceed to receive additional data. */
1644fcf3ce44SJohn Forte 	tmp_pdu_data = kmem_zalloc(payload_len, KM_SLEEP);
1645fcf3ce44SJohn Forte 	(void) memset((char *)&iovec[0], 0, sizeof (iovec_t));
1646fcf3ce44SJohn Forte 	iovec[0].iov_base = (void *)tmp_pdu_data;
1647fcf3ce44SJohn Forte 	iovec[0].iov_len = payload_len;
1648fcf3ce44SJohn Forte 
1649fcf3ce44SJohn Forte 	/* Initialization of the message header. */
1650fcf3ce44SJohn Forte 	bzero(&msg, sizeof (msg));
1651fcf3ce44SJohn Forte 	msg.msg_iov = &iovec[0];
1652fcf3ce44SJohn Forte 	msg.msg_flags   = MSG_WAITALL;
1653fcf3ce44SJohn Forte 	msg.msg_iovlen  = 1;
1654fcf3ce44SJohn Forte 
1655fcf3ce44SJohn Forte 	/* Poll and receive the rest of the PDU. */
1656fcf3ce44SJohn Forte 	poll_cnt = 0;
1657fcf3ce44SJohn Forte 	do {
1658fcf3ce44SJohn Forte 		bytes_received = iscsi_net->recvmsg(socket, &msg,
1659fcf3ce44SJohn Forte 		    ISNS_RCV_TIMEOUT);
1660fcf3ce44SJohn Forte 		if (bytes_received == 0) {
1661fcf3ce44SJohn Forte 			/* Not yet. Increase poll count and try again. */
1662fcf3ce44SJohn Forte 			poll_cnt++;
1663fcf3ce44SJohn Forte 			continue;
1664fcf3ce44SJohn Forte 		} else {
1665fcf3ce44SJohn Forte 			/* OK data received. */
1666fcf3ce44SJohn Forte 			break;
1667fcf3ce44SJohn Forte 		}
1668fcf3ce44SJohn Forte 	} while (poll_cnt < ISNS_RCV_RETRY_MAX);
1669fcf3ce44SJohn Forte 
1670fcf3ce44SJohn Forte 	DTRACE_PROBE2(isns_rcv_pdu_data_summary,
1671fcf3ce44SJohn Forte 	    int, poll_cnt, int, bytes_received);
1672fcf3ce44SJohn Forte 
1673fcf3ce44SJohn Forte 	if (poll_cnt >= ISNS_RCV_RETRY_MAX) {
1674fcf3ce44SJohn Forte 		kmem_free(tmp_pdu_data, payload_len);
1675fcf3ce44SJohn Forte 		kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1676fcf3ce44SJohn Forte 		*pdu = NULL;
1677fcf3ce44SJohn Forte 		*pdu_size = 0;
1678fcf3ce44SJohn Forte 		return (0);
1679fcf3ce44SJohn Forte 	}
1680fcf3ce44SJohn Forte 	if (bytes_received == 0 || bytes_received != payload_len) {
1681fcf3ce44SJohn Forte 		kmem_free(tmp_pdu_data, payload_len);
1682fcf3ce44SJohn Forte 		kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1683fcf3ce44SJohn Forte 		*pdu = NULL;
1684fcf3ce44SJohn Forte 		*pdu_size = 0;
1685fcf3ce44SJohn Forte 		return (0);
1686fcf3ce44SJohn Forte 	}
1687fcf3ce44SJohn Forte 	total_bytes_received += bytes_received;
1688fcf3ce44SJohn Forte 
1689fcf3ce44SJohn Forte 	*pdu_size = ISNSP_HEADER_SIZE + payload_len;
1690fcf3ce44SJohn Forte 	(*pdu) = (isns_pdu_t *)kmem_zalloc((*pdu_size), KM_SLEEP);
1691fcf3ce44SJohn Forte 	(*pdu)->version = ntohs(tmp_pdu_hdr->version);
1692fcf3ce44SJohn Forte 	(*pdu)->func_id = ntohs(tmp_pdu_hdr->func_id);
1693fcf3ce44SJohn Forte 	(*pdu)->payload_len = payload_len;
1694fcf3ce44SJohn Forte 	(*pdu)->flags = ntohs(tmp_pdu_hdr->flags);
1695fcf3ce44SJohn Forte 	(*pdu)->xid = ntohs(tmp_pdu_hdr->xid);
1696fcf3ce44SJohn Forte 	(*pdu)->seq = ntohs(tmp_pdu_hdr->seq);
1697fcf3ce44SJohn Forte 	bcopy(tmp_pdu_data, &((*pdu)->payload), payload_len);
1698fcf3ce44SJohn Forte 
1699fcf3ce44SJohn Forte 	kmem_free(tmp_pdu_data, payload_len);
1700fcf3ce44SJohn Forte 	tmp_pdu_data = NULL;
1701fcf3ce44SJohn Forte 	kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1702fcf3ce44SJohn Forte 	tmp_pdu_hdr = NULL;
1703fcf3ce44SJohn Forte 
1704fcf3ce44SJohn Forte 	return (total_bytes_received);
1705fcf3ce44SJohn Forte }
1706fcf3ce44SJohn Forte 
1707fcf3ce44SJohn Forte 
1708fcf3ce44SJohn Forte /*
1709fcf3ce44SJohn Forte  * isns_create_dev_attr_reg_pdu - isns client registration pdu
1710fcf3ce44SJohn Forte  */
1711fcf3ce44SJohn Forte static size_t
isns_create_dev_attr_reg_pdu(uint8_t * node_name,uint8_t * node_alias,uint32_t node_type,uint16_t * xid_p,isns_pdu_t ** out_pdu)1712fcf3ce44SJohn Forte isns_create_dev_attr_reg_pdu(
1713fcf3ce44SJohn Forte 	uint8_t *node_name,
1714fcf3ce44SJohn Forte 	uint8_t *node_alias,
1715fcf3ce44SJohn Forte 	uint32_t node_type,
1716fcf3ce44SJohn Forte 	uint16_t *xid_p,
1717fcf3ce44SJohn Forte 	isns_pdu_t **out_pdu)
1718fcf3ce44SJohn Forte {
1719fcf3ce44SJohn Forte 	in_port_t local_port;
1720fcf3ce44SJohn Forte 	isns_pdu_t *pdu;
1721fcf3ce44SJohn Forte 	size_t pdu_size, node_name_len, node_alias_len;
1722fcf3ce44SJohn Forte 	uint16_t flags;
17236362598eSbing zhao - Sun Microsystems - Beijing China 	boolean_t	rval	    = B_FALSE;
17246362598eSbing zhao - Sun Microsystems - Beijing China 	iscsi_addr_t	local_addr;
1725fcf3ce44SJohn Forte 
1726fcf3ce44SJohn Forte 	ASSERT(node_name != NULL);
1727fcf3ce44SJohn Forte 	ASSERT(node_alias != NULL);
1728fcf3ce44SJohn Forte 
1729fcf3ce44SJohn Forte 	/* RFC 4171 section 6.1 - NULLs included in the length. */
1730fcf3ce44SJohn Forte 	node_name_len = strlen((char *)node_name) + 1;
1731fcf3ce44SJohn Forte 	node_alias_len = strlen((char *)node_alias) + 1;
1732fcf3ce44SJohn Forte 
1733fcf3ce44SJohn Forte 	if (node_name_len == 1) {
1734fcf3ce44SJohn Forte 		*out_pdu = NULL;
1735fcf3ce44SJohn Forte 		return (0);
1736fcf3ce44SJohn Forte 	}
1737fcf3ce44SJohn Forte 
1738fcf3ce44SJohn Forte 	/*
1739fcf3ce44SJohn Forte 	 * Create DevAttrReg Message
1740fcf3ce44SJohn Forte 	 *
1741fcf3ce44SJohn Forte 	 * Enable the replace bit so that we can update
1742fcf3ce44SJohn Forte 	 * existing registration
1743fcf3ce44SJohn Forte 	 */
1744fcf3ce44SJohn Forte 	flags = ISNS_FLAG_FIRST_PDU |
1745fcf3ce44SJohn Forte 	    ISNS_FLAG_LAST_PDU |
1746fcf3ce44SJohn Forte 	    ISNS_FLAG_REPLACE_REG;
1747fcf3ce44SJohn Forte 	pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_REG, flags, &pdu);
1748fcf3ce44SJohn Forte 	*xid_p = pdu->xid;
1749fcf3ce44SJohn Forte 
1750fcf3ce44SJohn Forte 	/* Source attribute */
1751fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1752fcf3ce44SJohn Forte 	    node_name_len, node_name, 0) != 0) {
1753fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1754fcf3ce44SJohn Forte 		*out_pdu = NULL;
1755fcf3ce44SJohn Forte 		return (0);
1756fcf3ce44SJohn Forte 	}
1757fcf3ce44SJohn Forte 
1758fcf3ce44SJohn Forte 	/*
1759fcf3ce44SJohn Forte 	 * Message Key Attributes
1760fcf3ce44SJohn Forte 	 *
1761fcf3ce44SJohn Forte 	 * EID attribute - Section 6.2.1
1762fcf3ce44SJohn Forte 	 * This is required for re-registrations or Replace
1763fcf3ce44SJohn Forte 	 * Bit is ignored - Section 5.6.5.1
1764fcf3ce44SJohn Forte 	 */
1765fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID,
1766fcf3ce44SJohn Forte 	    node_name_len, node_name, 0) != 0) {
1767fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1768fcf3ce44SJohn Forte 		*out_pdu = NULL;
1769fcf3ce44SJohn Forte 		return (0);
1770fcf3ce44SJohn Forte 	}
1771fcf3ce44SJohn Forte 
1772fcf3ce44SJohn Forte 	/* Delimiter */
1773fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
1774fcf3ce44SJohn Forte 	    != 0) {
1775fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1776fcf3ce44SJohn Forte 		*out_pdu = NULL;
1777fcf3ce44SJohn Forte 		return (0);
1778fcf3ce44SJohn Forte 	}
1779fcf3ce44SJohn Forte 
1780fcf3ce44SJohn Forte 	/* EID attribute - Section 6.2.1 */
1781fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID,
1782fcf3ce44SJohn Forte 	    node_name_len, node_name, 0) != 0) {
1783fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1784fcf3ce44SJohn Forte 		*out_pdu = NULL;
1785fcf3ce44SJohn Forte 		return (0);
1786fcf3ce44SJohn Forte 	}
1787fcf3ce44SJohn Forte 
1788fcf3ce44SJohn Forte 	/* ENTITY Protocol - Section 6.2.2 */
1789fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_ENTITY_PROTOCOL_ATTR_ID, 4,
1790fcf3ce44SJohn Forte 	    0, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) {
1791fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1792fcf3ce44SJohn Forte 		*out_pdu = NULL;
1793fcf3ce44SJohn Forte 		return (0);
1794fcf3ce44SJohn Forte 	}
1795fcf3ce44SJohn Forte 
1796fcf3ce44SJohn Forte 	/* iSCSI Name - Section 6.4.1 */
1797fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1798fcf3ce44SJohn Forte 	    node_name_len, node_name, 0) != 0) {
1799fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1800fcf3ce44SJohn Forte 		*out_pdu = NULL;
1801fcf3ce44SJohn Forte 		return (0);
1802fcf3ce44SJohn Forte 	}
1803fcf3ce44SJohn Forte 
1804fcf3ce44SJohn Forte 	/* iSCSI Alias - Section 6.4.3 Optional */
1805fcf3ce44SJohn Forte 	if (node_alias_len > 1) {
1806fcf3ce44SJohn Forte 		if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_ALIAS_ATTR_ID,
1807fcf3ce44SJohn Forte 		    node_alias_len, node_alias, 0) != 0) {
1808fcf3ce44SJohn Forte 			kmem_free(pdu, pdu_size);
1809fcf3ce44SJohn Forte 			*out_pdu = NULL;
1810fcf3ce44SJohn Forte 			return (0);
1811fcf3ce44SJohn Forte 		}
1812fcf3ce44SJohn Forte 	}
1813fcf3ce44SJohn Forte 
1814fcf3ce44SJohn Forte 	/* iSCSI Node Type - Section 6.4.2 */
1815fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NODE_TYPE_ATTR_ID, 4,
1816fcf3ce44SJohn Forte 	    0, node_type) != 0) {
1817fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1818fcf3ce44SJohn Forte 		*out_pdu = NULL;
1819fcf3ce44SJohn Forte 		return (0);
1820fcf3ce44SJohn Forte 	}
1821fcf3ce44SJohn Forte 
1822fcf3ce44SJohn Forte 	mutex_enter(&esi_scn_thr_mutex);
18236362598eSbing zhao - Sun Microsystems - Beijing China 	if (instance_listening_so != NULL) {
18246362598eSbing zhao - Sun Microsystems - Beijing China 		rval = find_listening_addr(&local_addr, instance_listening_so);
18256362598eSbing zhao - Sun Microsystems - Beijing China 		if (rval == B_FALSE) {
18266362598eSbing zhao - Sun Microsystems - Beijing China 			kmem_free(pdu, pdu_size);
18276362598eSbing zhao - Sun Microsystems - Beijing China 			*out_pdu = NULL;
18286362598eSbing zhao - Sun Microsystems - Beijing China 			mutex_exit(&esi_scn_thr_mutex);
18296362598eSbing zhao - Sun Microsystems - Beijing China 			return (0);
18306362598eSbing zhao - Sun Microsystems - Beijing China 		}
18316362598eSbing zhao - Sun Microsystems - Beijing China 	} else {
18326362598eSbing zhao - Sun Microsystems - Beijing China 		kmem_free(pdu, pdu_size);
18336362598eSbing zhao - Sun Microsystems - Beijing China 		*out_pdu = NULL;
18346362598eSbing zhao - Sun Microsystems - Beijing China 		mutex_exit(&esi_scn_thr_mutex);
18356362598eSbing zhao - Sun Microsystems - Beijing China 		return (0);
18366362598eSbing zhao - Sun Microsystems - Beijing China 	}
18376362598eSbing zhao - Sun Microsystems - Beijing China 	local_port = local_addr.a_port;
1838fcf3ce44SJohn Forte 	/* Portal IP Address - Section 6.5.2 */
1839fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_PORTAL_IP_ADDR_ATTR_ID, 16,
18406362598eSbing zhao - Sun Microsystems - Beijing China 	    &(local_addr.a_addr.i_addr.in4),
18416362598eSbing zhao - Sun Microsystems - Beijing China 	    local_addr.a_addr.i_insize) != 0) {
1842fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1843fcf3ce44SJohn Forte 		*out_pdu = NULL;
1844fcf3ce44SJohn Forte 		mutex_exit(&esi_scn_thr_mutex);
1845fcf3ce44SJohn Forte 		return (0);
1846fcf3ce44SJohn Forte 	}
1847fcf3ce44SJohn Forte 	mutex_exit(&esi_scn_thr_mutex);
1848fcf3ce44SJohn Forte 
1849fcf3ce44SJohn Forte 	/* Portal Port  - Section 6.5.3 */
1850fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_PORTAL_PORT_ATTR_ID, 4, 0,
1851fcf3ce44SJohn Forte 	    local_port) != 0) {
1852fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1853fcf3ce44SJohn Forte 		*out_pdu = NULL;
1854fcf3ce44SJohn Forte 		return (0);
1855fcf3ce44SJohn Forte 	}
1856fcf3ce44SJohn Forte 
1857fcf3ce44SJohn Forte 	/* SCN Port  - Section 6.3.7 */
1858fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_SCN_PORT_ATTR_ID, 4, 0,
1859fcf3ce44SJohn Forte 	    local_port) != 0) {
1860fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1861fcf3ce44SJohn Forte 		*out_pdu = NULL;
1862fcf3ce44SJohn Forte 		return (0);
1863fcf3ce44SJohn Forte 	}
1864fcf3ce44SJohn Forte 
1865fcf3ce44SJohn Forte 	/* ESI Port - Section 6.3.5 */
1866fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_ESI_PORT_ATTR_ID, 4, 0,
1867fcf3ce44SJohn Forte 	    local_port) != 0) {
1868fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1869fcf3ce44SJohn Forte 		*out_pdu = NULL;
1870fcf3ce44SJohn Forte 		return (0);
1871fcf3ce44SJohn Forte 	}
1872fcf3ce44SJohn Forte 
1873fcf3ce44SJohn Forte 	*out_pdu = pdu;
1874fcf3ce44SJohn Forte 	return (pdu_size);
1875fcf3ce44SJohn Forte }
1876fcf3ce44SJohn Forte 
1877fcf3ce44SJohn Forte /*
1878fcf3ce44SJohn Forte  * isns_create_dev_dereg_pdu - Create an iSNS PDU for deregistration.
1879fcf3ce44SJohn Forte  */
1880fcf3ce44SJohn Forte static size_t
isns_create_dev_dereg_pdu(uint8_t * node_name,uint16_t * xid_p,isns_pdu_t ** out_pdu)1881fcf3ce44SJohn Forte isns_create_dev_dereg_pdu(
1882fcf3ce44SJohn Forte 	uint8_t *node_name,
1883fcf3ce44SJohn Forte 	uint16_t *xid_p,
1884fcf3ce44SJohn Forte 	isns_pdu_t **out_pdu)
1885fcf3ce44SJohn Forte {
1886fcf3ce44SJohn Forte 	isns_pdu_t *pdu;
1887fcf3ce44SJohn Forte 	size_t pdu_size, node_name_len;
1888fcf3ce44SJohn Forte 	uint16_t flags;
1889fcf3ce44SJohn Forte 
1890fcf3ce44SJohn Forte 	ASSERT(node_name != NULL);
1891fcf3ce44SJohn Forte 
1892fcf3ce44SJohn Forte 	/* RFC 4171 section 6.1 - NULLs included in the length. */
1893fcf3ce44SJohn Forte 	node_name_len = strlen((char *)node_name) + 1;
1894fcf3ce44SJohn Forte 
1895fcf3ce44SJohn Forte 	if (node_name_len == 1) {
1896fcf3ce44SJohn Forte 		*out_pdu = NULL;
1897fcf3ce44SJohn Forte 		return (0);
1898fcf3ce44SJohn Forte 	}
1899fcf3ce44SJohn Forte 
1900fcf3ce44SJohn Forte 	/*
1901fcf3ce44SJohn Forte 	 * Create DevDeReg Message
1902fcf3ce44SJohn Forte 	 */
1903fcf3ce44SJohn Forte 	flags = ISNS_FLAG_FIRST_PDU |
1904fcf3ce44SJohn Forte 	    ISNS_FLAG_LAST_PDU;
1905fcf3ce44SJohn Forte 	pdu_size = isns_create_pdu_header(ISNS_DEV_DEREG, flags, &pdu);
1906fcf3ce44SJohn Forte 	*xid_p = pdu->xid;
1907fcf3ce44SJohn Forte 
1908fcf3ce44SJohn Forte 	/* Source attribute */
1909fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1910fcf3ce44SJohn Forte 	    node_name_len, node_name, 0) != 0) {
1911fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1912fcf3ce44SJohn Forte 		*out_pdu = NULL;
1913fcf3ce44SJohn Forte 		return (0);
1914fcf3ce44SJohn Forte 	}
1915fcf3ce44SJohn Forte 
1916fcf3ce44SJohn Forte 	/* Delimiter */
1917fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
1918fcf3ce44SJohn Forte 	    != 0) {
1919fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1920fcf3ce44SJohn Forte 		*out_pdu = NULL;
1921fcf3ce44SJohn Forte 		return (0);
1922fcf3ce44SJohn Forte 	}
1923fcf3ce44SJohn Forte 
1924fcf3ce44SJohn Forte 	/* Entity Identifier */
1925fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID,
1926fcf3ce44SJohn Forte 	    node_name_len, node_name, 0) != 0) {
1927fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
1928fcf3ce44SJohn Forte 		*out_pdu = NULL;
1929fcf3ce44SJohn Forte 		return (0);
1930fcf3ce44SJohn Forte 	}
1931fcf3ce44SJohn Forte 
1932fcf3ce44SJohn Forte 	*out_pdu = pdu;
1933fcf3ce44SJohn Forte 	return (pdu_size);
1934fcf3ce44SJohn Forte }
1935fcf3ce44SJohn Forte 
1936fcf3ce44SJohn Forte /*
1937fcf3ce44SJohn Forte  * isns_create_dev_attr_target_nodes_pdu - get all accessible targets
1938fcf3ce44SJohn Forte  *
1939fcf3ce44SJohn Forte  * Querys for a list of all accessible target nodes for this
1940fcf3ce44SJohn Forte  * initiator.  Requests all required login information (name,
1941fcf3ce44SJohn Forte  * ip, port, tpgt).
1942fcf3ce44SJohn Forte  */
1943fcf3ce44SJohn Forte static size_t
isns_create_dev_attr_qry_target_nodes_pdu(uint8_t * node_name,uint8_t * node_alias,uint16_t * xid_p,isns_pdu_t ** out_pdu)1944fcf3ce44SJohn Forte isns_create_dev_attr_qry_target_nodes_pdu(
1945fcf3ce44SJohn Forte 	uint8_t *node_name,
1946fcf3ce44SJohn Forte 	uint8_t *node_alias,
1947fcf3ce44SJohn Forte 	uint16_t *xid_p, isns_pdu_t **out_pdu)
1948fcf3ce44SJohn Forte {
1949fcf3ce44SJohn Forte 	isns_pdu_t *pdu_p;
1950fcf3ce44SJohn Forte 	uint16_t flags;
1951fcf3ce44SJohn Forte 	size_t pdu_size, node_name_len;
1952fcf3ce44SJohn Forte 
1953fcf3ce44SJohn Forte 	ASSERT(node_name != NULL);
1954fcf3ce44SJohn Forte 	ASSERT(node_alias != NULL);
1955fcf3ce44SJohn Forte 
1956fcf3ce44SJohn Forte 	/* RFC 4171 section 6.1 - NULLs included in the length. */
1957fcf3ce44SJohn Forte 	node_name_len = strlen((char *)node_name) + 1;
1958fcf3ce44SJohn Forte 
1959fcf3ce44SJohn Forte 	if (node_name_len == 1) {
1960fcf3ce44SJohn Forte 		*out_pdu = NULL;
1961fcf3ce44SJohn Forte 		return (0);
1962fcf3ce44SJohn Forte 	}
1963fcf3ce44SJohn Forte 
1964fcf3ce44SJohn Forte 	/* Create DevAttrQry Message */
1965fcf3ce44SJohn Forte 	flags = ISNS_FLAG_FIRST_PDU |
1966fcf3ce44SJohn Forte 	    ISNS_FLAG_LAST_PDU;
1967fcf3ce44SJohn Forte 	pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_QRY, flags, &pdu_p);
1968fcf3ce44SJohn Forte 	*xid_p = pdu_p->xid;
1969fcf3ce44SJohn Forte 
1970fcf3ce44SJohn Forte 	/* Source attribute */
1971fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1972fcf3ce44SJohn Forte 	    node_name_len, node_name, 0) != 0) {
1973fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
1974fcf3ce44SJohn Forte 		*out_pdu = NULL;
1975fcf3ce44SJohn Forte 		return (0);
1976fcf3ce44SJohn Forte 	}
1977fcf3ce44SJohn Forte 
1978fcf3ce44SJohn Forte 	/*
1979fcf3ce44SJohn Forte 	 * Message Key Attribute
1980fcf3ce44SJohn Forte 	 *
1981fcf3ce44SJohn Forte 	 * iSCSI Node Type
1982fcf3ce44SJohn Forte 	 * Query target nodes only
1983fcf3ce44SJohn Forte 	 */
1984fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NODE_TYPE_ATTR_ID,
1985fcf3ce44SJohn Forte 	    4, 0, ISNS_TARGET_NODE_TYPE) != 0) {
1986fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
1987fcf3ce44SJohn Forte 		*out_pdu = NULL;
1988fcf3ce44SJohn Forte 		return (0);
1989fcf3ce44SJohn Forte 	}
1990fcf3ce44SJohn Forte 
1991fcf3ce44SJohn Forte 	/* Delimiter */
1992fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size,
1993fcf3ce44SJohn Forte 	    ISNS_DELIMITER_ATTR_ID, 0, 0, 0) != 0) {
1994fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
1995fcf3ce44SJohn Forte 		*out_pdu = NULL;
1996fcf3ce44SJohn Forte 		return (0);
1997fcf3ce44SJohn Forte 	}
1998fcf3ce44SJohn Forte 
1999fcf3ce44SJohn Forte 	/* PG iSCSI Name - Zero length TLV */
2000fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_ISCSI_NAME_ATTR_ID,
2001fcf3ce44SJohn Forte 	    0, 0, 0) != 0) {
2002fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
2003fcf3ce44SJohn Forte 		*out_pdu = NULL;
2004fcf3ce44SJohn Forte 		return (0);
2005fcf3ce44SJohn Forte 	}
2006fcf3ce44SJohn Forte 
2007fcf3ce44SJohn Forte 	/* PG Portal IP Address - Zero length TLV */
2008fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
2009fcf3ce44SJohn Forte 	    0, 0, 0) != 0) {
2010fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
2011fcf3ce44SJohn Forte 		*out_pdu = NULL;
2012fcf3ce44SJohn Forte 		return (0);
2013fcf3ce44SJohn Forte 	}
2014fcf3ce44SJohn Forte 
2015fcf3ce44SJohn Forte 	/* PG Portal Port - Zero length TLV */
2016fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_PORT_ATTR_ID,
2017fcf3ce44SJohn Forte 	    0, 0, 0) != 0) {
2018fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
2019fcf3ce44SJohn Forte 		*out_pdu = NULL;
2020fcf3ce44SJohn Forte 		return (0);
2021fcf3ce44SJohn Forte 	}
2022fcf3ce44SJohn Forte 
2023fcf3ce44SJohn Forte 	/* PG Portal Group Tag - Zero length TLV */
2024fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size,
2025fcf3ce44SJohn Forte 	    ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) {
2026fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
2027fcf3ce44SJohn Forte 		*out_pdu = NULL;
2028fcf3ce44SJohn Forte 		return (0);
2029fcf3ce44SJohn Forte 	}
2030fcf3ce44SJohn Forte 
2031fcf3ce44SJohn Forte 	*out_pdu = pdu_p;
2032fcf3ce44SJohn Forte 	return (pdu_size);
2033fcf3ce44SJohn Forte }
2034fcf3ce44SJohn Forte 
2035fcf3ce44SJohn Forte static
2036fcf3ce44SJohn Forte size_t
isns_create_dev_attr_qry_one_pg_pdu(uint8_t * target_node_name,uint8_t * source_node_name,uint16_t * xid_p,isns_pdu_t ** out_pdu)2037fcf3ce44SJohn Forte isns_create_dev_attr_qry_one_pg_pdu(
2038fcf3ce44SJohn Forte 	uint8_t *target_node_name,
2039fcf3ce44SJohn Forte 	uint8_t *source_node_name,
2040fcf3ce44SJohn Forte 	uint16_t *xid_p,
2041fcf3ce44SJohn Forte 	isns_pdu_t **out_pdu)
2042fcf3ce44SJohn Forte {
2043fcf3ce44SJohn Forte 	isns_pdu_t *pdu_p;
2044fcf3ce44SJohn Forte 	uint16_t flags;
2045fcf3ce44SJohn Forte 	size_t pdu_size, source_node_name_len, target_node_name_len;
2046fcf3ce44SJohn Forte 
2047fcf3ce44SJohn Forte 	ASSERT(target_node_name != NULL);
2048fcf3ce44SJohn Forte 	ASSERT(source_node_name != NULL);
2049fcf3ce44SJohn Forte 
2050fcf3ce44SJohn Forte 	/* RFC 4171 section 6.1 - NULLs included in the length. */
2051fcf3ce44SJohn Forte 	source_node_name_len = strlen((char *)source_node_name) + 1;
2052fcf3ce44SJohn Forte 	target_node_name_len = strlen((char *)target_node_name) + 1;
2053fcf3ce44SJohn Forte 
2054fcf3ce44SJohn Forte 	if (source_node_name_len == 1) {
2055fcf3ce44SJohn Forte 		*out_pdu = NULL;
2056fcf3ce44SJohn Forte 		return (0);
2057fcf3ce44SJohn Forte 	}
2058fcf3ce44SJohn Forte 
2059fcf3ce44SJohn Forte 	/* Create DevAttrQry message scoped to target_node_name */
2060fcf3ce44SJohn Forte 	flags = ISNS_FLAG_FIRST_PDU |
2061fcf3ce44SJohn Forte 	    ISNS_FLAG_LAST_PDU;
2062fcf3ce44SJohn Forte 	pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_QRY, flags, &pdu_p);
2063fcf3ce44SJohn Forte 	*xid_p = pdu_p->xid;
2064fcf3ce44SJohn Forte 
2065fcf3ce44SJohn Forte 	/* Source attribute */
2066fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2067fcf3ce44SJohn Forte 	    source_node_name_len, source_node_name, 0) != 0) {
2068fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
2069fcf3ce44SJohn Forte 		*out_pdu = NULL;
2070fcf3ce44SJohn Forte 		return (0);
2071fcf3ce44SJohn Forte 	}
2072fcf3ce44SJohn Forte 
2073fcf3ce44SJohn Forte 	/* Message key attribute */
2074fcf3ce44SJohn Forte 	/* iSCSI Node Name */
2075fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2076fcf3ce44SJohn Forte 	    target_node_name_len,
2077fcf3ce44SJohn Forte 	    target_node_name, 0) != 0) {
2078fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
2079fcf3ce44SJohn Forte 		*out_pdu = NULL;
2080fcf3ce44SJohn Forte 		return (0);
2081fcf3ce44SJohn Forte 	}
2082fcf3ce44SJohn Forte 
2083fcf3ce44SJohn Forte 	/* Delimiter */
2084fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size,
2085fcf3ce44SJohn Forte 	    ISNS_DELIMITER_ATTR_ID, 0, 0, 0) != 0) {
2086fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
2087fcf3ce44SJohn Forte 		*out_pdu = NULL;
2088fcf3ce44SJohn Forte 		return (0);
2089fcf3ce44SJohn Forte 	}
2090fcf3ce44SJohn Forte 
2091fcf3ce44SJohn Forte 	/* PG iSCSI Name - Zero length TLV */
2092fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_ISCSI_NAME_ATTR_ID,
2093fcf3ce44SJohn Forte 	    0, 0, 0) != 0) {
2094fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
2095fcf3ce44SJohn Forte 		*out_pdu = NULL;
2096fcf3ce44SJohn Forte 		return (0);
2097fcf3ce44SJohn Forte 	}
2098fcf3ce44SJohn Forte 
2099fcf3ce44SJohn Forte 	/* PG Portal IP Address - Zero length TLV */
2100fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
2101fcf3ce44SJohn Forte 	    0, 0, 0) != 0) {
2102fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
2103fcf3ce44SJohn Forte 		*out_pdu = NULL;
2104fcf3ce44SJohn Forte 		return (0);
2105fcf3ce44SJohn Forte 	}
2106fcf3ce44SJohn Forte 
2107fcf3ce44SJohn Forte 	/* PG Portal Port - Zero length TLV */
2108fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_PORT_ATTR_ID,
2109fcf3ce44SJohn Forte 	    0, 0, 0) != 0) {
2110fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
2111fcf3ce44SJohn Forte 		*out_pdu = NULL;
2112fcf3ce44SJohn Forte 		return (0);
2113fcf3ce44SJohn Forte 	}
2114fcf3ce44SJohn Forte 
2115fcf3ce44SJohn Forte 	/* PG Portal Group Tag - Zero length TLV */
2116fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size,
2117fcf3ce44SJohn Forte 	    ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) {
2118fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
2119fcf3ce44SJohn Forte 		*out_pdu = NULL;
2120fcf3ce44SJohn Forte 		return (0);
2121fcf3ce44SJohn Forte 	}
2122fcf3ce44SJohn Forte 
2123fcf3ce44SJohn Forte 	*out_pdu = pdu_p;
2124fcf3ce44SJohn Forte 	return (pdu_size);
2125fcf3ce44SJohn Forte }
2126fcf3ce44SJohn Forte 
2127fcf3ce44SJohn Forte static
2128fcf3ce44SJohn Forte size_t
isns_create_scn_reg_pdu(uint8_t * node_name,uint8_t * node_alias,uint16_t * xid_p,isns_pdu_t ** out_pdu)2129fcf3ce44SJohn Forte isns_create_scn_reg_pdu(
2130fcf3ce44SJohn Forte 	uint8_t *node_name,
2131fcf3ce44SJohn Forte 	uint8_t *node_alias,
2132fcf3ce44SJohn Forte 	uint16_t *xid_p,
2133fcf3ce44SJohn Forte 	isns_pdu_t **out_pdu)
2134fcf3ce44SJohn Forte {
2135fcf3ce44SJohn Forte 	isns_pdu_t *pdu;
2136fcf3ce44SJohn Forte 	size_t pdu_size, node_name_len;
2137fcf3ce44SJohn Forte 	uint16_t flags;
2138fcf3ce44SJohn Forte 
2139fcf3ce44SJohn Forte 	ASSERT(node_name != NULL);
2140fcf3ce44SJohn Forte 	ASSERT(node_alias != NULL);
2141fcf3ce44SJohn Forte 
2142fcf3ce44SJohn Forte 	/* RFC 4171 section 6.1 - NULLs included in the length. */
2143fcf3ce44SJohn Forte 	node_name_len = strlen((char *)node_name) + 1;
2144fcf3ce44SJohn Forte 
2145fcf3ce44SJohn Forte 	if (node_name_len == 1) {
2146fcf3ce44SJohn Forte 		*out_pdu = NULL;
2147fcf3ce44SJohn Forte 		return (0);
2148fcf3ce44SJohn Forte 	}
2149fcf3ce44SJohn Forte 
2150fcf3ce44SJohn Forte 	/* Create SCNReg Message */
2151fcf3ce44SJohn Forte 	flags = ISNS_FLAG_FIRST_PDU |
2152fcf3ce44SJohn Forte 	    ISNS_FLAG_LAST_PDU;
2153fcf3ce44SJohn Forte 	pdu_size = isns_create_pdu_header(ISNS_SCN_REG, flags, &pdu);
2154fcf3ce44SJohn Forte 	*xid_p = pdu->xid;
2155fcf3ce44SJohn Forte 
2156fcf3ce44SJohn Forte 	/* Source attribute */
2157fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2158fcf3ce44SJohn Forte 	    node_name_len, node_name, 0) != 0) {
2159fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
2160fcf3ce44SJohn Forte 		*out_pdu = NULL;
2161fcf3ce44SJohn Forte 		return (0);
2162fcf3ce44SJohn Forte 	}
2163fcf3ce44SJohn Forte 
2164fcf3ce44SJohn Forte 	/* Message attribute */
2165fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2166fcf3ce44SJohn Forte 	    node_name_len, node_name, 0) != 0) {
2167fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
2168fcf3ce44SJohn Forte 		*out_pdu = NULL;
2169fcf3ce44SJohn Forte 		return (0);
2170fcf3ce44SJohn Forte 	}
2171fcf3ce44SJohn Forte 
2172fcf3ce44SJohn Forte 	/* Delimiter */
2173fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
2174fcf3ce44SJohn Forte 	    != 0) {
2175fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
2176fcf3ce44SJohn Forte 		*out_pdu = NULL;
2177fcf3ce44SJohn Forte 		return (0);
2178fcf3ce44SJohn Forte 	}
2179fcf3ce44SJohn Forte 
2180fcf3ce44SJohn Forte 	/* Operating attribute */
2181fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_SCN_BITMAP_ATTR_ID,
2182fcf3ce44SJohn Forte 	    4,
2183fcf3ce44SJohn Forte 	    0,
2184fcf3ce44SJohn Forte 	/*
2185fcf3ce44SJohn Forte 	 * Microsoft seems to not differentiate between init and
2186fcf3ce44SJohn Forte 	 * target. Hence, it makes no difference to turn on/off
2187fcf3ce44SJohn Forte 	 * the initiator/target bit.
2188fcf3ce44SJohn Forte 	 */
2189fcf3ce44SJohn Forte 	    ISNS_TARGET_SELF_INFO_ONLY |
2190fcf3ce44SJohn Forte 	    ISNS_OBJ_REMOVED |
2191fcf3ce44SJohn Forte 	    ISNS_OBJ_ADDED |
2192fcf3ce44SJohn Forte 	    ISNS_OBJ_UPDATED) != 0) {
2193fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
2194fcf3ce44SJohn Forte 		*out_pdu = NULL;
2195fcf3ce44SJohn Forte 		return (0);
2196fcf3ce44SJohn Forte 	}
2197fcf3ce44SJohn Forte 
2198fcf3ce44SJohn Forte 	*out_pdu = pdu;
2199fcf3ce44SJohn Forte 	return (pdu_size);
2200fcf3ce44SJohn Forte }
2201fcf3ce44SJohn Forte 
2202fcf3ce44SJohn Forte static
2203fcf3ce44SJohn Forte size_t
isns_create_scn_dereg_pdu(uint8_t * node_name,uint16_t * xid_p,isns_pdu_t ** out_pdu)2204fcf3ce44SJohn Forte isns_create_scn_dereg_pdu(
2205fcf3ce44SJohn Forte 	uint8_t *node_name,
2206fcf3ce44SJohn Forte 	uint16_t *xid_p,
2207fcf3ce44SJohn Forte 	isns_pdu_t **out_pdu)
2208fcf3ce44SJohn Forte {
2209fcf3ce44SJohn Forte 	isns_pdu_t *pdu;
2210fcf3ce44SJohn Forte 	size_t pdu_size, node_name_len;
2211fcf3ce44SJohn Forte 	uint16_t flags;
2212fcf3ce44SJohn Forte 
2213fcf3ce44SJohn Forte 	ASSERT(node_name != NULL);
2214fcf3ce44SJohn Forte 
2215fcf3ce44SJohn Forte 	/* RFC 4171 section 6.1 - NULLs included in the length. */
2216fcf3ce44SJohn Forte 	node_name_len = strlen((char *)node_name) + 1;
2217fcf3ce44SJohn Forte 
2218fcf3ce44SJohn Forte 	if (node_name_len == 1) {
2219fcf3ce44SJohn Forte 		*out_pdu = NULL;
2220fcf3ce44SJohn Forte 		return (0);
2221fcf3ce44SJohn Forte 	}
2222fcf3ce44SJohn Forte 
2223fcf3ce44SJohn Forte 	/* Create SCNReg Message */
2224fcf3ce44SJohn Forte 	flags = ISNS_FLAG_FIRST_PDU |
2225fcf3ce44SJohn Forte 	    ISNS_FLAG_LAST_PDU;
2226fcf3ce44SJohn Forte 	pdu_size = isns_create_pdu_header(ISNS_SCN_DEREG, flags, &pdu);
2227fcf3ce44SJohn Forte 	*xid_p = pdu->xid;
2228fcf3ce44SJohn Forte 
2229fcf3ce44SJohn Forte 	/* Source attribute */
2230fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2231fcf3ce44SJohn Forte 	    node_name_len, node_name, 0) != 0) {
2232fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
2233fcf3ce44SJohn Forte 		*out_pdu = NULL;
2234fcf3ce44SJohn Forte 		return (0);
2235fcf3ce44SJohn Forte 	}
2236fcf3ce44SJohn Forte 
2237fcf3ce44SJohn Forte 	/* Message attribute */
2238fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2239fcf3ce44SJohn Forte 	    node_name_len, node_name, 0) != 0) {
2240fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
2241fcf3ce44SJohn Forte 		*out_pdu = NULL;
2242fcf3ce44SJohn Forte 		return (0);
2243fcf3ce44SJohn Forte 	}
2244fcf3ce44SJohn Forte 
2245fcf3ce44SJohn Forte 	/* Delimiter */
2246fcf3ce44SJohn Forte 	if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
2247fcf3ce44SJohn Forte 	    != 0) {
2248fcf3ce44SJohn Forte 		kmem_free(pdu, pdu_size);
2249fcf3ce44SJohn Forte 		*out_pdu = NULL;
2250fcf3ce44SJohn Forte 		return (0);
2251fcf3ce44SJohn Forte 	}
2252fcf3ce44SJohn Forte 
2253fcf3ce44SJohn Forte 	/* No operating attribute */
2254fcf3ce44SJohn Forte 
2255fcf3ce44SJohn Forte 	*out_pdu = pdu;
2256fcf3ce44SJohn Forte 	return (pdu_size);
2257fcf3ce44SJohn Forte }
2258fcf3ce44SJohn Forte 
2259fcf3ce44SJohn Forte static
2260fcf3ce44SJohn Forte size_t
isns_create_esi_rsp_pdu(uint32_t rsp_status_code,isns_pdu_t * esi_pdu,uint16_t * xid_p,isns_pdu_t ** out_pdu)2261fcf3ce44SJohn Forte isns_create_esi_rsp_pdu(uint32_t rsp_status_code,
2262fcf3ce44SJohn Forte 	isns_pdu_t *esi_pdu,
2263fcf3ce44SJohn Forte 	uint16_t *xid_p,
2264fcf3ce44SJohn Forte 	isns_pdu_t **out_pdu)
2265fcf3ce44SJohn Forte {
2266fcf3ce44SJohn Forte 	isns_pdu_t *pdu_p;
2267fcf3ce44SJohn Forte 	uint16_t flags;
2268fcf3ce44SJohn Forte 	uint8_t *payload_ptr;
2269fcf3ce44SJohn Forte 	uint32_t swapped_status_code = htonl(rsp_status_code);
2270fcf3ce44SJohn Forte 	size_t pdu_size, payload_len = 0;
2271fcf3ce44SJohn Forte 
2272fcf3ce44SJohn Forte 	/* Create ESIRsp Message */
2273fcf3ce44SJohn Forte 	flags = ISNS_FLAG_FIRST_PDU |
2274fcf3ce44SJohn Forte 	    ISNS_FLAG_LAST_PDU;
2275fcf3ce44SJohn Forte 	pdu_size = isns_create_pdu_header(ISNS_ESI_RSP, flags, &pdu_p);
2276fcf3ce44SJohn Forte 	*xid_p = pdu_p->xid;
2277fcf3ce44SJohn Forte 
2278fcf3ce44SJohn Forte 	payload_len = ntohs(pdu_p->payload_len);
2279fcf3ce44SJohn Forte 
2280fcf3ce44SJohn Forte 	/* Status Code */
2281fcf3ce44SJohn Forte 	payload_ptr = pdu_p->payload + payload_len;
2282fcf3ce44SJohn Forte 	bcopy(&swapped_status_code, payload_ptr, 4);
2283fcf3ce44SJohn Forte 	payload_len += 4;
2284fcf3ce44SJohn Forte 
2285fcf3ce44SJohn Forte 	payload_ptr = pdu_p->payload + payload_len;
2286fcf3ce44SJohn Forte 	if ((esi_pdu->payload_len) < ISNSP_MAX_PAYLOAD_SIZE) {
2287fcf3ce44SJohn Forte 		bcopy(esi_pdu->payload, payload_ptr,
2288fcf3ce44SJohn Forte 		    (esi_pdu->payload_len));
2289fcf3ce44SJohn Forte 		payload_len += (esi_pdu->payload_len);
2290fcf3ce44SJohn Forte 	} else {
2291fcf3ce44SJohn Forte 		bcopy(esi_pdu->payload, payload_ptr, ISNSP_MAX_PAYLOAD_SIZE);
2292fcf3ce44SJohn Forte 		payload_len += ISNSP_MAX_PAYLOAD_SIZE;
2293fcf3ce44SJohn Forte 	}
2294fcf3ce44SJohn Forte 	pdu_p->payload_len = htons(payload_len);
2295fcf3ce44SJohn Forte 
2296fcf3ce44SJohn Forte 	/* Delimiter */
2297fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
2298fcf3ce44SJohn Forte 	    != 0) {
2299fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
2300fcf3ce44SJohn Forte 		*out_pdu = NULL;
2301fcf3ce44SJohn Forte 		return (0);
2302fcf3ce44SJohn Forte 	}
2303fcf3ce44SJohn Forte 
2304fcf3ce44SJohn Forte 	*out_pdu = pdu_p;
2305fcf3ce44SJohn Forte 	return (pdu_size);
2306fcf3ce44SJohn Forte }
2307fcf3ce44SJohn Forte 
2308fcf3ce44SJohn Forte static
2309fcf3ce44SJohn Forte size_t
isns_create_scn_rsp_pdu(uint32_t rsp_status_code,isns_pdu_t * scn_pdu,uint16_t * xid_p,isns_pdu_t ** out_pdu)2310fcf3ce44SJohn Forte isns_create_scn_rsp_pdu(uint32_t rsp_status_code,
2311fcf3ce44SJohn Forte 	isns_pdu_t *scn_pdu,
2312fcf3ce44SJohn Forte 	uint16_t *xid_p,
2313fcf3ce44SJohn Forte 	isns_pdu_t **out_pdu)
2314fcf3ce44SJohn Forte {
2315fcf3ce44SJohn Forte 	isns_pdu_t *pdu_p;
2316fcf3ce44SJohn Forte 	uint16_t flags;
2317fcf3ce44SJohn Forte 	uint8_t *payload_ptr;
2318fcf3ce44SJohn Forte 	uint32_t swapped_status_code = htonl(rsp_status_code);
2319fcf3ce44SJohn Forte 	size_t pdu_size, payload_len = 0;
2320fcf3ce44SJohn Forte 
2321fcf3ce44SJohn Forte 	/* Create SCNRsp Message */
2322fcf3ce44SJohn Forte 	flags = ISNS_FLAG_FIRST_PDU |
2323fcf3ce44SJohn Forte 	    ISNS_FLAG_LAST_PDU;
2324fcf3ce44SJohn Forte 	pdu_size = isns_create_pdu_header(ISNS_SCN_RSP, flags, &pdu_p);
2325fcf3ce44SJohn Forte 	*xid_p = pdu_p->xid;
2326fcf3ce44SJohn Forte 
2327fcf3ce44SJohn Forte 	payload_len = ntohs(pdu_p->payload_len);
2328fcf3ce44SJohn Forte 
2329fcf3ce44SJohn Forte 	/* Status Code */
2330fcf3ce44SJohn Forte 	payload_ptr = pdu_p->payload + payload_len;
2331fcf3ce44SJohn Forte 	bcopy(&swapped_status_code, payload_ptr, 4);
2332fcf3ce44SJohn Forte 	payload_len += 4;
2333fcf3ce44SJohn Forte 
2334fcf3ce44SJohn Forte 	payload_ptr = pdu_p->payload + payload_len;
2335fcf3ce44SJohn Forte 	if ((scn_pdu->payload_len) < ISNSP_MAX_PAYLOAD_SIZE) {
2336fcf3ce44SJohn Forte 		bcopy(scn_pdu->payload, payload_ptr,
2337fcf3ce44SJohn Forte 		    (scn_pdu->payload_len));
2338fcf3ce44SJohn Forte 		payload_len += (scn_pdu->payload_len);
2339fcf3ce44SJohn Forte 	} else {
2340fcf3ce44SJohn Forte 		bcopy(scn_pdu->payload, payload_ptr, ISNSP_MAX_PAYLOAD_SIZE);
2341fcf3ce44SJohn Forte 		payload_len += ISNSP_MAX_PAYLOAD_SIZE;
2342fcf3ce44SJohn Forte 	}
2343fcf3ce44SJohn Forte 	pdu_p->payload_len = htons(payload_len);
2344fcf3ce44SJohn Forte 
2345fcf3ce44SJohn Forte 	/* Delimiter */
2346fcf3ce44SJohn Forte 	if (isns_add_attr(pdu_p, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
2347fcf3ce44SJohn Forte 	    != 0) {
2348fcf3ce44SJohn Forte 		kmem_free(pdu_p, pdu_size);
2349fcf3ce44SJohn Forte 		*out_pdu = NULL;
2350fcf3ce44SJohn Forte 		return (0);
2351fcf3ce44SJohn Forte 	}
2352fcf3ce44SJohn Forte 
2353fcf3ce44SJohn Forte 	*out_pdu = pdu_p;
2354fcf3ce44SJohn Forte 	return (pdu_size);
2355fcf3ce44SJohn Forte }
2356fcf3ce44SJohn Forte 
2357fcf3ce44SJohn Forte static
2358fcf3ce44SJohn Forte uint32_t
isns_process_dev_attr_reg_rsp(isns_pdu_t * resp_pdu_p)2359fcf3ce44SJohn Forte isns_process_dev_attr_reg_rsp(isns_pdu_t *resp_pdu_p)
2360fcf3ce44SJohn Forte {
2361fcf3ce44SJohn Forte 	isns_resp_t *resp_p;
2362fcf3ce44SJohn Forte 
2363fcf3ce44SJohn Forte 	if (resp_pdu_p->func_id != ISNS_DEV_ATTR_REG_RSP) {
2364fcf3ce44SJohn Forte 		/* If this happens the iSNS server may have a problem. */
2365fcf3ce44SJohn Forte 		return (ISNS_RSP_MSG_FORMAT_ERROR);
2366fcf3ce44SJohn Forte 	}
2367fcf3ce44SJohn Forte 
2368fcf3ce44SJohn Forte 	/* Check response's status code */
2369fcf3ce44SJohn Forte 	resp_p = (isns_resp_t *)resp_pdu_p->payload;
2370fcf3ce44SJohn Forte 	if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2371fcf3ce44SJohn Forte 		return (ntohl(resp_p->status));
2372fcf3ce44SJohn Forte 	}
2373fcf3ce44SJohn Forte 
2374fcf3ce44SJohn Forte 	return (ISNS_RSP_SUCCESSFUL);
2375fcf3ce44SJohn Forte }
2376fcf3ce44SJohn Forte 
2377fcf3ce44SJohn Forte static
2378fcf3ce44SJohn Forte uint32_t
isns_process_dev_attr_dereg_rsp(isns_pdu_t * resp_pdu_p)2379fcf3ce44SJohn Forte isns_process_dev_attr_dereg_rsp(isns_pdu_t *resp_pdu_p)
2380fcf3ce44SJohn Forte {
2381fcf3ce44SJohn Forte 	isns_resp_t *resp_p;
2382fcf3ce44SJohn Forte 
2383fcf3ce44SJohn Forte 	if (resp_pdu_p->func_id != ISNS_DEV_DEREG_RSP) {
2384fcf3ce44SJohn Forte 		/* If this happens the iSNS server may have a problem. */
2385fcf3ce44SJohn Forte 		return (ISNS_RSP_MSG_FORMAT_ERROR);
2386fcf3ce44SJohn Forte 	}
2387fcf3ce44SJohn Forte 
2388fcf3ce44SJohn Forte 	/* Check response's status code */
2389fcf3ce44SJohn Forte 	resp_p = (isns_resp_t *)resp_pdu_p->payload;
2390fcf3ce44SJohn Forte 	if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2391fcf3ce44SJohn Forte 		return (ntohl(resp_p->status));
2392fcf3ce44SJohn Forte 	}
2393fcf3ce44SJohn Forte 
2394fcf3ce44SJohn Forte 	return (ISNS_RSP_SUCCESSFUL);
2395fcf3ce44SJohn Forte }
2396fcf3ce44SJohn Forte 
2397fcf3ce44SJohn Forte static
2398fcf3ce44SJohn Forte uint32_t
isns_process_scn_reg_rsp(isns_pdu_t * resp_pdu_p)2399fcf3ce44SJohn Forte isns_process_scn_reg_rsp(isns_pdu_t *resp_pdu_p)
2400fcf3ce44SJohn Forte {
2401fcf3ce44SJohn Forte 	isns_resp_t *resp_p;
2402fcf3ce44SJohn Forte 
2403fcf3ce44SJohn Forte 	ASSERT(resp_pdu_p != NULL);
2404fcf3ce44SJohn Forte 	if (resp_pdu_p->func_id != ISNS_SCN_REG_RSP) {
2405fcf3ce44SJohn Forte 		/* If this happens the iSNS server may have a problem. */
2406fcf3ce44SJohn Forte 		return (ISNS_RSP_MSG_FORMAT_ERROR);
2407fcf3ce44SJohn Forte 	}
2408fcf3ce44SJohn Forte 
2409fcf3ce44SJohn Forte 	/* Check response's status code */
2410fcf3ce44SJohn Forte 	resp_p = (isns_resp_t *)resp_pdu_p->payload;
2411fcf3ce44SJohn Forte 	if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2412fcf3ce44SJohn Forte 		return (ntohl(resp_p->status));
2413fcf3ce44SJohn Forte 	}
2414fcf3ce44SJohn Forte 	return (ISNS_RSP_SUCCESSFUL);
2415fcf3ce44SJohn Forte }
2416fcf3ce44SJohn Forte 
2417fcf3ce44SJohn Forte static
2418fcf3ce44SJohn Forte uint32_t
isns_process_scn_dereg_rsp(isns_pdu_t * resp_pdu_p)2419fcf3ce44SJohn Forte isns_process_scn_dereg_rsp(isns_pdu_t *resp_pdu_p)
2420fcf3ce44SJohn Forte {
2421fcf3ce44SJohn Forte 	isns_resp_t *resp_p;
2422fcf3ce44SJohn Forte 
2423fcf3ce44SJohn Forte 	ASSERT(resp_pdu_p != NULL);
2424fcf3ce44SJohn Forte 	if (resp_pdu_p->func_id != ISNS_SCN_DEREG_RSP) {
2425fcf3ce44SJohn Forte 		/* If this happens the iSNS server may have a problem. */
2426fcf3ce44SJohn Forte 		return (ISNS_RSP_MSG_FORMAT_ERROR);
2427fcf3ce44SJohn Forte 	}
2428fcf3ce44SJohn Forte 
2429fcf3ce44SJohn Forte 	/* Check response's status code */
2430fcf3ce44SJohn Forte 	resp_p = (isns_resp_t *)resp_pdu_p->payload;
2431fcf3ce44SJohn Forte 	if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2432fcf3ce44SJohn Forte 		return (ntohl(resp_p->status));
2433fcf3ce44SJohn Forte 	}
2434fcf3ce44SJohn Forte 	return (ISNS_RSP_SUCCESSFUL);
2435fcf3ce44SJohn Forte }
2436fcf3ce44SJohn Forte 
2437fcf3ce44SJohn Forte static
2438fcf3ce44SJohn Forte uint32_t
isns_process_dev_attr_qry_target_nodes_pdu(iscsi_addr_t * isns_server_addr,uint16_t payload_funcId,isns_resp_t * resp_p,size_t resp_len,isns_portal_group_list_t ** pg_list)2439fcf3ce44SJohn Forte isns_process_dev_attr_qry_target_nodes_pdu(
2440fcf3ce44SJohn Forte 	iscsi_addr_t *isns_server_addr, uint16_t payload_funcId,
2441fcf3ce44SJohn Forte 	isns_resp_t *resp_p, size_t resp_len,
2442fcf3ce44SJohn Forte 	isns_portal_group_list_t **pg_list)
2443fcf3ce44SJohn Forte {
2444fcf3ce44SJohn Forte 	boolean_t done_b, found_delimiter_b, target_node_type_b;
2445fcf3ce44SJohn Forte 	int num_of_pgs = 0, pg_sz, idx;
2446fcf3ce44SJohn Forte 	isns_tlv_t *attr_tlv_p;
2447fcf3ce44SJohn Forte 	uint8_t *data_p;
2448fcf3ce44SJohn Forte 	uint32_t len, total_payload_len = 0;
2449fcf3ce44SJohn Forte 	isns_portal_group_t *pg;
2450fcf3ce44SJohn Forte 	uint8_t	junk[IPV4_RSVD_BYTES];
2451fcf3ce44SJohn Forte 
2452fcf3ce44SJohn Forte 	*pg_list = NULL;
2453fcf3ce44SJohn Forte 	bzero(junk, IPV4_RSVD_BYTES);
2454fcf3ce44SJohn Forte 
2455fcf3ce44SJohn Forte 	if (payload_funcId != ISNS_DEV_ATTR_QRY_RSP) {
2456fcf3ce44SJohn Forte 		/* If this happens the iSNS server may have a problem. */
2457fcf3ce44SJohn Forte 		return (ISNS_RSP_MSG_FORMAT_ERROR);
2458fcf3ce44SJohn Forte 	}
2459fcf3ce44SJohn Forte 
2460fcf3ce44SJohn Forte 	if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2461fcf3ce44SJohn Forte 		return (ntohl(resp_p->status));
2462fcf3ce44SJohn Forte 	}
2463fcf3ce44SJohn Forte 
2464fcf3ce44SJohn Forte 	/*
2465fcf3ce44SJohn Forte 	 * If payload is smaller than the length of even 1 attribute
2466fcf3ce44SJohn Forte 	 * there is something wrong with the PDU.
2467fcf3ce44SJohn Forte 	 */
2468fcf3ce44SJohn Forte 	if (resp_len < (ISNS_TLV_ATTR_ID_LEN +
2469fcf3ce44SJohn Forte 	    ISNS_TLV_ATTR_LEN_LEN)) {
2470fcf3ce44SJohn Forte 		return (ISNS_RSP_MSG_FORMAT_ERROR);
2471fcf3ce44SJohn Forte 	}
2472fcf3ce44SJohn Forte 
2473fcf3ce44SJohn Forte 	/*
2474fcf3ce44SJohn Forte 	 * Expected DevAttrQryRsp message format:
2475fcf3ce44SJohn Forte 	 *
2476fcf3ce44SJohn Forte 	 * Status Code
2477fcf3ce44SJohn Forte 	 * iSCSI Node Type
2478fcf3ce44SJohn Forte 	 * Delimiter
2479fcf3ce44SJohn Forte 	 * PG iSCSI Name		[Optional]
2480fcf3ce44SJohn Forte 	 * PG Portal IP Address		[Optional]
2481fcf3ce44SJohn Forte 	 * PG Portal Port		[Optional]
2482fcf3ce44SJohn Forte 	 * PG Tag			[Optional]
2483fcf3ce44SJohn Forte 	 * PG iSCSI Name		[Optional]
2484fcf3ce44SJohn Forte 	 * PG Portal IP Address		[Optional]
2485fcf3ce44SJohn Forte 	 * PG Portal Port		[Optional]
2486fcf3ce44SJohn Forte 	 * PG Tag			[Optional]
2487fcf3ce44SJohn Forte 	 * .
2488fcf3ce44SJohn Forte 	 * .
2489fcf3ce44SJohn Forte 	 * .
2490fcf3ce44SJohn Forte 	 */
2491fcf3ce44SJohn Forte 	data_p = resp_p->data;
2492fcf3ce44SJohn Forte 	done_b = B_FALSE;
2493fcf3ce44SJohn Forte 	found_delimiter_b = B_FALSE;
2494fcf3ce44SJohn Forte 	num_of_pgs = 0;
2495fcf3ce44SJohn Forte 	total_payload_len = sizeof (resp_p->status);
2496fcf3ce44SJohn Forte 	/* Find out the number of entries retrieved */
2497fcf3ce44SJohn Forte 	while (!done_b) {
2498fcf3ce44SJohn Forte 		attr_tlv_p = (isns_tlv_t *)data_p;
2499fcf3ce44SJohn Forte 		if (ntohl(attr_tlv_p->attr_id) == ISNS_DELIMITER_ATTR_ID) {
2500fcf3ce44SJohn Forte 			if (found_delimiter_b) {
2501fcf3ce44SJohn Forte 				done_b = B_TRUE;
2502fcf3ce44SJohn Forte 			} else {
2503fcf3ce44SJohn Forte 				found_delimiter_b = B_TRUE;
2504fcf3ce44SJohn Forte 			}
2505fcf3ce44SJohn Forte 		} else if (ntohl(attr_tlv_p->attr_id) ==
2506fcf3ce44SJohn Forte 		    ISNS_PG_TAG_ATTR_ID) {
2507*d3e3772eSyi zhang - Sun Microsystems - Beijing China 			if (ntohl(attr_tlv_p->attr_len) > 0) {
2508*d3e3772eSyi zhang - Sun Microsystems - Beijing China 				/*
2509*d3e3772eSyi zhang - Sun Microsystems - Beijing China 				 * Count only those iSCSI node that have a
2510*d3e3772eSyi zhang - Sun Microsystems - Beijing China 				 * non-NULL PGT value as valid Entity.
2511*d3e3772eSyi zhang - Sun Microsystems - Beijing China 				 * Per rfc4171 section 3.4 - If the PGT value
2512*d3e3772eSyi zhang - Sun Microsystems - Beijing China 				 * registered for a specified Portal and iSCSI
2513*d3e3772eSyi zhang - Sun Microsystems - Beijing China 				 * Node is NULL, or if no PGT value is
2514*d3e3772eSyi zhang - Sun Microsystems - Beijing China 				 * registered, then the Portal does not provide
2515*d3e3772eSyi zhang - Sun Microsystems - Beijing China 				 * access to that iSCSI Node in the Entity.
2516*d3e3772eSyi zhang - Sun Microsystems - Beijing China 				 */
2517*d3e3772eSyi zhang - Sun Microsystems - Beijing China 				num_of_pgs++;
2518*d3e3772eSyi zhang - Sun Microsystems - Beijing China 			}
2519fcf3ce44SJohn Forte 		}
2520fcf3ce44SJohn Forte 		len = ntohl(attr_tlv_p->attr_len);
2521fcf3ce44SJohn Forte 
2522fcf3ce44SJohn Forte 		total_payload_len += (ISNS_TLV_ATTR_ID_LEN +
2523fcf3ce44SJohn Forte 		    ISNS_TLV_ATTR_LEN_LEN + len);
2524fcf3ce44SJohn Forte 		if (total_payload_len >= resp_len) {
2525fcf3ce44SJohn Forte 			done_b = B_TRUE;
2526fcf3ce44SJohn Forte 		} else {
2527fcf3ce44SJohn Forte 			data_p += (ISNS_TLV_ATTR_ID_LEN +
2528fcf3ce44SJohn Forte 			    ISNS_TLV_ATTR_LEN_LEN + len);
2529fcf3ce44SJohn Forte 		}
2530fcf3ce44SJohn Forte 	}
2531fcf3ce44SJohn Forte 
2532fcf3ce44SJohn Forte 	pg_sz = sizeof (isns_portal_group_list_t);
2533fcf3ce44SJohn Forte 	if (num_of_pgs > 0) {
2534fcf3ce44SJohn Forte 		pg_sz += (num_of_pgs - 1) * sizeof (isns_portal_group_t);
2535fcf3ce44SJohn Forte 	}
2536fcf3ce44SJohn Forte 	DTRACE_PROBE1(isns_process_dev_attr_qry_target_nodes_pdu_pg_size,
2537fcf3ce44SJohn Forte 	    int, pg_sz);
2538fcf3ce44SJohn Forte 	/*
2539fcf3ce44SJohn Forte 	 * Once we passed this point, if for any reason we need to return
2540fcf3ce44SJohn Forte 	 * because of a failure, we need to free the memory allocated for
2541fcf3ce44SJohn Forte 	 * the pg_list and nullify it.
2542fcf3ce44SJohn Forte 	 */
2543fcf3ce44SJohn Forte 	*pg_list = (isns_portal_group_list_t *)kmem_zalloc(pg_sz, KM_SLEEP);
2544fcf3ce44SJohn Forte 	(*pg_list)->pg_out_cnt = 0;
2545fcf3ce44SJohn Forte 
2546fcf3ce44SJohn Forte 	/* Assign the isns_server information to all portal groups */
2547fcf3ce44SJohn Forte 	for (idx = 0; idx < num_of_pgs; idx++) {
2548fcf3ce44SJohn Forte 		pg = &((*pg_list)->pg_list[idx]);
2549fcf3ce44SJohn Forte 		bcopy(&isns_server_addr->a_addr, &pg->isns_server_ip,
2550fcf3ce44SJohn Forte 		    sizeof (iscsi_ipaddr_t));
2551fcf3ce44SJohn Forte 		pg->isns_server_port = isns_server_addr->a_port;
2552fcf3ce44SJohn Forte 	}
2553fcf3ce44SJohn Forte 
2554fcf3ce44SJohn Forte 	data_p = resp_p->data;
2555fcf3ce44SJohn Forte 	done_b = B_FALSE;
2556fcf3ce44SJohn Forte 	found_delimiter_b = B_FALSE;
2557fcf3ce44SJohn Forte 	total_payload_len = sizeof (resp_p->status);
2558fcf3ce44SJohn Forte 	while (!done_b) {
2559fcf3ce44SJohn Forte 		attr_tlv_p = (isns_tlv_t *)data_p;
2560fcf3ce44SJohn Forte 		pg = &((*pg_list)->pg_list[(*pg_list)->pg_out_cnt]);
2561fcf3ce44SJohn Forte 		switch (ntohl(attr_tlv_p->attr_id)) {
2562fcf3ce44SJohn Forte 			case ISNS_DELIMITER_ATTR_ID:
2563fcf3ce44SJohn Forte 				if (found_delimiter_b) {
2564fcf3ce44SJohn Forte 					done_b = B_TRUE;
2565fcf3ce44SJohn Forte 				} else {
2566fcf3ce44SJohn Forte 					found_delimiter_b = B_TRUE;
2567fcf3ce44SJohn Forte 				}
2568fcf3ce44SJohn Forte 				break;
2569fcf3ce44SJohn Forte 
2570fcf3ce44SJohn Forte 			case ISNS_PG_ISCSI_NAME_ATTR_ID:
2571fcf3ce44SJohn Forte 				target_node_type_b = B_TRUE;
2572fcf3ce44SJohn Forte 				bcopy(attr_tlv_p->attr_value,
2573fcf3ce44SJohn Forte 				    (char *)pg->pg_iscsi_name,
2574fcf3ce44SJohn Forte 				    ntohl(attr_tlv_p->attr_len) <
2575fcf3ce44SJohn Forte 				    ISCSI_MAX_NAME_LEN ?
2576fcf3ce44SJohn Forte 				    ntohl(attr_tlv_p->attr_len) :
2577fcf3ce44SJohn Forte 				    ISCSI_MAX_NAME_LEN);
2578fcf3ce44SJohn Forte 
2579fcf3ce44SJohn Forte 				DTRACE_PROBE1(isns_dev_attr_qry_process1,
2580fcf3ce44SJohn Forte 				    char *, (char *)pg->pg_iscsi_name);
2581fcf3ce44SJohn Forte 				break;
2582fcf3ce44SJohn Forte 
2583fcf3ce44SJohn Forte 			case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
2584fcf3ce44SJohn Forte 				if (target_node_type_b) {
2585fcf3ce44SJohn Forte 					/*
2586fcf3ce44SJohn Forte 					 * Section 6.3.1 - The Portal IP Address
2587fcf3ce44SJohn Forte 					 * is a 16-byte field that may contain
2588fcf3ce44SJohn Forte 					 * an IPv4 or IPv6 address. When this
2589fcf3ce44SJohn Forte 					 * field contains an IPv4 address, it
2590fcf3ce44SJohn Forte 					 * is stored as an IPv4-mapped IPv6
2591fcf3ce44SJohn Forte 					 * address
2592fcf3ce44SJohn Forte 					 */
2593fcf3ce44SJohn Forte 					if (ntohl(attr_tlv_p->attr_len) != 16) {
2594fcf3ce44SJohn Forte #define	STRING_AALR "address attribute length received "
2595fcf3ce44SJohn Forte #define	STRING_FISE16 "from iSNS server, Expected = 16, "
2596fcf3ce44SJohn Forte 						cmn_err(CE_NOTE, "Wrong IP "
2597fcf3ce44SJohn Forte 						    STRING_AALR
2598fcf3ce44SJohn Forte 						    STRING_FISE16
2599fcf3ce44SJohn Forte 						    "Received = %d",
2600fcf3ce44SJohn Forte 						    ntohl(
2601fcf3ce44SJohn Forte 						    attr_tlv_p->attr_len));
2602fcf3ce44SJohn Forte 						return (
2603fcf3ce44SJohn Forte 						    ISNS_RSP_MSG_FORMAT_ERROR);
2604fcf3ce44SJohn Forte #undef STRING_AALR
2605fcf3ce44SJohn Forte #undef STRING_FISE16
2606fcf3ce44SJohn Forte 					}
2607fcf3ce44SJohn Forte 
2608fcf3ce44SJohn Forte 					/*
2609fcf3ce44SJohn Forte 					 * Section 6.3.1 and RFC 2373 state
2610fcf3ce44SJohn Forte 					 * that an IPv4 address will be denoted
2611fcf3ce44SJohn Forte 					 * by the 10 top bytes as all zero
2612fcf3ce44SJohn Forte 					 * followed by either 2 bytes of
2613fcf3ce44SJohn Forte 					 * 0x0000 or 0xFFFF The 0x0000 states
2614fcf3ce44SJohn Forte 					 * that the address is is IPv6 capable
2615fcf3ce44SJohn Forte 					 * and 0xFFFF states its not capable.
2616fcf3ce44SJohn Forte 					 */
2617fcf3ce44SJohn Forte 					if ((bcmp(attr_tlv_p->attr_value, junk,
2618fcf3ce44SJohn Forte 					    IPV4_RSVD_BYTES) == 0) &&
2619fcf3ce44SJohn Forte 					    (((attr_tlv_p->attr_value[10] ==
2620fcf3ce44SJohn Forte 					    0x00) &&
2621fcf3ce44SJohn Forte 					    (attr_tlv_p->attr_value[11] ==
2622fcf3ce44SJohn Forte 					    0x00)) ||
2623fcf3ce44SJohn Forte 					    ((attr_tlv_p->attr_value[10] ==
2624fcf3ce44SJohn Forte 					    0xFF) &&
2625fcf3ce44SJohn Forte 					    (attr_tlv_p->attr_value[11] ==
2626fcf3ce44SJohn Forte 					    0xFF)))) {
2627fcf3ce44SJohn Forte 
2628fcf3ce44SJohn Forte 						/* IPv4 */
2629fcf3ce44SJohn Forte 						bcopy(attr_tlv_p->attr_value +
2630fcf3ce44SJohn Forte 						    12, &pg->pg_ip_addr.u_ip4,
2631fcf3ce44SJohn Forte 						    sizeof (struct in_addr));
2632fcf3ce44SJohn Forte 						pg->insize =
2633fcf3ce44SJohn Forte 						    sizeof (struct in_addr);
2634fcf3ce44SJohn Forte 					} else {
2635fcf3ce44SJohn Forte 						/* IPv6 */
2636fcf3ce44SJohn Forte 						bcopy(attr_tlv_p->attr_value,
2637fcf3ce44SJohn Forte 						    &pg->pg_ip_addr.u_ip6,
2638fcf3ce44SJohn Forte 						    sizeof (struct in6_addr));
2639fcf3ce44SJohn Forte 						pg->insize =
2640fcf3ce44SJohn Forte 						    sizeof (struct in6_addr);
2641fcf3ce44SJohn Forte 					}
2642fcf3ce44SJohn Forte 				}
2643fcf3ce44SJohn Forte 				break;
2644fcf3ce44SJohn Forte 
2645fcf3ce44SJohn Forte 			case ISNS_PG_PORTAL_PORT_ATTR_ID:
2646fcf3ce44SJohn Forte 				if (target_node_type_b) {
2647fcf3ce44SJohn Forte 					pg->pg_port =
2648fcf3ce44SJohn Forte 					    ntohl(*(uint32_t *)
2649fcf3ce44SJohn Forte 					    (*attr_tlv_p).
2650fcf3ce44SJohn Forte 					    attr_value);
2651fcf3ce44SJohn Forte 				}
2652fcf3ce44SJohn Forte 
2653fcf3ce44SJohn Forte 				break;
2654fcf3ce44SJohn Forte 
2655fcf3ce44SJohn Forte 			case ISNS_PG_TAG_ATTR_ID:
2656fcf3ce44SJohn Forte 				if (target_node_type_b) {
2657fcf3ce44SJohn Forte 					pg->pg_tag =
2658fcf3ce44SJohn Forte 					    ntohl(*(uint32_t *)
2659fcf3ce44SJohn Forte 					    (*attr_tlv_p).
2660fcf3ce44SJohn Forte 					    attr_value);
2661fcf3ce44SJohn Forte 				}
2662fcf3ce44SJohn Forte 				target_node_type_b = B_FALSE;
2663*d3e3772eSyi zhang - Sun Microsystems - Beijing China 				if (ntohl(attr_tlv_p->attr_len) > 0) {
2664*d3e3772eSyi zhang - Sun Microsystems - Beijing China 					/*
2665*d3e3772eSyi zhang - Sun Microsystems - Beijing China 					 * Only the iSCSI node that has a
2666*d3e3772eSyi zhang - Sun Microsystems - Beijing China 					 * non-NULL PGT value is an valid
2667*d3e3772eSyi zhang - Sun Microsystems - Beijing China 					 * Entity.
2668*d3e3772eSyi zhang - Sun Microsystems - Beijing China 					 */
2669*d3e3772eSyi zhang - Sun Microsystems - Beijing China 					(*pg_list)->pg_out_cnt++;
2670*d3e3772eSyi zhang - Sun Microsystems - Beijing China 				}
2671fcf3ce44SJohn Forte 				break;
2672fcf3ce44SJohn Forte 
2673fcf3ce44SJohn Forte 			default:
2674fcf3ce44SJohn Forte 				break;
2675fcf3ce44SJohn Forte 		}
2676fcf3ce44SJohn Forte 
2677fcf3ce44SJohn Forte 		len = ntohl(attr_tlv_p->attr_len);
2678fcf3ce44SJohn Forte 		total_payload_len += (ISNS_TLV_ATTR_ID_LEN +
2679fcf3ce44SJohn Forte 		    ISNS_TLV_ATTR_LEN_LEN + len);
2680fcf3ce44SJohn Forte 		if ((total_payload_len >= resp_len) ||
2681fcf3ce44SJohn Forte 		    ((*pg_list)->pg_out_cnt == num_of_pgs)) {
2682fcf3ce44SJohn Forte 			done_b = B_TRUE;
2683fcf3ce44SJohn Forte 		} else {
2684fcf3ce44SJohn Forte 			data_p += (ISNS_TLV_ATTR_ID_LEN +
2685fcf3ce44SJohn Forte 			    ISNS_TLV_ATTR_LEN_LEN + len);
2686fcf3ce44SJohn Forte 		}
2687fcf3ce44SJohn Forte 	}
2688fcf3ce44SJohn Forte 
2689fcf3ce44SJohn Forte 	return (ISNS_RSP_SUCCESSFUL);
2690fcf3ce44SJohn Forte }
2691fcf3ce44SJohn Forte 
2692fcf3ce44SJohn Forte /* ARGSUSED */
2693fcf3ce44SJohn Forte static
2694fcf3ce44SJohn Forte uint32_t
isns_process_esi(isns_pdu_t * esi_pdu_p)2695fcf3ce44SJohn Forte isns_process_esi(isns_pdu_t *esi_pdu_p)
2696fcf3ce44SJohn Forte {
2697fcf3ce44SJohn Forte 	/* There's nothing particular to process for ESI. */
2698fcf3ce44SJohn Forte 	return (ISNS_RSP_SUCCESSFUL);
2699fcf3ce44SJohn Forte }
2700fcf3ce44SJohn Forte 
2701fcf3ce44SJohn Forte static
2702fcf3ce44SJohn Forte uint32_t
isns_process_scn(isns_pdu_t * scn_pdu_p,uint8_t * lhba_handle)2703fcf3ce44SJohn Forte isns_process_scn(isns_pdu_t *scn_pdu_p, uint8_t *lhba_handle)
2704fcf3ce44SJohn Forte {
2705fcf3ce44SJohn Forte 	boolean_t dest_attr_found_b;
2706fcf3ce44SJohn Forte 	boolean_t done_b;
2707fcf3ce44SJohn Forte 	boolean_t scn_type_found_b;
2708fcf3ce44SJohn Forte 	isns_scn_callback_arg_t *scn_args_p;
2709fcf3ce44SJohn Forte 	isns_tlv_t *attr_tlv_p;
2710fcf3ce44SJohn Forte 	uint8_t *data_p;
2711fcf3ce44SJohn Forte 	uint8_t *src_attr;
2712fcf3ce44SJohn Forte 	uint32_t attr_eff_len, normalized_attr_len;
2713fcf3ce44SJohn Forte 	uint32_t scn_type;
2714fcf3ce44SJohn Forte 	uint32_t total_payload_len;
2715fcf3ce44SJohn Forte 	void (*scn_callback_to_use)(void *);
2716fcf3ce44SJohn Forte 
2717fcf3ce44SJohn Forte 	/* get the lhba_handle to use for the call back */
2718fcf3ce44SJohn Forte 	scn_callback_to_use = scn_callback_lookup(lhba_handle);
2719fcf3ce44SJohn Forte 	if (scn_callback_to_use == NULL) {
2720fcf3ce44SJohn Forte 		return (ISNS_RSP_INTERNAL_ERROR);
2721fcf3ce44SJohn Forte 	}
2722fcf3ce44SJohn Forte 
2723fcf3ce44SJohn Forte 	dest_attr_found_b = B_FALSE;
2724fcf3ce44SJohn Forte 	scn_type = 0;
2725fcf3ce44SJohn Forte 	scn_type_found_b = B_FALSE;
2726fcf3ce44SJohn Forte 	data_p = scn_pdu_p->payload;
2727fcf3ce44SJohn Forte 	done_b = B_FALSE;
2728fcf3ce44SJohn Forte 	total_payload_len = 0;
2729fcf3ce44SJohn Forte 	src_attr = (uint8_t *)kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
2730fcf3ce44SJohn Forte 	/*
2731fcf3ce44SJohn Forte 	 * Section 5.6.5.8 states an SCN can have more than one
2732fcf3ce44SJohn Forte 	 * source attribute.  Process all attributes until we
2733fcf3ce44SJohn Forte 	 * each process all the data or encounter the delimiter.
2734fcf3ce44SJohn Forte 	 */
2735fcf3ce44SJohn Forte 	while (!done_b) {
2736fcf3ce44SJohn Forte 		attr_tlv_p = (isns_tlv_t *)data_p;
2737fcf3ce44SJohn Forte 
2738fcf3ce44SJohn Forte 		switch (ntohl(attr_tlv_p->attr_id)) {
2739fcf3ce44SJohn Forte 		/* ISNS_ISCSI_NAME_ATTR_ID - attribute name */
2740fcf3ce44SJohn Forte 		case ISNS_ISCSI_NAME_ATTR_ID:
2741fcf3ce44SJohn Forte 			attr_eff_len = strlen(
2742fcf3ce44SJohn Forte 			    (char *)attr_tlv_p->attr_value) + 1;
2743fcf3ce44SJohn Forte 			/*
2744fcf3ce44SJohn Forte 			 * The attribute length must be 4-byte aligned.
2745fcf3ce44SJohn Forte 			 * Section 5.1.3, RFC 4171.
2746fcf3ce44SJohn Forte 			 */
2747fcf3ce44SJohn Forte 			normalized_attr_len = (attr_eff_len % 4) == 0 ?
2748fcf3ce44SJohn Forte 			    (attr_eff_len) :
2749fcf3ce44SJohn Forte 			    (attr_eff_len + (4 - (attr_eff_len % 4)));
2750fcf3ce44SJohn Forte 			if (normalized_attr_len !=
2751fcf3ce44SJohn Forte 			    ntohl(attr_tlv_p->attr_len)) {
2752fcf3ce44SJohn Forte 				/* This SCN is bad. */
2753fcf3ce44SJohn Forte 				kmem_free(src_attr, ISCSI_MAX_NAME_LEN);
2754fcf3ce44SJohn Forte 				return (ISNS_RSP_MSG_FORMAT_ERROR);
2755fcf3ce44SJohn Forte 			}
2756fcf3ce44SJohn Forte 
2757fcf3ce44SJohn Forte 			/* Check if this was the Destination Attribute */
2758fcf3ce44SJohn Forte 			if ((dest_attr_found_b == B_TRUE) &&
2759fcf3ce44SJohn Forte 			    (scn_type_found_b == B_TRUE)) {
2760fcf3ce44SJohn Forte 				bzero(src_attr, ISCSI_MAX_NAME_LEN);
2761fcf3ce44SJohn Forte 				bcopy(attr_tlv_p->attr_value,
2762fcf3ce44SJohn Forte 				    (char *)src_attr,
2763fcf3ce44SJohn Forte 				    ntohl(attr_tlv_p->attr_len) <
2764fcf3ce44SJohn Forte 				    ISCSI_MAX_NAME_LEN ?
2765fcf3ce44SJohn Forte 				    ntohl(attr_tlv_p->attr_len) :
2766fcf3ce44SJohn Forte 				    ISCSI_MAX_NAME_LEN);
2767fcf3ce44SJohn Forte 
2768fcf3ce44SJohn Forte 				/* allocate new callback structure */
2769fcf3ce44SJohn Forte 				scn_args_p =
2770fcf3ce44SJohn Forte 				    (isns_scn_callback_arg_t *)kmem_zalloc(
2771fcf3ce44SJohn Forte 				    sizeof (isns_scn_callback_arg_t),
2772fcf3ce44SJohn Forte 				    KM_SLEEP);
2773fcf3ce44SJohn Forte 				scn_args_p->scn_type = ntohl(scn_type);
2774fcf3ce44SJohn Forte 				bcopy(src_attr, scn_args_p->source_key_attr,
2775fcf3ce44SJohn Forte 				    sizeof (scn_args_p->source_key_attr));
2776fcf3ce44SJohn Forte 
2777fcf3ce44SJohn Forte 				/* Dispatch the callback to process the SCN */
2778fcf3ce44SJohn Forte 				mutex_enter(&scn_taskq_mutex);
2779fcf3ce44SJohn Forte 				if (scn_taskq != NULL) {
2780fcf3ce44SJohn Forte 					(void) ddi_taskq_dispatch(scn_taskq,
2781fcf3ce44SJohn Forte 					    scn_callback_to_use,
2782fcf3ce44SJohn Forte 					    scn_args_p, DDI_SLEEP);
2783fcf3ce44SJohn Forte 				}
2784fcf3ce44SJohn Forte 				mutex_exit(&scn_taskq_mutex);
2785fcf3ce44SJohn Forte 			} else {
2786fcf3ce44SJohn Forte 				/* Skip Destination Attribute */
2787fcf3ce44SJohn Forte 				dest_attr_found_b = B_TRUE;
2788fcf3ce44SJohn Forte 			}
2789fcf3ce44SJohn Forte 			break;
2790fcf3ce44SJohn Forte 
2791fcf3ce44SJohn Forte 		/* ISNS_ISCSI_SCN_BITMAP_ATTR_ID - change type */
2792fcf3ce44SJohn Forte 		case ISNS_ISCSI_SCN_BITMAP_ATTR_ID:
2793fcf3ce44SJohn Forte 			/*
2794fcf3ce44SJohn Forte 			 * Determine the type of action to take for this SCN.
2795fcf3ce44SJohn Forte 			 */
2796fcf3ce44SJohn Forte 			scn_type_found_b = B_TRUE;
2797fcf3ce44SJohn Forte 			bcopy(&(attr_tlv_p->attr_value), &scn_type, 4);
2798fcf3ce44SJohn Forte 			break;
2799fcf3ce44SJohn Forte 
2800fcf3ce44SJohn Forte 		/* ISNS_DELIMITER_ATTR_ID - end of the payload of a message */
2801fcf3ce44SJohn Forte 		case ISNS_DELIMITER_ATTR_ID:
2802fcf3ce44SJohn Forte 			done_b = B_TRUE;
2803fcf3ce44SJohn Forte 			break;
2804fcf3ce44SJohn Forte 		}
2805fcf3ce44SJohn Forte 
2806fcf3ce44SJohn Forte 		if (done_b == B_FALSE) {
2807fcf3ce44SJohn Forte 			total_payload_len += ntohl(attr_tlv_p->attr_len) +
2808fcf3ce44SJohn Forte 			    ISNS_TLV_ATTR_ID_LEN + ISNS_TLV_ATTR_LEN_LEN;
2809fcf3ce44SJohn Forte 			if ((total_payload_len >= scn_pdu_p->payload_len) ||
2810fcf3ce44SJohn Forte 			    (total_payload_len > ISNSP_MAX_PAYLOAD_SIZE)) {
2811fcf3ce44SJohn Forte 				/* No more Attributes to process */
2812fcf3ce44SJohn Forte 				done_b = B_TRUE;
2813fcf3ce44SJohn Forte 			} else {
2814fcf3ce44SJohn Forte 				if (scn_pdu_p->payload_len -
2815fcf3ce44SJohn Forte 				    total_payload_len <=
2816fcf3ce44SJohn Forte 				    ISNS_TLV_ATTR_ID_LEN +
2817fcf3ce44SJohn Forte 				    ISNS_TLV_ATTR_LEN_LEN) {
2818fcf3ce44SJohn Forte 					/*
2819fcf3ce44SJohn Forte 					 * The rest of the data in the PDU
2820fcf3ce44SJohn Forte 					 * is less than the size of a valid
2821fcf3ce44SJohn Forte 					 * iSNS TLV. This next attribute
2822fcf3ce44SJohn Forte 					 * probably spans across the PDU
2823fcf3ce44SJohn Forte 					 * boundary. For now, do not
2824fcf3ce44SJohn Forte 					 * process it further.
2825fcf3ce44SJohn Forte 					 */
2826fcf3ce44SJohn Forte 					done_b = B_TRUE;
2827fcf3ce44SJohn Forte 				} else {
2828fcf3ce44SJohn Forte 					/* Advance to the next Attribute */
2829fcf3ce44SJohn Forte 					data_p += (ISNS_TLV_ATTR_ID_LEN +
2830fcf3ce44SJohn Forte 					    ISNS_TLV_ATTR_LEN_LEN +
2831fcf3ce44SJohn Forte 					    ntohl(attr_tlv_p->attr_len));
2832fcf3ce44SJohn Forte 				}
2833fcf3ce44SJohn Forte 			}
2834fcf3ce44SJohn Forte 		}
2835fcf3ce44SJohn Forte 	}
2836fcf3ce44SJohn Forte 
2837fcf3ce44SJohn Forte 	kmem_free(src_attr, ISCSI_MAX_NAME_LEN);
2838fcf3ce44SJohn Forte 	return (ISNS_RSP_SUCCESSFUL);
2839fcf3ce44SJohn Forte }
2840fcf3ce44SJohn Forte 
2841fcf3ce44SJohn Forte static
2842fcf3ce44SJohn Forte size_t
isns_create_pdu_header(uint16_t func_id,uint16_t flags,isns_pdu_t ** pdu)2843fcf3ce44SJohn Forte isns_create_pdu_header(uint16_t func_id, uint16_t flags, isns_pdu_t **pdu)
2844fcf3ce44SJohn Forte {
2845fcf3ce44SJohn Forte 	/*
2846fcf3ce44SJohn Forte 	 * It should be ok to assume ISNSP_MAX_PDU_SIZE is large enough
2847fcf3ce44SJohn Forte 	 * since we are creating our own PDU which is fully under our control.
2848fcf3ce44SJohn Forte 	 */
2849fcf3ce44SJohn Forte 	size_t pdu_size = ISNSP_MAX_PDU_SIZE;
2850fcf3ce44SJohn Forte 
2851fcf3ce44SJohn Forte 	*pdu = (isns_pdu_t *)kmem_zalloc(pdu_size, KM_SLEEP);
2852fcf3ce44SJohn Forte 	(void) memset((*pdu), 0, pdu_size);
2853fcf3ce44SJohn Forte 	(*pdu)->version = htons((uint16_t)ISNSP_VERSION);
2854fcf3ce44SJohn Forte 	(*pdu)->func_id = htons((uint16_t)func_id);
2855fcf3ce44SJohn Forte 	(*pdu)->payload_len = htons(0);
2856fcf3ce44SJohn Forte 	(*pdu)->flags = htons((uint16_t)(flags | ISNS_FLAG_CLIENT));
2857fcf3ce44SJohn Forte 	(*pdu)->xid = htons(create_xid());
2858fcf3ce44SJohn Forte 	(*pdu)->seq = htons(0);
2859fcf3ce44SJohn Forte 
2860fcf3ce44SJohn Forte 	return (pdu_size);
2861fcf3ce44SJohn Forte }
2862fcf3ce44SJohn Forte 
2863fcf3ce44SJohn Forte static
2864fcf3ce44SJohn Forte int
isns_add_attr(isns_pdu_t * pdu,size_t max_pdu_size,uint32_t attr_id,uint32_t attr_len,void * attr_data,uint32_t attr_numeric_data)2865fcf3ce44SJohn Forte isns_add_attr(isns_pdu_t *pdu,
2866fcf3ce44SJohn Forte 	size_t max_pdu_size,
2867fcf3ce44SJohn Forte 	uint32_t attr_id,
2868fcf3ce44SJohn Forte 	uint32_t attr_len,
2869fcf3ce44SJohn Forte 	void *attr_data,
2870fcf3ce44SJohn Forte 	uint32_t attr_numeric_data)
2871fcf3ce44SJohn Forte {
2872fcf3ce44SJohn Forte 	isns_tlv_t *attr_tlv;
2873fcf3ce44SJohn Forte 	uint8_t *payload_ptr;
2874fcf3ce44SJohn Forte 	uint16_t payload_len;
2875fcf3ce44SJohn Forte 	uint32_t normalized_attr_len;
2876fcf3ce44SJohn Forte 	uint64_t attr_tlv_len;
2877fcf3ce44SJohn Forte 
2878fcf3ce44SJohn Forte 	/* The attribute length must be 4-byte aligned. Section 5.1.3. */
2879fcf3ce44SJohn Forte 	normalized_attr_len = (attr_len % 4) == 0 ? (attr_len) :
2880fcf3ce44SJohn Forte 	    (attr_len + (4 - (attr_len % 4)));
2881fcf3ce44SJohn Forte 	attr_tlv_len = ISNS_TLV_ATTR_ID_LEN
2882fcf3ce44SJohn Forte 	    + ISNS_TLV_ATTR_LEN_LEN
2883fcf3ce44SJohn Forte 	    + normalized_attr_len;
2884fcf3ce44SJohn Forte 	/* Check if we are going to exceed the maximum PDU length. */
2885fcf3ce44SJohn Forte 	payload_len = ntohs(pdu->payload_len);
2886fcf3ce44SJohn Forte 	if ((payload_len + attr_tlv_len) > max_pdu_size) {
2887fcf3ce44SJohn Forte 		return (1);
2888fcf3ce44SJohn Forte 	}
2889fcf3ce44SJohn Forte 
2890fcf3ce44SJohn Forte 	attr_tlv = (isns_tlv_t *)kmem_zalloc(attr_tlv_len, KM_SLEEP);
2891fcf3ce44SJohn Forte 
2892fcf3ce44SJohn Forte 	attr_tlv->attr_id = htonl(attr_id);
2893fcf3ce44SJohn Forte 
2894fcf3ce44SJohn Forte 	switch (attr_id) {
2895fcf3ce44SJohn Forte 		case ISNS_DELIMITER_ATTR_ID:
2896fcf3ce44SJohn Forte 		break;
2897fcf3ce44SJohn Forte 
2898fcf3ce44SJohn Forte 		case ISNS_PORTAL_IP_ADDR_ATTR_ID:
2899fcf3ce44SJohn Forte 		case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
2900fcf3ce44SJohn Forte 			if (attr_numeric_data == sizeof (in_addr_t)) {
2901fcf3ce44SJohn Forte 				/* IPv4 */
2902fcf3ce44SJohn Forte 				attr_tlv->attr_value[10] = 0xFF;
2903fcf3ce44SJohn Forte 				attr_tlv->attr_value[11] = 0xFF;
2904fcf3ce44SJohn Forte 				bcopy(attr_data, ((attr_tlv->attr_value) + 12),
2905fcf3ce44SJohn Forte 				    sizeof (in_addr_t));
2906fcf3ce44SJohn Forte 			} else if (attr_numeric_data == sizeof (in6_addr_t)) {
2907fcf3ce44SJohn Forte 				/* IPv6 */
2908fcf3ce44SJohn Forte 				bcopy(attr_data, attr_tlv->attr_value,
2909fcf3ce44SJohn Forte 				    sizeof (in6_addr_t));
2910fcf3ce44SJohn Forte 			} else if (attr_numeric_data == 0) {
2911fcf3ce44SJohn Forte 				/* EMPTY */
2912fcf3ce44SJohn Forte 				/* Do nothing */
2913fcf3ce44SJohn Forte 			} else {
2914fcf3ce44SJohn Forte 				kmem_free(attr_tlv, attr_tlv_len);
2915fcf3ce44SJohn Forte 				attr_tlv = NULL;
2916fcf3ce44SJohn Forte 				return (1);
2917fcf3ce44SJohn Forte 			}
2918fcf3ce44SJohn Forte 		break;
2919fcf3ce44SJohn Forte 
2920fcf3ce44SJohn Forte 		case ISNS_EID_ATTR_ID:
2921fcf3ce44SJohn Forte 		case ISNS_ISCSI_NAME_ATTR_ID:
2922fcf3ce44SJohn Forte 		case ISNS_ISCSI_ALIAS_ATTR_ID:
2923fcf3ce44SJohn Forte 		case ISNS_PG_ISCSI_NAME_ATTR_ID:
2924fcf3ce44SJohn Forte 			bcopy((char *)attr_data,
2925fcf3ce44SJohn Forte 			    attr_tlv->attr_value,
2926fcf3ce44SJohn Forte 			    attr_len);
2927fcf3ce44SJohn Forte 		break;
2928fcf3ce44SJohn Forte 
2929fcf3ce44SJohn Forte 		default:
2930fcf3ce44SJohn Forte 			switch (normalized_attr_len) {
2931fcf3ce44SJohn Forte 				case 0:
2932fcf3ce44SJohn Forte 				break;
2933fcf3ce44SJohn Forte 
2934fcf3ce44SJohn Forte 				case 4:
2935fcf3ce44SJohn Forte 					*(uint32_t *)attr_tlv->attr_value =
2936fcf3ce44SJohn Forte 					    htonl(attr_numeric_data);
2937fcf3ce44SJohn Forte 				break;
2938fcf3ce44SJohn Forte 
2939fcf3ce44SJohn Forte 				case 8:
2940fcf3ce44SJohn Forte 					*(uint64_t *)attr_tlv->attr_value =
2941fcf3ce44SJohn Forte 					    BE_64((uint64_t)
2942fcf3ce44SJohn Forte 					    attr_numeric_data);
2943fcf3ce44SJohn Forte 				break;
2944fcf3ce44SJohn Forte 			}
2945fcf3ce44SJohn Forte 	}
2946fcf3ce44SJohn Forte 
2947fcf3ce44SJohn Forte 	attr_tlv->attr_len = htonl(normalized_attr_len);
2948fcf3ce44SJohn Forte 	/*
2949fcf3ce44SJohn Forte 	 * Convert the network byte ordered payload length to host byte
2950fcf3ce44SJohn Forte 	 * ordered for local address calculation.
2951fcf3ce44SJohn Forte 	 */
2952fcf3ce44SJohn Forte 	payload_len = ntohs(pdu->payload_len);
2953fcf3ce44SJohn Forte 	payload_ptr = pdu->payload + payload_len;
2954fcf3ce44SJohn Forte 	bcopy(attr_tlv, payload_ptr, attr_tlv_len);
2955fcf3ce44SJohn Forte 	payload_len += attr_tlv_len;
2956fcf3ce44SJohn Forte 
2957fcf3ce44SJohn Forte 	/*
2958fcf3ce44SJohn Forte 	 * Convert the host byte ordered payload length back to network
2959fcf3ce44SJohn Forte 	 * byte ordered - it's now ready to be sent on the wire.
2960fcf3ce44SJohn Forte 	 */
2961fcf3ce44SJohn Forte 	pdu->payload_len = htons(payload_len);
2962fcf3ce44SJohn Forte 
2963fcf3ce44SJohn Forte 	kmem_free(attr_tlv, attr_tlv_len);
2964fcf3ce44SJohn Forte 	attr_tlv = NULL;
2965fcf3ce44SJohn Forte 
2966fcf3ce44SJohn Forte 	return (0);
2967fcf3ce44SJohn Forte }
2968fcf3ce44SJohn Forte 
2969fcf3ce44SJohn Forte /* ARGSUSED */
2970fcf3ce44SJohn Forte static
2971fcf3ce44SJohn Forte void
isns_service_esi_scn(iscsi_thread_t * thread,void * arg)2972fcf3ce44SJohn Forte isns_service_esi_scn(iscsi_thread_t *thread, void *arg)
2973fcf3ce44SJohn Forte {
2974fcf3ce44SJohn Forte 	int clnt_len;
2975fcf3ce44SJohn Forte 	isns_async_thread_arg_t *larg;
2976fcf3ce44SJohn Forte 	isns_pdu_t *in_pdu;
2977fcf3ce44SJohn Forte 	size_t bytes_received, in_pdu_size = 0;
2978fcf3ce44SJohn Forte 	uint8_t *lhba_handle;
29790f1702c5SYu Xiangning 	struct sockaddr_in6	 t_addr;
29800f1702c5SYu Xiangning 	socklen_t		t_addrlen;
2981fcf3ce44SJohn Forte 	union {
2982fcf3ce44SJohn Forte 		struct sockaddr sin;
2983fcf3ce44SJohn Forte 		struct sockaddr_in s_in4;
2984fcf3ce44SJohn Forte 		struct sockaddr_in6 s_in6;
2985fcf3ce44SJohn Forte 	} clnt_addr = { 0 };
2986fcf3ce44SJohn Forte 	union {
2987fcf3ce44SJohn Forte 		struct sockaddr_in	soa4;
2988fcf3ce44SJohn Forte 		struct sockaddr_in6	soa6;
2989fcf3ce44SJohn Forte 	} local_conn_prop;
2990fcf3ce44SJohn Forte 	void *listening_so, *connecting_so;
2991fcf3ce44SJohn Forte 
2992fcf3ce44SJohn Forte 	larg = (isns_async_thread_arg_t *)arg;
2993fcf3ce44SJohn Forte 	listening_so = larg->listening_so;
2994fcf3ce44SJohn Forte 	lhba_handle = larg->lhba_handle;
2995fcf3ce44SJohn Forte 
2996fcf3ce44SJohn Forte 	/* Done using the argument - free it */
2997fcf3ce44SJohn Forte 	kmem_free(larg, sizeof (*larg));
29980f1702c5SYu Xiangning 	bzero(&t_addr, sizeof (struct sockaddr_in6));
29990f1702c5SYu Xiangning 	t_addrlen = sizeof (struct sockaddr_in6);
3000fcf3ce44SJohn Forte 
30010f1702c5SYu Xiangning 	(void) iscsi_net->getsockname(listening_so,
30020f1702c5SYu Xiangning 	    (struct sockaddr *)&t_addr, &t_addrlen);
30030f1702c5SYu Xiangning 	if (t_addrlen <= sizeof (local_conn_prop)) {
30040f1702c5SYu Xiangning 		bcopy(&t_addr, &local_conn_prop, t_addrlen);
3005fcf3ce44SJohn Forte 	}
3006fcf3ce44SJohn Forte 
3007fcf3ce44SJohn Forte 	if (iscsi_net->listen(listening_so, 5) < 0) {
3008fcf3ce44SJohn Forte 		iscsi_net->close(listening_so);
3009fcf3ce44SJohn Forte 	}
3010fcf3ce44SJohn Forte 
3011fcf3ce44SJohn Forte 	for (;;) {
3012fcf3ce44SJohn Forte 		int rval;
3013fcf3ce44SJohn Forte 		isns_pdu_t *out_pdu;
3014fcf3ce44SJohn Forte 		size_t out_pdu_size;
3015fcf3ce44SJohn Forte 
3016fcf3ce44SJohn Forte 		clnt_len = sizeof (clnt_addr);
3017fcf3ce44SJohn Forte 
3018fcf3ce44SJohn Forte 		/* Blocking call */
3019fcf3ce44SJohn Forte 		connecting_so = iscsi_net->accept(
30200f1702c5SYu Xiangning 		    listening_so, &clnt_addr.sin, &clnt_len);
3021fcf3ce44SJohn Forte 
3022fcf3ce44SJohn Forte 		mutex_enter(&esi_scn_thr_mutex);
3023fcf3ce44SJohn Forte 		if (esi_scn_thr_to_shutdown == B_TRUE) {
3024fcf3ce44SJohn Forte 			/* Terminate the thread if instructed to do so. */
3025fcf3ce44SJohn Forte 			mutex_exit(&esi_scn_thr_mutex);
3026fcf3ce44SJohn Forte 			return;
3027fcf3ce44SJohn Forte 		}
3028fcf3ce44SJohn Forte 		mutex_exit(&esi_scn_thr_mutex);
3029fcf3ce44SJohn Forte 
3030fcf3ce44SJohn Forte 		if (connecting_so == NULL) {
3031fcf3ce44SJohn Forte 			iscsi_net->close(listening_so);
3032fcf3ce44SJohn Forte 			continue;
3033fcf3ce44SJohn Forte 		}
3034fcf3ce44SJohn Forte 
3035fcf3ce44SJohn Forte 		bytes_received = isns_rcv_pdu(connecting_so, &in_pdu,
3036fcf3ce44SJohn Forte 		    &in_pdu_size);
3037fcf3ce44SJohn Forte 		if (in_pdu == NULL) {
3038fcf3ce44SJohn Forte 			continue;
3039fcf3ce44SJohn Forte 		}
3040fcf3ce44SJohn Forte 		if (bytes_received == 0) {
3041fcf3ce44SJohn Forte 			continue;
3042fcf3ce44SJohn Forte 		}
3043fcf3ce44SJohn Forte 
3044fcf3ce44SJohn Forte 		switch (in_pdu->func_id) {
3045fcf3ce44SJohn Forte 		case ISNS_ESI:
3046fcf3ce44SJohn Forte 		case ISNS_SCN:
3047fcf3ce44SJohn Forte 			if (in_pdu->func_id == ISNS_ESI) {
3048fcf3ce44SJohn Forte 				rval = isns_process_esi(in_pdu);
3049fcf3ce44SJohn Forte 				out_pdu_size = isns_create_esi_rsp_pdu(
3050fcf3ce44SJohn Forte 				    rval,
3051fcf3ce44SJohn Forte 				    in_pdu,
3052fcf3ce44SJohn Forte 				    &xid,
3053fcf3ce44SJohn Forte 				    &out_pdu);
3054fcf3ce44SJohn Forte 			} else if (in_pdu->func_id == ISNS_SCN) {
3055fcf3ce44SJohn Forte 				rval = isns_process_scn(in_pdu,
3056fcf3ce44SJohn Forte 				    lhba_handle);
3057fcf3ce44SJohn Forte 				out_pdu_size = isns_create_scn_rsp_pdu(
3058fcf3ce44SJohn Forte 				    rval,
3059fcf3ce44SJohn Forte 				    in_pdu,
3060fcf3ce44SJohn Forte 				    &xid,
3061fcf3ce44SJohn Forte 				    &out_pdu);
3062fcf3ce44SJohn Forte 			} else {
3063fcf3ce44SJohn Forte 				/*
3064fcf3ce44SJohn Forte 				 * Ignore all traffics other than
3065fcf3ce44SJohn Forte 				 * ESI and SCN.
3066fcf3ce44SJohn Forte 				 */
3067fcf3ce44SJohn Forte 				kmem_free(in_pdu, in_pdu_size);
3068fcf3ce44SJohn Forte 				in_pdu = NULL;
3069fcf3ce44SJohn Forte 				continue;
3070fcf3ce44SJohn Forte 			}
3071fcf3ce44SJohn Forte 
3072fcf3ce44SJohn Forte 			if (out_pdu_size == 0) {
3073fcf3ce44SJohn Forte 				kmem_free(in_pdu, in_pdu_size);
3074fcf3ce44SJohn Forte 				in_pdu = NULL;
3075fcf3ce44SJohn Forte 				continue;
3076fcf3ce44SJohn Forte 			}
3077fcf3ce44SJohn Forte 
3078fcf3ce44SJohn Forte 			(void) isns_send_pdu(connecting_so, out_pdu);
3079fcf3ce44SJohn Forte 
3080fcf3ce44SJohn Forte 			kmem_free(out_pdu, out_pdu_size);
3081fcf3ce44SJohn Forte 			out_pdu = NULL;
3082fcf3ce44SJohn Forte 			kmem_free(in_pdu, in_pdu_size);
3083fcf3ce44SJohn Forte 			in_pdu = NULL;
3084fcf3ce44SJohn Forte 
3085fcf3ce44SJohn Forte 			iscsi_net->close(connecting_so);
3086fcf3ce44SJohn Forte 			break;
3087fcf3ce44SJohn Forte 
3088fcf3ce44SJohn Forte 		default:
3089fcf3ce44SJohn Forte 			kmem_free(in_pdu, in_pdu_size);
3090fcf3ce44SJohn Forte 			in_pdu = NULL;
3091fcf3ce44SJohn Forte 			continue;
3092fcf3ce44SJohn Forte 		}
3093fcf3ce44SJohn Forte 	}
3094fcf3ce44SJohn Forte }
3095fcf3ce44SJohn Forte 
30966362598eSbing zhao - Sun Microsystems - Beijing China static
30976362598eSbing zhao - Sun Microsystems - Beijing China boolean_t
find_listening_addr(iscsi_addr_t * local_addr,void * listening_so)30986362598eSbing zhao - Sun Microsystems - Beijing China find_listening_addr(iscsi_addr_t *local_addr, void *listening_so)
30996362598eSbing zhao - Sun Microsystems - Beijing China {
31006362598eSbing zhao - Sun Microsystems - Beijing China 	union {
31016362598eSbing zhao - Sun Microsystems - Beijing China 		struct sockaddr_in	soa4;
31026362598eSbing zhao - Sun Microsystems - Beijing China 		struct sockaddr_in6	soa6;
31036362598eSbing zhao - Sun Microsystems - Beijing China 	} local_conn_prop = { 0 };
31046362598eSbing zhao - Sun Microsystems - Beijing China 
31056362598eSbing zhao - Sun Microsystems - Beijing China 	struct sockaddr_in6	t_addr;
31066362598eSbing zhao - Sun Microsystems - Beijing China 	socklen_t		t_addrlen;
31076362598eSbing zhao - Sun Microsystems - Beijing China 
31086362598eSbing zhao - Sun Microsystems - Beijing China 	if (local_addr == NULL || listening_so == NULL) {
31096362598eSbing zhao - Sun Microsystems - Beijing China 		return (B_FALSE);
31106362598eSbing zhao - Sun Microsystems - Beijing China 	}
31116362598eSbing zhao - Sun Microsystems - Beijing China 
31126362598eSbing zhao - Sun Microsystems - Beijing China 	bzero(&t_addr, sizeof (struct sockaddr_in6));
31136362598eSbing zhao - Sun Microsystems - Beijing China 	t_addrlen = sizeof (struct sockaddr_in6);
31146362598eSbing zhao - Sun Microsystems - Beijing China 
31156362598eSbing zhao - Sun Microsystems - Beijing China 	(void) iscsi_net->getsockname(listening_so, (struct sockaddr *)&t_addr,
31166362598eSbing zhao - Sun Microsystems - Beijing China 	    &t_addrlen);
31176362598eSbing zhao - Sun Microsystems - Beijing China 	if (t_addrlen > sizeof (local_conn_prop)) {
31186362598eSbing zhao - Sun Microsystems - Beijing China 		return (B_FALSE);
31196362598eSbing zhao - Sun Microsystems - Beijing China 	}
31206362598eSbing zhao - Sun Microsystems - Beijing China 	bcopy(&t_addr, &local_conn_prop, t_addrlen);
31216362598eSbing zhao - Sun Microsystems - Beijing China 	if (local_conn_prop.soa4.sin_family == AF_INET) {
31226362598eSbing zhao - Sun Microsystems - Beijing China 		local_addr->a_addr.i_addr.in4.s_addr =
31236362598eSbing zhao - Sun Microsystems - Beijing China 		    local_conn_prop.soa4.sin_addr.s_addr;
31246362598eSbing zhao - Sun Microsystems - Beijing China 		local_addr->a_addr.i_insize = sizeof (in_addr_t);
31256362598eSbing zhao - Sun Microsystems - Beijing China 	} else if (local_conn_prop.soa4.sin_family == AF_INET6) {
31266362598eSbing zhao - Sun Microsystems - Beijing China 		/* Currently, IPv6 is not supported */
31276362598eSbing zhao - Sun Microsystems - Beijing China 		return (B_FALSE);
31286362598eSbing zhao - Sun Microsystems - Beijing China 	} else {
31296362598eSbing zhao - Sun Microsystems - Beijing China 		return (B_FALSE);
31306362598eSbing zhao - Sun Microsystems - Beijing China 	}
31316362598eSbing zhao - Sun Microsystems - Beijing China 
31326362598eSbing zhao - Sun Microsystems - Beijing China 	local_addr->a_port = ntohs(local_conn_prop.soa4.sin_port);
31336362598eSbing zhao - Sun Microsystems - Beijing China 
31346362598eSbing zhao - Sun Microsystems - Beijing China 	return (B_TRUE);
31356362598eSbing zhao - Sun Microsystems - Beijing China }
31366362598eSbing zhao - Sun Microsystems - Beijing China 
3137fcf3ce44SJohn Forte static
3138fcf3ce44SJohn Forte boolean_t
find_local_portal(iscsi_addr_t * isns_server_addr,iscsi_addr_t ** local_addr,void ** listening_so)3139fcf3ce44SJohn Forte find_local_portal(iscsi_addr_t *isns_server_addr,
3140fcf3ce44SJohn Forte     iscsi_addr_t **local_addr, void **listening_so)
3141fcf3ce44SJohn Forte {
3142fcf3ce44SJohn Forte 	union {
3143fcf3ce44SJohn Forte 		struct sockaddr_in	soa4;
3144fcf3ce44SJohn Forte 		struct sockaddr_in6	soa6;
3145fcf3ce44SJohn Forte 	} local_conn_prop = { 0 };
3146fcf3ce44SJohn Forte 	union {
3147fcf3ce44SJohn Forte 		struct sockaddr sin;
3148fcf3ce44SJohn Forte 		struct sockaddr_in s_in4;
3149fcf3ce44SJohn Forte 		struct sockaddr_in6 s_in6;
3150fcf3ce44SJohn Forte 	} serv_addr = { 0 };
3151fcf3ce44SJohn Forte 	void *so;
31520f1702c5SYu Xiangning 	struct sockaddr_in6	t_addr;
31530f1702c5SYu Xiangning 	socklen_t		t_addrlen;
3154fcf3ce44SJohn Forte 
31556362598eSbing zhao - Sun Microsystems - Beijing China 	if (listening_so == NULL) {
31566362598eSbing zhao - Sun Microsystems - Beijing China 		return (B_FALSE);
31576362598eSbing zhao - Sun Microsystems - Beijing China 	}
31586362598eSbing zhao - Sun Microsystems - Beijing China 
31596362598eSbing zhao - Sun Microsystems - Beijing China 	if (local_addr != NULL) {
31606362598eSbing zhao - Sun Microsystems - Beijing China 		*local_addr = NULL;
31616362598eSbing zhao - Sun Microsystems - Beijing China 	}
3162fcf3ce44SJohn Forte 
31636362598eSbing zhao - Sun Microsystems - Beijing China 	*listening_so = NULL;
31640f1702c5SYu Xiangning 	bzero(&t_addr, sizeof (struct sockaddr_in6));
31650f1702c5SYu Xiangning 	t_addrlen = sizeof (struct sockaddr_in6);
31666362598eSbing zhao - Sun Microsystems - Beijing China 
3167fcf3ce44SJohn Forte 	/*
3168fcf3ce44SJohn Forte 	 * Determine the local IP address.
3169fcf3ce44SJohn Forte 	 */
31706362598eSbing zhao - Sun Microsystems - Beijing China 	if (local_addr != NULL) {
31716362598eSbing zhao - Sun Microsystems - Beijing China 		so = isns_open(isns_server_addr);
31726362598eSbing zhao - Sun Microsystems - Beijing China 		if (so == NULL) {
31736362598eSbing zhao - Sun Microsystems - Beijing China 			return (B_FALSE);
31746362598eSbing zhao - Sun Microsystems - Beijing China 		}
3175fcf3ce44SJohn Forte 
31766362598eSbing zhao - Sun Microsystems - Beijing China 		iscsi_net->getsockname(so,
31776362598eSbing zhao - Sun Microsystems - Beijing China 		    (struct sockaddr *)&t_addr, &t_addrlen);
31786362598eSbing zhao - Sun Microsystems - Beijing China 		if (t_addrlen > sizeof (local_conn_prop)) {
31796362598eSbing zhao - Sun Microsystems - Beijing China 			iscsi_net->close(so);
31806362598eSbing zhao - Sun Microsystems - Beijing China 			return (B_FALSE);
31816362598eSbing zhao - Sun Microsystems - Beijing China 		}
31826362598eSbing zhao - Sun Microsystems - Beijing China 
31836362598eSbing zhao - Sun Microsystems - Beijing China 		bcopy(&t_addr, &local_conn_prop, t_addrlen);
31846362598eSbing zhao - Sun Microsystems - Beijing China 		t_addrlen = sizeof (struct sockaddr_in6);
31856362598eSbing zhao - Sun Microsystems - Beijing China 		if (local_conn_prop.soa4.sin_family == AF_INET) {
31866362598eSbing zhao - Sun Microsystems - Beijing China 			*local_addr =
31876362598eSbing zhao - Sun Microsystems - Beijing China 			    (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t),
31886362598eSbing zhao - Sun Microsystems - Beijing China 			    KM_SLEEP);
31896362598eSbing zhao - Sun Microsystems - Beijing China 			(*local_addr)->a_addr.i_addr.in4.s_addr =
31906362598eSbing zhao - Sun Microsystems - Beijing China 			    local_conn_prop.soa4.sin_addr.s_addr;
31916362598eSbing zhao - Sun Microsystems - Beijing China 			(*local_addr)->a_addr.i_insize = sizeof (in_addr_t);
31926362598eSbing zhao - Sun Microsystems - Beijing China 		} else if (local_conn_prop.soa4.sin_family == AF_INET6) {
31936362598eSbing zhao - Sun Microsystems - Beijing China 			/* Currently, IPv6 is not supported */
31946362598eSbing zhao - Sun Microsystems - Beijing China 			return (B_FALSE);
31956362598eSbing zhao - Sun Microsystems - Beijing China 		} else {
31966362598eSbing zhao - Sun Microsystems - Beijing China 			iscsi_net->close(so);
31976362598eSbing zhao - Sun Microsystems - Beijing China 			return (B_FALSE);
31986362598eSbing zhao - Sun Microsystems - Beijing China 		}
3199fcf3ce44SJohn Forte 
3200fcf3ce44SJohn Forte 		iscsi_net->close(so);
3201fcf3ce44SJohn Forte 	}
3202fcf3ce44SJohn Forte 	/*
3203fcf3ce44SJohn Forte 	 * Determine the local IP address. (End)
3204fcf3ce44SJohn Forte 	 */
3205fcf3ce44SJohn Forte 
3206fcf3ce44SJohn Forte 	serv_addr.s_in4.sin_family = AF_INET;
3207fcf3ce44SJohn Forte 	/*
3208fcf3ce44SJohn Forte 	 * Use INADDR_ANY to accept connections from any of the connected
3209fcf3ce44SJohn Forte 	 * networks.
3210fcf3ce44SJohn Forte 	 */
3211fcf3ce44SJohn Forte 	serv_addr.s_in4.sin_addr.s_addr = htonl(INADDR_ANY);
3212fcf3ce44SJohn Forte 	/*
3213fcf3ce44SJohn Forte 	 * Use port number 0 to allow the system to assign a unique unused
3214fcf3ce44SJohn Forte 	 * port.
3215fcf3ce44SJohn Forte 	 */
3216fcf3ce44SJohn Forte 	serv_addr.s_in4.sin_port = htons(0);
3217fcf3ce44SJohn Forte 
3218fcf3ce44SJohn Forte 	so = iscsi_net->socket(AF_INET, SOCK_STREAM, 0);
3219fcf3ce44SJohn Forte 	if (so == NULL) {
32206362598eSbing zhao - Sun Microsystems - Beijing China 		if (local_addr != NULL && (*local_addr != NULL)) {
32216362598eSbing zhao - Sun Microsystems - Beijing China 			kmem_free((*local_addr), sizeof (iscsi_addr_t));
32226362598eSbing zhao - Sun Microsystems - Beijing China 			*local_addr = NULL;
32236362598eSbing zhao - Sun Microsystems - Beijing China 		}
3224fcf3ce44SJohn Forte 		return (B_FALSE);
3225fcf3ce44SJohn Forte 	}
3226fcf3ce44SJohn Forte 
3227fcf3ce44SJohn Forte 	if (iscsi_net->bind(so, &serv_addr.sin,
3228fcf3ce44SJohn Forte 		sizeof (struct sockaddr), 0, 0) < 0) {
32296362598eSbing zhao - Sun Microsystems - Beijing China 		if (local_addr != NULL && (*local_addr != NULL)) {
32306362598eSbing zhao - Sun Microsystems - Beijing China 			kmem_free((*local_addr), sizeof (iscsi_addr_t));
32316362598eSbing zhao - Sun Microsystems - Beijing China 			*local_addr = NULL;
32326362598eSbing zhao - Sun Microsystems - Beijing China 		}
3233fcf3ce44SJohn Forte 		iscsi_net->close(so);
3234fcf3ce44SJohn Forte 		return (B_FALSE);
3235fcf3ce44SJohn Forte 	}
3236fcf3ce44SJohn Forte 
32376362598eSbing zhao - Sun Microsystems - Beijing China 	if (local_addr != NULL && (*local_addr != NULL)) {
32386362598eSbing zhao - Sun Microsystems - Beijing China 		(void) iscsi_net->getsockname(so, (struct sockaddr *)&t_addr,
32396362598eSbing zhao - Sun Microsystems - Beijing China 		    &t_addrlen);
32406362598eSbing zhao - Sun Microsystems - Beijing China 		if (t_addrlen <= sizeof (local_conn_prop)) {
32416362598eSbing zhao - Sun Microsystems - Beijing China 			bcopy(&t_addr, &local_conn_prop, t_addrlen);
32426362598eSbing zhao - Sun Microsystems - Beijing China 			(*local_addr)->a_port =
32436362598eSbing zhao - Sun Microsystems - Beijing China 			    ntohs(local_conn_prop.soa4.sin_port);
32446362598eSbing zhao - Sun Microsystems - Beijing China 		} else {
32456362598eSbing zhao - Sun Microsystems - Beijing China 			(*local_addr)->a_port = ISNS_DEFAULT_ESI_SCN_PORT;
32466362598eSbing zhao - Sun Microsystems - Beijing China 		}
3247fcf3ce44SJohn Forte 	}
3248fcf3ce44SJohn Forte 
3249fcf3ce44SJohn Forte 	*listening_so = so;
3250fcf3ce44SJohn Forte 
3251fcf3ce44SJohn Forte 	return (B_TRUE);
3252fcf3ce44SJohn Forte }
3253fcf3ce44SJohn Forte 
3254fcf3ce44SJohn Forte /* ARGSUSED */
3255fcf3ce44SJohn Forte static
3256fcf3ce44SJohn Forte void
scn_callback_lookup(uint8_t * lhba_handle)3257fcf3ce44SJohn Forte (*scn_callback_lookup(uint8_t *lhba_handle))(void *)
3258fcf3ce44SJohn Forte {
3259fcf3ce44SJohn Forte 	/*
3260fcf3ce44SJohn Forte 	 * When we support multiple HBA instance we will use lhba_handle
3261fcf3ce44SJohn Forte 	 * to look up the associated SCN callback. For now, we only support
3262fcf3ce44SJohn Forte 	 * one HBA instance therefore we always return the same SCN callback.
3263fcf3ce44SJohn Forte 	 */
3264fcf3ce44SJohn Forte 	return (scn_callback_p);
3265fcf3ce44SJohn Forte }
3266fcf3ce44SJohn Forte 
3267fcf3ce44SJohn Forte static
3268fcf3ce44SJohn Forte uint16_t
create_xid()3269fcf3ce44SJohn Forte create_xid()
3270fcf3ce44SJohn Forte {
3271fcf3ce44SJohn Forte 	return (xid++ % MAX_XID);
3272fcf3ce44SJohn Forte }
3273fcf3ce44SJohn Forte 
3274fcf3ce44SJohn Forte static
3275fcf3ce44SJohn Forte void
esi_scn_thr_cleanup()3276fcf3ce44SJohn Forte esi_scn_thr_cleanup()
3277fcf3ce44SJohn Forte {
32786362598eSbing zhao - Sun Microsystems - Beijing China 	boolean_t	unblock_esi_scn_thr_b		= B_FALSE;
32796362598eSbing zhao - Sun Microsystems - Beijing China 	iscsi_addr_t	local_addr;
3280fcf3ce44SJohn Forte 
3281fcf3ce44SJohn Forte 	mutex_enter(&esi_scn_thr_mutex);
32826362598eSbing zhao - Sun Microsystems - Beijing China 	if (esi_scn_thr_to_shutdown == B_FALSE) {
3283fcf3ce44SJohn Forte 
3284fcf3ce44SJohn Forte 		/* Instruct the ESI/SCN to shut itself down. */
3285fcf3ce44SJohn Forte 		esi_scn_thr_to_shutdown = B_TRUE;
3286fcf3ce44SJohn Forte 		if (instance_listening_so != NULL &&
32876362598eSbing zhao - Sun Microsystems - Beijing China 		    (find_listening_addr(&local_addr,
32886362598eSbing zhao - Sun Microsystems - Beijing China 		    instance_listening_so) == B_TRUE)) {
3289fcf3ce44SJohn Forte 			isns_pdu_t *out_pdu;
3290fcf3ce44SJohn Forte 			size_t out_pdu_size;
3291fcf3ce44SJohn Forte 			void *connecting_so;
3292fcf3ce44SJohn Forte 
3293fcf3ce44SJohn Forte 			/*
3294fcf3ce44SJohn Forte 			 * Open a connection to the local address and send
3295fcf3ce44SJohn Forte 			 * a dummy header to unblock the accept call so that
3296fcf3ce44SJohn Forte 			 * the ESI/SCN thread has a chance to terminate
3297fcf3ce44SJohn Forte 			 * itself.
3298fcf3ce44SJohn Forte 			 */
32996362598eSbing zhao - Sun Microsystems - Beijing China 			connecting_so = isns_open(&local_addr);
3300fcf3ce44SJohn Forte 			if (connecting_so == NULL) {
3301fcf3ce44SJohn Forte 				unblock_esi_scn_thr_b = B_FALSE;
33026362598eSbing zhao - Sun Microsystems - Beijing China 				esi_scn_thr_to_shutdown = B_FALSE;
3303fcf3ce44SJohn Forte 			} else {
3304fcf3ce44SJohn Forte 				out_pdu_size = isns_create_pdu_header(0,
3305fcf3ce44SJohn Forte 				    ISNS_FLAG_FIRST_PDU |
3306fcf3ce44SJohn Forte 				    ISNS_FLAG_LAST_PDU,
3307fcf3ce44SJohn Forte 				    &out_pdu);
3308fcf3ce44SJohn Forte 				if (isns_send_pdu(connecting_so,
3309fcf3ce44SJohn Forte 				    out_pdu) != 0) {
3310fcf3ce44SJohn Forte 					unblock_esi_scn_thr_b = B_FALSE;
33116362598eSbing zhao - Sun Microsystems - Beijing China 					esi_scn_thr_to_shutdown = B_FALSE;
3312fcf3ce44SJohn Forte 				} else {
3313fcf3ce44SJohn Forte 					unblock_esi_scn_thr_b = B_TRUE;
3314fcf3ce44SJohn Forte 				}
3315fcf3ce44SJohn Forte 				iscsi_net->close(connecting_so);
3316fcf3ce44SJohn Forte 				kmem_free(out_pdu, out_pdu_size);
3317fcf3ce44SJohn Forte 				out_pdu = NULL;
3318fcf3ce44SJohn Forte 			}
3319fcf3ce44SJohn Forte 		}
3320fcf3ce44SJohn Forte 
3321fcf3ce44SJohn Forte 		if (unblock_esi_scn_thr_b == B_TRUE) {
33226362598eSbing zhao - Sun Microsystems - Beijing China 			mutex_exit(&esi_scn_thr_mutex);
33236362598eSbing zhao - Sun Microsystems - Beijing China 			(void) iscsi_thread_stop(esi_scn_thr_id);
33246362598eSbing zhao - Sun Microsystems - Beijing China 			iscsi_thread_destroy(esi_scn_thr_id);
33256362598eSbing zhao - Sun Microsystems - Beijing China 			mutex_enter(&esi_scn_thr_mutex);
33266362598eSbing zhao - Sun Microsystems - Beijing China 			esi_scn_thr_id = NULL;
3327fcf3ce44SJohn Forte 
33286362598eSbing zhao - Sun Microsystems - Beijing China 			/*
33296362598eSbing zhao - Sun Microsystems - Beijing China 			 * Shutdown and close the listening socket.
33306362598eSbing zhao - Sun Microsystems - Beijing China 			 */
33316362598eSbing zhao - Sun Microsystems - Beijing China 			iscsi_net->shutdown(instance_listening_so, 2);
33326362598eSbing zhao - Sun Microsystems - Beijing China 			iscsi_net->close(instance_listening_so);
33336362598eSbing zhao - Sun Microsystems - Beijing China 			instance_listening_so = NULL;
3334fcf3ce44SJohn Forte 		}
3335fcf3ce44SJohn Forte 	}
33366362598eSbing zhao - Sun Microsystems - Beijing China 	mutex_exit(&esi_scn_thr_mutex);
3337fcf3ce44SJohn Forte }
3338