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