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
43typedef 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
53typedef enum _chap_type {
54	NO_CHAP		=	0,
55	CHAP		=	1,
56	Mutual_CHAP	=	2,
57	TYPE_UNKNOWN
58}chap_type;
59
60typedef 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
67typedef 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
77typedef 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
85typedef 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
95typedef 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
105typedef 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
121typedef 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
165typedef 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
189extern void *memset(void *s, int c, size_t n);
190extern int memcmp(const void *s1, const void *s2, size_t n);
191extern void bcopy(const void *s1, void *s2, size_t n);
192extern void iscsi_print_boot_property();
193
194int ibft_noprobe = 0;
195ib_boot_prop_t boot_property;		/* static allocated */
196extern ib_boot_prop_t *iscsiboot_prop;	/* to be filled */
197
198static ibft_status_t iscsi_parse_ibft_control(iscsi_ibft_ctl_t *ctl_hdr,
199    ushort_t *iscsi_offset_buf);
200
201static ibft_status_t iscsi_parse_ibft_initiator(char *begin_of_ibft,
202    iscsi_ibft_initiator_t *initiator);
203
204static ibft_status_t iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp);
205
206static 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 */
215static ibft_status_t
216iscsi_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 */
244static ibft_status_t
245iscsi_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 */
282static ibft_status_t
283iscsi_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
322static ibft_status_t
323iscsi_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 */
352static ibft_status_t
353iscsi_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
385static ibft_status_t
386iscsi_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 */
432static ibft_status_t
433iscsi_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 */
464static ibft_status_t
465iscsi_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 */
512static ibft_status_t
513iscsi_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 */
669static ibft_status_t
670iscsi_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 */
737void
738ld_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