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