summaryrefslogtreecommitdiff
path: root/usr/src/uts/i86pc/os/ibft.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/i86pc/os/ibft.c')
-rw-r--r--usr/src/uts/i86pc/os/ibft.c757
1 files changed, 757 insertions, 0 deletions
diff --git a/usr/src/uts/i86pc/os/ibft.c b/usr/src/uts/i86pc/os/ibft.c
new file mode 100644
index 0000000000..141b837988
--- /dev/null
+++ b/usr/src/uts/i86pc/os/ibft.c
@@ -0,0 +1,757 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * This is the place to implement ld_ib_props()
+ * For x86 it is to load iBFT and costruct the global ib props
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/mman.h>
+#include <sys/bootprops.h>
+#include <sys/kmem.h>
+#include <sys/psm.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+typedef enum ibft_structure_type {
+ Reserved = 0,
+ Control = 1,
+ Initiator = 2,
+ Nic = 3,
+ Target = 4,
+ Extensions = 5,
+ Type_End
+}ibft_struct_type;
+
+typedef enum _chap_type {
+ NO_CHAP = 0,
+ CHAP = 1,
+ Mutual_CHAP = 2,
+ TYPE_UNKNOWN
+}chap_type;
+
+typedef struct ibft_entry {
+ int af;
+ int e_port;
+ char target_name[224];
+ char target_addr[INET6_ADDRSTRLEN];
+}ibft_entry_t;
+
+typedef struct iSCSI_ibft_tbl_hdr {
+ char Signature[4];
+ int Length;
+ char Revision;
+ char Checksum;
+ char oem_id[6];
+ char oem_table_id[8];
+ char Reserved[24];
+}iscsi_ibft_tbl_hdr_t;
+
+typedef struct iSCSI_ibft_hdr {
+ char Structure_id;
+ char Version;
+ ushort_t Length;
+ char Index;
+ char Flags;
+}iscsi_ibft_hdr_t;
+
+typedef struct iSCSI_ibft_control {
+ iscsi_ibft_hdr_t header;
+ ushort_t Extensions;
+ ushort_t Initiator_offset;
+ ushort_t Nic0_offset;
+ ushort_t Target0_offset;
+ ushort_t Nic1_offset;
+ ushort_t Target1_offset;
+}iscsi_ibft_ctl_t;
+
+typedef struct iSCSI_ibft_initiator {
+ iscsi_ibft_hdr_t header;
+ uchar_t iSNS_Server[16];
+ uchar_t SLP_Server[16];
+ uchar_t Pri_Radius_Server[16];
+ uchar_t Sec_Radius_Server[16];
+ ushort_t ini_name_len;
+ ushort_t ini_name_offset;
+}iscsi_ibft_initiator_t;
+
+typedef struct iSCSI_ibft_nic {
+ iscsi_ibft_hdr_t header;
+ uchar_t ip_addr[16];
+ char Subnet_Mask_Prefix;
+ char Origin;
+ uchar_t Gateway[16];
+ uchar_t Primary_dns[16];
+ uchar_t Secondary_dns[16];
+ uchar_t dhcp[16];
+ ushort_t vlan;
+ char mac[6];
+ ushort_t pci_BDF;
+ ushort_t Hostname_len;
+ ushort_t Hostname_offset;
+}iscsi_ibft_nic_t;
+
+typedef struct iSCSI_ibft_target {
+ iscsi_ibft_hdr_t header;
+ uchar_t ip_addr[16];
+ ushort_t port;
+ uchar_t boot_lun[8];
+ uchar_t chap_type;
+ uchar_t nic_association;
+ ushort_t target_name_len;
+ ushort_t target_name_offset;
+ ushort_t chap_name_len;
+ ushort_t chap_name_offset;
+ ushort_t chap_secret_len;
+ ushort_t chap_secret_offset;
+ ushort_t rev_chap_name_len;
+ ushort_t rev_chap_name_offset;
+ ushort_t rev_chap_secret_len;
+ ushort_t rev_chap_secret_offset;
+}iscsi_ibft_tgt_t;
+
+#define ISCSI_IBFT_LOWER_ADDR 0x80000 /* 512K */
+#define ISCSI_IBFT_HIGHER_ADDR 0x100000 /* 1024K */
+#define ISCSI_IBFT_SIGNATRUE "iBFT"
+#define ISCSI_IBFT_SIGNATURE_LEN 4
+#define ISCSI_IBFT_TBL_BUF_LEN 1024
+#define ISCSI_IBFT_ALIGNED 16
+#define ISCSI_IBFT_CTL_OFFSET 48
+
+#define IBFT_BLOCK_VALID_YES 0x01 /* bit 0 */
+#define IBFT_FIRMWARE_BOOT_SELECTED 0x02 /* bit 1 */
+#define IBFT_USE_RADIUS_CHAP 0x04 /* bit 2 */
+#define IBFT_USE_GLOBLE 0x04 /* NIC structure */
+#define IBFT_USE_RADIUS_RHCAP 0x08 /* bit 3 */
+
+/*
+ * Currently, we only support initiator offset, NIC0 offset, Target0 offset,
+ * NIC1 offset and Target1 offset. So the length is 5. If we want to support
+ * extensions, we should change this number.
+ */
+#define IBFT_OFFSET_BUF_LEN 5
+#define IPV4_OFFSET 12
+
+#define IBFT_INVALID_MSG "Invalid iBFT table 0x%x"
+
+typedef enum ibft_status {
+ IBFT_STATUS_OK = 0,
+ /* General error */
+ IBFT_STATUS_ERR,
+ /* Bad header */
+ IBFT_STATUS_BADHDR,
+ /* Bad control ID */
+ IBFT_STATUS_BADCID,
+ /* Bad ip addr */
+ IBFT_STATUS_BADIP,
+ /* Bad af */
+ IBFT_STATUS_BADAF,
+ /* Bad chap name */
+ IBFT_STATUS_BADCHAPNAME,
+ /* Bad chap secret */
+ IBFT_STATUS_BADCHAPSEC,
+ /* Bad checksum */
+ IBFT_STATUS_BADCHECKSUM,
+ /* Low memory */
+ IBFT_STATUS_LOWMEM,
+ /* No table */
+ IBFT_STATUS_NOTABLE
+} ibft_status_t;
+
+extern void *memset(void *s, int c, size_t n);
+extern int memcmp(const void *s1, const void *s2, size_t n);
+extern void bcopy(const void *s1, void *s2, size_t n);
+extern void iscsi_print_boot_property();
+
+ib_boot_prop_t boot_property; /* static allocated */
+extern ib_boot_prop_t *iscsiboot_prop; /* to be filled */
+
+static ibft_status_t iscsi_parse_ibft_control(iscsi_ibft_ctl_t *ctl_hdr,
+ ushort_t *iscsi_offset_buf);
+
+static ibft_status_t iscsi_parse_ibft_initiator(char *begin_of_ibft,
+ iscsi_ibft_initiator_t *initiator);
+
+static ibft_status_t iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp);
+
+static ibft_status_t iscsi_parse_ibft_target(char *begin_of_ibft,
+ iscsi_ibft_tgt_t *tgtp);
+
+
+/*
+ * Return value:
+ * Success: IBFT_STATUS_OK
+ * Fail: IBFT_STATUS_BADCHECKSUM
+ */
+static ibft_status_t
+iscsi_ibft_hdr_checksum(iscsi_ibft_tbl_hdr_t *tbl_hdr)
+{
+ uchar_t checksum = 0;
+ uchar_t *start = NULL;
+ int length = 0;
+ int i = 0;
+
+ if (tbl_hdr == NULL) {
+ return (IBFT_STATUS_BADHDR);
+ }
+
+ length = tbl_hdr->Length;
+ start = (uchar_t *)tbl_hdr;
+
+ for (i = 0; i < length; i++) {
+ checksum = checksum + start[i];
+ }
+
+ if (!checksum)
+ return (IBFT_STATUS_OK);
+ else
+ return (IBFT_STATUS_BADCHECKSUM);
+}
+
+/*
+ * Now we only support one control structure in the IBFT.
+ * So there is no Control ID here.
+ */
+static ibft_status_t
+iscsi_parse_ibft_structure(char *begin_of_ibft, char *buf)
+{
+ iscsi_ibft_hdr_t *hdr = NULL;
+ ibft_status_t ret = IBFT_STATUS_OK;
+
+ if (buf == NULL) {
+ return (IBFT_STATUS_ERR);
+ }
+
+ hdr = (iscsi_ibft_hdr_t *)buf;
+ switch (hdr->Structure_id) {
+ case Initiator:
+ ret = iscsi_parse_ibft_initiator(
+ begin_of_ibft,
+ (iscsi_ibft_initiator_t *)buf);
+ break;
+ case Nic:
+ ret = iscsi_parse_ibft_NIC(
+ (iscsi_ibft_nic_t *)buf);
+ break;
+ case Target:
+ ret = iscsi_parse_ibft_target(
+ begin_of_ibft,
+ (iscsi_ibft_tgt_t *)buf);
+ break;
+ default:
+ ret = IBFT_STATUS_BADHDR;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * Parse the iBFT table
+ * return IBFT_STATUS_OK upon sucess
+ */
+static ibft_status_t
+iscsi_parse_ibft_tbl(iscsi_ibft_tbl_hdr_t *tbl_hdr)
+{
+ char *outbuf = NULL;
+ int i = 0;
+ ibft_status_t ret = IBFT_STATUS_OK;
+ ushort_t iscsi_offset_buf[IBFT_OFFSET_BUF_LEN] = {0};
+
+ if (tbl_hdr == NULL) {
+ return (IBFT_STATUS_ERR);
+ }
+
+ if (iscsi_ibft_hdr_checksum(tbl_hdr) != IBFT_STATUS_OK) {
+ return (IBFT_STATUS_BADCHECKSUM);
+ }
+
+ outbuf = (char *)tbl_hdr;
+
+ ret = iscsi_parse_ibft_control(
+ (iscsi_ibft_ctl_t *)&outbuf[ISCSI_IBFT_CTL_OFFSET],
+ iscsi_offset_buf);
+
+ if (ret == IBFT_STATUS_OK) {
+ ret = IBFT_STATUS_ERR;
+ for (i = 0; i < IBFT_OFFSET_BUF_LEN; i++) {
+ if (iscsi_offset_buf[i] != 0) {
+ ret = iscsi_parse_ibft_structure(
+ (char *)tbl_hdr,
+ (char *)tbl_hdr +
+ iscsi_offset_buf[i]);
+ if (ret != IBFT_STATUS_OK) {
+ return (ret);
+ }
+ }
+ }
+ }
+
+ return (ret);
+}
+
+static ibft_status_t
+iscsi_parse_ibft_control(iscsi_ibft_ctl_t *ctl_hdr,
+ ushort_t *iscsi_offset_buf)
+{
+ int i = 0;
+ ushort_t *offsetp = NULL;
+
+ if (ctl_hdr == NULL) {
+ return (IBFT_STATUS_BADHDR);
+ }
+
+ if (ctl_hdr->header.Structure_id != Control) {
+ return (IBFT_STATUS_BADCID);
+ }
+
+ /*
+ * Copy the offsets to offset buffer.
+ */
+ for (offsetp = &(ctl_hdr->Initiator_offset); i < IBFT_OFFSET_BUF_LEN;
+ offsetp++) {
+ iscsi_offset_buf[i++] = *offsetp;
+ }
+
+ return (IBFT_STATUS_OK);
+}
+
+/*
+ * We only copy the "Firmare Boot Selseted" and valid initiator
+ * to the boot property.
+ */
+static ibft_status_t
+iscsi_parse_ibft_initiator(char *begin_of_ibft,
+ iscsi_ibft_initiator_t *initiator)
+{
+ if (initiator == NULL) {
+ return (IBFT_STATUS_ERR);
+ }
+
+ if (initiator->header.Structure_id != Initiator) {
+ return (IBFT_STATUS_BADHDR);
+ }
+
+ if ((initiator->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
+ (initiator->header.Flags & IBFT_BLOCK_VALID_YES)) {
+ /*
+ * If the initiator name exists, we will copy it to our own
+ * property structure
+ */
+ if (initiator->ini_name_len != 0) {
+ boot_property.boot_init.ini_name =
+ (uchar_t *)kmem_zalloc(
+ initiator->ini_name_len + 1, KM_SLEEP);
+ (void) snprintf(
+ (char *)boot_property.boot_init.ini_name,
+ initiator->ini_name_len + 1, "%s",
+ begin_of_ibft + initiator->ini_name_offset);
+ }
+ }
+ return (IBFT_STATUS_OK);
+}
+
+static ibft_status_t
+iscsi_parse_ipaddr(uchar_t *source, char *dest, int *af)
+{
+ int i = 0;
+
+ if (source == NULL) {
+ return (IBFT_STATUS_ERR);
+ }
+
+ if (source[0] == 0x00 && source[1] == 0x00 &&
+ source[2] == 0x00 && source[3] == 0x00 &&
+ source[4] == 0x00 && source[5] == 0x00 &&
+ source[6] == 0x00 && source[7] == 0x00 &&
+ source[8] == 0x00 && source[9] == 0x00 &&
+ (source[10] == 0xff) && (source[11] == 0xff)) {
+ /*
+ * IPv4 address
+ */
+ if (dest != NULL) {
+ (void) sprintf(dest, "%d.%d.%d.%d",
+ source[12], source[13], source[14], source[15]);
+ }
+ if (af != NULL) {
+ *af = AF_INET;
+ }
+ } else {
+ if (dest != NULL) {
+ for (i = 0; i < 14; i = i + 2) {
+ (void) sprintf(dest, "%02x%02x:", source[i],
+ source[i+1]);
+ dest = dest + 5;
+ }
+ (void) sprintf(dest, "%02x%02x",
+ source[i], source[i+1]);
+ }
+ if (af != NULL) {
+ *af = AF_INET6;
+ }
+ }
+
+ return (IBFT_STATUS_OK);
+}
+
+/*
+ * Copy the ip address from ibft. If IPv4 is used, we should copy
+ * the address from 12th byte.
+ */
+static ibft_status_t
+iscsi_copy_ibft_ipaddr(uchar_t *source, void *dest, int *af)
+{
+ ibft_status_t ret = IBFT_STATUS_OK;
+ int sin_family = 0;
+
+ if (source == NULL || dest == NULL) {
+ return (IBFT_STATUS_ERR);
+ }
+ ret = iscsi_parse_ipaddr(source, NULL, &sin_family);
+ if (ret != 0) {
+ return (IBFT_STATUS_BADIP);
+ }
+
+ if (sin_family == AF_INET) {
+ bcopy(source+IPV4_OFFSET, dest, sizeof (struct in_addr));
+ } else if (sin_family == AF_INET6) {
+ bcopy(source, dest, sizeof (struct in6_addr));
+ } else {
+ return (IBFT_STATUS_BADAF);
+ }
+
+ if (af != NULL) {
+ *af = sin_family;
+ }
+ return (IBFT_STATUS_OK);
+}
+
+/*
+ * Maybe there are multiply NICs are available. We only copy the
+ * "Firmare Boot Selseted" and valid one to the boot property.
+ */
+static ibft_status_t
+iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp)
+{
+ ibft_status_t ret = IBFT_STATUS_OK;
+ int af = 0;
+
+ if (nicp == NULL) {
+ return (IBFT_STATUS_ERR);
+ }
+
+ if (nicp->header.Structure_id != Nic) {
+ return (IBFT_STATUS_ERR);
+ }
+
+ if ((nicp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
+ (nicp->header.Flags & IBFT_BLOCK_VALID_YES)) {
+ ret = iscsi_copy_ibft_ipaddr(nicp->ip_addr,
+ &boot_property.boot_nic.nic_ip_u, &af);
+ if (ret != IBFT_STATUS_OK) {
+ return (ret);
+ }
+
+ boot_property.boot_nic.sin_family = af;
+
+ ret = iscsi_copy_ibft_ipaddr(nicp->Gateway,
+ &boot_property.boot_nic.nic_gw_u, NULL);
+ if (ret != IBFT_STATUS_OK) {
+ return (ret);
+ }
+
+ ret = iscsi_copy_ibft_ipaddr(nicp->dhcp,
+ &boot_property.boot_nic.nic_dhcp_u, NULL);
+ if (ret != IBFT_STATUS_OK) {
+ return (ret);
+ }
+
+ bcopy(nicp->mac, boot_property.boot_nic.nic_mac, 6);
+ boot_property.boot_nic.sub_mask_prefix =
+ nicp->Subnet_Mask_Prefix;
+ }
+
+ return (IBFT_STATUS_OK);
+}
+
+/*
+ * Maybe there are multiply targets are available. We only copy the
+ * "Firmare Boot Selseted" and valid one to the boot property.
+ */
+static ibft_status_t
+iscsi_parse_ibft_target(char *begin_of_ibft, iscsi_ibft_tgt_t *tgtp)
+{
+ char *tmp = NULL;
+ int af = 0;
+ ibft_status_t ret = IBFT_STATUS_OK;
+
+ if (tgtp == NULL) {
+ return (IBFT_STATUS_ERR);
+ }
+
+ if (tgtp->header.Structure_id != Target) {
+ return (IBFT_STATUS_BADHDR);
+ }
+
+ if ((tgtp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
+ (tgtp->header.Flags & IBFT_BLOCK_VALID_YES)) {
+ /*
+ * Get Target Address
+ */
+ ret = iscsi_copy_ibft_ipaddr(tgtp->ip_addr,
+ &boot_property.boot_tgt.tgt_ip_u, &af);
+ if (ret != IBFT_STATUS_OK) {
+ return (ret);
+ }
+ boot_property.boot_tgt.sin_family = af;
+ /*
+ * Get Target Name
+ */
+ if (tgtp->target_name_len != 0) {
+ boot_property.boot_tgt.tgt_name =
+ (uchar_t *)kmem_zalloc(tgtp->target_name_len + 1,
+ KM_SLEEP);
+ (void) snprintf(
+ (char *)boot_property.boot_tgt.tgt_name,
+ tgtp->target_name_len + 1, "%s",
+ begin_of_ibft + tgtp->target_name_offset);
+ } else {
+ boot_property.boot_tgt.tgt_name = NULL;
+ }
+
+ /* Get Dest Port */
+ boot_property.boot_tgt.tgt_port = tgtp->port;
+
+ boot_property.boot_tgt.lun_online = 0;
+
+ /*
+ * Get CHAP secret and name.
+ */
+ if (tgtp->chap_type != NO_CHAP) {
+ if (tgtp->chap_name_len != 0) {
+ boot_property.boot_init.ini_chap_name =
+ (uchar_t *)kmem_zalloc(
+ tgtp->chap_name_len + 1,
+ KM_SLEEP);
+ tmp = (char *)
+ boot_property.boot_init.ini_chap_name;
+ (void) snprintf(
+ tmp,
+ tgtp->chap_name_len + 1, "%s",
+ begin_of_ibft + tgtp->chap_name_offset);
+ } else {
+ /*
+ * Just set NULL, initiator is able to deal
+ * with this
+ */
+ boot_property.boot_init.ini_chap_name = NULL;
+ }
+
+ if (tgtp->chap_secret_len != 0) {
+ boot_property.boot_init.ini_chap_sec =
+ (uchar_t *)kmem_zalloc(
+ tgtp->chap_secret_len + 1,
+ KM_SLEEP);
+ bcopy(begin_of_ibft +
+ tgtp->chap_secret_offset,
+ boot_property.boot_init.ini_chap_sec,
+ tgtp->chap_secret_len);
+ } else {
+ boot_property.boot_init.ini_chap_sec = NULL;
+ return (IBFT_STATUS_ERR);
+ }
+
+ if (tgtp->chap_type == Mutual_CHAP) {
+ if (tgtp->rev_chap_name_len != 0) {
+ boot_property.boot_tgt.tgt_chap_name =
+ (uchar_t *)kmem_zalloc(
+ tgtp->chap_name_len + 1,
+ KM_SLEEP);
+#define TGT_CHAP_NAME boot_property.boot_tgt.tgt_chap_name
+ tmp = (char *)TGT_CHAP_NAME;
+#undef TGT_CHAP_NAME
+ (void) snprintf(
+ tmp,
+ tgtp->chap_name_len + 1,
+ "%s",
+ begin_of_ibft +
+ tgtp->rev_chap_name_offset);
+ } else {
+ /*
+ * Just set NULL, initiator is able
+ * to deal with this
+ */
+ boot_property.boot_tgt.tgt_chap_name =
+ NULL;
+ }
+
+ if (tgtp->rev_chap_secret_len != 0) {
+ boot_property.boot_tgt.tgt_chap_sec =
+ (uchar_t *)kmem_zalloc(
+ tgtp->rev_chap_secret_len + 1,
+ KM_SLEEP);
+ tmp = (char *)
+ boot_property.boot_tgt.tgt_chap_sec;
+ (void) snprintf(
+ tmp,
+ tgtp->rev_chap_secret_len + 1,
+ "%s",
+ begin_of_ibft +
+ tgtp->chap_secret_offset);
+ } else {
+ boot_property.boot_tgt.tgt_chap_sec =
+ NULL;
+ return (IBFT_STATUS_BADCHAPSEC);
+ }
+ }
+ } else {
+ boot_property.boot_init.ini_chap_name = NULL;
+ boot_property.boot_init.ini_chap_sec = NULL;
+ }
+
+ /*
+ * Get Boot LUN
+ */
+ (void) bcopy(tgtp->boot_lun,
+ boot_property.boot_tgt.tgt_boot_lun, 8);
+ }
+
+ return (IBFT_STATUS_OK);
+}
+
+/*
+ * This function is used for scanning iBFT from the physical memory.
+ * Return Value:
+ * IBFT_STATUS_OK
+ * IBFT_STATUS_ERR
+ */
+static ibft_status_t
+iscsi_scan_ibft_tbl(char *ibft_tbl_buf)
+{
+ int start;
+ void *va = NULL;
+ int *len = NULL;
+ ibft_status_t ret = IBFT_STATUS_NOTABLE;
+
+ for (start = ISCSI_IBFT_LOWER_ADDR; start < ISCSI_IBFT_HIGHER_ADDR;
+ start = start + ISCSI_IBFT_ALIGNED) {
+ va = (void *)psm_map((paddr_t)(start&0xffffffff),
+ ISCSI_IBFT_SIGNATURE_LEN,
+ PROT_READ);
+
+ if (va == NULL) {
+ continue;
+ }
+ if (memcmp(va, ISCSI_IBFT_SIGNATRUE,
+ ISCSI_IBFT_SIGNATURE_LEN) == 0) {
+ ret = IBFT_STATUS_ERR;
+ /* Acquire table length */
+ len = (int *)psm_map(
+ (paddr_t)((start+\
+ ISCSI_IBFT_SIGNATURE_LEN)&0xffffffff),
+ ISCSI_IBFT_SIGNATURE_LEN, PROT_READ);
+ if (len == NULL) {
+ psm_unmap((caddr_t)va,
+ ISCSI_IBFT_SIGNATURE_LEN);
+ continue;
+ }
+ if (ISCSI_IBFT_LOWER_ADDR + *len <
+ ISCSI_IBFT_HIGHER_ADDR - 1) {
+ psm_unmap(va,
+ ISCSI_IBFT_SIGNATURE_LEN);
+ va = psm_map((paddr_t)(start&0xffffffff),
+ *len,
+ PROT_READ);
+ if (va != NULL) {
+ /*
+ * Copy data to our own buffer
+ */
+ bcopy(va, ibft_tbl_buf, *len);
+ ret = IBFT_STATUS_OK;
+ }
+ psm_unmap((caddr_t)va, *len);
+ psm_unmap((caddr_t)len,
+ ISCSI_IBFT_SIGNATURE_LEN);
+ break;
+ } else {
+ psm_unmap((caddr_t)va,
+ ISCSI_IBFT_SIGNATURE_LEN);
+ psm_unmap((caddr_t)len,
+ ISCSI_IBFT_SIGNATURE_LEN);
+ }
+ } else {
+ psm_unmap((caddr_t)va, ISCSI_IBFT_SIGNATURE_LEN);
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * Scan the ibft table and store the iSCSI boot properties
+ * If there is a valid table then set the iscsiboot_prop
+ * iBF should be off if the host is not intended
+ * to be booted from iSCSI disk
+ */
+void
+ld_ib_prop()
+{
+ ibft_status_t ret = IBFT_STATUS_OK;
+ char *ibft_tbl_buf;
+
+ ibft_tbl_buf = (char *)kmem_zalloc(ISCSI_IBFT_TBL_BUF_LEN,
+ KM_SLEEP);
+
+ if (!ibft_tbl_buf) {
+ /* Unlikely to happen */
+ cmn_err(CE_NOTE, IBFT_INVALID_MSG,
+ IBFT_STATUS_LOWMEM);
+ return;
+ }
+
+ (void) memset(&boot_property, 0, sizeof (boot_property));
+ if ((ret = iscsi_scan_ibft_tbl(ibft_tbl_buf)) ==
+ IBFT_STATUS_OK) {
+ ret = iscsi_parse_ibft_tbl(
+ (iscsi_ibft_tbl_hdr_t *)ibft_tbl_buf);
+ if (ret == IBFT_STATUS_OK) {
+ iscsiboot_prop = &boot_property;
+ iscsi_print_boot_property();
+ } else {
+ cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret);
+ }
+ } else if (ret != IBFT_STATUS_NOTABLE) {
+ cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret);
+ }
+
+ kmem_free(ibft_tbl_buf, ISCSI_IBFT_TBL_BUF_LEN);
+}