ibft.c revision dedec472759b1a1a25044d504201ef59ccbffb56
/*
* 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
* 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 2009 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/bootprops.h>
#include <sys/bootconf.h>
#ifndef NULL
#define NULL 0
#endif
typedef enum ibft_structure_type {
Reserved = 0,
Control = 1,
Initiator = 2,
Nic = 3,
Target = 4,
Extensions = 5,
typedef enum _chap_type {
NO_CHAP = 0,
CHAP = 1,
Mutual_CHAP = 2,
typedef struct ibft_entry {
int af;
int e_port;
char target_name[224];
char target_addr[INET6_ADDRSTRLEN];
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];
typedef struct iSCSI_ibft_hdr {
char Structure_id;
char Version;
char Index;
char Flags;
typedef struct iSCSI_ibft_control {
typedef struct iSCSI_ibft_initiator {
typedef struct iSCSI_ibft_nic {
char Subnet_Mask_Prefix;
char Origin;
char mac[6];
typedef struct iSCSI_ibft_target {
#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
/*
* 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"
#define IBFT_NOPROBE_MSG "iSCSI boot is disabled"
typedef enum ibft_status {
IBFT_STATUS_OK = 0,
/* General error */
/* Bad header */
/* Bad control ID */
/* Bad ip addr */
/* Bad af */
/* Bad chap name */
/* Bad chap secret */
/* Bad checksum */
/* Low memory */
/* No table */
extern void iscsi_print_boot_property();
int ibft_noprobe = 0;
/*
* Return value:
* Success: IBFT_STATUS_OK
* Fail: IBFT_STATUS_BADCHECKSUM
*/
static ibft_status_t
{
int length = 0;
int i = 0;
return (IBFT_STATUS_BADHDR);
}
for (i = 0; i < length; 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
{
return (IBFT_STATUS_ERR);
}
switch (hdr->Structure_id) {
case Initiator:
break;
case Nic:
(iscsi_ibft_nic_t *)buf);
break;
case Target:
(iscsi_ibft_tgt_t *)buf);
break;
default:
break;
}
return (ret);
}
/*
* Parse the iBFT table
* return IBFT_STATUS_OK upon sucess
*/
static ibft_status_t
{
int i = 0;
return (IBFT_STATUS_ERR);
}
return (IBFT_STATUS_BADCHECKSUM);
}
if (ret == IBFT_STATUS_OK) {
for (i = 0; i < IBFT_OFFSET_BUF_LEN; i++) {
if (iscsi_offset_buf[i] != 0) {
(char *)tbl_hdr,
(char *)tbl_hdr +
iscsi_offset_buf[i]);
if (ret != IBFT_STATUS_OK) {
return (ret);
}
}
}
}
return (ret);
}
static ibft_status_t
{
int i = 0;
return (IBFT_STATUS_BADHDR);
}
return (IBFT_STATUS_BADCID);
}
/*
* Copy the offsets to offset buffer.
*/
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
{
return (IBFT_STATUS_ERR);
}
return (IBFT_STATUS_BADHDR);
}
/*
* If the initiator name exists, we will copy it to our own
* property structure
*/
if (initiator->ini_name_len != 0) {
(uchar_t *)kmem_zalloc(
(void) snprintf(
}
}
return (IBFT_STATUS_OK);
}
static ibft_status_t
{
int i = 0;
return (IBFT_STATUS_ERR);
}
/*
* IPv4 address
*/
}
}
} else {
for (i = 0; i < 14; i = i + 2) {
source[i+1]);
}
}
}
}
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
{
int sin_family = 0;
return (IBFT_STATUS_ERR);
}
if (ret != 0) {
return (IBFT_STATUS_BADIP);
}
if (sin_family == AF_INET) {
} else if (sin_family == AF_INET6) {
} else {
return (IBFT_STATUS_BADAF);
}
*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
{
int af = 0;
return (IBFT_STATUS_ERR);
}
return (IBFT_STATUS_ERR);
}
if (ret != IBFT_STATUS_OK) {
return (ret);
}
if (ret != IBFT_STATUS_OK) {
return (ret);
}
if (ret != IBFT_STATUS_OK) {
return (ret);
}
}
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
{
int af = 0;
return (IBFT_STATUS_ERR);
}
return (IBFT_STATUS_BADHDR);
}
/*
* Get Target Address
*/
if (ret != IBFT_STATUS_OK) {
return (ret);
}
/*
* Get Target Name
*/
if (tgtp->target_name_len != 0) {
KM_SLEEP);
(void) snprintf(
} else {
}
/* Get Dest Port */
/*
* Get CHAP secret and name.
*/
if (tgtp->chap_name_len != 0) {
(uchar_t *)kmem_zalloc(
KM_SLEEP);
tmp = (char *)
(void) snprintf(
tmp,
} else {
/*
* Just set NULL, initiator is able to deal
* with this
*/
}
if (tgtp->chap_secret_len != 0) {
(uchar_t *)kmem_zalloc(
KM_SLEEP);
} else {
return (IBFT_STATUS_ERR);
}
if (tgtp->rev_chap_name_len != 0) {
(uchar_t *)kmem_zalloc(
KM_SLEEP);
tmp = (char *)TGT_CHAP_NAME;
(void) snprintf(
tmp,
"%s",
} else {
/*
* Just set NULL, initiator is able
* to deal with this
*/
NULL;
}
if (tgtp->rev_chap_secret_len != 0) {
(uchar_t *)kmem_zalloc(
KM_SLEEP);
tmp = (char *)
(void) snprintf(
tmp,
"%s",
} else {
NULL;
return (IBFT_STATUS_BADCHAPSEC);
}
}
} else {
}
/*
* Get Boot LUN
*/
}
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;
continue;
}
ISCSI_IBFT_SIGNATURE_LEN) == 0) {
/* Acquire table length */
ISCSI_IBFT_SIGNATURE_LEN)&0xffffffff),
continue;
}
if (ISCSI_IBFT_LOWER_ADDR + *len <
ISCSI_IBFT_HIGHER_ADDR - 1) {
*len,
/*
* Copy data to our own buffer
*/
}
break;
} else {
}
} else {
}
}
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
{
char *ibft_tbl_buf;
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
*/
return;
}
KM_SLEEP);
if (!ibft_tbl_buf) {
/* Unlikely to happen */
return;
}
if (ret == IBFT_STATUS_OK) {
} else {
}
} else if (ret != IBFT_STATUS_NOTABLE) {
}
}