xref: /illumos-gate/usr/src/uts/i86pc/os/ibft.c (revision 56f33205c9ed776c3c909e07d52e94610a675740)
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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * This is the place to implement ld_ib_props()
29  * For x86 it is to load iBFT and costruct the global ib props
30  */
31 
32 #include <sys/types.h>
33 #include <sys/cmn_err.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <sys/mman.h>
37 #include <sys/bootprops.h>
38 #include <sys/kmem.h>
39 #include <sys/psm.h>
40 #include <sys/bootconf.h>
41 
42 #ifndef	NULL
43 #define	NULL	0
44 #endif
45 
46 typedef enum ibft_structure_type {
47 	Reserved	=	0,
48 	Control		=	1,
49 	Initiator	=	2,
50 	Nic		=	3,
51 	Target		=	4,
52 	Extensions	=	5,
53 	Type_End
54 }ibft_struct_type;
55 
56 typedef enum _chap_type {
57 	NO_CHAP		=	0,
58 	CHAP		=	1,
59 	Mutual_CHAP	=	2,
60 	TYPE_UNKNOWN
61 }chap_type;
62 
63 typedef struct ibft_entry {
64 	int	af;
65 	int	e_port;
66 	char	target_name[224];
67 	char	target_addr[INET6_ADDRSTRLEN];
68 }ibft_entry_t;
69 
70 typedef struct iSCSI_ibft_tbl_hdr {
71 	char	    Signature[4];
72 	int	    Length;
73 	char	    Revision;
74 	char	    Checksum;
75 	char	    oem_id[6];
76 	char	    oem_table_id[8];
77 	char	    Reserved[24];
78 }iscsi_ibft_tbl_hdr_t;
79 
80 typedef struct iSCSI_ibft_hdr {
81 	char	    Structure_id;
82 	char	    Version;
83 	ushort_t    Length;
84 	char	    Index;
85 	char	    Flags;
86 }iscsi_ibft_hdr_t;
87 
88 typedef struct iSCSI_ibft_control {
89 	iscsi_ibft_hdr_t    header;
90 	ushort_t	    Extensions;
91 	ushort_t	    Initiator_offset;
92 	ushort_t	    Nic0_offset;
93 	ushort_t	    Target0_offset;
94 	ushort_t	    Nic1_offset;
95 	ushort_t	    Target1_offset;
96 }iscsi_ibft_ctl_t;
97 
98 typedef struct iSCSI_ibft_initiator {
99 	iscsi_ibft_hdr_t    header;
100 	uchar_t		    iSNS_Server[16];
101 	uchar_t		    SLP_Server[16];
102 	uchar_t		    Pri_Radius_Server[16];
103 	uchar_t		    Sec_Radius_Server[16];
104 	ushort_t	    ini_name_len;
105 	ushort_t	    ini_name_offset;
106 }iscsi_ibft_initiator_t;
107 
108 typedef struct iSCSI_ibft_nic {
109 	iscsi_ibft_hdr_t    header;
110 	uchar_t		    ip_addr[16];
111 	char		    Subnet_Mask_Prefix;
112 	char		    Origin;
113 	uchar_t		    Gateway[16];
114 	uchar_t		    Primary_dns[16];
115 	uchar_t		    Secondary_dns[16];
116 	uchar_t		    dhcp[16];
117 	ushort_t	    vlan;
118 	char		    mac[6];
119 	ushort_t	    pci_BDF;
120 	ushort_t	    Hostname_len;
121 	ushort_t	    Hostname_offset;
122 }iscsi_ibft_nic_t;
123 
124 typedef struct iSCSI_ibft_target {
125 	iscsi_ibft_hdr_t    header;
126 	uchar_t		    ip_addr[16];
127 	ushort_t	    port;
128 	uchar_t		    boot_lun[8];
129 	uchar_t		    chap_type;
130 	uchar_t		    nic_association;
131 	ushort_t	    target_name_len;
132 	ushort_t	    target_name_offset;
133 	ushort_t	    chap_name_len;
134 	ushort_t	    chap_name_offset;
135 	ushort_t	    chap_secret_len;
136 	ushort_t	    chap_secret_offset;
137 	ushort_t	    rev_chap_name_len;
138 	ushort_t	    rev_chap_name_offset;
139 	ushort_t	    rev_chap_secret_len;
140 	ushort_t	    rev_chap_secret_offset;
141 }iscsi_ibft_tgt_t;
142 
143 #define	ISCSI_IBFT_LOWER_ADDR		0x80000	    /* 512K */
144 #define	ISCSI_IBFT_HIGHER_ADDR		0x100000    /* 1024K */
145 #define	ISCSI_IBFT_SIGNATRUE		"iBFT"
146 #define	ISCSI_IBFT_SIGNATURE_LEN	4
147 #define	ISCSI_IBFT_TBL_BUF_LEN		1024
148 #define	ISCSI_IBFT_ALIGNED		16
149 #define	ISCSI_IBFT_CTL_OFFSET		48
150 
151 #define	IBFT_BLOCK_VALID_YES		0x01	/* bit 0 */
152 #define	IBFT_FIRMWARE_BOOT_SELECTED	0x02	/* bit 1 */
153 #define	IBFT_USE_RADIUS_CHAP		0x04	/* bit 2 */
154 #define	IBFT_USE_GLOBLE			0x04	/* NIC structure */
155 #define	IBFT_USE_RADIUS_RHCAP		0x08	/* bit 3 */
156 
157 /*
158  * Currently, we only support initiator offset, NIC0 offset, Target0 offset,
159  * NIC1 offset and Target1 offset. So the length is 5. If we want to support
160  * extensions, we should change this number.
161  */
162 #define	IBFT_OFFSET_BUF_LEN		5
163 #define	IPV4_OFFSET			12
164 
165 #define	IBFT_INVALID_MSG		"Invalid iBFT table 0x%x"
166 #define	IBFT_NOPROBE_MSG		"iSCSI boot is disabled"
167 
168 typedef enum ibft_status {
169 	IBFT_STATUS_OK = 0,
170 	/* General error */
171 	IBFT_STATUS_ERR,
172 	/* Bad header */
173 	IBFT_STATUS_BADHDR,
174 	/* Bad control ID */
175 	IBFT_STATUS_BADCID,
176 	/* Bad ip addr */
177 	IBFT_STATUS_BADIP,
178 	/* Bad af */
179 	IBFT_STATUS_BADAF,
180 	/* Bad chap name */
181 	IBFT_STATUS_BADCHAPNAME,
182 	/* Bad chap secret */
183 	IBFT_STATUS_BADCHAPSEC,
184 	/* Bad checksum */
185 	IBFT_STATUS_BADCHECKSUM,
186 	/* Low memory */
187 	IBFT_STATUS_LOWMEM,
188 	/* No table */
189 	IBFT_STATUS_NOTABLE
190 } ibft_status_t;
191 
192 extern void *memset(void *s, int c, size_t n);
193 extern int memcmp(const void *s1, const void *s2, size_t n);
194 extern void bcopy(const void *s1, void *s2, size_t n);
195 extern void iscsi_print_boot_property();
196 
197 int ibft_noprobe = 0;
198 ib_boot_prop_t boot_property;		/* static allocated */
199 extern ib_boot_prop_t *iscsiboot_prop;	/* to be filled */
200 
201 static ibft_status_t iscsi_parse_ibft_control(iscsi_ibft_ctl_t *ctl_hdr,
202     ushort_t *iscsi_offset_buf);
203 
204 static ibft_status_t iscsi_parse_ibft_initiator(char *begin_of_ibft,
205     iscsi_ibft_initiator_t *initiator);
206 
207 static ibft_status_t iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp);
208 
209 static ibft_status_t iscsi_parse_ibft_target(char *begin_of_ibft,
210     iscsi_ibft_tgt_t *tgtp);
211 
212 
213 /*
214  * Return value:
215  * Success: IBFT_STATUS_OK
216  * Fail: IBFT_STATUS_BADCHECKSUM
217  */
218 static ibft_status_t
219 iscsi_ibft_hdr_checksum(iscsi_ibft_tbl_hdr_t *tbl_hdr)
220 {
221 	uchar_t	checksum    =	0;
222 	uchar_t	*start	    =	NULL;
223 	int	length	    =	0;
224 	int	i	    =	0;
225 
226 	if (tbl_hdr == NULL) {
227 		return (IBFT_STATUS_BADHDR);
228 	}
229 
230 	length = tbl_hdr->Length;
231 	start = (uchar_t *)tbl_hdr;
232 
233 	for (i = 0; i < length; i++) {
234 		checksum = checksum + start[i];
235 	}
236 
237 	if (!checksum)
238 		return (IBFT_STATUS_OK);
239 	else
240 		return (IBFT_STATUS_BADCHECKSUM);
241 }
242 
243 /*
244  * Now we only support one control structure in the IBFT.
245  * So there is no Control ID here.
246  */
247 static ibft_status_t
248 iscsi_parse_ibft_structure(char *begin_of_ibft, char *buf)
249 {
250 	iscsi_ibft_hdr_t	*hdr	=   NULL;
251 	ibft_status_t		ret	=   IBFT_STATUS_OK;
252 
253 	if (buf == NULL) {
254 		return (IBFT_STATUS_ERR);
255 	}
256 
257 	hdr = (iscsi_ibft_hdr_t *)buf;
258 	switch (hdr->Structure_id) {
259 		case Initiator:
260 			ret = iscsi_parse_ibft_initiator(
261 			    begin_of_ibft,
262 			    (iscsi_ibft_initiator_t *)buf);
263 			break;
264 		case Nic:
265 			ret = iscsi_parse_ibft_NIC(
266 			    (iscsi_ibft_nic_t *)buf);
267 			break;
268 		case Target:
269 			ret = iscsi_parse_ibft_target(
270 			    begin_of_ibft,
271 			    (iscsi_ibft_tgt_t *)buf);
272 			break;
273 		default:
274 			ret = IBFT_STATUS_BADHDR;
275 			break;
276 	}
277 
278 	return (ret);
279 }
280 
281 /*
282  * Parse the iBFT table
283  * return IBFT_STATUS_OK upon sucess
284  */
285 static ibft_status_t
286 iscsi_parse_ibft_tbl(iscsi_ibft_tbl_hdr_t *tbl_hdr)
287 {
288 	char		*outbuf	    =	NULL;
289 	int		i	    =	0;
290 	ibft_status_t	ret	    =	IBFT_STATUS_OK;
291 	ushort_t	iscsi_offset_buf[IBFT_OFFSET_BUF_LEN] = {0};
292 
293 	if (tbl_hdr == NULL) {
294 		return (IBFT_STATUS_ERR);
295 	}
296 
297 	if (iscsi_ibft_hdr_checksum(tbl_hdr) != IBFT_STATUS_OK) {
298 		return (IBFT_STATUS_BADCHECKSUM);
299 	}
300 
301 	outbuf = (char *)tbl_hdr;
302 
303 	ret = iscsi_parse_ibft_control(
304 	    (iscsi_ibft_ctl_t *)&outbuf[ISCSI_IBFT_CTL_OFFSET],
305 	    iscsi_offset_buf);
306 
307 	if (ret == IBFT_STATUS_OK) {
308 		ret = IBFT_STATUS_ERR;
309 		for (i = 0; i < IBFT_OFFSET_BUF_LEN; i++) {
310 			if (iscsi_offset_buf[i] != 0) {
311 				ret = iscsi_parse_ibft_structure(
312 				    (char *)tbl_hdr,
313 				    (char *)tbl_hdr +
314 				    iscsi_offset_buf[i]);
315 				if (ret != IBFT_STATUS_OK) {
316 					return (ret);
317 				}
318 			}
319 		}
320 	}
321 
322 	return (ret);
323 }
324 
325 static ibft_status_t
326 iscsi_parse_ibft_control(iscsi_ibft_ctl_t *ctl_hdr,
327     ushort_t	*iscsi_offset_buf)
328 {
329 	int	    i		=	0;
330 	ushort_t    *offsetp	=	NULL;
331 
332 	if (ctl_hdr == NULL) {
333 		return (IBFT_STATUS_BADHDR);
334 	}
335 
336 	if (ctl_hdr->header.Structure_id != Control) {
337 		return (IBFT_STATUS_BADCID);
338 	}
339 
340 	/*
341 	 * Copy the offsets to offset buffer.
342 	 */
343 	for (offsetp = &(ctl_hdr->Initiator_offset); i < IBFT_OFFSET_BUF_LEN;
344 	    offsetp++) {
345 		iscsi_offset_buf[i++] = *offsetp;
346 	}
347 
348 	return (IBFT_STATUS_OK);
349 }
350 
351 /*
352  * We only copy the "Firmare Boot Selseted" and valid initiator
353  * to the boot property.
354  */
355 static ibft_status_t
356 iscsi_parse_ibft_initiator(char *begin_of_ibft,
357     iscsi_ibft_initiator_t *initiator)
358 {
359 	if (initiator == NULL) {
360 		return (IBFT_STATUS_ERR);
361 	}
362 
363 	if (initiator->header.Structure_id != Initiator) {
364 		return (IBFT_STATUS_BADHDR);
365 	}
366 
367 	if ((initiator->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
368 	    (initiator->header.Flags & IBFT_BLOCK_VALID_YES)) {
369 		/*
370 		 * If the initiator name exists, we will copy it to our own
371 		 * property structure
372 		 */
373 		if (initiator->ini_name_len != 0) {
374 			boot_property.boot_init.ini_name =
375 			    (uchar_t *)kmem_zalloc(
376 			    initiator->ini_name_len + 1, KM_SLEEP);
377 			boot_property.boot_init.ini_name_len =
378 			    initiator->ini_name_len + 1;
379 			(void) snprintf(
380 			    (char *)boot_property.boot_init.ini_name,
381 			    initiator->ini_name_len + 1, "%s",
382 			    begin_of_ibft + initiator->ini_name_offset);
383 		}
384 	}
385 	return (IBFT_STATUS_OK);
386 }
387 
388 static ibft_status_t
389 iscsi_parse_ipaddr(uchar_t *source, char *dest, int *af)
390 {
391 	int i = 0;
392 
393 	if (source == NULL) {
394 		return (IBFT_STATUS_ERR);
395 	}
396 
397 	if (source[0] == 0x00 && source[1] == 0x00 &&
398 	    source[2] == 0x00 && source[3] == 0x00 &&
399 	    source[4] == 0x00 && source[5] == 0x00 &&
400 	    source[6] == 0x00 && source[7] == 0x00 &&
401 	    source[8] == 0x00 && source[9] == 0x00 &&
402 	    (source[10] == 0xff) && (source[11] == 0xff)) {
403 		/*
404 		 * IPv4 address
405 		 */
406 		if (dest != NULL) {
407 			(void) sprintf(dest, "%d.%d.%d.%d",
408 			    source[12], source[13], source[14], source[15]);
409 		}
410 		if (af != NULL) {
411 			*af = AF_INET;
412 		}
413 	} else {
414 		if (dest != NULL) {
415 			for (i = 0; i < 14; i = i + 2) {
416 				(void) sprintf(dest, "%02x%02x:", source[i],
417 				    source[i+1]);
418 				dest = dest + 5;
419 			}
420 			(void) sprintf(dest, "%02x%02x",
421 			    source[i], source[i+1]);
422 		}
423 		if (af != NULL) {
424 			*af = AF_INET6;
425 		}
426 	}
427 
428 	return (IBFT_STATUS_OK);
429 }
430 
431 /*
432  * Copy the ip address from ibft. If IPv4 is used, we should copy
433  * the address from 12th byte.
434  */
435 static ibft_status_t
436 iscsi_copy_ibft_ipaddr(uchar_t *source, void *dest, int *af)
437 {
438 	ibft_status_t	ret		=	IBFT_STATUS_OK;
439 	int		sin_family	=	0;
440 
441 	if (source == NULL || dest == NULL) {
442 		return (IBFT_STATUS_ERR);
443 	}
444 	ret = iscsi_parse_ipaddr(source, NULL, &sin_family);
445 	if (ret != 0) {
446 		return (IBFT_STATUS_BADIP);
447 	}
448 
449 	if (sin_family == AF_INET) {
450 		bcopy(source+IPV4_OFFSET, dest, sizeof (struct in_addr));
451 	} else if (sin_family == AF_INET6) {
452 		bcopy(source, dest, sizeof (struct in6_addr));
453 	} else {
454 		return (IBFT_STATUS_BADAF);
455 	}
456 
457 	if (af != NULL) {
458 		*af = sin_family;
459 	}
460 	return (IBFT_STATUS_OK);
461 }
462 
463 /*
464  * Maybe there are multiply NICs are available. We only copy the
465  * "Firmare Boot Selseted" and valid one to the boot property.
466  */
467 static ibft_status_t
468 iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp)
469 {
470 	ibft_status_t	ret	=	IBFT_STATUS_OK;
471 	int		af	=	0;
472 
473 	if (nicp == NULL) {
474 		return (IBFT_STATUS_ERR);
475 	}
476 
477 	if (nicp->header.Structure_id != Nic) {
478 		return (IBFT_STATUS_ERR);
479 	}
480 
481 	if ((nicp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
482 	    (nicp->header.Flags & IBFT_BLOCK_VALID_YES)) {
483 		ret = iscsi_copy_ibft_ipaddr(nicp->ip_addr,
484 		    &boot_property.boot_nic.nic_ip_u, &af);
485 		if (ret != IBFT_STATUS_OK) {
486 			return (ret);
487 		}
488 
489 		boot_property.boot_nic.sin_family = af;
490 
491 		ret = iscsi_copy_ibft_ipaddr(nicp->Gateway,
492 		    &boot_property.boot_nic.nic_gw_u, NULL);
493 		if (ret != IBFT_STATUS_OK) {
494 			return (ret);
495 		}
496 
497 		ret = iscsi_copy_ibft_ipaddr(nicp->dhcp,
498 		    &boot_property.boot_nic.nic_dhcp_u, NULL);
499 		if (ret != IBFT_STATUS_OK) {
500 			return (ret);
501 		}
502 
503 		bcopy(nicp->mac, boot_property.boot_nic.nic_mac, 6);
504 		boot_property.boot_nic.sub_mask_prefix =
505 		    nicp->Subnet_Mask_Prefix;
506 	}
507 
508 	return (IBFT_STATUS_OK);
509 }
510 
511 /*
512  * Maybe there are multiply targets are available. We only copy the
513  * "Firmare Boot Selseted" and valid one to the boot property.
514  */
515 static ibft_status_t
516 iscsi_parse_ibft_target(char *begin_of_ibft, iscsi_ibft_tgt_t *tgtp)
517 {
518 	char		*tmp	=   NULL;
519 	int		af	=   0;
520 	ibft_status_t	ret	=   IBFT_STATUS_OK;
521 
522 	if (tgtp == NULL) {
523 		return (IBFT_STATUS_ERR);
524 	}
525 
526 	if (tgtp->header.Structure_id != Target) {
527 		return (IBFT_STATUS_BADHDR);
528 	}
529 
530 	if ((tgtp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
531 	    (tgtp->header.Flags & IBFT_BLOCK_VALID_YES)) {
532 		/*
533 		 * Get Target Address
534 		 */
535 		ret = iscsi_copy_ibft_ipaddr(tgtp->ip_addr,
536 		    &boot_property.boot_tgt.tgt_ip_u, &af);
537 		if (ret != IBFT_STATUS_OK) {
538 			return (ret);
539 		}
540 		boot_property.boot_tgt.sin_family = af;
541 		/*
542 		 * Get Target Name
543 		 */
544 		if (tgtp->target_name_len != 0) {
545 			boot_property.boot_tgt.tgt_name =
546 			    (uchar_t *)kmem_zalloc(tgtp->target_name_len + 1,
547 			    KM_SLEEP);
548 			boot_property.boot_tgt.tgt_name_len =
549 			    tgtp->target_name_len + 1;
550 			(void) snprintf(
551 			    (char *)boot_property.boot_tgt.tgt_name,
552 			    tgtp->target_name_len + 1, "%s",
553 			    begin_of_ibft + tgtp->target_name_offset);
554 		} else {
555 			boot_property.boot_tgt.tgt_name = NULL;
556 		}
557 
558 		/* Get Dest Port */
559 		boot_property.boot_tgt.tgt_port = tgtp->port;
560 
561 		boot_property.boot_tgt.lun_online = 0;
562 
563 		/*
564 		 * Get CHAP secret and name.
565 		 */
566 		if (tgtp->chap_type != NO_CHAP) {
567 			if (tgtp->chap_name_len != 0) {
568 				boot_property.boot_init.ini_chap_name =
569 				    (uchar_t *)kmem_zalloc(
570 				    tgtp->chap_name_len + 1,
571 				    KM_SLEEP);
572 				boot_property.boot_init.ini_chap_name_len =
573 				    tgtp->chap_name_len + 1;
574 				tmp = (char *)
575 				    boot_property.boot_init.ini_chap_name;
576 				(void) snprintf(
577 				    tmp,
578 				    tgtp->chap_name_len + 1, "%s",
579 				    begin_of_ibft + tgtp->chap_name_offset);
580 			} else {
581 				/*
582 				 * Just set NULL, initiator is able to deal
583 				 * with this
584 				 */
585 				boot_property.boot_init.ini_chap_name = NULL;
586 			}
587 
588 			if (tgtp->chap_secret_len != 0) {
589 				boot_property.boot_init.ini_chap_sec =
590 				    (uchar_t *)kmem_zalloc(
591 				    tgtp->chap_secret_len + 1,
592 				    KM_SLEEP);
593 				boot_property.boot_init.ini_chap_sec_len =
594 				    tgtp->chap_secret_len + 1;
595 				bcopy(begin_of_ibft +
596 				    tgtp->chap_secret_offset,
597 				    boot_property.boot_init.ini_chap_sec,
598 				    tgtp->chap_secret_len);
599 			} else {
600 				boot_property.boot_init.ini_chap_sec = NULL;
601 				return (IBFT_STATUS_ERR);
602 			}
603 
604 			if (tgtp->chap_type == Mutual_CHAP) {
605 				if (tgtp->rev_chap_name_len != 0) {
606 					boot_property.boot_tgt.tgt_chap_name =
607 					    (uchar_t *)kmem_zalloc(
608 					    tgtp->rev_chap_name_len + 1,
609 					    KM_SLEEP);
610 					boot_property.boot_tgt.tgt_chap_name_len
611 					    = tgtp->rev_chap_name_len + 1;
612 #define	TGT_CHAP_NAME	boot_property.boot_tgt.tgt_chap_name
613 					tmp = (char *)TGT_CHAP_NAME;
614 #undef	TGT_CHAP_NAME
615 					(void) snprintf(
616 					    tmp,
617 					    tgtp->rev_chap_name_len + 1,
618 					    "%s",
619 					    begin_of_ibft +
620 					    tgtp->rev_chap_name_offset);
621 				} else {
622 					/*
623 					 * Just set NULL, initiator is able
624 					 * to deal with this
625 					 */
626 					boot_property.boot_tgt.tgt_chap_name =
627 					    NULL;
628 				}
629 
630 				if (tgtp->rev_chap_secret_len != 0) {
631 					boot_property.boot_tgt.tgt_chap_sec =
632 					    (uchar_t *)kmem_zalloc(
633 					    tgtp->rev_chap_secret_len + 1,
634 					    KM_SLEEP);
635 					boot_property.boot_tgt.tgt_chap_sec_len
636 					    = tgtp->rev_chap_secret_len + 1;
637 					tmp = (char *)
638 					    boot_property.boot_tgt.tgt_chap_sec;
639 					(void) snprintf(
640 					    tmp,
641 					    tgtp->rev_chap_secret_len + 1,
642 					    "%s",
643 					    begin_of_ibft +
644 					    tgtp->chap_secret_offset);
645 				} else {
646 					boot_property.boot_tgt.tgt_chap_sec =
647 					    NULL;
648 					return (IBFT_STATUS_BADCHAPSEC);
649 				}
650 			}
651 		} else {
652 			boot_property.boot_init.ini_chap_name = NULL;
653 			boot_property.boot_init.ini_chap_sec = NULL;
654 		}
655 
656 		/*
657 		 * Get Boot LUN
658 		 */
659 		(void) bcopy(tgtp->boot_lun,
660 		    boot_property.boot_tgt.tgt_boot_lun, 8);
661 	}
662 
663 	return (IBFT_STATUS_OK);
664 }
665 
666 /*
667  * This function is used for scanning iBFT from the physical memory.
668  * Return Value:
669  * IBFT_STATUS_OK
670  * IBFT_STATUS_ERR
671  */
672 static ibft_status_t
673 iscsi_scan_ibft_tbl(char *ibft_tbl_buf)
674 {
675 	int		start;
676 	void		*va		= NULL;
677 	int		*len 		= NULL;
678 	ibft_status_t	ret		= IBFT_STATUS_NOTABLE;
679 
680 	for (start = ISCSI_IBFT_LOWER_ADDR; start < ISCSI_IBFT_HIGHER_ADDR;
681 	    start = start + ISCSI_IBFT_ALIGNED) {
682 		va = (void *)psm_map((paddr_t)(start&0xffffffff),
683 		    ISCSI_IBFT_SIGNATURE_LEN,
684 		    PROT_READ);
685 
686 		if (va == NULL) {
687 			continue;
688 		}
689 		if (memcmp(va, ISCSI_IBFT_SIGNATRUE,
690 		    ISCSI_IBFT_SIGNATURE_LEN) == 0) {
691 			ret = IBFT_STATUS_ERR;
692 			/* Acquire table length */
693 			len = (int *)psm_map(
694 			    (paddr_t)((start+\
695 			    ISCSI_IBFT_SIGNATURE_LEN)&0xffffffff),
696 			    ISCSI_IBFT_SIGNATURE_LEN, PROT_READ);
697 			if (len == NULL) {
698 				psm_unmap((caddr_t)va,
699 				    ISCSI_IBFT_SIGNATURE_LEN);
700 				continue;
701 			}
702 			if (ISCSI_IBFT_LOWER_ADDR + *len <
703 			    ISCSI_IBFT_HIGHER_ADDR - 1) {
704 				psm_unmap(va,
705 				    ISCSI_IBFT_SIGNATURE_LEN);
706 				va = psm_map((paddr_t)(start&0xffffffff),
707 				    *len,
708 				    PROT_READ);
709 				if (va != NULL) {
710 					/*
711 					 * Copy data to our own buffer
712 					 */
713 					bcopy(va, ibft_tbl_buf, *len);
714 					ret = IBFT_STATUS_OK;
715 				}
716 				psm_unmap((caddr_t)va, *len);
717 				psm_unmap((caddr_t)len,
718 				    ISCSI_IBFT_SIGNATURE_LEN);
719 				break;
720 			} else {
721 				psm_unmap((caddr_t)va,
722 				    ISCSI_IBFT_SIGNATURE_LEN);
723 				psm_unmap((caddr_t)len,
724 				    ISCSI_IBFT_SIGNATURE_LEN);
725 			}
726 		} else {
727 			psm_unmap((caddr_t)va, ISCSI_IBFT_SIGNATURE_LEN);
728 		}
729 	}
730 
731 	return (ret);
732 }
733 
734 /*
735  * Scan the ibft table and store the iSCSI boot properties
736  * If there is a valid table then set the iscsiboot_prop
737  * iBF should be off if the host is not intended
738  * to be booted from iSCSI disk
739  */
740 void
741 ld_ib_prop()
742 {
743 	ibft_status_t	ret	=   IBFT_STATUS_OK;
744 	char		*ibft_tbl_buf;
745 
746 	if (do_bsys_getproplen(NULL, "ibft-noprobe") > 0)
747 		ibft_noprobe = 1;
748 
749 	if (ibft_noprobe != 0) {
750 		/*
751 		 * Scanning for iBFT may conflict with devices which use memory
752 		 * in 640-1024KB of physical address space.  The iBFT
753 		 * specification suggests use of low RAM method - scanning
754 		 * physical memory 512-1024 KB for iBFT table.  However, the
755 		 * Upper Memory Area (UMA) 640-1024 KB may contain device
756 		 * memory or memory mapped I/O.  Although reading from I/O area
757 		 * is usually fine, the actual behavior depends on device
758 		 * implementation.  In some cases, the user may want to disable
759 		 * low RAM method and prevent reading from device I/O area.
760 		 *
761 		 * To disable low RAM method:
762 		 * 1) pass "-B ibft-noprobe=1" on kernel command line
763 		 * 2) add line "set ibft_noprobe=1" in /etc/system
764 		 */
765 		cmn_err(CE_NOTE, IBFT_NOPROBE_MSG);
766 		return;
767 	}
768 
769 	ibft_tbl_buf = (char *)kmem_zalloc(ISCSI_IBFT_TBL_BUF_LEN,
770 	    KM_SLEEP);
771 
772 	if (!ibft_tbl_buf) {
773 		/* Unlikely to happen */
774 		cmn_err(CE_NOTE, IBFT_INVALID_MSG,
775 		    IBFT_STATUS_LOWMEM);
776 		return;
777 	}
778 
779 	(void) memset(&boot_property, 0, sizeof (boot_property));
780 	if ((ret = iscsi_scan_ibft_tbl(ibft_tbl_buf)) ==
781 	    IBFT_STATUS_OK) {
782 		ret = iscsi_parse_ibft_tbl(
783 		    (iscsi_ibft_tbl_hdr_t *)ibft_tbl_buf);
784 		if (ret == IBFT_STATUS_OK) {
785 			iscsiboot_prop = &boot_property;
786 			iscsi_print_boot_property();
787 		} else {
788 			cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret);
789 		}
790 	} else if (ret != IBFT_STATUS_NOTABLE) {
791 		cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret);
792 	}
793 
794 	kmem_free(ibft_tbl_buf, ISCSI_IBFT_TBL_BUF_LEN);
795 }
796