xref: /illumos-gate/usr/src/uts/i86pc/os/ibft.c (revision d67944fbe3fa0b31893a7116a09b0718eecf6078)
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 			(void) snprintf(
378 			    (char *)boot_property.boot_init.ini_name,
379 			    initiator->ini_name_len + 1, "%s",
380 			    begin_of_ibft + initiator->ini_name_offset);
381 		}
382 	}
383 	return (IBFT_STATUS_OK);
384 }
385 
386 static ibft_status_t
387 iscsi_parse_ipaddr(uchar_t *source, char *dest, int *af)
388 {
389 	int i = 0;
390 
391 	if (source == NULL) {
392 		return (IBFT_STATUS_ERR);
393 	}
394 
395 	if (source[0] == 0x00 && source[1] == 0x00 &&
396 	    source[2] == 0x00 && source[3] == 0x00 &&
397 	    source[4] == 0x00 && source[5] == 0x00 &&
398 	    source[6] == 0x00 && source[7] == 0x00 &&
399 	    source[8] == 0x00 && source[9] == 0x00 &&
400 	    (source[10] == 0xff) && (source[11] == 0xff)) {
401 		/*
402 		 * IPv4 address
403 		 */
404 		if (dest != NULL) {
405 			(void) sprintf(dest, "%d.%d.%d.%d",
406 			    source[12], source[13], source[14], source[15]);
407 		}
408 		if (af != NULL) {
409 			*af = AF_INET;
410 		}
411 	} else {
412 		if (dest != NULL) {
413 			for (i = 0; i < 14; i = i + 2) {
414 				(void) sprintf(dest, "%02x%02x:", source[i],
415 				    source[i+1]);
416 				dest = dest + 5;
417 			}
418 			(void) sprintf(dest, "%02x%02x",
419 			    source[i], source[i+1]);
420 		}
421 		if (af != NULL) {
422 			*af = AF_INET6;
423 		}
424 	}
425 
426 	return (IBFT_STATUS_OK);
427 }
428 
429 /*
430  * Copy the ip address from ibft. If IPv4 is used, we should copy
431  * the address from 12th byte.
432  */
433 static ibft_status_t
434 iscsi_copy_ibft_ipaddr(uchar_t *source, void *dest, int *af)
435 {
436 	ibft_status_t	ret		=	IBFT_STATUS_OK;
437 	int		sin_family	=	0;
438 
439 	if (source == NULL || dest == NULL) {
440 		return (IBFT_STATUS_ERR);
441 	}
442 	ret = iscsi_parse_ipaddr(source, NULL, &sin_family);
443 	if (ret != 0) {
444 		return (IBFT_STATUS_BADIP);
445 	}
446 
447 	if (sin_family == AF_INET) {
448 		bcopy(source+IPV4_OFFSET, dest, sizeof (struct in_addr));
449 	} else if (sin_family == AF_INET6) {
450 		bcopy(source, dest, sizeof (struct in6_addr));
451 	} else {
452 		return (IBFT_STATUS_BADAF);
453 	}
454 
455 	if (af != NULL) {
456 		*af = sin_family;
457 	}
458 	return (IBFT_STATUS_OK);
459 }
460 
461 /*
462  * Maybe there are multiply NICs are available. We only copy the
463  * "Firmare Boot Selseted" and valid one to the boot property.
464  */
465 static ibft_status_t
466 iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp)
467 {
468 	ibft_status_t	ret	=	IBFT_STATUS_OK;
469 	int		af	=	0;
470 
471 	if (nicp == NULL) {
472 		return (IBFT_STATUS_ERR);
473 	}
474 
475 	if (nicp->header.Structure_id != Nic) {
476 		return (IBFT_STATUS_ERR);
477 	}
478 
479 	if ((nicp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
480 	    (nicp->header.Flags & IBFT_BLOCK_VALID_YES)) {
481 		ret = iscsi_copy_ibft_ipaddr(nicp->ip_addr,
482 		    &boot_property.boot_nic.nic_ip_u, &af);
483 		if (ret != IBFT_STATUS_OK) {
484 			return (ret);
485 		}
486 
487 		boot_property.boot_nic.sin_family = af;
488 
489 		ret = iscsi_copy_ibft_ipaddr(nicp->Gateway,
490 		    &boot_property.boot_nic.nic_gw_u, NULL);
491 		if (ret != IBFT_STATUS_OK) {
492 			return (ret);
493 		}
494 
495 		ret = iscsi_copy_ibft_ipaddr(nicp->dhcp,
496 		    &boot_property.boot_nic.nic_dhcp_u, NULL);
497 		if (ret != IBFT_STATUS_OK) {
498 			return (ret);
499 		}
500 
501 		bcopy(nicp->mac, boot_property.boot_nic.nic_mac, 6);
502 		boot_property.boot_nic.sub_mask_prefix =
503 		    nicp->Subnet_Mask_Prefix;
504 	}
505 
506 	return (IBFT_STATUS_OK);
507 }
508 
509 /*
510  * Maybe there are multiply targets are available. We only copy the
511  * "Firmare Boot Selseted" and valid one to the boot property.
512  */
513 static ibft_status_t
514 iscsi_parse_ibft_target(char *begin_of_ibft, iscsi_ibft_tgt_t *tgtp)
515 {
516 	char		*tmp	=   NULL;
517 	int		af	=   0;
518 	ibft_status_t	ret	=   IBFT_STATUS_OK;
519 
520 	if (tgtp == NULL) {
521 		return (IBFT_STATUS_ERR);
522 	}
523 
524 	if (tgtp->header.Structure_id != Target) {
525 		return (IBFT_STATUS_BADHDR);
526 	}
527 
528 	if ((tgtp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
529 	    (tgtp->header.Flags & IBFT_BLOCK_VALID_YES)) {
530 		/*
531 		 * Get Target Address
532 		 */
533 		ret = iscsi_copy_ibft_ipaddr(tgtp->ip_addr,
534 		    &boot_property.boot_tgt.tgt_ip_u, &af);
535 		if (ret != IBFT_STATUS_OK) {
536 			return (ret);
537 		}
538 		boot_property.boot_tgt.sin_family = af;
539 		/*
540 		 * Get Target Name
541 		 */
542 		if (tgtp->target_name_len != 0) {
543 			boot_property.boot_tgt.tgt_name =
544 			    (uchar_t *)kmem_zalloc(tgtp->target_name_len + 1,
545 			    KM_SLEEP);
546 			(void) snprintf(
547 			    (char *)boot_property.boot_tgt.tgt_name,
548 			    tgtp->target_name_len + 1, "%s",
549 			    begin_of_ibft + tgtp->target_name_offset);
550 		} else {
551 			boot_property.boot_tgt.tgt_name = NULL;
552 		}
553 
554 		/* Get Dest Port */
555 		boot_property.boot_tgt.tgt_port = tgtp->port;
556 
557 		boot_property.boot_tgt.lun_online = 0;
558 
559 		/*
560 		 * Get CHAP secret and name.
561 		 */
562 		if (tgtp->chap_type != NO_CHAP) {
563 			if (tgtp->chap_name_len != 0) {
564 				boot_property.boot_init.ini_chap_name =
565 				    (uchar_t *)kmem_zalloc(
566 				    tgtp->chap_name_len + 1,
567 				    KM_SLEEP);
568 				tmp = (char *)
569 				    boot_property.boot_init.ini_chap_name;
570 				(void) snprintf(
571 				    tmp,
572 				    tgtp->chap_name_len + 1, "%s",
573 				    begin_of_ibft + tgtp->chap_name_offset);
574 			} else {
575 				/*
576 				 * Just set NULL, initiator is able to deal
577 				 * with this
578 				 */
579 				boot_property.boot_init.ini_chap_name = NULL;
580 			}
581 
582 			if (tgtp->chap_secret_len != 0) {
583 				boot_property.boot_init.ini_chap_sec =
584 				    (uchar_t *)kmem_zalloc(
585 				    tgtp->chap_secret_len + 1,
586 				    KM_SLEEP);
587 				bcopy(begin_of_ibft +
588 				    tgtp->chap_secret_offset,
589 				    boot_property.boot_init.ini_chap_sec,
590 				    tgtp->chap_secret_len);
591 			} else {
592 				boot_property.boot_init.ini_chap_sec = NULL;
593 				return (IBFT_STATUS_ERR);
594 			}
595 
596 			if (tgtp->chap_type == Mutual_CHAP) {
597 				if (tgtp->rev_chap_name_len != 0) {
598 					boot_property.boot_tgt.tgt_chap_name =
599 					    (uchar_t *)kmem_zalloc(
600 					    tgtp->chap_name_len + 1,
601 					    KM_SLEEP);
602 #define	TGT_CHAP_NAME	boot_property.boot_tgt.tgt_chap_name
603 					tmp = (char *)TGT_CHAP_NAME;
604 #undef	TGT_CHAP_NAME
605 					(void) snprintf(
606 					    tmp,
607 					    tgtp->chap_name_len + 1,
608 					    "%s",
609 					    begin_of_ibft +
610 					    tgtp->rev_chap_name_offset);
611 				} else {
612 					/*
613 					 * Just set NULL, initiator is able
614 					 * to deal with this
615 					 */
616 					boot_property.boot_tgt.tgt_chap_name =
617 					    NULL;
618 				}
619 
620 				if (tgtp->rev_chap_secret_len != 0) {
621 					boot_property.boot_tgt.tgt_chap_sec =
622 					    (uchar_t *)kmem_zalloc(
623 					    tgtp->rev_chap_secret_len + 1,
624 					    KM_SLEEP);
625 					tmp = (char *)
626 					    boot_property.boot_tgt.tgt_chap_sec;
627 					(void) snprintf(
628 					    tmp,
629 					    tgtp->rev_chap_secret_len + 1,
630 					    "%s",
631 					    begin_of_ibft +
632 					    tgtp->chap_secret_offset);
633 				} else {
634 					boot_property.boot_tgt.tgt_chap_sec =
635 					    NULL;
636 					return (IBFT_STATUS_BADCHAPSEC);
637 				}
638 			}
639 		} else {
640 			boot_property.boot_init.ini_chap_name = NULL;
641 			boot_property.boot_init.ini_chap_sec = NULL;
642 		}
643 
644 		/*
645 		 * Get Boot LUN
646 		 */
647 		(void) bcopy(tgtp->boot_lun,
648 		    boot_property.boot_tgt.tgt_boot_lun, 8);
649 	}
650 
651 	return (IBFT_STATUS_OK);
652 }
653 
654 /*
655  * This function is used for scanning iBFT from the physical memory.
656  * Return Value:
657  * IBFT_STATUS_OK
658  * IBFT_STATUS_ERR
659  */
660 static ibft_status_t
661 iscsi_scan_ibft_tbl(char *ibft_tbl_buf)
662 {
663 	int		start;
664 	void		*va		= NULL;
665 	int		*len 		= NULL;
666 	ibft_status_t	ret		= IBFT_STATUS_NOTABLE;
667 
668 	for (start = ISCSI_IBFT_LOWER_ADDR; start < ISCSI_IBFT_HIGHER_ADDR;
669 	    start = start + ISCSI_IBFT_ALIGNED) {
670 		va = (void *)psm_map((paddr_t)(start&0xffffffff),
671 		    ISCSI_IBFT_SIGNATURE_LEN,
672 		    PROT_READ);
673 
674 		if (va == NULL) {
675 			continue;
676 		}
677 		if (memcmp(va, ISCSI_IBFT_SIGNATRUE,
678 		    ISCSI_IBFT_SIGNATURE_LEN) == 0) {
679 			ret = IBFT_STATUS_ERR;
680 			/* Acquire table length */
681 			len = (int *)psm_map(
682 			    (paddr_t)((start+\
683 			    ISCSI_IBFT_SIGNATURE_LEN)&0xffffffff),
684 			    ISCSI_IBFT_SIGNATURE_LEN, PROT_READ);
685 			if (len == NULL) {
686 				psm_unmap((caddr_t)va,
687 				    ISCSI_IBFT_SIGNATURE_LEN);
688 				continue;
689 			}
690 			if (ISCSI_IBFT_LOWER_ADDR + *len <
691 			    ISCSI_IBFT_HIGHER_ADDR - 1) {
692 				psm_unmap(va,
693 				    ISCSI_IBFT_SIGNATURE_LEN);
694 				va = psm_map((paddr_t)(start&0xffffffff),
695 				    *len,
696 				    PROT_READ);
697 				if (va != NULL) {
698 					/*
699 					 * Copy data to our own buffer
700 					 */
701 					bcopy(va, ibft_tbl_buf, *len);
702 					ret = IBFT_STATUS_OK;
703 				}
704 				psm_unmap((caddr_t)va, *len);
705 				psm_unmap((caddr_t)len,
706 				    ISCSI_IBFT_SIGNATURE_LEN);
707 				break;
708 			} else {
709 				psm_unmap((caddr_t)va,
710 				    ISCSI_IBFT_SIGNATURE_LEN);
711 				psm_unmap((caddr_t)len,
712 				    ISCSI_IBFT_SIGNATURE_LEN);
713 			}
714 		} else {
715 			psm_unmap((caddr_t)va, ISCSI_IBFT_SIGNATURE_LEN);
716 		}
717 	}
718 
719 	return (ret);
720 }
721 
722 /*
723  * Scan the ibft table and store the iSCSI boot properties
724  * If there is a valid table then set the iscsiboot_prop
725  * iBF should be off if the host is not intended
726  * to be booted from iSCSI disk
727  */
728 void
729 ld_ib_prop()
730 {
731 	ibft_status_t	ret	=   IBFT_STATUS_OK;
732 	char		*ibft_tbl_buf;
733 
734 	if (do_bsys_getproplen(NULL, "ibft-noprobe") > 0)
735 		ibft_noprobe = 1;
736 
737 	if (ibft_noprobe != 0) {
738 		/*
739 		 * Scanning for iBFT may conflict with devices which use memory
740 		 * in 640-1024KB of physical address space.  The iBFT
741 		 * specification suggests use of low RAM method - scanning
742 		 * physical memory 512-1024 KB for iBFT table.  However, the
743 		 * Upper Memory Area (UMA) 640-1024 KB may contain device
744 		 * memory or memory mapped I/O.  Although reading from I/O area
745 		 * is usually fine, the actual behavior depends on device
746 		 * implementation.  In some cases, the user may want to disable
747 		 * low RAM method and prevent reading from device I/O area.
748 		 *
749 		 * To disable low RAM method:
750 		 * 1) pass "-B ibft-noprobe=1" on kernel command line
751 		 * 2) add line "set ibft_noprobe=1" in /etc/system
752 		 */
753 		cmn_err(CE_NOTE, IBFT_NOPROBE_MSG);
754 		return;
755 	}
756 
757 	ibft_tbl_buf = (char *)kmem_zalloc(ISCSI_IBFT_TBL_BUF_LEN,
758 	    KM_SLEEP);
759 
760 	if (!ibft_tbl_buf) {
761 		/* Unlikely to happen */
762 		cmn_err(CE_NOTE, IBFT_INVALID_MSG,
763 		    IBFT_STATUS_LOWMEM);
764 		return;
765 	}
766 
767 	(void) memset(&boot_property, 0, sizeof (boot_property));
768 	if ((ret = iscsi_scan_ibft_tbl(ibft_tbl_buf)) ==
769 	    IBFT_STATUS_OK) {
770 		ret = iscsi_parse_ibft_tbl(
771 		    (iscsi_ibft_tbl_hdr_t *)ibft_tbl_buf);
772 		if (ret == IBFT_STATUS_OK) {
773 			iscsiboot_prop = &boot_property;
774 			iscsi_print_boot_property();
775 		} else {
776 			cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret);
777 		}
778 	} else if (ret != IBFT_STATUS_NOTABLE) {
779 		cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret);
780 	}
781 
782 	kmem_free(ibft_tbl_buf, ISCSI_IBFT_TBL_BUF_LEN);
783 }
784