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