ibft.c revision 474eb465d09aa894e5ec02eed423ac868e325855
0N/A/*
1472N/A * CDDL HEADER START
0N/A *
0N/A * The contents of this file are subject to the terms of the
0N/A * Common Development and Distribution License (the "License").
0N/A * You may not use this file except in compliance with the License.
0N/A *
0N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
0N/A * or http://www.opensolaris.org/os/licensing.
0N/A * See the License for the specific language governing permissions
0N/A * and limitations under the License.
0N/A *
0N/A * When distributing Covered Code, include this CDDL HEADER in each
0N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
0N/A * If applicable, add the following below this CDDL HEADER, with the
0N/A * fields enclosed by brackets "[]" replaced with your own identifying
0N/A * information: Portions Copyright [yyyy] [name of copyright owner]
0N/A *
1472N/A * CDDL HEADER END
1472N/A */
1472N/A
0N/A/*
0N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
0N/A * Use is subject to license terms.
1879N/A */
1879N/A
1879N/A/*
1879N/A * This is the place to implement ld_ib_props()
1879N/A * For x86 it is to load iBFT and costruct the global ib props
1879N/A */
0N/A
0N/A#include <sys/types.h>
0N/A#include <sys/cmn_err.h>
0N/A#include <sys/socket.h>
0N/A#include <netinet/in.h>
0N/A#include <sys/mman.h>
0N/A#include <sys/bootprops.h>
0N/A#include <sys/kmem.h>
0N/A#include <sys/psm.h>
0N/A#include <sys/bootconf.h>
0N/A
0N/A#ifndef NULL
0N/A#define NULL 0
0N/A#endif
0N/A
0N/Atypedef enum ibft_structure_type {
0N/A Reserved = 0,
0N/A Control = 1,
0N/A Initiator = 2,
0N/A Nic = 3,
0N/A Target = 4,
0N/A Extensions = 5,
0N/A Type_End
0N/A}ibft_struct_type;
0N/A
0N/Atypedef enum _chap_type {
0N/A NO_CHAP = 0,
0N/A CHAP = 1,
0N/A Mutual_CHAP = 2,
0N/A TYPE_UNKNOWN
0N/A}chap_type;
0N/A
0N/Atypedef struct ibft_entry {
0N/A int af;
0N/A int e_port;
0N/A char target_name[224];
0N/A char target_addr[INET6_ADDRSTRLEN];
0N/A}ibft_entry_t;
0N/A
0N/Atypedef struct iSCSI_ibft_tbl_hdr {
0N/A char Signature[4];
0N/A int Length;
0N/A char Revision;
0N/A char Checksum;
0N/A char oem_id[6];
0N/A char oem_table_id[8];
0N/A char Reserved[24];
0N/A}iscsi_ibft_tbl_hdr_t;
0N/A
0N/Atypedef struct iSCSI_ibft_hdr {
0N/A char Structure_id;
0N/A char Version;
0N/A ushort_t Length;
0N/A char Index;
0N/A char Flags;
0N/A}iscsi_ibft_hdr_t;
1564N/A
1564N/Atypedef struct iSCSI_ibft_control {
0N/A iscsi_ibft_hdr_t header;
0N/A ushort_t Extensions;
0N/A ushort_t Initiator_offset;
0N/A ushort_t Nic0_offset;
1483N/A ushort_t Target0_offset;
0N/A ushort_t Nic1_offset;
0N/A ushort_t Target1_offset;
0N/A}iscsi_ibft_ctl_t;
0N/A
0N/Atypedef struct iSCSI_ibft_initiator {
0N/A iscsi_ibft_hdr_t header;
0N/A uchar_t iSNS_Server[16];
0N/A uchar_t SLP_Server[16];
0N/A uchar_t Pri_Radius_Server[16];
0N/A uchar_t Sec_Radius_Server[16];
0N/A ushort_t ini_name_len;
0N/A ushort_t ini_name_offset;
0N/A}iscsi_ibft_initiator_t;
0N/A
0N/Atypedef struct iSCSI_ibft_nic {
0N/A iscsi_ibft_hdr_t header;
0N/A uchar_t ip_addr[16];
0N/A char Subnet_Mask_Prefix;
0N/A char Origin;
0N/A uchar_t Gateway[16];
0N/A uchar_t Primary_dns[16];
0N/A uchar_t Secondary_dns[16];
989N/A uchar_t dhcp[16];
0N/A ushort_t vlan;
0N/A char mac[6];
0N/A ushort_t pci_BDF;
0N/A ushort_t Hostname_len;
1536N/A ushort_t Hostname_offset;
0N/A}iscsi_ibft_nic_t;
989N/A
989N/Atypedef struct iSCSI_ibft_target {
989N/A iscsi_ibft_hdr_t header;
1202N/A uchar_t ip_addr[16];
989N/A ushort_t port;
989N/A uchar_t boot_lun[8];
989N/A uchar_t chap_type;
0N/A uchar_t nic_association;
0N/A ushort_t target_name_len;
0N/A ushort_t target_name_offset;
1564N/A ushort_t chap_name_len;
1564N/A ushort_t chap_name_offset;
1564N/A ushort_t chap_secret_len;
1564N/A ushort_t chap_secret_offset;
1564N/A ushort_t rev_chap_name_len;
0N/A ushort_t rev_chap_name_offset;
0N/A ushort_t rev_chap_secret_len;
1204N/A ushort_t rev_chap_secret_offset;
1204N/A}iscsi_ibft_tgt_t;
0N/A
1204N/A#define ISCSI_IBFT_LOWER_ADDR 0x80000 /* 512K */
1204N/A#define ISCSI_IBFT_HIGHER_ADDR 0x100000 /* 1024K */
1204N/A#define ISCSI_IBFT_SIGNATRUE "iBFT"
1378N/A#define ISCSI_IBFT_SIGNATURE_LEN 4
1378N/A#define ISCSI_IBFT_TBL_BUF_LEN 1024
1378N/A#define ISCSI_IBFT_ALIGNED 16
116N/A#define ISCSI_IBFT_CTL_OFFSET 48
116N/A
116N/A#define IBFT_BLOCK_VALID_YES 0x01 /* bit 0 */
1682N/A#define IBFT_FIRMWARE_BOOT_SELECTED 0x02 /* bit 1 */
0N/A#define IBFT_USE_RADIUS_CHAP 0x04 /* bit 2 */
1483N/A#define IBFT_USE_GLOBLE 0x04 /* NIC structure */
0N/A#define IBFT_USE_RADIUS_RHCAP 0x08 /* bit 3 */
0N/A
0N/A/*
0N/A * Currently, we only support initiator offset, NIC0 offset, Target0 offset,
0N/A * NIC1 offset and Target1 offset. So the length is 5. If we want to support
0N/A * extensions, we should change this number.
0N/A */
0N/A#define IBFT_OFFSET_BUF_LEN 5
0N/A#define IPV4_OFFSET 12
0N/A
0N/A#define IBFT_INVALID_MSG "Invalid iBFT table 0x%x"
1564N/A#define IBFT_NOPROBE_MSG "iSCSI boot is disabled"
1564N/A
1564N/Atypedef enum ibft_status {
1564N/A IBFT_STATUS_OK = 0,
1564N/A /* General error */
1564N/A IBFT_STATUS_ERR,
1564N/A /* Bad header */
1564N/A IBFT_STATUS_BADHDR,
1564N/A /* Bad control ID */
0N/A IBFT_STATUS_BADCID,
1564N/A /* Bad ip addr */
1564N/A IBFT_STATUS_BADIP,
0N/A /* Bad af */
1564N/A IBFT_STATUS_BADAF,
1564N/A /* Bad chap name */
1564N/A IBFT_STATUS_BADCHAPNAME,
1564N/A /* Bad chap secret */
1564N/A IBFT_STATUS_BADCHAPSEC,
1564N/A /* Bad checksum */
1564N/A IBFT_STATUS_BADCHECKSUM,
1646N/A /* Low memory */
1646N/A IBFT_STATUS_LOWMEM,
1646N/A /* No table */
1646N/A IBFT_STATUS_NOTABLE
0N/A} ibft_status_t;
605N/A
0N/Aextern void *memset(void *s, int c, size_t n);
0N/Aextern int memcmp(const void *s1, const void *s2, size_t n);
0N/Aextern void bcopy(const void *s1, void *s2, size_t n);
0N/Aextern void iscsi_print_boot_property();
989N/A
989N/Aint ibft_noprobe = 0;
0N/Aib_boot_prop_t boot_property; /* static allocated */
0N/Aextern ib_boot_prop_t *iscsiboot_prop; /* to be filled */
0N/A
0N/Astatic ibft_status_t iscsi_parse_ibft_control(iscsi_ibft_ctl_t *ctl_hdr,
0N/A ushort_t *iscsi_offset_buf);
0N/A
0N/Astatic ibft_status_t iscsi_parse_ibft_initiator(char *begin_of_ibft,
0N/A iscsi_ibft_initiator_t *initiator);
0N/A
0N/Astatic ibft_status_t iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp);
0N/A
0N/Astatic ibft_status_t iscsi_parse_ibft_target(char *begin_of_ibft,
0N/A iscsi_ibft_tgt_t *tgtp);
0N/A
0N/A
0N/A/*
0N/A * Return value:
0N/A * Success: IBFT_STATUS_OK
0N/A * Fail: IBFT_STATUS_BADCHECKSUM
0N/A */
0N/Astatic ibft_status_t
0N/Aiscsi_ibft_hdr_checksum(iscsi_ibft_tbl_hdr_t *tbl_hdr)
0N/A{
0N/A uchar_t checksum = 0;
0N/A uchar_t *start = NULL;
0N/A int length = 0;
0N/A int i = 0;
0N/A
0N/A if (tbl_hdr == NULL) {
0N/A return (IBFT_STATUS_BADHDR);
0N/A }
0N/A
0N/A length = tbl_hdr->Length;
0N/A start = (uchar_t *)tbl_hdr;
0N/A
0N/A for (i = 0; i < length; i++) {
0N/A checksum = checksum + start[i];
0N/A }
0N/A
0N/A if (!checksum)
116N/A return (IBFT_STATUS_OK);
116N/A else
116N/A return (IBFT_STATUS_BADCHECKSUM);
116N/A}
116N/A
116N/A/*
116N/A * Now we only support one control structure in the IBFT.
116N/A * So there is no Control ID here.
116N/A */
0N/Astatic ibft_status_t
0N/Aiscsi_parse_ibft_structure(char *begin_of_ibft, char *buf)
0N/A{
0N/A iscsi_ibft_hdr_t *hdr = NULL;
0N/A ibft_status_t ret = IBFT_STATUS_OK;
0N/A
0N/A if (buf == NULL) {
0N/A return (IBFT_STATUS_ERR);
0N/A }
0N/A
0N/A hdr = (iscsi_ibft_hdr_t *)buf;
0N/A switch (hdr->Structure_id) {
0N/A case Initiator:
0N/A ret = iscsi_parse_ibft_initiator(
0N/A begin_of_ibft,
0N/A (iscsi_ibft_initiator_t *)buf);
0N/A break;
0N/A case Nic:
0N/A ret = iscsi_parse_ibft_NIC(
0N/A (iscsi_ibft_nic_t *)buf);
0N/A break;
1109N/A case Target:
1109N/A ret = iscsi_parse_ibft_target(
1141N/A begin_of_ibft,
0N/A (iscsi_ibft_tgt_t *)buf);
0N/A break;
0N/A default:
0N/A ret = IBFT_STATUS_BADHDR;
0N/A break;
0N/A }
0N/A
1564N/A return (ret);
1564N/A}
1564N/A
1564N/A/*
0N/A * Parse the iBFT table
0N/A * return IBFT_STATUS_OK upon sucess
0N/A */
0N/Astatic ibft_status_t
0N/Aiscsi_parse_ibft_tbl(iscsi_ibft_tbl_hdr_t *tbl_hdr)
0N/A{
0N/A char *outbuf = NULL;
0N/A int i = 0;
0N/A ibft_status_t ret = IBFT_STATUS_OK;
0N/A ushort_t iscsi_offset_buf[IBFT_OFFSET_BUF_LEN] = {0};
0N/A
0N/A if (tbl_hdr == NULL) {
0N/A return (IBFT_STATUS_ERR);
0N/A }
0N/A
0N/A if (iscsi_ibft_hdr_checksum(tbl_hdr) != IBFT_STATUS_OK) {
0N/A return (IBFT_STATUS_BADCHECKSUM);
0N/A }
0N/A
0N/A outbuf = (char *)tbl_hdr;
0N/A
0N/A ret = iscsi_parse_ibft_control(
0N/A (iscsi_ibft_ctl_t *)&outbuf[ISCSI_IBFT_CTL_OFFSET],
0N/A iscsi_offset_buf);
0N/A
0N/A if (ret == IBFT_STATUS_OK) {
0N/A ret = IBFT_STATUS_ERR;
116N/A for (i = 0; i < IBFT_OFFSET_BUF_LEN; i++) {
116N/A if (iscsi_offset_buf[i] != 0) {
116N/A ret = iscsi_parse_ibft_structure(
116N/A (char *)tbl_hdr,
116N/A (char *)tbl_hdr +
116N/A iscsi_offset_buf[i]);
116N/A if (ret != IBFT_STATUS_OK) {
116N/A return (ret);
116N/A }
116N/A }
116N/A }
116N/A }
1668N/A
116N/A return (ret);
116N/A}
116N/A
0N/Astatic ibft_status_t
0N/Aiscsi_parse_ibft_control(iscsi_ibft_ctl_t *ctl_hdr,
0N/A ushort_t *iscsi_offset_buf)
0N/A{
0N/A int i = 0;
0N/A ushort_t *offsetp = NULL;
0N/A
0N/A if (ctl_hdr == NULL) {
0N/A return (IBFT_STATUS_BADHDR);
0N/A }
0N/A
0N/A if (ctl_hdr->header.Structure_id != Control) {
0N/A return (IBFT_STATUS_BADCID);
0N/A }
0N/A
0N/A /*
0N/A * Copy the offsets to offset buffer.
1612N/A */
0N/A for (offsetp = &(ctl_hdr->Initiator_offset); i < IBFT_OFFSET_BUF_LEN;
0N/A offsetp++) {
1682N/A iscsi_offset_buf[i++] = *offsetp;
1682N/A }
1682N/A
1668N/A return (IBFT_STATUS_OK);
1682N/A}
1682N/A
1204N/A/*
1204N/A * We only copy the "Firmare Boot Selseted" and valid initiator
1204N/A * to the boot property.
1378N/A */
1483N/Astatic ibft_status_t
1483N/Aiscsi_parse_ibft_initiator(char *begin_of_ibft,
1483N/A iscsi_ibft_initiator_t *initiator)
1204N/A{
1204N/A if (initiator == NULL) {
1204N/A return (IBFT_STATUS_ERR);
1204N/A }
1204N/A
1204N/A if (initiator->header.Structure_id != Initiator) {
1204N/A return (IBFT_STATUS_BADHDR);
1204N/A }
1204N/A
1204N/A if ((initiator->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
0N/A (initiator->header.Flags & IBFT_BLOCK_VALID_YES)) {
1483N/A /*
1682N/A * If the initiator name exists, we will copy it to our own
1668N/A * property structure
1483N/A */
1483N/A if (initiator->ini_name_len != 0) {
1483N/A boot_property.boot_init.ini_name =
1483N/A (uchar_t *)kmem_zalloc(
1483N/A initiator->ini_name_len + 1, KM_SLEEP);
1483N/A (void) snprintf(
1483N/A (char *)boot_property.boot_init.ini_name,
0N/A initiator->ini_name_len + 1, "%s",
0N/A begin_of_ibft + initiator->ini_name_offset);
0N/A }
1483N/A }
1682N/A return (IBFT_STATUS_OK);
1668N/A}
0N/A
1483N/Astatic ibft_status_t
0N/Aiscsi_parse_ipaddr(uchar_t *source, char *dest, int *af)
0N/A{
0N/A int i = 0;
0N/A
0N/A if (source == NULL) {
0N/A return (IBFT_STATUS_ERR);
0N/A }
0N/A
0N/A if (source[0] == 0x00 && source[1] == 0x00 &&
0N/A source[2] == 0x00 && source[3] == 0x00 &&
1564N/A source[4] == 0x00 && source[5] == 0x00 &&
1564N/A source[6] == 0x00 && source[7] == 0x00 &&
1564N/A source[8] == 0x00 && source[9] == 0x00 &&
1564N/A (source[10] == 0xff) && (source[11] == 0xff)) {
1564N/A /*
0N/A * IPv4 address
1109N/A */
1109N/A if (dest != NULL) {
1109N/A (void) sprintf(dest, "%d.%d.%d.%d",
1109N/A source[12], source[13], source[14], source[15]);
1109N/A }
1109N/A if (af != NULL) {
0N/A *af = AF_INET;
0N/A }
0N/A } else {
0N/A if (dest != NULL) {
0N/A for (i = 0; i < 14; i = i + 2) {
1564N/A (void) sprintf(dest, "%02x%02x:", source[i],
1564N/A source[i+1]);
0N/A dest = dest + 5;
0N/A }
0N/A (void) sprintf(dest, "%02x%02x",
0N/A source[i], source[i+1]);
0N/A }
1564N/A if (af != NULL) {
1564N/A *af = AF_INET6;
0N/A }
1564N/A }
0N/A
0N/A return (IBFT_STATUS_OK);
1564N/A}
1564N/A
1564N/A/*
1564N/A * Copy the ip address from ibft. If IPv4 is used, we should copy
1564N/A * the address from 12th byte.
0N/A */
1564N/Astatic ibft_status_t
1564N/Aiscsi_copy_ibft_ipaddr(uchar_t *source, void *dest, int *af)
0N/A{
1564N/A ibft_status_t ret = IBFT_STATUS_OK;
1564N/A int sin_family = 0;
1202N/A
0N/A if (source == NULL || dest == NULL) {
0N/A return (IBFT_STATUS_ERR);
1483N/A }
1483N/A ret = iscsi_parse_ipaddr(source, NULL, &sin_family);
1483N/A if (ret != 0) {
1483N/A return (IBFT_STATUS_BADIP);
1483N/A }
1483N/A
1646N/A if (sin_family == AF_INET) {
1483N/A bcopy(source+IPV4_OFFSET, dest, sizeof (struct in_addr));
1483N/A } else if (sin_family == AF_INET6) {
1483N/A bcopy(source, dest, sizeof (struct in6_addr));
1483N/A } else {
1483N/A return (IBFT_STATUS_BADAF);
1483N/A }
1483N/A
1483N/A if (af != NULL) {
1483N/A *af = sin_family;
1483N/A }
1483N/A return (IBFT_STATUS_OK);
1483N/A}
1483N/A
1483N/A/*
1483N/A * Maybe there are multiply NICs are available. We only copy the
1483N/A * "Firmare Boot Selseted" and valid one to the boot property.
1483N/A */
989N/Astatic ibft_status_t
989N/Aiscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp)
989N/A{
989N/A ibft_status_t ret = IBFT_STATUS_OK;
989N/A int af = 0;
989N/A
989N/A if (nicp == NULL) {
989N/A return (IBFT_STATUS_ERR);
989N/A }
989N/A
989N/A if (nicp->header.Structure_id != Nic) {
989N/A return (IBFT_STATUS_ERR);
989N/A }
989N/A
989N/A if ((nicp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
989N/A (nicp->header.Flags & IBFT_BLOCK_VALID_YES)) {
1202N/A ret = iscsi_copy_ibft_ipaddr(nicp->ip_addr,
1202N/A &boot_property.boot_nic.nic_ip_u, &af);
1202N/A if (ret != IBFT_STATUS_OK) {
989N/A return (ret);
989N/A }
0N/A
0N/A boot_property.boot_nic.sin_family = af;
0N/A
0N/A ret = iscsi_copy_ibft_ipaddr(nicp->Gateway,
0N/A &boot_property.boot_nic.nic_gw_u, NULL);
0N/A if (ret != IBFT_STATUS_OK) {
0N/A return (ret);
0N/A }
0N/A
0N/A ret = iscsi_copy_ibft_ipaddr(nicp->dhcp,
0N/A &boot_property.boot_nic.nic_dhcp_u, NULL);
0N/A if (ret != IBFT_STATUS_OK) {
0N/A return (ret);
0N/A }
0N/A
0N/A bcopy(nicp->mac, boot_property.boot_nic.nic_mac, 6);
0N/A boot_property.boot_nic.sub_mask_prefix =
0N/A nicp->Subnet_Mask_Prefix;
989N/A }
989N/A
0N/A return (IBFT_STATUS_OK);
0N/A}
0N/A
0N/A/*
0N/A * Maybe there are multiply targets are available. We only copy the
0N/A * "Firmare Boot Selseted" and valid one to the boot property.
0N/A */
0N/Astatic ibft_status_t
0N/Aiscsi_parse_ibft_target(char *begin_of_ibft, iscsi_ibft_tgt_t *tgtp)
1668N/A{
0N/A char *tmp = NULL;
0N/A int af = 0;
0N/A ibft_status_t ret = IBFT_STATUS_OK;
0N/A
0N/A if (tgtp == NULL) {
0N/A return (IBFT_STATUS_ERR);
0N/A }
0N/A
0N/A if (tgtp->header.Structure_id != Target) {
0N/A return (IBFT_STATUS_BADHDR);
0N/A }
0N/A
0N/A if ((tgtp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) &&
0N/A (tgtp->header.Flags & IBFT_BLOCK_VALID_YES)) {
0N/A /*
0N/A * Get Target Address
0N/A */
0N/A ret = iscsi_copy_ibft_ipaddr(tgtp->ip_addr,
0N/A &boot_property.boot_tgt.tgt_ip_u, &af);
0N/A if (ret != IBFT_STATUS_OK) {
0N/A return (ret);
0N/A }
0N/A boot_property.boot_tgt.sin_family = af;
0N/A /*
0N/A * Get Target Name
0N/A */
0N/A if (tgtp->target_name_len != 0) {
0N/A boot_property.boot_tgt.tgt_name =
0N/A (uchar_t *)kmem_zalloc(tgtp->target_name_len + 1,
1483N/A KM_SLEEP);
1483N/A (void) snprintf(
989N/A (char *)boot_property.boot_tgt.tgt_name,
989N/A tgtp->target_name_len + 1, "%s",
989N/A begin_of_ibft + tgtp->target_name_offset);
989N/A } else {
989N/A boot_property.boot_tgt.tgt_name = NULL;
989N/A }
989N/A
989N/A /* Get Dest Port */
0N/A boot_property.boot_tgt.tgt_port = tgtp->port;
0N/A
0N/A boot_property.boot_tgt.lun_online = 0;
0N/A
0N/A /*
0N/A * Get CHAP secret and name.
0N/A */
1204N/A if (tgtp->chap_type != NO_CHAP) {
0N/A if (tgtp->chap_name_len != 0) {
0N/A boot_property.boot_init.ini_chap_name =
0N/A (uchar_t *)kmem_zalloc(
0N/A tgtp->chap_name_len + 1,
0N/A KM_SLEEP);
1668N/A tmp = (char *)
0N/A boot_property.boot_init.ini_chap_name;
0N/A (void) snprintf(
0N/A tmp,
0N/A tgtp->chap_name_len + 1, "%s",
0N/A begin_of_ibft + tgtp->chap_name_offset);
0N/A } else {
0N/A /*
0N/A * Just set NULL, initiator is able to deal
0N/A * with this
0N/A */
0N/A boot_property.boot_init.ini_chap_name = NULL;
0N/A }
0N/A
0N/A if (tgtp->chap_secret_len != 0) {
0N/A boot_property.boot_init.ini_chap_sec =
0N/A (uchar_t *)kmem_zalloc(
1204N/A tgtp->chap_secret_len + 1,
1204N/A KM_SLEEP);
1204N/A bcopy(begin_of_ibft +
1204N/A tgtp->chap_secret_offset,
1204N/A boot_property.boot_init.ini_chap_sec,
0N/A tgtp->chap_secret_len);
0N/A } else {
0N/A boot_property.boot_init.ini_chap_sec = NULL;
0N/A return (IBFT_STATUS_ERR);
1204N/A }
1204N/A
1135N/A if (tgtp->chap_type == Mutual_CHAP) {
1135N/A if (tgtp->rev_chap_name_len != 0) {
1135N/A boot_property.boot_tgt.tgt_chap_name =
0N/A (uchar_t *)kmem_zalloc(
0N/A tgtp->chap_name_len + 1,
1536N/A KM_SLEEP);
0N/A#define TGT_CHAP_NAME boot_property.boot_tgt.tgt_chap_name
0N/A tmp = (char *)TGT_CHAP_NAME;
0N/A#undef TGT_CHAP_NAME
0N/A (void) snprintf(
0N/A tmp,
0N/A tgtp->chap_name_len + 1,
1703N/A "%s",
1703N/A begin_of_ibft +
1703N/A tgtp->rev_chap_name_offset);
1703N/A } else {
0N/A /*
100N/A * Just set NULL, initiator is able
100N/A * to deal with this
0N/A */
0N/A boot_property.boot_tgt.tgt_chap_name =
0N/A NULL;
0N/A }
0N/A
0N/A if (tgtp->rev_chap_secret_len != 0) {
0N/A boot_property.boot_tgt.tgt_chap_sec =
0N/A (uchar_t *)kmem_zalloc(
100N/A tgtp->rev_chap_secret_len + 1,
0N/A KM_SLEEP);
1601N/A tmp = (char *)
1601N/A boot_property.boot_tgt.tgt_chap_sec;
0N/A (void) snprintf(
0N/A tmp,
0N/A tgtp->rev_chap_secret_len + 1,
0N/A "%s",
0N/A begin_of_ibft +
1109N/A tgtp->chap_secret_offset);
0N/A } else {
1155N/A boot_property.boot_tgt.tgt_chap_sec =
1155N/A NULL;
1155N/A return (IBFT_STATUS_BADCHAPSEC);
1155N/A }
1155N/A }
1155N/A } else {
1155N/A boot_property.boot_init.ini_chap_name = NULL;
0N/A boot_property.boot_init.ini_chap_sec = NULL;
100N/A }
0N/A
0N/A /*
0N/A * Get Boot LUN
0N/A */
0N/A (void) bcopy(tgtp->boot_lun,
0N/A boot_property.boot_tgt.tgt_boot_lun, 8);
0N/A }
0N/A
0N/A return (IBFT_STATUS_OK);
0N/A}
0N/A
0N/A/*
0N/A * This function is used for scanning iBFT from the physical memory.
0N/A * Return Value:
0N/A * IBFT_STATUS_OK
0N/A * IBFT_STATUS_ERR
0N/A */
0N/Astatic ibft_status_t
0N/Aiscsi_scan_ibft_tbl(char *ibft_tbl_buf)
0N/A{
0N/A int start;
0N/A void *va = NULL;
0N/A int *len = NULL;
0N/A ibft_status_t ret = IBFT_STATUS_NOTABLE;
0N/A
0N/A for (start = ISCSI_IBFT_LOWER_ADDR; start < ISCSI_IBFT_HIGHER_ADDR;
0N/A start = start + ISCSI_IBFT_ALIGNED) {
0N/A va = (void *)psm_map((paddr_t)(start&0xffffffff),
0N/A ISCSI_IBFT_SIGNATURE_LEN,
0N/A PROT_READ);
0N/A
0N/A if (va == NULL) {
0N/A continue;
0N/A }
0N/A if (memcmp(va, ISCSI_IBFT_SIGNATRUE,
0N/A ISCSI_IBFT_SIGNATURE_LEN) == 0) {
0N/A ret = IBFT_STATUS_ERR;
0N/A /* Acquire table length */
0N/A len = (int *)psm_map(
0N/A (paddr_t)((start+\
0N/A ISCSI_IBFT_SIGNATURE_LEN)&0xffffffff),
0N/A ISCSI_IBFT_SIGNATURE_LEN, PROT_READ);
0N/A if (len == NULL) {
0N/A psm_unmap((caddr_t)va,
0N/A ISCSI_IBFT_SIGNATURE_LEN);
0N/A continue;
0N/A }
0N/A if (ISCSI_IBFT_LOWER_ADDR + *len <
0N/A ISCSI_IBFT_HIGHER_ADDR - 1) {
0N/A psm_unmap(va,
0N/A ISCSI_IBFT_SIGNATURE_LEN);
0N/A va = psm_map((paddr_t)(start&0xffffffff),
0N/A *len,
0N/A PROT_READ);
0N/A if (va != NULL) {
0N/A /*
0N/A * Copy data to our own buffer
0N/A */
0N/A bcopy(va, ibft_tbl_buf, *len);
0N/A ret = IBFT_STATUS_OK;
0N/A }
0N/A psm_unmap((caddr_t)va, *len);
0N/A psm_unmap((caddr_t)len,
0N/A ISCSI_IBFT_SIGNATURE_LEN);
0N/A break;
0N/A } else {
0N/A psm_unmap((caddr_t)va,
0N/A ISCSI_IBFT_SIGNATURE_LEN);
0N/A psm_unmap((caddr_t)len,
0N/A ISCSI_IBFT_SIGNATURE_LEN);
1879N/A }
1879N/A } 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;
if (do_bsys_getproplen(NULL, "ibft-noprobe") > 0)
ibft_noprobe = 1;
if (ibft_noprobe != 0) {
/*
* Scanning for iBFT may conflict with devices which use memory
* in 640-1024KB of physical address space. The iBFT
* specification suggests use of low RAM method - scanning
* physical memory 512-1024 KB for iBFT table. However, the
* Upper Memory Area (UMA) 640-1024 KB may contain device
* memory or memory mapped I/O. Although reading from I/O area
* is usually fine, the actual behavior depends on device
* implementation. In some cases, the user may want to disable
* low RAM method and prevent reading from device I/O area.
*
* To disable low RAM method:
* 1) pass "-B ibft-noprobe=1" on kernel command line
* 2) add line "set ibft_noprobe=1" in /etc/system
*/
cmn_err(CE_NOTE, IBFT_NOPROBE_MSG);
return;
}
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);
}