xref: /illumos-gate/usr/src/uts/common/io/scsi/adapters/iscsi/persistent.c (revision 635216b673cf196ac523ff2a7ab715717e553292)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include "iscsi.h"
27 #include "nvfile.h"
28 #include "persistent.h"
29 #include <sys/scsi/adapters/iscsi_if.h>
30 #include <netinet/in.h>
31 
32 /*
33  * MAX_KEY_SIZE needs to be the same size of the ISCSI_MAX_NAME_LEN
34  * plus space for a ',' and a string form of tpgt (5 bytes).
35  */
36 #define	MAX_KEY_SIZE	(ISCSI_MAX_NAME_LEN + 5)
37 
38 /*
39  * Name identifiers for the various types of data
40  */
41 #define	DISCOVERY_METHOD_ID		"DiscMethod"
42 #define	NODE_NAME_ID			"NodeName"
43 #define	NODE_ALIAS_ID			"NodeAlias"
44 #define	STATIC_ADDR_ID			"StaticAddr"
45 #define	STATIC_ADDR2_ID			"StaticAddr2"
46 #define	DISCOVERY_ADDR_ID		"DiscAddr"
47 #define	ISNS_SERVER_ADDR_ID		"ISNSAddr"
48 #define	LOGIN_PARAMS_ID			"Login"
49 #define	CHAP_PARAMS_ID			"Chap"
50 #define	RADIUS_PARAMS_ID		"Radius"
51 #define	BIDIR_AUTH_PARAMS_ID		"BidirAuth"
52 #define	SESSION_PARAMS_ID		"Session"
53 #define	TUNABLE_PARAMS_ID		"Tunable"
54 
55 /*
56  *  Local Global Variables
57  */
58 static kmutex_t		static_addr_data_lock;
59 static kmutex_t		disc_addr_data_lock;
60 static kmutex_t		isns_addr_data_lock;
61 static kmutex_t		param_data_lock;
62 static kmutex_t		chap_data_lock;
63 static kmutex_t		auth_data_lock;
64 static kmutex_t		tunable_data_lock;
65 /*
66  *  Local Function Prototypes
67  */
68 static boolean_t persistent_disc_meth_common(iSCSIDiscoveryMethod_t method,
69 		    boolean_t do_clear);
70 static void persistent_static_addr_upgrade_to_v2();
71 
72 /*
73  * persistent_init_disc_addr_oids - Oid is stored with discovery address
74  * however oids are not persisted and the discovery address oids need to
75  * be regenerated during initialization.
76  */
77 static void persistent_init_disc_addr_oids()
78 {
79 	uint32_t addr_count = 0;
80 	void *void_p = NULL;
81 	entry_t	e;
82 	uint32_t i, curr_count;
83 
84 	/*
85 	 * Using two loops here as as addresses are updated and readded we get
86 	 * into an infinite loop while doing persistent_disc_addr_next if we
87 	 * update the entry as we go.  The first loop will get the number of
88 	 * addresses that need to be updated and the second will update that
89 	 * many addresses.
90 	 */
91 	persistent_disc_addr_lock();
92 	while (persistent_disc_addr_next(&void_p, &e) == B_TRUE) {
93 		addr_count++;
94 	}
95 	persistent_disc_addr_unlock();
96 
97 	for (i = 0; i < addr_count; i++) {
98 		curr_count = 0;
99 
100 		void_p = NULL;
101 		persistent_disc_addr_lock();
102 
103 		/* Use curr_count to skip previously updated addresses */
104 		while (persistent_disc_addr_next(&void_p, &e) ==
105 		    B_TRUE && i < curr_count) {
106 			curr_count++;
107 		}
108 		persistent_disc_addr_unlock();
109 
110 		mutex_enter(&iscsi_oid_mutex);
111 		e.e_oid = iscsi_oid++;
112 		mutex_exit(&iscsi_oid_mutex);
113 
114 		if (persistent_disc_addr_set(&e) == B_FALSE) {
115 			break;
116 		}
117 	}
118 }
119 
120 /*
121  * persistent_init_static_addr_oids - Oid is stored with static address
122  * however oids are not persisted and the static address oids need to
123  * be regenerated during initialization.
124  */
125 static void persistent_init_static_addr_oids()
126 {
127 	uint32_t addr_count = 0;
128 	void *void_p = NULL;
129 	entry_t	e;
130 	uint32_t i, curr_count;
131 	char	*target_name;
132 
133 	/*
134 	 * Solaris 10 Update 1/2 initially had a database
135 	 * that didn't support the multiple static-config
136 	 * entries to the same target.  The below call
137 	 * will check if the database is still of that
138 	 * old structure and upgrade it.  It will leave
139 	 * the old records incase a down grade of the
140 	 * software is required.
141 	 */
142 	persistent_static_addr_upgrade_to_v2();
143 
144 	/*
145 	 * Using two loops here as as addresses are updated and readded we get
146 	 * into an infinite loop while doing persistent_disc_addr_next if we
147 	 * update the entry as we go.  The first loop will get the number of
148 	 * addresses that need to be updated and the second will update that
149 	 * many addresses.
150 	 */
151 	target_name = kmem_alloc(MAX_KEY_SIZE, KM_SLEEP);
152 	persistent_static_addr_lock();
153 	while (persistent_static_addr_next(&void_p, target_name, &e) ==
154 	    B_TRUE) {
155 		addr_count++;
156 	}
157 
158 	for (i = 0; i < addr_count; i++) {
159 		curr_count = 0;
160 
161 		void_p = NULL;
162 
163 		/* Use curr_count to skip previously updated addresses */
164 		while ((persistent_static_addr_next(
165 		    &void_p, target_name, &e) == B_TRUE) &&
166 		    (i < curr_count)) {
167 			curr_count++;
168 		}
169 
170 		/* Skip the target whose address size length is 0 */
171 		if (e.e_insize == 0) {
172 			continue;
173 		}
174 
175 		mutex_enter(&iscsi_oid_mutex);
176 		e.e_oid = iscsi_oid++;
177 		mutex_exit(&iscsi_oid_mutex);
178 
179 		if (persistent_static_addr_set(target_name, &e) == B_FALSE) {
180 			break;
181 		}
182 	}
183 	persistent_static_addr_unlock();
184 	kmem_free(target_name, MAX_KEY_SIZE);
185 }
186 
187 /*
188  * persistent_static_addr_upgrade_to_v2 - checks to see if the
189  * STATIC_ADDR2_ID exists in the persistent store tree.  If not
190  * found then it converts the STATIC_ADDR_ID data into the
191  * STATIC_ADDR2_ID format and saves the branch.
192  */
193 static void
194 persistent_static_addr_upgrade_to_v2()
195 {
196 	entry_t	    e;
197 	char	    *target_name;
198 	char	    *c_end;
199 	void	    *void_p = NULL;
200 
201 	/*
202 	 * Check is version 2 of STATIC_ADDR list exists.
203 	 */
204 	target_name = kmem_zalloc(MAX_KEY_SIZE, KM_SLEEP);
205 	persistent_static_addr_lock();
206 	if (nvf_list_check(STATIC_ADDR2_ID) == B_FALSE) {
207 		/*
208 		 * We need to upgrade any existing
209 		 * STATIC_ADDR data to version 2.  Loop
210 		 * thru all old entries and set new version
211 		 * values.
212 		 */
213 		while (nvf_data_next(STATIC_ADDR_ID, &void_p,
214 		    target_name, (void *)&e, sizeof (e)) == B_TRUE) {
215 			/* Convert STATIC_ADDR to STATIC_ADDR2 */
216 			c_end = strchr(target_name, ',');
217 			if (c_end == NULL) {
218 				continue;
219 			}
220 			*c_end = '\0';
221 			/* Skip the target whose address size length is 0 */
222 			if (e.e_insize == 0) {
223 				continue;
224 			}
225 			/* Add updated record */
226 			(void) persistent_static_addr_set(target_name, &e);
227 		}
228 	}
229 	persistent_static_addr_unlock();
230 	kmem_free(target_name, MAX_KEY_SIZE);
231 }
232 
233 /*
234  * persistent_init -- initialize use of the persistent store
235  */
236 void
237 persistent_init()
238 {
239 	nvf_init();
240 	mutex_init(&static_addr_data_lock, NULL, MUTEX_DRIVER, NULL);
241 	mutex_init(&disc_addr_data_lock, NULL, MUTEX_DRIVER, NULL);
242 	mutex_init(&isns_addr_data_lock, NULL, MUTEX_DRIVER, NULL);
243 	mutex_init(&param_data_lock, NULL, MUTEX_DRIVER, NULL);
244 	mutex_init(&chap_data_lock, NULL, MUTEX_DRIVER, NULL);
245 	mutex_init(&auth_data_lock, NULL, MUTEX_DRIVER, NULL);
246 	mutex_init(&tunable_data_lock, NULL, MUTEX_DRIVER, NULL);
247 }
248 
249 /*
250  * persistent_load -- load the persistent store
251  */
252 boolean_t
253 persistent_load()
254 {
255 	boolean_t	rval = B_FALSE;
256 
257 	rval = nvf_load();
258 	if (rval == B_TRUE) {
259 		persistent_init_disc_addr_oids();
260 		persistent_init_static_addr_oids();
261 	}
262 
263 	return (rval);
264 }
265 
266 /*
267  * persistent_fini --  finish using the persistent store
268  */
269 void
270 persistent_fini(void)
271 {
272 	nvf_fini();
273 
274 	mutex_destroy(&static_addr_data_lock);
275 	mutex_destroy(&disc_addr_data_lock);
276 	mutex_destroy(&param_data_lock);
277 	mutex_destroy(&chap_data_lock);
278 	mutex_destroy(&auth_data_lock);
279 	mutex_destroy(&tunable_data_lock);
280 }
281 
282 
283 /*
284  * +--------------------------------------------------------------------+
285  * | Discovery Method Interfaces                                        |
286  * +--------------------------------------------------------------------+
287  */
288 
289 /*
290  * persistent_disc_meth_set -- enable a specific discovery method
291  */
292 boolean_t
293 persistent_disc_meth_set(iSCSIDiscoveryMethod_t method)
294 {
295 	return (persistent_disc_meth_common(method, B_FALSE));
296 }
297 
298 /*
299  * persistent_disc_meth_get -- return the status of all discovery methods as
300  * found in the persistent store
301  */
302 iSCSIDiscoveryMethod_t
303 persistent_disc_meth_get(void)
304 {
305 	boolean_t		rval;
306 	iSCSIDiscoveryMethod_t	methods;
307 
308 	rval = nvf_node_value_get(DISCOVERY_METHOD_ID, (uint32_t *)&methods);
309 	if (rval == B_FALSE) {
310 		methods = iSCSIDiscoveryMethodUnknown;
311 	}
312 
313 	return (methods);
314 }
315 
316 /*
317  * persistent_disc_meth_clear -- disable a specific discovery method
318  */
319 boolean_t
320 persistent_disc_meth_clear(iSCSIDiscoveryMethod_t method)
321 {
322 	return (persistent_disc_meth_common(method, B_TRUE));
323 }
324 
325 
326 
327 /*
328  * persistent_disc_meth_common - common function used to set or clear the
329  * status of a discovery method in the persistent store.
330  */
331 static boolean_t
332 persistent_disc_meth_common(iSCSIDiscoveryMethod_t method, boolean_t do_clear)
333 {
334 	boolean_t		rval;
335 	iSCSIDiscoveryMethod_t	discovery_types = iSCSIDiscoveryMethodUnknown;
336 
337 	(void) nvf_node_value_get(DISCOVERY_METHOD_ID,
338 	    (uint32_t *)&discovery_types);
339 	if (do_clear) {
340 		discovery_types &= ~method;
341 	} else {
342 		discovery_types |= method;
343 	}
344 
345 	rval = nvf_node_value_set(DISCOVERY_METHOD_ID, discovery_types);
346 
347 	return (rval);
348 }
349 
350 
351 
352 /*
353  * +--------------------------------------------------------------------+
354  * | Node/Initiator Name Interfaces                                     |
355  * +--------------------------------------------------------------------+
356  */
357 
358 /*
359  * persistent_initiator_name_set -- sets the node's initiator name
360  */
361 boolean_t
362 persistent_initiator_name_set(char *p)
363 {
364 	return (nvf_node_name_set(NODE_NAME_ID, p));
365 }
366 
367 /*
368  * persistent_initiator_name_get -- returns the node's initiator name
369  */
370 boolean_t
371 persistent_initiator_name_get(char *p, int size)
372 {
373 	return (nvf_node_name_get(NODE_NAME_ID, p, size));
374 }
375 
376 
377 /*
378  * +--------------------------------------------------------------------+
379  * | Node/Initiator Alias Interfaces                                    |
380  * +--------------------------------------------------------------------+
381  */
382 
383 /*
384  * persistent_alias_name_set -- sets the node's initiator name alias
385  */
386 boolean_t
387 persistent_alias_name_set(char *p)
388 {
389 	return (nvf_node_name_set(NODE_ALIAS_ID, p));
390 }
391 
392 /*
393  * persistent_initiator_name_get -- returns the node's initiator name alias
394  */
395 boolean_t
396 persistent_alias_name_get(char *p, int size)
397 {
398 	return (nvf_node_name_get(NODE_ALIAS_ID, p, size));
399 }
400 
401 
402 /*
403  * +--------------------------------------------------------------------+
404  * | Static Target Address Interfaces                                   |
405  * +--------------------------------------------------------------------+
406  */
407 
408 /*
409  * persistent_static_addr_set -- store hostname, IP address, and port
410  * information for a specific target.
411  */
412 boolean_t
413 persistent_static_addr_set(char *target_name, entry_t *e)
414 {
415 	boolean_t	rval;
416 	char		*key;
417 	char		*ip_str;
418 
419 	ASSERT(target_name != NULL);
420 	ASSERT(e != NULL);
421 	ASSERT(mutex_owned(&static_addr_data_lock));
422 
423 	key = kmem_zalloc(MAX_KEY_SIZE, KM_SLEEP);
424 	ip_str = kmem_zalloc(INET6_ADDRSTRLEN, KM_SLEEP);
425 	if (e->e_insize == sizeof (struct in_addr)) {
426 		(void) inet_ntop(AF_INET, &e->e_u.u_in4,
427 		    ip_str, INET6_ADDRSTRLEN);
428 	} else {
429 		(void) inet_ntop(AF_INET6, &e->e_u.u_in6,
430 		    ip_str, INET6_ADDRSTRLEN);
431 	}
432 
433 	if (snprintf(key, MAX_KEY_SIZE - 1, "%s,%s:%d,%d",
434 	    target_name, ip_str, e->e_port, e->e_tpgt) >= MAX_KEY_SIZE) {
435 		kmem_free(key, MAX_KEY_SIZE);
436 		kmem_free(ip_str, INET6_ADDRSTRLEN);
437 		return (B_FALSE);
438 	}
439 
440 	rval = nvf_data_set(STATIC_ADDR2_ID, key, (void *)e,
441 	    sizeof (entry_t));
442 
443 	kmem_free(key, MAX_KEY_SIZE);
444 	kmem_free(ip_str, INET6_ADDRSTRLEN);
445 	return (rval);
446 }
447 
448 /*
449  * persistent_static_addr_next -- get the next target's hostname, IP address,
450  * and port information.
451  *
452  * The first time this function is called, the argument (void **v)
453  * should be a pointer to a value of NULL which causes this function to obtain
454  * the first static target element.
455  *
456  * This function assumes the associated static address lock is held.
457  *
458  * Returns B_TRUE when data is valid. B_FALSE returned when data is
459  * not available (end of configured targets has been reached).
460  *
461  */
462 boolean_t
463 persistent_static_addr_next(void **v, char *target_name, entry_t *e)
464 {
465 	boolean_t   rval;
466 	char	    *c_end, *key;
467 
468 	ASSERT(v != NULL);
469 	ASSERT(target_name != NULL);
470 	ASSERT(e != NULL);
471 	ASSERT(mutex_owned(&static_addr_data_lock));
472 
473 	key = kmem_zalloc(MAX_KEY_SIZE, KM_SLEEP);
474 	rval = nvf_data_next(STATIC_ADDR2_ID, v, key,
475 	    (void *)e, sizeof (*e));
476 
477 	/* extract target_name */
478 	c_end = strchr(key, ',');
479 	if (c_end == NULL) {
480 		kmem_free(key, MAX_KEY_SIZE);
481 		return (B_FALSE);
482 	}
483 	*c_end = '\0';
484 	/* copy target name */
485 	(void) strcpy(target_name, key);
486 
487 	kmem_free(key, MAX_KEY_SIZE);
488 
489 	return (rval);
490 }
491 
492 /*
493  * persistent_static_addr_clear -- remove the next hostname, IP address, and
494  * port information for a specific target from the configured static targets.
495  */
496 boolean_t
497 persistent_static_addr_clear(uint32_t oid)
498 {
499 	boolean_t	rval = B_FALSE;
500 	void		*void_p = NULL;
501 	entry_t		e;
502 	char		*key;
503 	char		*target_name;
504 	char		*ip_str;
505 
506 	/* Find the entry based on oid then record the name and tpgt */
507 	target_name = kmem_zalloc(MAX_KEY_SIZE, KM_SLEEP);
508 	persistent_static_addr_lock();
509 	while (persistent_static_addr_next(
510 	    &void_p, target_name, &e) == B_TRUE) {
511 		if (e.e_oid == oid) {
512 			break;
513 		}
514 	}
515 
516 	/* If we found a match clear the entry */
517 	if (e.e_oid == oid) {
518 		ip_str = kmem_zalloc(INET6_ADDRSTRLEN, KM_SLEEP);
519 		key = kmem_zalloc(MAX_KEY_SIZE, KM_SLEEP);
520 		if (e.e_insize == sizeof (struct in_addr)) {
521 			(void) inet_ntop(AF_INET, &e.e_u.u_in4,
522 			    ip_str, INET6_ADDRSTRLEN);
523 		} else {
524 			(void) inet_ntop(AF_INET6, &e.e_u.u_in6,
525 			    ip_str, INET6_ADDRSTRLEN);
526 		}
527 
528 		if (snprintf(key, MAX_KEY_SIZE - 1, "%s,%s:%d,%d",
529 		    target_name, ip_str, e.e_port, e.e_tpgt) >= MAX_KEY_SIZE) {
530 			persistent_static_addr_unlock();
531 			kmem_free(key, MAX_KEY_SIZE);
532 			kmem_free(ip_str, INET6_ADDRSTRLEN);
533 			kmem_free(target_name, MAX_KEY_SIZE);
534 			return (B_FALSE);
535 		}
536 
537 		rval = nvf_data_clear(STATIC_ADDR2_ID, key);
538 		kmem_free(key, MAX_KEY_SIZE);
539 		kmem_free(ip_str, INET6_ADDRSTRLEN);
540 	}
541 	persistent_static_addr_unlock();
542 	kmem_free(target_name, MAX_KEY_SIZE);
543 
544 	return (rval);
545 }
546 
547 
548 /*
549  * persistent_static_addr_lock -- lock access to static targets.  This
550  * ensures static targets are unchanged while the lock is held.  The
551  * lock should be grabbed while walking through the static targets.
552  */
553 void
554 persistent_static_addr_lock(void)
555 {
556 	mutex_enter(&static_addr_data_lock);
557 }
558 
559 /*
560  * persistent_static_addr_unlock -- unlock access to the configured of static
561  * targets.
562  */
563 void
564 persistent_static_addr_unlock(void)
565 {
566 	mutex_exit(&static_addr_data_lock);
567 }
568 
569 
570 /*
571  * +--------------------------------------------------------------------+
572  * | ISNS Server Address Interfaces                                     |
573  * +--------------------------------------------------------------------+
574  */
575 
576 /*
577  * persistent_addr_set -- store entry address information
578  */
579 boolean_t
580 persistent_isns_addr_set(entry_t *e)
581 {
582 	char		name[INET6_ADDRSTRLEN];
583 	boolean_t	rval;
584 
585 	/*
586 	 * Create name from given discovery address - SendTargets discovery
587 	 * nodes do not have an associated node name. A name is manufactured
588 	 * from the IP address given.
589 	 */
590 	if (e->e_insize == sizeof (struct in_addr)) {
591 		(void) inet_ntop(AF_INET, &e->e_u.u_in4, name, sizeof (name));
592 	} else {
593 		(void) inet_ntop(AF_INET6, &e->e_u.u_in6, name, sizeof (name));
594 	}
595 
596 	mutex_enter(&isns_addr_data_lock);
597 	rval = nvf_data_set(ISNS_SERVER_ADDR_ID, name,
598 	    (void *)e, sizeof (entry_t));
599 	mutex_exit(&isns_addr_data_lock);
600 
601 	return (rval);
602 }
603 
604 /*
605  * persistent_disc_addr_next -- get the next iSCSI discovery node's address
606  * and port information.
607  *
608  * The first time this function is called, the argument (void **v)
609  * should be a pointer to a value of NULL which causes this function to obtain
610  * the first discovery address element.
611  *
612  * This function assumes the associated disccovery address lock is held.
613  *
614  * Returns B_TRUE when data is valid. B_FALSE returned when data is
615  * not available (end of configured discovery addresses has been reached).
616  *
617  */
618 boolean_t
619 persistent_isns_addr_next(void **v, entry_t *e)
620 {
621 	char		name[INET6_ADDRSTRLEN];
622 
623 	ASSERT(mutex_owned(&isns_addr_data_lock));
624 
625 	return (nvf_data_next(ISNS_SERVER_ADDR_ID, v, name,
626 	    (void *)e, sizeof (*e)));
627 }
628 
629 /*
630  * persistent_disc_addr_clear -- remove IP address and port information from
631  * the configured SendTargets discovery nodes.
632  */
633 boolean_t
634 persistent_isns_addr_clear(entry_t *e)
635 {
636 	char		name[INET6_ADDRSTRLEN];
637 	boolean_t	rval;
638 
639 	/*
640 	 * Create name from given discovery address - SendTargets discovery
641 	 * nodes do not have an associated node name. A name is manufactured
642 	 * from the IP address given.
643 	 */
644 	if (e->e_insize == sizeof (struct in_addr)) {
645 		(void) inet_ntop(AF_INET, &e->e_u.u_in4, name, sizeof (name));
646 	} else {
647 		(void) inet_ntop(AF_INET6, &e->e_u.u_in6, name, sizeof (name));
648 	}
649 
650 	mutex_enter(&static_addr_data_lock);
651 	rval = nvf_data_clear(ISNS_SERVER_ADDR_ID, name);
652 	mutex_exit(&static_addr_data_lock);
653 
654 	return (rval);
655 }
656 
657 
658 /*
659  * persistent_disc_addr_lock -- lock access to the SendTargets discovery
660  * addresses.  This ensures discovery addresses are unchanged while the lock
661  * is held.  The lock should be grabbed while walking through the discovery
662  * addresses
663  */
664 void
665 persistent_isns_addr_lock(void)
666 {
667 	mutex_enter(&isns_addr_data_lock);
668 }
669 
670 /*
671  * persistent_disc_addr_unlock -- unlock access to discovery addresses.
672  */
673 void
674 persistent_isns_addr_unlock(void)
675 {
676 	mutex_exit(&isns_addr_data_lock);
677 }
678 
679 /*
680  * +--------------------------------------------------------------------+
681  * | Discovery Address Interfaces                                       |
682  * +--------------------------------------------------------------------+
683  */
684 
685 /*
686  * persistent_disc_addr_set -- store IP address, and port information for
687  * for an iSCSI discovery node that provides target information via a
688  * SendTargets response.
689  */
690 boolean_t
691 persistent_disc_addr_set(entry_t *e)
692 {
693 	char		name[INET6_ADDRSTRLEN];
694 	boolean_t	rval;
695 
696 	/*
697 	 * Create name from given discovery address - SendTargets discovery
698 	 * nodes do not have an associated node name. A name is manufactured
699 	 * from the IP address given.
700 	 */
701 	if (e->e_insize == sizeof (struct in_addr)) {
702 		(void) inet_ntop(AF_INET, &e->e_u.u_in4, name, sizeof (name));
703 	} else {
704 		(void) inet_ntop(AF_INET6, &e->e_u.u_in6, name, sizeof (name));
705 	}
706 
707 	mutex_enter(&disc_addr_data_lock);
708 	rval = nvf_data_set(DISCOVERY_ADDR_ID, name,
709 	    (void *)e, sizeof (entry_t));
710 	mutex_exit(&disc_addr_data_lock);
711 
712 	return (rval);
713 }
714 
715 /*
716  * persistent_disc_addr_next -- get the next iSCSI discovery node's address
717  * and port information.
718  *
719  * The first time this function is called, the argument (void **v)
720  * should be a pointer to a value of NULL which causes this function to obtain
721  * the first discovery address element.
722  *
723  * This function assumes the associated disccovery address lock is held.
724  *
725  * Returns B_TRUE when data is valid. B_FALSE returned when data is
726  * not available (end of configured discovery addresses has been reached).
727  *
728  */
729 boolean_t
730 persistent_disc_addr_next(void **v, entry_t *e)
731 {
732 	char		name[INET6_ADDRSTRLEN];
733 
734 	ASSERT(mutex_owned(&disc_addr_data_lock));
735 
736 	return (nvf_data_next(DISCOVERY_ADDR_ID, v, name,
737 	    (void *)e, sizeof (*e)));
738 }
739 
740 /*
741  * persistent_disc_addr_clear -- remove IP address and port information from
742  * the configured SendTargets discovery nodes.
743  */
744 boolean_t
745 persistent_disc_addr_clear(entry_t *e)
746 {
747 	char		name[INET6_ADDRSTRLEN];
748 	boolean_t	rval;
749 
750 	/*
751 	 * Create name from given discovery address - SendTargets discovery
752 	 * nodes do not have an associated node name. A name is manufactured
753 	 * from the IP address given.
754 	 */
755 	if (e->e_insize == sizeof (struct in_addr)) {
756 		(void) inet_ntop(AF_INET, &e->e_u.u_in4, name, sizeof (name));
757 	} else {
758 		(void) inet_ntop(AF_INET6, &e->e_u.u_in6, name, sizeof (name));
759 	}
760 
761 	mutex_enter(&static_addr_data_lock);
762 	rval = nvf_data_clear(DISCOVERY_ADDR_ID, name);
763 	mutex_exit(&static_addr_data_lock);
764 
765 	return (rval);
766 }
767 
768 
769 /*
770  * persistent_disc_addr_lock -- lock access to the SendTargets discovery
771  * addresses.  This ensures discovery addresses are unchanged while the lock
772  * is held.  The lock should be grabbed while walking through the discovery
773  * addresses
774  */
775 void
776 persistent_disc_addr_lock(void)
777 {
778 	mutex_enter(&disc_addr_data_lock);
779 }
780 
781 /*
782  * persistent_disc_addr_unlock -- unlock access to discovery addresses.
783  */
784 void
785 persistent_disc_addr_unlock(void)
786 {
787 	mutex_exit(&disc_addr_data_lock);
788 }
789 
790 
791 /*
792  * +--------------------------------------------------------------------+
793  * | Login Parameter Interfaces                                         |
794  * +--------------------------------------------------------------------+
795  */
796 
797 /*
798  * persistent_param_set -- store login parameters for a specific target
799  */
800 boolean_t
801 persistent_param_set(char *node, persistent_param_t *param)
802 {
803 	boolean_t	rval;
804 
805 	mutex_enter(&param_data_lock);
806 	rval = nvf_data_set(LOGIN_PARAMS_ID, node,
807 	    (void *)param, sizeof (persistent_param_t));
808 	mutex_exit(&param_data_lock);
809 
810 	return (rval);
811 }
812 
813 /*
814  * persistent_param_get -- obtain login parameters for a specific target
815  */
816 boolean_t
817 persistent_param_get(char *node, persistent_param_t *param)
818 {
819 	return (nvf_data_get(LOGIN_PARAMS_ID, node,
820 	    (void *)param, sizeof (*param)));
821 }
822 
823 /*
824  * persistent_param_next -- get the next target's login parameters.
825  *
826  * The first time this function is called, the argument (void **v)
827  * should be a pointer to a value of NULL which causes this function to obtain
828  * the first target's login parameters.
829  *
830  * This function assumes the associated login parameter lock is held.
831  *
832  * Returns B_TRUE when data in *param is valid. B_FALSE returned when no
833  * more data is available (end of configured target login parameters).
834  */
835 boolean_t
836 persistent_param_next(void **v, char *node, persistent_param_t *param)
837 {
838 	ASSERT(mutex_owned(&param_data_lock));
839 
840 	return (nvf_data_next(LOGIN_PARAMS_ID, v, node,
841 	    (void *)param, sizeof (*param)));
842 }
843 
844 /*
845  * persistent_param_clear -- remove login parameters for a specific target
846  */
847 boolean_t
848 persistent_param_clear(char *node)
849 {
850 	boolean_t	rval1, rval2, rval3;
851 
852 	mutex_enter(&param_data_lock);
853 	rval1 = nvf_data_clear(LOGIN_PARAMS_ID, node);
854 	rval2 = nvf_data_clear(SESSION_PARAMS_ID, node);
855 	rval3 = nvf_data_clear(TUNABLE_PARAMS_ID, node);
856 	mutex_exit(&param_data_lock);
857 
858 	return (((rval1 == B_TRUE) || (rval2 == B_TRUE) || (rval3 == B_TRUE))
859 	    ? B_TRUE : B_FALSE);
860 }
861 
862 /*
863  * persistent_param_lock -- lock access to login parameters.  This
864  * ensures the login parameters will be unchanged while the lock is held.
865  * The lock should be grabbed while walking through the login parameters.
866  */
867 void
868 persistent_param_lock(void)
869 {
870 	mutex_enter(&param_data_lock);
871 }
872 
873 /*
874  * persistent_param_unlock -- unlock access to login parameters.
875  */
876 void
877 persistent_param_unlock(void)
878 {
879 	mutex_exit(&param_data_lock);
880 }
881 
882 /*
883  * +--------------------------------------------------------------------+
884  * | Session Config Interfaces                                          |
885  * +--------------------------------------------------------------------+
886  */
887 
888 
889 /*
890  * persistent_set_config_session -- store configured sessions
891  *					for a specific target
892  */
893 boolean_t
894 persistent_set_config_session(char *node, iscsi_config_sess_t *ics)
895 {
896 	boolean_t	rval;
897 	int		size;
898 
899 	/*
900 	 * Make ics_out match ics_in.  Since when someone gets
901 	 * this information the in value becomes the out.
902 	 */
903 	ics->ics_out = ics->ics_in;
904 
905 	/* calculate size */
906 	size = ISCSI_SESSION_CONFIG_SIZE(ics->ics_in);
907 
908 	mutex_enter(&param_data_lock);
909 	rval = nvf_data_set(SESSION_PARAMS_ID, node, (void *)ics, size);
910 	mutex_exit(&param_data_lock);
911 
912 	return (rval);
913 }
914 
915 /*
916  * persistent_get_config_session -- obtain configured sessions
917  *					for a specific target
918  */
919 boolean_t
920 persistent_get_config_session(char *node, iscsi_config_sess_t *ics)
921 {
922 	boolean_t	status;
923 	int		in;
924 	int		size;
925 
926 	ASSERT(ics->ics_in >= 1);
927 
928 	/* record caller buffer size */
929 	in = ics->ics_in;
930 
931 	/* Get base config_sess information */
932 	size = ISCSI_SESSION_CONFIG_SIZE(in);
933 	status = nvf_data_get(SESSION_PARAMS_ID, node,
934 	    (void *)ics, size);
935 
936 	/* reset the in size */
937 	ics->ics_in = in;
938 
939 	return (status);
940 }
941 
942 /*
943  * persistent_get_tunable_param -- obtain tunable parameters
944  *					for a specific target
945  */
946 boolean_t
947 persistent_get_tunable_param(char *node, persistent_tunable_param_t *tpsg)
948 {
949 	return (nvf_data_get(TUNABLE_PARAMS_ID, node,
950 	    (void *)tpsg, sizeof (persistent_tunable_param_t)));
951 }
952 
953 /*
954  * persistent_set_tunable_param -- store tunable parameters
955  *					for a specific target
956  */
957 boolean_t
958 persistent_set_tunable_param(char *node, persistent_tunable_param_t *tpss)
959 {
960 	boolean_t	rval;
961 	mutex_enter(&tunable_data_lock);
962 	rval = nvf_data_set(TUNABLE_PARAMS_ID, node,
963 	    (void *)tpss, sizeof (persistent_tunable_param_t));
964 	mutex_exit(&tunable_data_lock);
965 	return (rval);
966 }
967 
968 /*
969  * +--------------------------------------------------------------------+
970  * | CHAP Parameter Interfaces                                          |
971  * +--------------------------------------------------------------------+
972  */
973 
974 /*
975  * persistent_chap_set -- store CHAP parameters for a specific target
976  */
977 boolean_t
978 persistent_chap_set(char *node, iscsi_chap_props_t *chap)
979 {
980 	boolean_t	rval;
981 
982 	mutex_enter(&chap_data_lock);
983 	rval = nvf_data_set(CHAP_PARAMS_ID, node,
984 	    (void *)chap, sizeof (iscsi_chap_props_t));
985 	mutex_exit(&chap_data_lock);
986 
987 	return (rval);
988 }
989 
990 /*
991  * persistent_chap_get -- obtain CHAP parameters for a specific target
992  */
993 boolean_t
994 persistent_chap_get(char *node, iscsi_chap_props_t *chap)
995 {
996 	return (nvf_data_get(CHAP_PARAMS_ID, node,
997 	    (void *)chap, sizeof (*chap)));
998 }
999 
1000 /*
1001  * persistent_chap_next -- copy the next target's chap parameters.
1002  *
1003  * The first time this function is called, the argument (void **v)
1004  * should be a pointer to a value of NULL which causes this function to obtain
1005  * the first target's login parameters.
1006  *
1007  * This function assumes the associated chap parameter lock is held.
1008  *
1009  * Returns B_TRUE when data in *param is valid. B_FALSE returned when no
1010  * more data is available.
1011  */
1012 boolean_t
1013 persistent_chap_next(void **v, char *node, iscsi_chap_props_t *chap)
1014 {
1015 	ASSERT(mutex_owned(&chap_data_lock));
1016 
1017 	return (nvf_data_next(CHAP_PARAMS_ID, v, node,
1018 	    (void *)chap, sizeof (*chap)));
1019 }
1020 
1021 /*
1022  * persistent_chap_clear -- remove CHAP parameters for a specific target
1023  */
1024 boolean_t
1025 persistent_chap_clear(char *node)
1026 {
1027 	boolean_t	rval;
1028 
1029 	mutex_enter(&chap_data_lock);
1030 	rval = nvf_data_clear(CHAP_PARAMS_ID, node);
1031 	mutex_exit(&chap_data_lock);
1032 
1033 	return (rval);
1034 }
1035 
1036 /*
1037  * persistent_chap_lock -- lock access to chap parameters.  This
1038  * ensures the chap parameters will be unchanged while the lock is held.
1039  * The lock should be grabbed while walking through the chap parameters.
1040  */
1041 void
1042 persistent_chap_lock(void)
1043 {
1044 	mutex_enter(&chap_data_lock);
1045 }
1046 
1047 /*
1048  * persistent_chap_unlock -- unlock access to chap parameters.
1049  */
1050 void
1051 persistent_chap_unlock(void)
1052 {
1053 	mutex_exit(&chap_data_lock);
1054 }
1055 
1056 
1057 /*
1058  * +--------------------------------------------------------------------+
1059  * | RADIUS Configuration Interfaces                                    |
1060  * +--------------------------------------------------------------------+
1061  */
1062 
1063 /*
1064  * persistent_radius_set -- stores the RADIUS configuration info
1065  */
1066 boolean_t
1067 persistent_radius_set(iscsi_radius_props_t *radius)
1068 {
1069 	return (nvf_node_data_set(RADIUS_PARAMS_ID, (void *)radius,
1070 	    sizeof (iscsi_radius_props_t)));
1071 }
1072 
1073 /*
1074  * persistent_radius_get -- obtain the RADIUS configuration info
1075  */
1076 iscsi_nvfile_status_t
1077 persistent_radius_get(iscsi_radius_props_t *radius)
1078 {
1079 	return (nvf_node_data_get(RADIUS_PARAMS_ID,
1080 	    (void *)radius, sizeof (*radius)));
1081 }
1082 
1083 
1084 /*
1085  * +--------------------------------------------------------------------+
1086  * | Authentication Configuration Interface                             |
1087  * +--------------------------------------------------------------------+
1088  */
1089 
1090 /*
1091  * persistent_auth_set -- stores the bidirectional authentication settings
1092  * for a specific target
1093  */
1094 boolean_t
1095 persistent_auth_set(char *node, iscsi_auth_props_t *auth)
1096 {
1097 	boolean_t	rval;
1098 
1099 	mutex_enter(&auth_data_lock);
1100 	rval = nvf_data_set(BIDIR_AUTH_PARAMS_ID, node,
1101 	    (void *)auth, sizeof (iscsi_auth_props_t));
1102 	mutex_exit(&auth_data_lock);
1103 
1104 	return (rval);
1105 }
1106 
1107 /*
1108  * persistent_auth_get -- gets the bidirectional authentication settings
1109  * for a specific target
1110  */
1111 boolean_t
1112 persistent_auth_get(char *node, iscsi_auth_props_t *auth)
1113 {
1114 	return (nvf_data_get(BIDIR_AUTH_PARAMS_ID, node,
1115 	    (void *)auth, sizeof (*auth)));
1116 }
1117 
1118 /*
1119  * persistent_auth_next -- get the next target's bidirectional authentication
1120  * parameters.
1121  *
1122  * The first time this function is called, the argument (void **v)
1123  * should be a pointer to a value of NULL which causes this function to obtain
1124  * the first target's login parameters.
1125  *
1126  * This function assumes the associated bidirectional authentication lock is
1127  * held.
1128  *
1129  * Returns B_TRUE when data in *param is valid. B_FALSE returned when no
1130  * more data is available.
1131  */
1132 boolean_t
1133 persistent_auth_next(void **v,  char *node, iscsi_auth_props_t *auth)
1134 {
1135 	ASSERT(mutex_owned(&auth_data_lock));
1136 
1137 	return (nvf_data_next(BIDIR_AUTH_PARAMS_ID, v, node,
1138 	    (void *)auth, sizeof (*auth)));
1139 }
1140 
1141 /*
1142  * persistent_auth_clear -- remove bidirectional authentication parameters for
1143  * a specific target
1144  */
1145 boolean_t
1146 persistent_auth_clear(char *node)
1147 {
1148 	boolean_t	rval;
1149 
1150 	mutex_enter(&auth_data_lock);
1151 	rval = nvf_data_clear(BIDIR_AUTH_PARAMS_ID, node);
1152 	mutex_exit(&auth_data_lock);
1153 
1154 	return (rval);
1155 }
1156 
1157 /*
1158  * persistent_auth_lock -- lock access to bidirectional authentication
1159  * parameters.  This ensures the authentication parameters will be unchanged
1160  * while the lock is held.  The lock should be grabbed while walking through
1161  * the authentication parameters.
1162  */
1163 void
1164 persistent_auth_lock(void)
1165 {
1166 	mutex_enter(&auth_data_lock);
1167 }
1168 
1169 /*
1170  * persistent_auth_unlock -- unlock access to bidirectional authentication
1171  * parameters.
1172  */
1173 void
1174 persistent_auth_unlock(void)
1175 {
1176 	mutex_exit(&auth_data_lock);
1177 }
1178 
1179 
1180 /*
1181  * +--------------------------------------------------------------------+
1182  * | Debug Functions                                                    |
1183  * +--------------------------------------------------------------------+
1184  */
1185 
1186 #define	BITBUF_LEN	128
1187 
1188 /*
1189  * persistent_dump_data -- dump contents of persistent store
1190  */
1191 void
1192 persistent_dump_data(void)
1193 {
1194 	boolean_t		rval;
1195 	char			*name;
1196 	iSCSIDiscoveryMethod_t	methods;
1197 	char			*bitbuf;
1198 	iscsi_radius_props_t	*radius;
1199 	entry_t			*entry;
1200 	void			*v;
1201 	char			*addr_buf;
1202 	persistent_param_t	*param;
1203 	uint32_t		param_id;
1204 	char			*param_name;
1205 	iscsi_chap_props_t	*chap;
1206 	iscsi_auth_props_t	*auth;
1207 
1208 	name = (char *)kmem_alloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
1209 	addr_buf = (char *)kmem_alloc(INET6_ADDRSTRLEN, KM_SLEEP);
1210 	bitbuf = (char *)kmem_alloc(BITBUF_LEN, KM_SLEEP);
1211 
1212 	rval = persistent_initiator_name_get(name, ISCSI_MAX_NAME_LEN);
1213 	if (rval == B_TRUE) {
1214 		cmn_err(CE_CONT, "    Node Name: %s\n", name);
1215 	}
1216 
1217 	rval = persistent_alias_name_get(name, ISCSI_MAX_NAME_LEN);
1218 	if (rval == B_TRUE) {
1219 		cmn_err(CE_CONT, "    Node Alias: %s\n", name);
1220 	}
1221 
1222 	methods = persistent_disc_meth_get();
1223 	if (methods != iSCSIDiscoveryMethodUnknown) {
1224 		cmn_err(CE_CONT, "    Methods: <%s>\n",
1225 		    prt_bitmap(methods,
1226 		    "\003SendTarget\002iSNS\001SLP\000Static",
1227 		    bitbuf, BITBUF_LEN));
1228 	}
1229 
1230 	radius = (iscsi_radius_props_t *)kmem_alloc(sizeof (*radius),
1231 	    KM_SLEEP);
1232 	if (persistent_radius_get(radius) == ISCSI_NVFILE_SUCCESS) {
1233 		cmn_err(CE_CONT, "    <------ RADIUS Configuration ------>\n");
1234 		if (radius->r_insize == sizeof (struct in_addr)) {
1235 			(void) inet_ntop(AF_INET, &radius->r_addr.u_in4,
1236 			    addr_buf, INET6_ADDRSTRLEN);
1237 		} else {
1238 			(void) inet_ntop(AF_INET6, &radius->r_addr.u_in6,
1239 			    addr_buf, INET6_ADDRSTRLEN);
1240 		}
1241 		cmn_err(CE_CONT, "    IP: %s, port %d\n", addr_buf,
1242 		    radius->r_port);
1243 	}
1244 	kmem_free(radius, sizeof (*radius));
1245 
1246 	entry = (entry_t *)kmem_alloc(sizeof (*entry), KM_SLEEP);
1247 	v = NULL;
1248 	cmn_err(CE_CONT,
1249 	    "    <------ Static Target Discovery Addresses ------>\n");
1250 	persistent_static_addr_lock();
1251 	while (persistent_static_addr_next(&v, name, entry) == B_TRUE) {
1252 		cmn_err(CE_CONT, "    Target Name: %s  TPGT: %d\n",
1253 		    name, entry->e_tpgt);
1254 		if (entry->e_insize == sizeof (struct in_addr)) {
1255 			(void) inet_ntop(AF_INET, &entry->e_u.u_in4,
1256 			    addr_buf, INET6_ADDRSTRLEN);
1257 		} else {
1258 			(void) inet_ntop(AF_INET6, &entry->e_u.u_in6,
1259 			    addr_buf, INET6_ADDRSTRLEN);
1260 		}
1261 		cmn_err(CE_CONT,
1262 		    "        IP: %s, port %d\n", addr_buf, entry->e_port);
1263 	}
1264 	persistent_static_addr_unlock();
1265 
1266 	v = NULL;
1267 	cmn_err(CE_CONT,
1268 	    "    <------ SendTargets Discovery Addresses ------>\n");
1269 	persistent_disc_addr_lock();
1270 	while (persistent_disc_addr_next(&v, entry) == B_TRUE) {
1271 		if (entry->e_insize == sizeof (struct in_addr)) {
1272 			(void) inet_ntop(AF_INET, &entry->e_u.u_in4,
1273 			    addr_buf, INET6_ADDRSTRLEN);
1274 		} else {
1275 			(void) inet_ntop(AF_INET6, &entry->e_u.u_in6,
1276 			    addr_buf, INET6_ADDRSTRLEN);
1277 		}
1278 		cmn_err(CE_CONT,
1279 		    "    IP: %s, port %d\n", addr_buf, entry->e_port);
1280 	}
1281 	persistent_disc_addr_unlock();
1282 
1283 	v = NULL;
1284 	cmn_err(CE_CONT,
1285 	    "    <------ ISNS Server Discovery Addresses ------>\n");
1286 	persistent_isns_addr_lock();
1287 	while (persistent_isns_addr_next(&v, entry) == B_TRUE) {
1288 		if (entry->e_insize == sizeof (struct in_addr)) {
1289 			(void) inet_ntop(AF_INET, &entry->e_u.u_in4,
1290 			    addr_buf, INET6_ADDRSTRLEN);
1291 		} else {
1292 			(void) inet_ntop(AF_INET6, &entry->e_u.u_in6,
1293 			    addr_buf, INET6_ADDRSTRLEN);
1294 		}
1295 		cmn_err(CE_CONT,
1296 		    "    IP: %s, port %d\n", addr_buf, entry->e_port);
1297 	}
1298 	persistent_isns_addr_unlock();
1299 	kmem_free(entry, sizeof (*entry));
1300 
1301 	param = (persistent_param_t *)kmem_alloc(sizeof (*param), KM_SLEEP);
1302 	v = NULL;
1303 	cmn_err(CE_CONT, "    <------ Overriden Login Parameters ------>\n");
1304 	persistent_param_lock();
1305 	while (persistent_param_next(&v, name, param) == B_TRUE) {
1306 		cmn_err(CE_CONT, "    Host: %s\n", name);
1307 		cmn_err(CE_CONT, "    Bitmap: <%s>\n",
1308 		    prt_bitmap(param->p_bitmap,
1309 		    "\015DDIG\014HDIG\013SEGLEN\012OUT_R2T\011"
1310 		    "DATAPDU\010MAXCONN\007BURST\006R2T\005"
1311 		    "IMMDATA\004FIRSTBURST\003LEVEL\002T2WAIT"
1312 		    "\001T2RETAIN\000SEQIN", bitbuf, BITBUF_LEN));
1313 		for (param_id = 0; param_id < ISCSI_NUM_LOGIN_PARAM;
1314 		    param_id++) {
1315 			if (param->p_bitmap & (1 << param_id)) {
1316 				param_name = utils_map_param(param_id);
1317 				if (param_name == NULL) {
1318 					param_name = "Param_Not_Found";
1319 				}
1320 				switch (param_id) {
1321 				case ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER:
1322 					cmn_err(CE_CONT, "    %s = %s",
1323 					    param_name, (param->p_params.
1324 					    data_sequence_in_order == B_TRUE) ?
1325 					    "True" : "False");
1326 					break;
1327 				case ISCSI_LOGIN_PARAM_INITIAL_R2T:
1328 					cmn_err(CE_CONT, "    %s = %s",
1329 					    param_name, (param->p_params.
1330 					    initial_r2t == B_TRUE) ?
1331 					    "True" : "False");
1332 					break;
1333 				case ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER:
1334 					cmn_err(CE_CONT, "    %s = %s",
1335 					    param_name, (param->p_params.
1336 					    data_pdu_in_order == B_TRUE) ?
1337 					    "True" : "False");
1338 					break;
1339 				case ISCSI_LOGIN_PARAM_HEADER_DIGEST:
1340 					cmn_err(CE_CONT, "    %s = %d",
1341 					    param_name, param->p_params.
1342 					    header_digest);
1343 					break;
1344 				case ISCSI_LOGIN_PARAM_DATA_DIGEST:
1345 					cmn_err(CE_CONT, "    %s = %d",
1346 					    param_name, param->p_params.
1347 					    data_digest);
1348 					break;
1349 			case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN:
1350 					cmn_err(CE_CONT, "    %s = %d",
1351 					    param_name, param->p_params.
1352 					    default_time_to_retain);
1353 					break;
1354 				case ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT:
1355 					cmn_err(CE_CONT, "    %s = %d",
1356 					    param_name, param->p_params.
1357 					    default_time_to_wait);
1358 					break;
1359 			case ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH:
1360 					cmn_err(CE_CONT, "    %s = %d",
1361 					    param_name, param->p_params.
1362 					    max_recv_data_seg_len);
1363 					break;
1364 				case ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH:
1365 					cmn_err(CE_CONT, "    %s = %d",
1366 					    param_name, param->p_params.
1367 					    first_burst_length);
1368 					break;
1369 				case ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH:
1370 					cmn_err(CE_CONT, "    %s = %d",
1371 					    param_name, param->p_params.
1372 					    max_burst_length);
1373 					break;
1374 				case ISCSI_LOGIN_PARAM_MAX_CONNECTIONS:
1375 					cmn_err(CE_CONT, "    %s = %d",
1376 					    param_name, param->p_params.
1377 					    max_connections);
1378 					break;
1379 				case ISCSI_LOGIN_PARAM_OUTSTANDING_R2T:
1380 					cmn_err(CE_CONT, "    %s = %d",
1381 					    param_name, param->p_params.
1382 					    max_outstanding_r2t);
1383 					break;
1384 				case ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL:
1385 					cmn_err(CE_CONT, "    %s = %d",
1386 					    param_name, param->p_params.
1387 					    error_recovery_level);
1388 					break;
1389 				default:
1390 					break;
1391 				}
1392 			}
1393 		}
1394 	}
1395 	persistent_param_unlock();
1396 	kmem_free(param, sizeof (*param));
1397 
1398 	chap = (iscsi_chap_props_t *)kmem_alloc(sizeof (*chap), KM_SLEEP);
1399 	v = NULL;
1400 	cmn_err(CE_CONT, "    <------ Chap Parameters ------>\n");
1401 	persistent_chap_lock();
1402 	while (persistent_chap_next(&v, name, chap) == B_TRUE) {
1403 		cmn_err(CE_CONT, "    Host: %s\n", name);
1404 		cmn_err(CE_CONT, "        User: %s  Secret: %s\n",
1405 		    chap->c_user, chap->c_secret);
1406 	}
1407 	persistent_chap_unlock();
1408 	kmem_free(chap, sizeof (*chap));
1409 
1410 	auth = (iscsi_auth_props_t *)kmem_alloc(sizeof (*auth), KM_SLEEP);
1411 	v = NULL;
1412 	cmn_err(CE_CONT, "    <------ Bidirectional Authentication  ------>\n");
1413 	persistent_auth_lock();
1414 	while (persistent_auth_next(&v, name, auth) == B_TRUE) {
1415 		cmn_err(CE_CONT, "    Host: %s\n", name);
1416 		cmn_err(CE_CONT, "       Bidir Auth = %s\n",
1417 		    (auth->a_bi_auth == B_TRUE) ? "True" : "False");
1418 	}
1419 	persistent_auth_unlock();
1420 	kmem_free(auth, sizeof (*auth));
1421 
1422 
1423 	kmem_free(bitbuf, BITBUF_LEN);
1424 	kmem_free(addr_buf, INET6_ADDRSTRLEN);
1425 	kmem_free(name, ISCSI_MAX_NAME_LEN);
1426 }
1427