xref: /onnv-gate/usr/src/uts/i86pc/os/ibft.c (revision 10822:2a6b5dc1374c)
18194SJack.Meng@Sun.COM /*
28194SJack.Meng@Sun.COM  * CDDL HEADER START
38194SJack.Meng@Sun.COM  *
48194SJack.Meng@Sun.COM  * The contents of this file are subject to the terms of the
58194SJack.Meng@Sun.COM  * Common Development and Distribution License (the "License").
68194SJack.Meng@Sun.COM  * You may not use this file except in compliance with the License.
78194SJack.Meng@Sun.COM  *
88194SJack.Meng@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98194SJack.Meng@Sun.COM  * or http://www.opensolaris.org/os/licensing.
108194SJack.Meng@Sun.COM  * See the License for the specific language governing permissions
118194SJack.Meng@Sun.COM  * and limitations under the License.
128194SJack.Meng@Sun.COM  *
138194SJack.Meng@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
148194SJack.Meng@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158194SJack.Meng@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
168194SJack.Meng@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
178194SJack.Meng@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
188194SJack.Meng@Sun.COM  *
198194SJack.Meng@Sun.COM  * CDDL HEADER END
208194SJack.Meng@Sun.COM  */
218194SJack.Meng@Sun.COM 
228194SJack.Meng@Sun.COM /*
238953SVitezslav.Batrla@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
248194SJack.Meng@Sun.COM  * Use is subject to license terms.
258194SJack.Meng@Sun.COM  */
268194SJack.Meng@Sun.COM 
278194SJack.Meng@Sun.COM /*
288194SJack.Meng@Sun.COM  * This is the place to implement ld_ib_props()
298194SJack.Meng@Sun.COM  * For x86 it is to load iBFT and costruct the global ib props
308194SJack.Meng@Sun.COM  */
318194SJack.Meng@Sun.COM 
328194SJack.Meng@Sun.COM #include <sys/types.h>
338194SJack.Meng@Sun.COM #include <sys/cmn_err.h>
348194SJack.Meng@Sun.COM #include <sys/socket.h>
358194SJack.Meng@Sun.COM #include <netinet/in.h>
368194SJack.Meng@Sun.COM #include <sys/mman.h>
378194SJack.Meng@Sun.COM #include <sys/bootprops.h>
388194SJack.Meng@Sun.COM #include <sys/kmem.h>
398194SJack.Meng@Sun.COM #include <sys/psm.h>
408953SVitezslav.Batrla@Sun.COM #include <sys/bootconf.h>
418194SJack.Meng@Sun.COM 
428194SJack.Meng@Sun.COM #ifndef	NULL
438194SJack.Meng@Sun.COM #define	NULL	0
448194SJack.Meng@Sun.COM #endif
458194SJack.Meng@Sun.COM 
468194SJack.Meng@Sun.COM typedef enum ibft_structure_type {
478194SJack.Meng@Sun.COM 	Reserved	=	0,
488194SJack.Meng@Sun.COM 	Control		=	1,
498194SJack.Meng@Sun.COM 	Initiator	=	2,
508194SJack.Meng@Sun.COM 	Nic		=	3,
518194SJack.Meng@Sun.COM 	Target		=	4,
528194SJack.Meng@Sun.COM 	Extensions	=	5,
538194SJack.Meng@Sun.COM 	Type_End
548194SJack.Meng@Sun.COM }ibft_struct_type;
558194SJack.Meng@Sun.COM 
568194SJack.Meng@Sun.COM typedef enum _chap_type {
578194SJack.Meng@Sun.COM 	NO_CHAP		=	0,
588194SJack.Meng@Sun.COM 	CHAP		=	1,
598194SJack.Meng@Sun.COM 	Mutual_CHAP	=	2,
608194SJack.Meng@Sun.COM 	TYPE_UNKNOWN
618194SJack.Meng@Sun.COM }chap_type;
628194SJack.Meng@Sun.COM 
638194SJack.Meng@Sun.COM typedef struct ibft_entry {
648194SJack.Meng@Sun.COM 	int	af;
658194SJack.Meng@Sun.COM 	int	e_port;
668194SJack.Meng@Sun.COM 	char	target_name[224];
678194SJack.Meng@Sun.COM 	char	target_addr[INET6_ADDRSTRLEN];
688194SJack.Meng@Sun.COM }ibft_entry_t;
698194SJack.Meng@Sun.COM 
708194SJack.Meng@Sun.COM typedef struct iSCSI_ibft_tbl_hdr {
718194SJack.Meng@Sun.COM 	char	    Signature[4];
728194SJack.Meng@Sun.COM 	int	    Length;
738194SJack.Meng@Sun.COM 	char	    Revision;
748194SJack.Meng@Sun.COM 	char	    Checksum;
758194SJack.Meng@Sun.COM 	char	    oem_id[6];
768194SJack.Meng@Sun.COM 	char	    oem_table_id[8];
778194SJack.Meng@Sun.COM 	char	    Reserved[24];
788194SJack.Meng@Sun.COM }iscsi_ibft_tbl_hdr_t;
798194SJack.Meng@Sun.COM 
808194SJack.Meng@Sun.COM typedef struct iSCSI_ibft_hdr {
818194SJack.Meng@Sun.COM 	char	    Structure_id;
828194SJack.Meng@Sun.COM 	char	    Version;
838194SJack.Meng@Sun.COM 	ushort_t    Length;
848194SJack.Meng@Sun.COM 	char	    Index;
858194SJack.Meng@Sun.COM 	char	    Flags;
868194SJack.Meng@Sun.COM }iscsi_ibft_hdr_t;
878194SJack.Meng@Sun.COM 
888194SJack.Meng@Sun.COM typedef struct iSCSI_ibft_control {
898194SJack.Meng@Sun.COM 	iscsi_ibft_hdr_t    header;
908194SJack.Meng@Sun.COM 	ushort_t	    Extensions;
918194SJack.Meng@Sun.COM 	ushort_t	    Initiator_offset;
928194SJack.Meng@Sun.COM 	ushort_t	    Nic0_offset;
938194SJack.Meng@Sun.COM 	ushort_t	    Target0_offset;
948194SJack.Meng@Sun.COM 	ushort_t	    Nic1_offset;
958194SJack.Meng@Sun.COM 	ushort_t	    Target1_offset;
968194SJack.Meng@Sun.COM }iscsi_ibft_ctl_t;
978194SJack.Meng@Sun.COM 
988194SJack.Meng@Sun.COM typedef struct iSCSI_ibft_initiator {
998194SJack.Meng@Sun.COM 	iscsi_ibft_hdr_t    header;
1008194SJack.Meng@Sun.COM 	uchar_t		    iSNS_Server[16];
1018194SJack.Meng@Sun.COM 	uchar_t		    SLP_Server[16];
1028194SJack.Meng@Sun.COM 	uchar_t		    Pri_Radius_Server[16];
1038194SJack.Meng@Sun.COM 	uchar_t		    Sec_Radius_Server[16];
1048194SJack.Meng@Sun.COM 	ushort_t	    ini_name_len;
1058194SJack.Meng@Sun.COM 	ushort_t	    ini_name_offset;
1068194SJack.Meng@Sun.COM }iscsi_ibft_initiator_t;
1078194SJack.Meng@Sun.COM 
1088194SJack.Meng@Sun.COM typedef struct iSCSI_ibft_nic {
1098194SJack.Meng@Sun.COM 	iscsi_ibft_hdr_t    header;
1108194SJack.Meng@Sun.COM 	uchar_t		    ip_addr[16];
1118194SJack.Meng@Sun.COM 	char		    Subnet_Mask_Prefix;
1128194SJack.Meng@Sun.COM 	char		    Origin;
1138194SJack.Meng@Sun.COM 	uchar_t		    Gateway[16];
1148194SJack.Meng@Sun.COM 	uchar_t		    Primary_dns[16];
1158194SJack.Meng@Sun.COM 	uchar_t		    Secondary_dns[16];
1168194SJack.Meng@Sun.COM 	uchar_t		    dhcp[16];
1178194SJack.Meng@Sun.COM 	ushort_t	    vlan;
1188194SJack.Meng@Sun.COM 	char		    mac[6];
1198194SJack.Meng@Sun.COM 	ushort_t	    pci_BDF;
1208194SJack.Meng@Sun.COM 	ushort_t	    Hostname_len;
1218194SJack.Meng@Sun.COM 	ushort_t	    Hostname_offset;
1228194SJack.Meng@Sun.COM }iscsi_ibft_nic_t;
1238194SJack.Meng@Sun.COM 
1248194SJack.Meng@Sun.COM typedef struct iSCSI_ibft_target {
1258194SJack.Meng@Sun.COM 	iscsi_ibft_hdr_t    header;
1268194SJack.Meng@Sun.COM 	uchar_t		    ip_addr[16];
1278194SJack.Meng@Sun.COM 	ushort_t	    port;
1288194SJack.Meng@Sun.COM 	uchar_t		    boot_lun[8];
1298194SJack.Meng@Sun.COM 	uchar_t		    chap_type;
1308194SJack.Meng@Sun.COM 	uchar_t		    nic_association;
1318194SJack.Meng@Sun.COM 	ushort_t	    target_name_len;
1328194SJack.Meng@Sun.COM 	ushort_t	    target_name_offset;
1338194SJack.Meng@Sun.COM 	ushort_t	    chap_name_len;
1348194SJack.Meng@Sun.COM 	ushort_t	    chap_name_offset;
1358194SJack.Meng@Sun.COM 	ushort_t	    chap_secret_len;
1368194SJack.Meng@Sun.COM 	ushort_t	    chap_secret_offset;
1378194SJack.Meng@Sun.COM 	ushort_t	    rev_chap_name_len;
1388194SJack.Meng@Sun.COM 	ushort_t	    rev_chap_name_offset;
1398194SJack.Meng@Sun.COM 	ushort_t	    rev_chap_secret_len;
1408194SJack.Meng@Sun.COM 	ushort_t	    rev_chap_secret_offset;
1418194SJack.Meng@Sun.COM }iscsi_ibft_tgt_t;
1428194SJack.Meng@Sun.COM 
1438194SJack.Meng@Sun.COM #define	ISCSI_IBFT_LOWER_ADDR		0x80000	    /* 512K */
1448194SJack.Meng@Sun.COM #define	ISCSI_IBFT_HIGHER_ADDR		0x100000    /* 1024K */
1458194SJack.Meng@Sun.COM #define	ISCSI_IBFT_SIGNATRUE		"iBFT"
1468194SJack.Meng@Sun.COM #define	ISCSI_IBFT_SIGNATURE_LEN	4
1478194SJack.Meng@Sun.COM #define	ISCSI_IBFT_TBL_BUF_LEN		1024
1488194SJack.Meng@Sun.COM #define	ISCSI_IBFT_ALIGNED		16
1498194SJack.Meng@Sun.COM #define	ISCSI_IBFT_CTL_OFFSET		48
1508194SJack.Meng@Sun.COM 
1518194SJack.Meng@Sun.COM #define	IBFT_BLOCK_VALID_YES		0x01	/* bit 0 */
1528194SJack.Meng@Sun.COM #define	IBFT_FIRMWARE_BOOT_SELECTED	0x02	/* bit 1 */
1538194SJack.Meng@Sun.COM #define	IBFT_USE_RADIUS_CHAP		0x04	/* bit 2 */
1548194SJack.Meng@Sun.COM #define	IBFT_USE_GLOBLE			0x04	/* NIC structure */
1558194SJack.Meng@Sun.COM #define	IBFT_USE_RADIUS_RHCAP		0x08	/* bit 3 */
1568194SJack.Meng@Sun.COM 
1578194SJack.Meng@Sun.COM /*
1588194SJack.Meng@Sun.COM  * Currently, we only support initiator offset, NIC0 offset, Target0 offset,
1598194SJack.Meng@Sun.COM  * NIC1 offset and Target1 offset. So the length is 5. If we want to support
1608194SJack.Meng@Sun.COM  * extensions, we should change this number.
1618194SJack.Meng@Sun.COM  */
1628194SJack.Meng@Sun.COM #define	IBFT_OFFSET_BUF_LEN		5
1638194SJack.Meng@Sun.COM #define	IPV4_OFFSET			12
1648194SJack.Meng@Sun.COM 
1658194SJack.Meng@Sun.COM #define	IBFT_INVALID_MSG		"Invalid iBFT table 0x%x"
1668953SVitezslav.Batrla@Sun.COM #define	IBFT_NOPROBE_MSG		"iSCSI boot is disabled"
1678194SJack.Meng@Sun.COM 
1688194SJack.Meng@Sun.COM typedef enum ibft_status {
1698194SJack.Meng@Sun.COM 	IBFT_STATUS_OK = 0,
1708194SJack.Meng@Sun.COM 	/* General error */
1718194SJack.Meng@Sun.COM 	IBFT_STATUS_ERR,
1728194SJack.Meng@Sun.COM 	/* Bad header */
1738194SJack.Meng@Sun.COM 	IBFT_STATUS_BADHDR,
1748194SJack.Meng@Sun.COM 	/* Bad control ID */
1758194SJack.Meng@Sun.COM 	IBFT_STATUS_BADCID,
1768194SJack.Meng@Sun.COM 	/* Bad ip addr */
1778194SJack.Meng@Sun.COM 	IBFT_STATUS_BADIP,
1788194SJack.Meng@Sun.COM 	/* Bad af */
1798194SJack.Meng@Sun.COM 	IBFT_STATUS_BADAF,
1808194SJack.Meng@Sun.COM 	/* Bad chap name */
1818194SJack.Meng@Sun.COM 	IBFT_STATUS_BADCHAPNAME,
1828194SJack.Meng@Sun.COM 	/* Bad chap secret */
1838194SJack.Meng@Sun.COM 	IBFT_STATUS_BADCHAPSEC,
1848194SJack.Meng@Sun.COM 	/* Bad checksum */
1858194SJack.Meng@Sun.COM 	IBFT_STATUS_BADCHECKSUM,
1868194SJack.Meng@Sun.COM 	/* Low memory */
1878194SJack.Meng@Sun.COM 	IBFT_STATUS_LOWMEM,
1888194SJack.Meng@Sun.COM 	/* No table */
1898194SJack.Meng@Sun.COM 	IBFT_STATUS_NOTABLE
1908194SJack.Meng@Sun.COM } ibft_status_t;
1918194SJack.Meng@Sun.COM 
1928194SJack.Meng@Sun.COM extern void *memset(void *s, int c, size_t n);
1938194SJack.Meng@Sun.COM extern int memcmp(const void *s1, const void *s2, size_t n);
1948194SJack.Meng@Sun.COM extern void bcopy(const void *s1, void *s2, size_t n);
1958194SJack.Meng@Sun.COM extern void iscsi_print_boot_property();
1968194SJack.Meng@Sun.COM 
1978953SVitezslav.Batrla@Sun.COM int ibft_noprobe = 0;
1988194SJack.Meng@Sun.COM ib_boot_prop_t boot_property;		/* static allocated */
1998194SJack.Meng@Sun.COM extern ib_boot_prop_t *iscsiboot_prop;	/* to be filled */
2008194SJack.Meng@Sun.COM 
2018194SJack.Meng@Sun.COM static ibft_status_t iscsi_parse_ibft_control(iscsi_ibft_ctl_t *ctl_hdr,
2028194SJack.Meng@Sun.COM     ushort_t *iscsi_offset_buf);
2038194SJack.Meng@Sun.COM 
2048194SJack.Meng@Sun.COM static ibft_status_t iscsi_parse_ibft_initiator(char *begin_of_ibft,
2058194SJack.Meng@Sun.COM     iscsi_ibft_initiator_t *initiator);
2068194SJack.Meng@Sun.COM 
2078194SJack.Meng@Sun.COM static ibft_status_t iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp);
2088194SJack.Meng@Sun.COM 
2098194SJack.Meng@Sun.COM static ibft_status_t iscsi_parse_ibft_target(char *begin_of_ibft,
2108194SJack.Meng@Sun.COM     iscsi_ibft_tgt_t *tgtp);
2118194SJack.Meng@Sun.COM 
2128194SJack.Meng@Sun.COM 
2138194SJack.Meng@Sun.COM /*
2148194SJack.Meng@Sun.COM  * Return value:
2158194SJack.Meng@Sun.COM  * Success: IBFT_STATUS_OK
2168194SJack.Meng@Sun.COM  * Fail: IBFT_STATUS_BADCHECKSUM
2178194SJack.Meng@Sun.COM  */
2188194SJack.Meng@Sun.COM static ibft_status_t
iscsi_ibft_hdr_checksum(iscsi_ibft_tbl_hdr_t * tbl_hdr)2198194SJack.Meng@Sun.COM iscsi_ibft_hdr_checksum(iscsi_ibft_tbl_hdr_t *tbl_hdr)
2208194SJack.Meng@Sun.COM {
2218194SJack.Meng@Sun.COM 	uchar_t	checksum    =	0;
2228194SJack.Meng@Sun.COM 	uchar_t	*start	    =	NULL;
2238194SJack.Meng@Sun.COM 	int	length	    =	0;
2248194SJack.Meng@Sun.COM 	int	i	    =	0;
2258194SJack.Meng@Sun.COM 
2268194SJack.Meng@Sun.COM 	if (tbl_hdr == NULL) {
2278194SJack.Meng@Sun.COM 		return (IBFT_STATUS_BADHDR);
2288194SJack.Meng@Sun.COM 	}
2298194SJack.Meng@Sun.COM 
2308194SJack.Meng@Sun.COM 	length = tbl_hdr->Length;
2318194SJack.Meng@Sun.COM 	start = (uchar_t *)tbl_hdr;
2328194SJack.Meng@Sun.COM 
2338194SJack.Meng@Sun.COM 	for (i = 0; i < length; i++) {
2348194SJack.Meng@Sun.COM 		checksum = checksum + start[i];
2358194SJack.Meng@Sun.COM 	}
2368194SJack.Meng@Sun.COM 
2378194SJack.Meng@Sun.COM 	if (!checksum)
2388194SJack.Meng@Sun.COM 		return (IBFT_STATUS_OK);
2398194SJack.Meng@Sun.COM 	else
2408194SJack.Meng@Sun.COM 		return (IBFT_STATUS_BADCHECKSUM);
2418194SJack.Meng@Sun.COM }
2428194SJack.Meng@Sun.COM 
2438194SJack.Meng@Sun.COM /*
2448194SJack.Meng@Sun.COM  * Now we only support one control structure in the IBFT.
2458194SJack.Meng@Sun.COM  * So there is no Control ID here.
2468194SJack.Meng@Sun.COM  */
2478194SJack.Meng@Sun.COM static ibft_status_t
iscsi_parse_ibft_structure(char * begin_of_ibft,char * buf)2488194SJack.Meng@Sun.COM iscsi_parse_ibft_structure(char *begin_of_ibft, char *buf)
2498194SJack.Meng@Sun.COM {
2508194SJack.Meng@Sun.COM 	iscsi_ibft_hdr_t	*hdr	=   NULL;
2518194SJack.Meng@Sun.COM 	ibft_status_t		ret	=   IBFT_STATUS_OK;
2528194SJack.Meng@Sun.COM 
2538194SJack.Meng@Sun.COM 	if (buf == NULL) {
2548194SJack.Meng@Sun.COM 		return (IBFT_STATUS_ERR);
2558194SJack.Meng@Sun.COM 	}
2568194SJack.Meng@Sun.COM 
2578194SJack.Meng@Sun.COM 	hdr = (iscsi_ibft_hdr_t *)buf;
2588194SJack.Meng@Sun.COM 	switch (hdr->Structure_id) {
2598194SJack.Meng@Sun.COM 		case Initiator:
2608194SJack.Meng@Sun.COM 			ret = iscsi_parse_ibft_initiator(
2618194SJack.Meng@Sun.COM 			    begin_of_ibft,
2628194SJack.Meng@Sun.COM 			    (iscsi_ibft_initiator_t *)buf);
2638194SJack.Meng@Sun.COM 			break;
2648194SJack.Meng@Sun.COM 		case Nic:
2658194SJack.Meng@Sun.COM 			ret = iscsi_parse_ibft_NIC(
2668194SJack.Meng@Sun.COM 			    (iscsi_ibft_nic_t *)buf);
2678194SJack.Meng@Sun.COM 			break;
2688194SJack.Meng@Sun.COM 		case Target:
2698194SJack.Meng@Sun.COM 			ret = iscsi_parse_ibft_target(
2708194SJack.Meng@Sun.COM 			    begin_of_ibft,
2718194SJack.Meng@Sun.COM 			    (iscsi_ibft_tgt_t *)buf);
2728194SJack.Meng@Sun.COM 			break;
2738194SJack.Meng@Sun.COM 		default:
2748194SJack.Meng@Sun.COM 			ret = IBFT_STATUS_BADHDR;
2758194SJack.Meng@Sun.COM 			break;
2768194SJack.Meng@Sun.COM 	}
2778194SJack.Meng@Sun.COM 
2788194SJack.Meng@Sun.COM 	return (ret);
2798194SJack.Meng@Sun.COM }
2808194SJack.Meng@Sun.COM 
2818194SJack.Meng@Sun.COM /*
2828194SJack.Meng@Sun.COM  * Parse the iBFT table
2838194SJack.Meng@Sun.COM  * return IBFT_STATUS_OK upon sucess
2848194SJack.Meng@Sun.COM  */
2858194SJack.Meng@Sun.COM static ibft_status_t
iscsi_parse_ibft_tbl(iscsi_ibft_tbl_hdr_t * tbl_hdr)2868194SJack.Meng@Sun.COM iscsi_parse_ibft_tbl(iscsi_ibft_tbl_hdr_t *tbl_hdr)
2878194SJack.Meng@Sun.COM {
2888194SJack.Meng@Sun.COM 	char		*outbuf	    =	NULL;
2898194SJack.Meng@Sun.COM 	int		i	    =	0;
2908194SJack.Meng@Sun.COM 	ibft_status_t	ret	    =	IBFT_STATUS_OK;
2918194SJack.Meng@Sun.COM 	ushort_t	iscsi_offset_buf[IBFT_OFFSET_BUF_LEN] = {0};
2928194SJack.Meng@Sun.COM 
2938194SJack.Meng@Sun.COM 	if (tbl_hdr == NULL) {
2948194SJack.Meng@Sun.COM 		return (IBFT_STATUS_ERR);
2958194SJack.Meng@Sun.COM 	}
2968194SJack.Meng@Sun.COM 
2978194SJack.Meng@Sun.COM 	if (iscsi_ibft_hdr_checksum(tbl_hdr) != IBFT_STATUS_OK) {
2988194SJack.Meng@Sun.COM 		return (IBFT_STATUS_BADCHECKSUM);
2998194SJack.Meng@Sun.COM 	}
3008194SJack.Meng@Sun.COM 
3018194SJack.Meng@Sun.COM 	outbuf = (char *)tbl_hdr;
3028194SJack.Meng@Sun.COM 
3038194SJack.Meng@Sun.COM 	ret = iscsi_parse_ibft_control(
3048194SJack.Meng@Sun.COM 	    (iscsi_ibft_ctl_t *)&outbuf[ISCSI_IBFT_CTL_OFFSET],
3058194SJack.Meng@Sun.COM 	    iscsi_offset_buf);
3068194SJack.Meng@Sun.COM 
3078194SJack.Meng@Sun.COM 	if (ret == IBFT_STATUS_OK) {
3088194SJack.Meng@Sun.COM 		ret = IBFT_STATUS_ERR;
3098194SJack.Meng@Sun.COM 		for (i = 0; i < IBFT_OFFSET_BUF_LEN; i++) {
3108194SJack.Meng@Sun.COM 			if (iscsi_offset_buf[i] != 0) {
3118194SJack.Meng@Sun.COM 				ret = iscsi_parse_ibft_structure(
3128194SJack.Meng@Sun.COM 				    (char *)tbl_hdr,
3138194SJack.Meng@Sun.COM 				    (char *)tbl_hdr +
3148194SJack.Meng@Sun.COM 				    iscsi_offset_buf[i]);
3158194SJack.Meng@Sun.COM 				if (ret != IBFT_STATUS_OK) {
3168194SJack.Meng@Sun.COM 					return (ret);
3178194SJack.Meng@Sun.COM 				}
3188194SJack.Meng@Sun.COM 			}
3198194SJack.Meng@Sun.COM 		}
3208194SJack.Meng@Sun.COM 	}
3218194SJack.Meng@Sun.COM 
3228194SJack.Meng@Sun.COM 	return (ret);
3238194SJack.Meng@Sun.COM }
3248194SJack.Meng@Sun.COM 
3258194SJack.Meng@Sun.COM static ibft_status_t
iscsi_parse_ibft_control(iscsi_ibft_ctl_t * ctl_hdr,ushort_t * iscsi_offset_buf)3268194SJack.Meng@Sun.COM iscsi_parse_ibft_control(iscsi_ibft_ctl_t *ctl_hdr,
3278194SJack.Meng@Sun.COM     ushort_t	*iscsi_offset_buf)
3288194SJack.Meng@Sun.COM {
3298194SJack.Meng@Sun.COM 	int	    i		=	0;
3308194SJack.Meng@Sun.COM 	ushort_t    *offsetp	=	NULL;
3318194SJack.Meng@Sun.COM 
3328194SJack.Meng@Sun.COM 	if (ctl_hdr == NULL) {
3338194SJack.Meng@Sun.COM 		return (IBFT_STATUS_BADHDR);
3348194SJack.Meng@Sun.COM 	}
3358194SJack.Meng@Sun.COM 
3368194SJack.Meng@Sun.COM 	if (ctl_hdr->header.Structure_id != Control) {
3378194SJack.Meng@Sun.COM 		return (IBFT_STATUS_BADCID);
3388194SJack.Meng@Sun.COM 	}
3398194SJack.Meng@Sun.COM 
3408194SJack.Meng@Sun.COM 	/*
3418194SJack.Meng@Sun.COM 	 * Copy the offsets to offset buffer.
3428194SJack.Meng@Sun.COM 	 */
3438194SJack.Meng@Sun.COM 	for (offsetp = &(ctl_hdr->Initiator_offset); i < IBFT_OFFSET_BUF_LEN;
3448194SJack.Meng@Sun.COM 	    offsetp++) {
3458194SJack.Meng@Sun.COM 		iscsi_offset_buf[i++] = *offsetp;
3468194SJack.Meng@Sun.COM 	}
3478194SJack.Meng@Sun.COM 
3488194SJack.Meng@Sun.COM 	return (IBFT_STATUS_OK);
3498194SJack.Meng@Sun.COM }
3508194SJack.Meng@Sun.COM 
3518194SJack.Meng@Sun.COM /*
3528194SJack.Meng@Sun.COM  * We only copy the "Firmare Boot Selseted" and valid initiator
3538194SJack.Meng@Sun.COM  * to the boot property.
3548194SJack.Meng@Sun.COM  */
3558194SJack.Meng@Sun.COM static ibft_status_t
iscsi_parse_ibft_initiator(char * begin_of_ibft,iscsi_ibft_initiator_t * initiator)3568194SJack.Meng@Sun.COM iscsi_parse_ibft_initiator(char *begin_of_ibft,
3578194SJack.Meng@Sun.COM     iscsi_ibft_initiator_t *initiator)
3588194SJack.Meng@Sun.COM {
3598194SJack.Meng@Sun.COM 	if (initiator == NULL) {
3608194SJack.Meng@Sun.COM 		return (IBFT_STATUS_ERR);
3618194SJack.Meng@Sun.COM 	}
3628194SJack.Meng@Sun.COM 
3638194SJack.Meng@Sun.COM 	if (initiator->header.Structure_id != Initiator) {
3648194SJack.Meng@Sun.COM 		return (IBFT_STATUS_BADHDR);
3658194SJack.Meng@Sun.COM 	}
3668194SJack.Meng@Sun.COM 
3678194SJack.Meng@Sun.COM 	if ((initiator->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
3688194SJack.Meng@Sun.COM 	    (initiator->header.Flags & IBFT_BLOCK_VALID_YES)) {
3698194SJack.Meng@Sun.COM 		/*
3708194SJack.Meng@Sun.COM 		 * If the initiator name exists, we will copy it to our own
3718194SJack.Meng@Sun.COM 		 * property structure
3728194SJack.Meng@Sun.COM 		 */
3738194SJack.Meng@Sun.COM 		if (initiator->ini_name_len != 0) {
3748194SJack.Meng@Sun.COM 			boot_property.boot_init.ini_name =
3758194SJack.Meng@Sun.COM 			    (uchar_t *)kmem_zalloc(
3768194SJack.Meng@Sun.COM 			    initiator->ini_name_len + 1, KM_SLEEP);
377*10822SJack.Meng@Sun.COM 			boot_property.boot_init.ini_name_len =
378*10822SJack.Meng@Sun.COM 			    initiator->ini_name_len + 1;
3798194SJack.Meng@Sun.COM 			(void) snprintf(
3808194SJack.Meng@Sun.COM 			    (char *)boot_property.boot_init.ini_name,
3818194SJack.Meng@Sun.COM 			    initiator->ini_name_len + 1, "%s",
3828194SJack.Meng@Sun.COM 			    begin_of_ibft + initiator->ini_name_offset);
3838194SJack.Meng@Sun.COM 		}
3848194SJack.Meng@Sun.COM 	}
3858194SJack.Meng@Sun.COM 	return (IBFT_STATUS_OK);
3868194SJack.Meng@Sun.COM }
3878194SJack.Meng@Sun.COM 
3888194SJack.Meng@Sun.COM static ibft_status_t
iscsi_parse_ipaddr(uchar_t * source,char * dest,int * af)3898194SJack.Meng@Sun.COM iscsi_parse_ipaddr(uchar_t *source, char *dest, int *af)
3908194SJack.Meng@Sun.COM {
3918194SJack.Meng@Sun.COM 	int i = 0;
3928194SJack.Meng@Sun.COM 
3938194SJack.Meng@Sun.COM 	if (source == NULL) {
3948194SJack.Meng@Sun.COM 		return (IBFT_STATUS_ERR);
3958194SJack.Meng@Sun.COM 	}
3968194SJack.Meng@Sun.COM 
3978194SJack.Meng@Sun.COM 	if (source[0] == 0x00 && source[1] == 0x00 &&
3988194SJack.Meng@Sun.COM 	    source[2] == 0x00 && source[3] == 0x00 &&
3998194SJack.Meng@Sun.COM 	    source[4] == 0x00 && source[5] == 0x00 &&
4008194SJack.Meng@Sun.COM 	    source[6] == 0x00 && source[7] == 0x00 &&
4018194SJack.Meng@Sun.COM 	    source[8] == 0x00 && source[9] == 0x00 &&
4028194SJack.Meng@Sun.COM 	    (source[10] == 0xff) && (source[11] == 0xff)) {
4038194SJack.Meng@Sun.COM 		/*
4048194SJack.Meng@Sun.COM 		 * IPv4 address
4058194SJack.Meng@Sun.COM 		 */
4068194SJack.Meng@Sun.COM 		if (dest != NULL) {
4078194SJack.Meng@Sun.COM 			(void) sprintf(dest, "%d.%d.%d.%d",
4088194SJack.Meng@Sun.COM 			    source[12], source[13], source[14], source[15]);
4098194SJack.Meng@Sun.COM 		}
4108194SJack.Meng@Sun.COM 		if (af != NULL) {
4118194SJack.Meng@Sun.COM 			*af = AF_INET;
4128194SJack.Meng@Sun.COM 		}
4138194SJack.Meng@Sun.COM 	} else {
4148194SJack.Meng@Sun.COM 		if (dest != NULL) {
4158194SJack.Meng@Sun.COM 			for (i = 0; i < 14; i = i + 2) {
4168194SJack.Meng@Sun.COM 				(void) sprintf(dest, "%02x%02x:", source[i],
4178194SJack.Meng@Sun.COM 				    source[i+1]);
4188194SJack.Meng@Sun.COM 				dest = dest + 5;
4198194SJack.Meng@Sun.COM 			}
4208194SJack.Meng@Sun.COM 			(void) sprintf(dest, "%02x%02x",
4218194SJack.Meng@Sun.COM 			    source[i], source[i+1]);
4228194SJack.Meng@Sun.COM 		}
4238194SJack.Meng@Sun.COM 		if (af != NULL) {
4248194SJack.Meng@Sun.COM 			*af = AF_INET6;
4258194SJack.Meng@Sun.COM 		}
4268194SJack.Meng@Sun.COM 	}
4278194SJack.Meng@Sun.COM 
4288194SJack.Meng@Sun.COM 	return (IBFT_STATUS_OK);
4298194SJack.Meng@Sun.COM }
4308194SJack.Meng@Sun.COM 
4318194SJack.Meng@Sun.COM /*
4328194SJack.Meng@Sun.COM  * Copy the ip address from ibft. If IPv4 is used, we should copy
4338194SJack.Meng@Sun.COM  * the address from 12th byte.
4348194SJack.Meng@Sun.COM  */
4358194SJack.Meng@Sun.COM static ibft_status_t
iscsi_copy_ibft_ipaddr(uchar_t * source,void * dest,int * af)4368194SJack.Meng@Sun.COM iscsi_copy_ibft_ipaddr(uchar_t *source, void *dest, int *af)
4378194SJack.Meng@Sun.COM {
4388194SJack.Meng@Sun.COM 	ibft_status_t	ret		=	IBFT_STATUS_OK;
4398194SJack.Meng@Sun.COM 	int		sin_family	=	0;
4408194SJack.Meng@Sun.COM 
4418194SJack.Meng@Sun.COM 	if (source == NULL || dest == NULL) {
4428194SJack.Meng@Sun.COM 		return (IBFT_STATUS_ERR);
4438194SJack.Meng@Sun.COM 	}
4448194SJack.Meng@Sun.COM 	ret = iscsi_parse_ipaddr(source, NULL, &sin_family);
4458194SJack.Meng@Sun.COM 	if (ret != 0) {
4468194SJack.Meng@Sun.COM 		return (IBFT_STATUS_BADIP);
4478194SJack.Meng@Sun.COM 	}
4488194SJack.Meng@Sun.COM 
4498194SJack.Meng@Sun.COM 	if (sin_family == AF_INET) {
4508194SJack.Meng@Sun.COM 		bcopy(source+IPV4_OFFSET, dest, sizeof (struct in_addr));
4518194SJack.Meng@Sun.COM 	} else if (sin_family == AF_INET6) {
4528194SJack.Meng@Sun.COM 		bcopy(source, dest, sizeof (struct in6_addr));
4538194SJack.Meng@Sun.COM 	} else {
4548194SJack.Meng@Sun.COM 		return (IBFT_STATUS_BADAF);
4558194SJack.Meng@Sun.COM 	}
4568194SJack.Meng@Sun.COM 
4578194SJack.Meng@Sun.COM 	if (af != NULL) {
4588194SJack.Meng@Sun.COM 		*af = sin_family;
4598194SJack.Meng@Sun.COM 	}
4608194SJack.Meng@Sun.COM 	return (IBFT_STATUS_OK);
4618194SJack.Meng@Sun.COM }
4628194SJack.Meng@Sun.COM 
4638194SJack.Meng@Sun.COM /*
4648194SJack.Meng@Sun.COM  * Maybe there are multiply NICs are available. We only copy the
4658194SJack.Meng@Sun.COM  * "Firmare Boot Selseted" and valid one to the boot property.
4668194SJack.Meng@Sun.COM  */
4678194SJack.Meng@Sun.COM static ibft_status_t
iscsi_parse_ibft_NIC(iscsi_ibft_nic_t * nicp)4688194SJack.Meng@Sun.COM iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp)
4698194SJack.Meng@Sun.COM {
4708194SJack.Meng@Sun.COM 	ibft_status_t	ret	=	IBFT_STATUS_OK;
4718194SJack.Meng@Sun.COM 	int		af	=	0;
4728194SJack.Meng@Sun.COM 
4738194SJack.Meng@Sun.COM 	if (nicp == NULL) {
4748194SJack.Meng@Sun.COM 		return (IBFT_STATUS_ERR);
4758194SJack.Meng@Sun.COM 	}
4768194SJack.Meng@Sun.COM 
4778194SJack.Meng@Sun.COM 	if (nicp->header.Structure_id != Nic) {
4788194SJack.Meng@Sun.COM 		return (IBFT_STATUS_ERR);
4798194SJack.Meng@Sun.COM 	}
4808194SJack.Meng@Sun.COM 
4818194SJack.Meng@Sun.COM 	if ((nicp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
4828194SJack.Meng@Sun.COM 	    (nicp->header.Flags & IBFT_BLOCK_VALID_YES)) {
4838194SJack.Meng@Sun.COM 		ret = iscsi_copy_ibft_ipaddr(nicp->ip_addr,
4848194SJack.Meng@Sun.COM 		    &boot_property.boot_nic.nic_ip_u, &af);
4858194SJack.Meng@Sun.COM 		if (ret != IBFT_STATUS_OK) {
4868194SJack.Meng@Sun.COM 			return (ret);
4878194SJack.Meng@Sun.COM 		}
4888194SJack.Meng@Sun.COM 
4898194SJack.Meng@Sun.COM 		boot_property.boot_nic.sin_family = af;
4908194SJack.Meng@Sun.COM 
4918194SJack.Meng@Sun.COM 		ret = iscsi_copy_ibft_ipaddr(nicp->Gateway,
4928194SJack.Meng@Sun.COM 		    &boot_property.boot_nic.nic_gw_u, NULL);
4938194SJack.Meng@Sun.COM 		if (ret != IBFT_STATUS_OK) {
4948194SJack.Meng@Sun.COM 			return (ret);
4958194SJack.Meng@Sun.COM 		}
4968194SJack.Meng@Sun.COM 
4978194SJack.Meng@Sun.COM 		ret = iscsi_copy_ibft_ipaddr(nicp->dhcp,
4988194SJack.Meng@Sun.COM 		    &boot_property.boot_nic.nic_dhcp_u, NULL);
4998194SJack.Meng@Sun.COM 		if (ret != IBFT_STATUS_OK) {
5008194SJack.Meng@Sun.COM 			return (ret);
5018194SJack.Meng@Sun.COM 		}
5028194SJack.Meng@Sun.COM 
5038194SJack.Meng@Sun.COM 		bcopy(nicp->mac, boot_property.boot_nic.nic_mac, 6);
5048194SJack.Meng@Sun.COM 		boot_property.boot_nic.sub_mask_prefix =
5058194SJack.Meng@Sun.COM 		    nicp->Subnet_Mask_Prefix;
5068194SJack.Meng@Sun.COM 	}
5078194SJack.Meng@Sun.COM 
5088194SJack.Meng@Sun.COM 	return (IBFT_STATUS_OK);
5098194SJack.Meng@Sun.COM }
5108194SJack.Meng@Sun.COM 
5118194SJack.Meng@Sun.COM /*
5128194SJack.Meng@Sun.COM  * Maybe there are multiply targets are available. We only copy the
5138194SJack.Meng@Sun.COM  * "Firmare Boot Selseted" and valid one to the boot property.
5148194SJack.Meng@Sun.COM  */
5158194SJack.Meng@Sun.COM static ibft_status_t
iscsi_parse_ibft_target(char * begin_of_ibft,iscsi_ibft_tgt_t * tgtp)5168194SJack.Meng@Sun.COM iscsi_parse_ibft_target(char *begin_of_ibft, iscsi_ibft_tgt_t *tgtp)
5178194SJack.Meng@Sun.COM {
5188194SJack.Meng@Sun.COM 	char		*tmp	=   NULL;
5198194SJack.Meng@Sun.COM 	int		af	=   0;
5208194SJack.Meng@Sun.COM 	ibft_status_t	ret	=   IBFT_STATUS_OK;
5218194SJack.Meng@Sun.COM 
5228194SJack.Meng@Sun.COM 	if (tgtp == NULL) {
5238194SJack.Meng@Sun.COM 		return (IBFT_STATUS_ERR);
5248194SJack.Meng@Sun.COM 	}
5258194SJack.Meng@Sun.COM 
5268194SJack.Meng@Sun.COM 	if (tgtp->header.Structure_id != Target) {
5278194SJack.Meng@Sun.COM 		return (IBFT_STATUS_BADHDR);
5288194SJack.Meng@Sun.COM 	}
5298194SJack.Meng@Sun.COM 
5308194SJack.Meng@Sun.COM 	if ((tgtp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
5318194SJack.Meng@Sun.COM 	    (tgtp->header.Flags & IBFT_BLOCK_VALID_YES)) {
5328194SJack.Meng@Sun.COM 		/*
5338194SJack.Meng@Sun.COM 		 * Get Target Address
5348194SJack.Meng@Sun.COM 		 */
5358194SJack.Meng@Sun.COM 		ret = iscsi_copy_ibft_ipaddr(tgtp->ip_addr,
5368194SJack.Meng@Sun.COM 		    &boot_property.boot_tgt.tgt_ip_u, &af);
5378194SJack.Meng@Sun.COM 		if (ret != IBFT_STATUS_OK) {
5388194SJack.Meng@Sun.COM 			return (ret);
5398194SJack.Meng@Sun.COM 		}
5408194SJack.Meng@Sun.COM 		boot_property.boot_tgt.sin_family = af;
5418194SJack.Meng@Sun.COM 		/*
5428194SJack.Meng@Sun.COM 		 * Get Target Name
5438194SJack.Meng@Sun.COM 		 */
5448194SJack.Meng@Sun.COM 		if (tgtp->target_name_len != 0) {
5458194SJack.Meng@Sun.COM 			boot_property.boot_tgt.tgt_name =
5468194SJack.Meng@Sun.COM 			    (uchar_t *)kmem_zalloc(tgtp->target_name_len + 1,
5478194SJack.Meng@Sun.COM 			    KM_SLEEP);
548*10822SJack.Meng@Sun.COM 			boot_property.boot_tgt.tgt_name_len =
549*10822SJack.Meng@Sun.COM 			    tgtp->target_name_len + 1;
5508194SJack.Meng@Sun.COM 			(void) snprintf(
5518194SJack.Meng@Sun.COM 			    (char *)boot_property.boot_tgt.tgt_name,
5528194SJack.Meng@Sun.COM 			    tgtp->target_name_len + 1, "%s",
5538194SJack.Meng@Sun.COM 			    begin_of_ibft + tgtp->target_name_offset);
5548194SJack.Meng@Sun.COM 		} else {
5558194SJack.Meng@Sun.COM 			boot_property.boot_tgt.tgt_name = NULL;
5568194SJack.Meng@Sun.COM 		}
5578194SJack.Meng@Sun.COM 
5588194SJack.Meng@Sun.COM 		/* Get Dest Port */
5598194SJack.Meng@Sun.COM 		boot_property.boot_tgt.tgt_port = tgtp->port;
5608194SJack.Meng@Sun.COM 
5618194SJack.Meng@Sun.COM 		boot_property.boot_tgt.lun_online = 0;
5628194SJack.Meng@Sun.COM 
5638194SJack.Meng@Sun.COM 		/*
5648194SJack.Meng@Sun.COM 		 * Get CHAP secret and name.
5658194SJack.Meng@Sun.COM 		 */
5668194SJack.Meng@Sun.COM 		if (tgtp->chap_type != NO_CHAP) {
5678194SJack.Meng@Sun.COM 			if (tgtp->chap_name_len != 0) {
5688194SJack.Meng@Sun.COM 				boot_property.boot_init.ini_chap_name =
5698194SJack.Meng@Sun.COM 				    (uchar_t *)kmem_zalloc(
5708194SJack.Meng@Sun.COM 				    tgtp->chap_name_len + 1,
5718194SJack.Meng@Sun.COM 				    KM_SLEEP);
572*10822SJack.Meng@Sun.COM 				boot_property.boot_init.ini_chap_name_len =
573*10822SJack.Meng@Sun.COM 				    tgtp->chap_name_len + 1;
5748194SJack.Meng@Sun.COM 				tmp = (char *)
5758194SJack.Meng@Sun.COM 				    boot_property.boot_init.ini_chap_name;
5768194SJack.Meng@Sun.COM 				(void) snprintf(
5778194SJack.Meng@Sun.COM 				    tmp,
5788194SJack.Meng@Sun.COM 				    tgtp->chap_name_len + 1, "%s",
5798194SJack.Meng@Sun.COM 				    begin_of_ibft + tgtp->chap_name_offset);
5808194SJack.Meng@Sun.COM 			} else {
5818194SJack.Meng@Sun.COM 				/*
5828194SJack.Meng@Sun.COM 				 * Just set NULL, initiator is able to deal
5838194SJack.Meng@Sun.COM 				 * with this
5848194SJack.Meng@Sun.COM 				 */
5858194SJack.Meng@Sun.COM 				boot_property.boot_init.ini_chap_name = NULL;
5868194SJack.Meng@Sun.COM 			}
5878194SJack.Meng@Sun.COM 
5888194SJack.Meng@Sun.COM 			if (tgtp->chap_secret_len != 0) {
5898194SJack.Meng@Sun.COM 				boot_property.boot_init.ini_chap_sec =
5908194SJack.Meng@Sun.COM 				    (uchar_t *)kmem_zalloc(
5918194SJack.Meng@Sun.COM 				    tgtp->chap_secret_len + 1,
5928194SJack.Meng@Sun.COM 				    KM_SLEEP);
593*10822SJack.Meng@Sun.COM 				boot_property.boot_init.ini_chap_sec_len =
594*10822SJack.Meng@Sun.COM 				    tgtp->chap_secret_len + 1;
5958194SJack.Meng@Sun.COM 				bcopy(begin_of_ibft +
5968194SJack.Meng@Sun.COM 				    tgtp->chap_secret_offset,
5978194SJack.Meng@Sun.COM 				    boot_property.boot_init.ini_chap_sec,
5988194SJack.Meng@Sun.COM 				    tgtp->chap_secret_len);
5998194SJack.Meng@Sun.COM 			} else {
6008194SJack.Meng@Sun.COM 				boot_property.boot_init.ini_chap_sec = NULL;
6018194SJack.Meng@Sun.COM 				return (IBFT_STATUS_ERR);
6028194SJack.Meng@Sun.COM 			}
6038194SJack.Meng@Sun.COM 
6048194SJack.Meng@Sun.COM 			if (tgtp->chap_type == Mutual_CHAP) {
6058194SJack.Meng@Sun.COM 				if (tgtp->rev_chap_name_len != 0) {
6068194SJack.Meng@Sun.COM 					boot_property.boot_tgt.tgt_chap_name =
6078194SJack.Meng@Sun.COM 					    (uchar_t *)kmem_zalloc(
608*10822SJack.Meng@Sun.COM 					    tgtp->rev_chap_name_len + 1,
6098194SJack.Meng@Sun.COM 					    KM_SLEEP);
610*10822SJack.Meng@Sun.COM 					boot_property.boot_tgt.tgt_chap_name_len
611*10822SJack.Meng@Sun.COM 					    = tgtp->rev_chap_name_len + 1;
6128194SJack.Meng@Sun.COM #define	TGT_CHAP_NAME	boot_property.boot_tgt.tgt_chap_name
6138194SJack.Meng@Sun.COM 					tmp = (char *)TGT_CHAP_NAME;
6148194SJack.Meng@Sun.COM #undef	TGT_CHAP_NAME
6158194SJack.Meng@Sun.COM 					(void) snprintf(
6168194SJack.Meng@Sun.COM 					    tmp,
617*10822SJack.Meng@Sun.COM 					    tgtp->rev_chap_name_len + 1,
6188194SJack.Meng@Sun.COM 					    "%s",
6198194SJack.Meng@Sun.COM 					    begin_of_ibft +
6208194SJack.Meng@Sun.COM 					    tgtp->rev_chap_name_offset);
6218194SJack.Meng@Sun.COM 				} else {
6228194SJack.Meng@Sun.COM 					/*
6238194SJack.Meng@Sun.COM 					 * Just set NULL, initiator is able
6248194SJack.Meng@Sun.COM 					 * to deal with this
6258194SJack.Meng@Sun.COM 					 */
6268194SJack.Meng@Sun.COM 					boot_property.boot_tgt.tgt_chap_name =
6278194SJack.Meng@Sun.COM 					    NULL;
6288194SJack.Meng@Sun.COM 				}
6298194SJack.Meng@Sun.COM 
6308194SJack.Meng@Sun.COM 				if (tgtp->rev_chap_secret_len != 0) {
6318194SJack.Meng@Sun.COM 					boot_property.boot_tgt.tgt_chap_sec =
6328194SJack.Meng@Sun.COM 					    (uchar_t *)kmem_zalloc(
6338194SJack.Meng@Sun.COM 					    tgtp->rev_chap_secret_len + 1,
6348194SJack.Meng@Sun.COM 					    KM_SLEEP);
635*10822SJack.Meng@Sun.COM 					boot_property.boot_tgt.tgt_chap_sec_len
636*10822SJack.Meng@Sun.COM 					    = tgtp->rev_chap_secret_len + 1;
6378194SJack.Meng@Sun.COM 					tmp = (char *)
6388194SJack.Meng@Sun.COM 					    boot_property.boot_tgt.tgt_chap_sec;
6398194SJack.Meng@Sun.COM 					(void) snprintf(
6408194SJack.Meng@Sun.COM 					    tmp,
6418194SJack.Meng@Sun.COM 					    tgtp->rev_chap_secret_len + 1,
6428194SJack.Meng@Sun.COM 					    "%s",
6438194SJack.Meng@Sun.COM 					    begin_of_ibft +
6448194SJack.Meng@Sun.COM 					    tgtp->chap_secret_offset);
6458194SJack.Meng@Sun.COM 				} else {
6468194SJack.Meng@Sun.COM 					boot_property.boot_tgt.tgt_chap_sec =
6478194SJack.Meng@Sun.COM 					    NULL;
6488194SJack.Meng@Sun.COM 					return (IBFT_STATUS_BADCHAPSEC);
6498194SJack.Meng@Sun.COM 				}
6508194SJack.Meng@Sun.COM 			}
6518194SJack.Meng@Sun.COM 		} else {
6528194SJack.Meng@Sun.COM 			boot_property.boot_init.ini_chap_name = NULL;
6538194SJack.Meng@Sun.COM 			boot_property.boot_init.ini_chap_sec = NULL;
6548194SJack.Meng@Sun.COM 		}
6558194SJack.Meng@Sun.COM 
6568194SJack.Meng@Sun.COM 		/*
6578194SJack.Meng@Sun.COM 		 * Get Boot LUN
6588194SJack.Meng@Sun.COM 		 */
6598194SJack.Meng@Sun.COM 		(void) bcopy(tgtp->boot_lun,
6608194SJack.Meng@Sun.COM 		    boot_property.boot_tgt.tgt_boot_lun, 8);
6618194SJack.Meng@Sun.COM 	}
6628194SJack.Meng@Sun.COM 
6638194SJack.Meng@Sun.COM 	return (IBFT_STATUS_OK);
6648194SJack.Meng@Sun.COM }
6658194SJack.Meng@Sun.COM 
6668194SJack.Meng@Sun.COM /*
6678194SJack.Meng@Sun.COM  * This function is used for scanning iBFT from the physical memory.
6688194SJack.Meng@Sun.COM  * Return Value:
6698194SJack.Meng@Sun.COM  * IBFT_STATUS_OK
6708194SJack.Meng@Sun.COM  * IBFT_STATUS_ERR
6718194SJack.Meng@Sun.COM  */
6728194SJack.Meng@Sun.COM static ibft_status_t
iscsi_scan_ibft_tbl(char * ibft_tbl_buf)6738194SJack.Meng@Sun.COM iscsi_scan_ibft_tbl(char *ibft_tbl_buf)
6748194SJack.Meng@Sun.COM {
6758194SJack.Meng@Sun.COM 	int		start;
6768194SJack.Meng@Sun.COM 	void		*va		= NULL;
6778194SJack.Meng@Sun.COM 	int		*len 		= NULL;
6788194SJack.Meng@Sun.COM 	ibft_status_t	ret		= IBFT_STATUS_NOTABLE;
6798194SJack.Meng@Sun.COM 
6808194SJack.Meng@Sun.COM 	for (start = ISCSI_IBFT_LOWER_ADDR; start < ISCSI_IBFT_HIGHER_ADDR;
6818194SJack.Meng@Sun.COM 	    start = start + ISCSI_IBFT_ALIGNED) {
6828194SJack.Meng@Sun.COM 		va = (void *)psm_map((paddr_t)(start&0xffffffff),
6838194SJack.Meng@Sun.COM 		    ISCSI_IBFT_SIGNATURE_LEN,
6848194SJack.Meng@Sun.COM 		    PROT_READ);
6858194SJack.Meng@Sun.COM 
6868194SJack.Meng@Sun.COM 		if (va == NULL) {
6878194SJack.Meng@Sun.COM 			continue;
6888194SJack.Meng@Sun.COM 		}
6898194SJack.Meng@Sun.COM 		if (memcmp(va, ISCSI_IBFT_SIGNATRUE,
6908194SJack.Meng@Sun.COM 		    ISCSI_IBFT_SIGNATURE_LEN) == 0) {
6918194SJack.Meng@Sun.COM 			ret = IBFT_STATUS_ERR;
6928194SJack.Meng@Sun.COM 			/* Acquire table length */
6938194SJack.Meng@Sun.COM 			len = (int *)psm_map(
6948194SJack.Meng@Sun.COM 			    (paddr_t)((start+\
6958194SJack.Meng@Sun.COM 			    ISCSI_IBFT_SIGNATURE_LEN)&0xffffffff),
6968194SJack.Meng@Sun.COM 			    ISCSI_IBFT_SIGNATURE_LEN, PROT_READ);
6978194SJack.Meng@Sun.COM 			if (len == NULL) {
6988194SJack.Meng@Sun.COM 				psm_unmap((caddr_t)va,
6998194SJack.Meng@Sun.COM 				    ISCSI_IBFT_SIGNATURE_LEN);
7008194SJack.Meng@Sun.COM 				continue;
7018194SJack.Meng@Sun.COM 			}
7028194SJack.Meng@Sun.COM 			if (ISCSI_IBFT_LOWER_ADDR + *len <
7038194SJack.Meng@Sun.COM 			    ISCSI_IBFT_HIGHER_ADDR - 1) {
7048194SJack.Meng@Sun.COM 				psm_unmap(va,
7058194SJack.Meng@Sun.COM 				    ISCSI_IBFT_SIGNATURE_LEN);
7068194SJack.Meng@Sun.COM 				va = psm_map((paddr_t)(start&0xffffffff),
7078194SJack.Meng@Sun.COM 				    *len,
7088194SJack.Meng@Sun.COM 				    PROT_READ);
7098194SJack.Meng@Sun.COM 				if (va != NULL) {
7108194SJack.Meng@Sun.COM 					/*
7118194SJack.Meng@Sun.COM 					 * Copy data to our own buffer
7128194SJack.Meng@Sun.COM 					 */
7138194SJack.Meng@Sun.COM 					bcopy(va, ibft_tbl_buf, *len);
7148194SJack.Meng@Sun.COM 					ret = IBFT_STATUS_OK;
7158194SJack.Meng@Sun.COM 				}
7168194SJack.Meng@Sun.COM 				psm_unmap((caddr_t)va, *len);
7178194SJack.Meng@Sun.COM 				psm_unmap((caddr_t)len,
7188194SJack.Meng@Sun.COM 				    ISCSI_IBFT_SIGNATURE_LEN);
7198194SJack.Meng@Sun.COM 				break;
7208194SJack.Meng@Sun.COM 			} else {
7218194SJack.Meng@Sun.COM 				psm_unmap((caddr_t)va,
7228194SJack.Meng@Sun.COM 				    ISCSI_IBFT_SIGNATURE_LEN);
7238194SJack.Meng@Sun.COM 				psm_unmap((caddr_t)len,
7248194SJack.Meng@Sun.COM 				    ISCSI_IBFT_SIGNATURE_LEN);
7258194SJack.Meng@Sun.COM 			}
7268194SJack.Meng@Sun.COM 		} else {
7278194SJack.Meng@Sun.COM 			psm_unmap((caddr_t)va, ISCSI_IBFT_SIGNATURE_LEN);
7288194SJack.Meng@Sun.COM 		}
7298194SJack.Meng@Sun.COM 	}
7308194SJack.Meng@Sun.COM 
7318194SJack.Meng@Sun.COM 	return (ret);
7328194SJack.Meng@Sun.COM }
7338194SJack.Meng@Sun.COM 
7348194SJack.Meng@Sun.COM /*
7358194SJack.Meng@Sun.COM  * Scan the ibft table and store the iSCSI boot properties
7368194SJack.Meng@Sun.COM  * If there is a valid table then set the iscsiboot_prop
7378194SJack.Meng@Sun.COM  * iBF should be off if the host is not intended
7388194SJack.Meng@Sun.COM  * to be booted from iSCSI disk
7398194SJack.Meng@Sun.COM  */
7408194SJack.Meng@Sun.COM void
ld_ib_prop()7418194SJack.Meng@Sun.COM ld_ib_prop()
7428194SJack.Meng@Sun.COM {
7438194SJack.Meng@Sun.COM 	ibft_status_t	ret	=   IBFT_STATUS_OK;
7448194SJack.Meng@Sun.COM 	char		*ibft_tbl_buf;
7458194SJack.Meng@Sun.COM 
7468953SVitezslav.Batrla@Sun.COM 	if (do_bsys_getproplen(NULL, "ibft-noprobe") > 0)
7478953SVitezslav.Batrla@Sun.COM 		ibft_noprobe = 1;
7488953SVitezslav.Batrla@Sun.COM 
7498953SVitezslav.Batrla@Sun.COM 	if (ibft_noprobe != 0) {
7508953SVitezslav.Batrla@Sun.COM 		/*
7518953SVitezslav.Batrla@Sun.COM 		 * Scanning for iBFT may conflict with devices which use memory
7528953SVitezslav.Batrla@Sun.COM 		 * in 640-1024KB of physical address space.  The iBFT
7538953SVitezslav.Batrla@Sun.COM 		 * specification suggests use of low RAM method - scanning
7548953SVitezslav.Batrla@Sun.COM 		 * physical memory 512-1024 KB for iBFT table.  However, the
7558953SVitezslav.Batrla@Sun.COM 		 * Upper Memory Area (UMA) 640-1024 KB may contain device
7568953SVitezslav.Batrla@Sun.COM 		 * memory or memory mapped I/O.  Although reading from I/O area
7578953SVitezslav.Batrla@Sun.COM 		 * is usually fine, the actual behavior depends on device
7588953SVitezslav.Batrla@Sun.COM 		 * implementation.  In some cases, the user may want to disable
7598953SVitezslav.Batrla@Sun.COM 		 * low RAM method and prevent reading from device I/O area.
7608953SVitezslav.Batrla@Sun.COM 		 *
7618953SVitezslav.Batrla@Sun.COM 		 * To disable low RAM method:
7628953SVitezslav.Batrla@Sun.COM 		 * 1) pass "-B ibft-noprobe=1" on kernel command line
7638953SVitezslav.Batrla@Sun.COM 		 * 2) add line "set ibft_noprobe=1" in /etc/system
7648953SVitezslav.Batrla@Sun.COM 		 */
7658953SVitezslav.Batrla@Sun.COM 		cmn_err(CE_NOTE, IBFT_NOPROBE_MSG);
7668953SVitezslav.Batrla@Sun.COM 		return;
7678953SVitezslav.Batrla@Sun.COM 	}
7688953SVitezslav.Batrla@Sun.COM 
7698194SJack.Meng@Sun.COM 	ibft_tbl_buf = (char *)kmem_zalloc(ISCSI_IBFT_TBL_BUF_LEN,
7708194SJack.Meng@Sun.COM 	    KM_SLEEP);
7718194SJack.Meng@Sun.COM 
7728194SJack.Meng@Sun.COM 	if (!ibft_tbl_buf) {
7738194SJack.Meng@Sun.COM 		/* Unlikely to happen */
7748194SJack.Meng@Sun.COM 		cmn_err(CE_NOTE, IBFT_INVALID_MSG,
7758194SJack.Meng@Sun.COM 		    IBFT_STATUS_LOWMEM);
7768194SJack.Meng@Sun.COM 		return;
7778194SJack.Meng@Sun.COM 	}
7788194SJack.Meng@Sun.COM 
7798194SJack.Meng@Sun.COM 	(void) memset(&boot_property, 0, sizeof (boot_property));
7808194SJack.Meng@Sun.COM 	if ((ret = iscsi_scan_ibft_tbl(ibft_tbl_buf)) ==
7818194SJack.Meng@Sun.COM 	    IBFT_STATUS_OK) {
7828194SJack.Meng@Sun.COM 		ret = iscsi_parse_ibft_tbl(
7838194SJack.Meng@Sun.COM 		    (iscsi_ibft_tbl_hdr_t *)ibft_tbl_buf);
7848194SJack.Meng@Sun.COM 		if (ret == IBFT_STATUS_OK) {
7858194SJack.Meng@Sun.COM 			iscsiboot_prop = &boot_property;
7868194SJack.Meng@Sun.COM 			iscsi_print_boot_property();
7878194SJack.Meng@Sun.COM 		} else {
7888194SJack.Meng@Sun.COM 			cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret);
7898194SJack.Meng@Sun.COM 		}
7908194SJack.Meng@Sun.COM 	} else if (ret != IBFT_STATUS_NOTABLE) {
7918194SJack.Meng@Sun.COM 		cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret);
7928194SJack.Meng@Sun.COM 	}
7938194SJack.Meng@Sun.COM 
7948194SJack.Meng@Sun.COM 	kmem_free(ibft_tbl_buf, ISCSI_IBFT_TBL_BUF_LEN);
7958194SJack.Meng@Sun.COM }
796