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