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