1*6cefaae1SJack Meng /* 2*6cefaae1SJack Meng * CDDL HEADER START 3*6cefaae1SJack Meng * 4*6cefaae1SJack Meng * The contents of this file are subject to the terms of the 5*6cefaae1SJack Meng * Common Development and Distribution License (the "License"). 6*6cefaae1SJack Meng * You may not use this file except in compliance with the License. 7*6cefaae1SJack Meng * 8*6cefaae1SJack Meng * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*6cefaae1SJack Meng * or http://www.opensolaris.org/os/licensing. 10*6cefaae1SJack Meng * See the License for the specific language governing permissions 11*6cefaae1SJack Meng * and limitations under the License. 12*6cefaae1SJack Meng * 13*6cefaae1SJack Meng * When distributing Covered Code, include this CDDL HEADER in each 14*6cefaae1SJack Meng * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*6cefaae1SJack Meng * If applicable, add the following below this CDDL HEADER, with the 16*6cefaae1SJack Meng * fields enclosed by brackets "[]" replaced with your own identifying 17*6cefaae1SJack Meng * information: Portions Copyright [yyyy] [name of copyright owner] 18*6cefaae1SJack Meng * 19*6cefaae1SJack Meng * CDDL HEADER END 20*6cefaae1SJack Meng */ 21*6cefaae1SJack Meng 22*6cefaae1SJack Meng /* 23*6cefaae1SJack Meng * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*6cefaae1SJack Meng * Use is subject to license terms. 25*6cefaae1SJack Meng */ 26*6cefaae1SJack Meng 27*6cefaae1SJack Meng /* 28*6cefaae1SJack Meng * This is the place to implement ld_ib_props() 29*6cefaae1SJack Meng * For x86 it is to load iBFT and costruct the global ib props 30*6cefaae1SJack Meng */ 31*6cefaae1SJack Meng 32*6cefaae1SJack Meng #include <sys/types.h> 33*6cefaae1SJack Meng #include <sys/cmn_err.h> 34*6cefaae1SJack Meng #include <sys/socket.h> 35*6cefaae1SJack Meng #include <netinet/in.h> 36*6cefaae1SJack Meng #include <sys/mman.h> 37*6cefaae1SJack Meng #include <sys/bootprops.h> 38*6cefaae1SJack Meng #include <sys/kmem.h> 39*6cefaae1SJack Meng #include <sys/psm.h> 40*6cefaae1SJack Meng 41*6cefaae1SJack Meng #ifndef NULL 42*6cefaae1SJack Meng #define NULL 0 43*6cefaae1SJack Meng #endif 44*6cefaae1SJack Meng 45*6cefaae1SJack Meng typedef enum ibft_structure_type { 46*6cefaae1SJack Meng Reserved = 0, 47*6cefaae1SJack Meng Control = 1, 48*6cefaae1SJack Meng Initiator = 2, 49*6cefaae1SJack Meng Nic = 3, 50*6cefaae1SJack Meng Target = 4, 51*6cefaae1SJack Meng Extensions = 5, 52*6cefaae1SJack Meng Type_End 53*6cefaae1SJack Meng }ibft_struct_type; 54*6cefaae1SJack Meng 55*6cefaae1SJack Meng typedef enum _chap_type { 56*6cefaae1SJack Meng NO_CHAP = 0, 57*6cefaae1SJack Meng CHAP = 1, 58*6cefaae1SJack Meng Mutual_CHAP = 2, 59*6cefaae1SJack Meng TYPE_UNKNOWN 60*6cefaae1SJack Meng }chap_type; 61*6cefaae1SJack Meng 62*6cefaae1SJack Meng typedef struct ibft_entry { 63*6cefaae1SJack Meng int af; 64*6cefaae1SJack Meng int e_port; 65*6cefaae1SJack Meng char target_name[224]; 66*6cefaae1SJack Meng char target_addr[INET6_ADDRSTRLEN]; 67*6cefaae1SJack Meng }ibft_entry_t; 68*6cefaae1SJack Meng 69*6cefaae1SJack Meng typedef struct iSCSI_ibft_tbl_hdr { 70*6cefaae1SJack Meng char Signature[4]; 71*6cefaae1SJack Meng int Length; 72*6cefaae1SJack Meng char Revision; 73*6cefaae1SJack Meng char Checksum; 74*6cefaae1SJack Meng char oem_id[6]; 75*6cefaae1SJack Meng char oem_table_id[8]; 76*6cefaae1SJack Meng char Reserved[24]; 77*6cefaae1SJack Meng }iscsi_ibft_tbl_hdr_t; 78*6cefaae1SJack Meng 79*6cefaae1SJack Meng typedef struct iSCSI_ibft_hdr { 80*6cefaae1SJack Meng char Structure_id; 81*6cefaae1SJack Meng char Version; 82*6cefaae1SJack Meng ushort_t Length; 83*6cefaae1SJack Meng char Index; 84*6cefaae1SJack Meng char Flags; 85*6cefaae1SJack Meng }iscsi_ibft_hdr_t; 86*6cefaae1SJack Meng 87*6cefaae1SJack Meng typedef struct iSCSI_ibft_control { 88*6cefaae1SJack Meng iscsi_ibft_hdr_t header; 89*6cefaae1SJack Meng ushort_t Extensions; 90*6cefaae1SJack Meng ushort_t Initiator_offset; 91*6cefaae1SJack Meng ushort_t Nic0_offset; 92*6cefaae1SJack Meng ushort_t Target0_offset; 93*6cefaae1SJack Meng ushort_t Nic1_offset; 94*6cefaae1SJack Meng ushort_t Target1_offset; 95*6cefaae1SJack Meng }iscsi_ibft_ctl_t; 96*6cefaae1SJack Meng 97*6cefaae1SJack Meng typedef struct iSCSI_ibft_initiator { 98*6cefaae1SJack Meng iscsi_ibft_hdr_t header; 99*6cefaae1SJack Meng uchar_t iSNS_Server[16]; 100*6cefaae1SJack Meng uchar_t SLP_Server[16]; 101*6cefaae1SJack Meng uchar_t Pri_Radius_Server[16]; 102*6cefaae1SJack Meng uchar_t Sec_Radius_Server[16]; 103*6cefaae1SJack Meng ushort_t ini_name_len; 104*6cefaae1SJack Meng ushort_t ini_name_offset; 105*6cefaae1SJack Meng }iscsi_ibft_initiator_t; 106*6cefaae1SJack Meng 107*6cefaae1SJack Meng typedef struct iSCSI_ibft_nic { 108*6cefaae1SJack Meng iscsi_ibft_hdr_t header; 109*6cefaae1SJack Meng uchar_t ip_addr[16]; 110*6cefaae1SJack Meng char Subnet_Mask_Prefix; 111*6cefaae1SJack Meng char Origin; 112*6cefaae1SJack Meng uchar_t Gateway[16]; 113*6cefaae1SJack Meng uchar_t Primary_dns[16]; 114*6cefaae1SJack Meng uchar_t Secondary_dns[16]; 115*6cefaae1SJack Meng uchar_t dhcp[16]; 116*6cefaae1SJack Meng ushort_t vlan; 117*6cefaae1SJack Meng char mac[6]; 118*6cefaae1SJack Meng ushort_t pci_BDF; 119*6cefaae1SJack Meng ushort_t Hostname_len; 120*6cefaae1SJack Meng ushort_t Hostname_offset; 121*6cefaae1SJack Meng }iscsi_ibft_nic_t; 122*6cefaae1SJack Meng 123*6cefaae1SJack Meng typedef struct iSCSI_ibft_target { 124*6cefaae1SJack Meng iscsi_ibft_hdr_t header; 125*6cefaae1SJack Meng uchar_t ip_addr[16]; 126*6cefaae1SJack Meng ushort_t port; 127*6cefaae1SJack Meng uchar_t boot_lun[8]; 128*6cefaae1SJack Meng uchar_t chap_type; 129*6cefaae1SJack Meng uchar_t nic_association; 130*6cefaae1SJack Meng ushort_t target_name_len; 131*6cefaae1SJack Meng ushort_t target_name_offset; 132*6cefaae1SJack Meng ushort_t chap_name_len; 133*6cefaae1SJack Meng ushort_t chap_name_offset; 134*6cefaae1SJack Meng ushort_t chap_secret_len; 135*6cefaae1SJack Meng ushort_t chap_secret_offset; 136*6cefaae1SJack Meng ushort_t rev_chap_name_len; 137*6cefaae1SJack Meng ushort_t rev_chap_name_offset; 138*6cefaae1SJack Meng ushort_t rev_chap_secret_len; 139*6cefaae1SJack Meng ushort_t rev_chap_secret_offset; 140*6cefaae1SJack Meng }iscsi_ibft_tgt_t; 141*6cefaae1SJack Meng 142*6cefaae1SJack Meng #define ISCSI_IBFT_LOWER_ADDR 0x80000 /* 512K */ 143*6cefaae1SJack Meng #define ISCSI_IBFT_HIGHER_ADDR 0x100000 /* 1024K */ 144*6cefaae1SJack Meng #define ISCSI_IBFT_SIGNATRUE "iBFT" 145*6cefaae1SJack Meng #define ISCSI_IBFT_SIGNATURE_LEN 4 146*6cefaae1SJack Meng #define ISCSI_IBFT_TBL_BUF_LEN 1024 147*6cefaae1SJack Meng #define ISCSI_IBFT_ALIGNED 16 148*6cefaae1SJack Meng #define ISCSI_IBFT_CTL_OFFSET 48 149*6cefaae1SJack Meng 150*6cefaae1SJack Meng #define IBFT_BLOCK_VALID_YES 0x01 /* bit 0 */ 151*6cefaae1SJack Meng #define IBFT_FIRMWARE_BOOT_SELECTED 0x02 /* bit 1 */ 152*6cefaae1SJack Meng #define IBFT_USE_RADIUS_CHAP 0x04 /* bit 2 */ 153*6cefaae1SJack Meng #define IBFT_USE_GLOBLE 0x04 /* NIC structure */ 154*6cefaae1SJack Meng #define IBFT_USE_RADIUS_RHCAP 0x08 /* bit 3 */ 155*6cefaae1SJack Meng 156*6cefaae1SJack Meng /* 157*6cefaae1SJack Meng * Currently, we only support initiator offset, NIC0 offset, Target0 offset, 158*6cefaae1SJack Meng * NIC1 offset and Target1 offset. So the length is 5. If we want to support 159*6cefaae1SJack Meng * extensions, we should change this number. 160*6cefaae1SJack Meng */ 161*6cefaae1SJack Meng #define IBFT_OFFSET_BUF_LEN 5 162*6cefaae1SJack Meng #define IPV4_OFFSET 12 163*6cefaae1SJack Meng 164*6cefaae1SJack Meng #define IBFT_INVALID_MSG "Invalid iBFT table 0x%x" 165*6cefaae1SJack Meng 166*6cefaae1SJack Meng typedef enum ibft_status { 167*6cefaae1SJack Meng IBFT_STATUS_OK = 0, 168*6cefaae1SJack Meng /* General error */ 169*6cefaae1SJack Meng IBFT_STATUS_ERR, 170*6cefaae1SJack Meng /* Bad header */ 171*6cefaae1SJack Meng IBFT_STATUS_BADHDR, 172*6cefaae1SJack Meng /* Bad control ID */ 173*6cefaae1SJack Meng IBFT_STATUS_BADCID, 174*6cefaae1SJack Meng /* Bad ip addr */ 175*6cefaae1SJack Meng IBFT_STATUS_BADIP, 176*6cefaae1SJack Meng /* Bad af */ 177*6cefaae1SJack Meng IBFT_STATUS_BADAF, 178*6cefaae1SJack Meng /* Bad chap name */ 179*6cefaae1SJack Meng IBFT_STATUS_BADCHAPNAME, 180*6cefaae1SJack Meng /* Bad chap secret */ 181*6cefaae1SJack Meng IBFT_STATUS_BADCHAPSEC, 182*6cefaae1SJack Meng /* Bad checksum */ 183*6cefaae1SJack Meng IBFT_STATUS_BADCHECKSUM, 184*6cefaae1SJack Meng /* Low memory */ 185*6cefaae1SJack Meng IBFT_STATUS_LOWMEM, 186*6cefaae1SJack Meng /* No table */ 187*6cefaae1SJack Meng IBFT_STATUS_NOTABLE 188*6cefaae1SJack Meng } ibft_status_t; 189*6cefaae1SJack Meng 190*6cefaae1SJack Meng extern void *memset(void *s, int c, size_t n); 191*6cefaae1SJack Meng extern int memcmp(const void *s1, const void *s2, size_t n); 192*6cefaae1SJack Meng extern void bcopy(const void *s1, void *s2, size_t n); 193*6cefaae1SJack Meng extern void iscsi_print_boot_property(); 194*6cefaae1SJack Meng 195*6cefaae1SJack Meng ib_boot_prop_t boot_property; /* static allocated */ 196*6cefaae1SJack Meng extern ib_boot_prop_t *iscsiboot_prop; /* to be filled */ 197*6cefaae1SJack Meng 198*6cefaae1SJack Meng static ibft_status_t iscsi_parse_ibft_control(iscsi_ibft_ctl_t *ctl_hdr, 199*6cefaae1SJack Meng ushort_t *iscsi_offset_buf); 200*6cefaae1SJack Meng 201*6cefaae1SJack Meng static ibft_status_t iscsi_parse_ibft_initiator(char *begin_of_ibft, 202*6cefaae1SJack Meng iscsi_ibft_initiator_t *initiator); 203*6cefaae1SJack Meng 204*6cefaae1SJack Meng static ibft_status_t iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp); 205*6cefaae1SJack Meng 206*6cefaae1SJack Meng static ibft_status_t iscsi_parse_ibft_target(char *begin_of_ibft, 207*6cefaae1SJack Meng iscsi_ibft_tgt_t *tgtp); 208*6cefaae1SJack Meng 209*6cefaae1SJack Meng 210*6cefaae1SJack Meng /* 211*6cefaae1SJack Meng * Return value: 212*6cefaae1SJack Meng * Success: IBFT_STATUS_OK 213*6cefaae1SJack Meng * Fail: IBFT_STATUS_BADCHECKSUM 214*6cefaae1SJack Meng */ 215*6cefaae1SJack Meng static ibft_status_t 216*6cefaae1SJack Meng iscsi_ibft_hdr_checksum(iscsi_ibft_tbl_hdr_t *tbl_hdr) 217*6cefaae1SJack Meng { 218*6cefaae1SJack Meng uchar_t checksum = 0; 219*6cefaae1SJack Meng uchar_t *start = NULL; 220*6cefaae1SJack Meng int length = 0; 221*6cefaae1SJack Meng int i = 0; 222*6cefaae1SJack Meng 223*6cefaae1SJack Meng if (tbl_hdr == NULL) { 224*6cefaae1SJack Meng return (IBFT_STATUS_BADHDR); 225*6cefaae1SJack Meng } 226*6cefaae1SJack Meng 227*6cefaae1SJack Meng length = tbl_hdr->Length; 228*6cefaae1SJack Meng start = (uchar_t *)tbl_hdr; 229*6cefaae1SJack Meng 230*6cefaae1SJack Meng for (i = 0; i < length; i++) { 231*6cefaae1SJack Meng checksum = checksum + start[i]; 232*6cefaae1SJack Meng } 233*6cefaae1SJack Meng 234*6cefaae1SJack Meng if (!checksum) 235*6cefaae1SJack Meng return (IBFT_STATUS_OK); 236*6cefaae1SJack Meng else 237*6cefaae1SJack Meng return (IBFT_STATUS_BADCHECKSUM); 238*6cefaae1SJack Meng } 239*6cefaae1SJack Meng 240*6cefaae1SJack Meng /* 241*6cefaae1SJack Meng * Now we only support one control structure in the IBFT. 242*6cefaae1SJack Meng * So there is no Control ID here. 243*6cefaae1SJack Meng */ 244*6cefaae1SJack Meng static ibft_status_t 245*6cefaae1SJack Meng iscsi_parse_ibft_structure(char *begin_of_ibft, char *buf) 246*6cefaae1SJack Meng { 247*6cefaae1SJack Meng iscsi_ibft_hdr_t *hdr = NULL; 248*6cefaae1SJack Meng ibft_status_t ret = IBFT_STATUS_OK; 249*6cefaae1SJack Meng 250*6cefaae1SJack Meng if (buf == NULL) { 251*6cefaae1SJack Meng return (IBFT_STATUS_ERR); 252*6cefaae1SJack Meng } 253*6cefaae1SJack Meng 254*6cefaae1SJack Meng hdr = (iscsi_ibft_hdr_t *)buf; 255*6cefaae1SJack Meng switch (hdr->Structure_id) { 256*6cefaae1SJack Meng case Initiator: 257*6cefaae1SJack Meng ret = iscsi_parse_ibft_initiator( 258*6cefaae1SJack Meng begin_of_ibft, 259*6cefaae1SJack Meng (iscsi_ibft_initiator_t *)buf); 260*6cefaae1SJack Meng break; 261*6cefaae1SJack Meng case Nic: 262*6cefaae1SJack Meng ret = iscsi_parse_ibft_NIC( 263*6cefaae1SJack Meng (iscsi_ibft_nic_t *)buf); 264*6cefaae1SJack Meng break; 265*6cefaae1SJack Meng case Target: 266*6cefaae1SJack Meng ret = iscsi_parse_ibft_target( 267*6cefaae1SJack Meng begin_of_ibft, 268*6cefaae1SJack Meng (iscsi_ibft_tgt_t *)buf); 269*6cefaae1SJack Meng break; 270*6cefaae1SJack Meng default: 271*6cefaae1SJack Meng ret = IBFT_STATUS_BADHDR; 272*6cefaae1SJack Meng break; 273*6cefaae1SJack Meng } 274*6cefaae1SJack Meng 275*6cefaae1SJack Meng return (ret); 276*6cefaae1SJack Meng } 277*6cefaae1SJack Meng 278*6cefaae1SJack Meng /* 279*6cefaae1SJack Meng * Parse the iBFT table 280*6cefaae1SJack Meng * return IBFT_STATUS_OK upon sucess 281*6cefaae1SJack Meng */ 282*6cefaae1SJack Meng static ibft_status_t 283*6cefaae1SJack Meng iscsi_parse_ibft_tbl(iscsi_ibft_tbl_hdr_t *tbl_hdr) 284*6cefaae1SJack Meng { 285*6cefaae1SJack Meng char *outbuf = NULL; 286*6cefaae1SJack Meng int i = 0; 287*6cefaae1SJack Meng ibft_status_t ret = IBFT_STATUS_OK; 288*6cefaae1SJack Meng ushort_t iscsi_offset_buf[IBFT_OFFSET_BUF_LEN] = {0}; 289*6cefaae1SJack Meng 290*6cefaae1SJack Meng if (tbl_hdr == NULL) { 291*6cefaae1SJack Meng return (IBFT_STATUS_ERR); 292*6cefaae1SJack Meng } 293*6cefaae1SJack Meng 294*6cefaae1SJack Meng if (iscsi_ibft_hdr_checksum(tbl_hdr) != IBFT_STATUS_OK) { 295*6cefaae1SJack Meng return (IBFT_STATUS_BADCHECKSUM); 296*6cefaae1SJack Meng } 297*6cefaae1SJack Meng 298*6cefaae1SJack Meng outbuf = (char *)tbl_hdr; 299*6cefaae1SJack Meng 300*6cefaae1SJack Meng ret = iscsi_parse_ibft_control( 301*6cefaae1SJack Meng (iscsi_ibft_ctl_t *)&outbuf[ISCSI_IBFT_CTL_OFFSET], 302*6cefaae1SJack Meng iscsi_offset_buf); 303*6cefaae1SJack Meng 304*6cefaae1SJack Meng if (ret == IBFT_STATUS_OK) { 305*6cefaae1SJack Meng ret = IBFT_STATUS_ERR; 306*6cefaae1SJack Meng for (i = 0; i < IBFT_OFFSET_BUF_LEN; i++) { 307*6cefaae1SJack Meng if (iscsi_offset_buf[i] != 0) { 308*6cefaae1SJack Meng ret = iscsi_parse_ibft_structure( 309*6cefaae1SJack Meng (char *)tbl_hdr, 310*6cefaae1SJack Meng (char *)tbl_hdr + 311*6cefaae1SJack Meng iscsi_offset_buf[i]); 312*6cefaae1SJack Meng if (ret != IBFT_STATUS_OK) { 313*6cefaae1SJack Meng return (ret); 314*6cefaae1SJack Meng } 315*6cefaae1SJack Meng } 316*6cefaae1SJack Meng } 317*6cefaae1SJack Meng } 318*6cefaae1SJack Meng 319*6cefaae1SJack Meng return (ret); 320*6cefaae1SJack Meng } 321*6cefaae1SJack Meng 322*6cefaae1SJack Meng static ibft_status_t 323*6cefaae1SJack Meng iscsi_parse_ibft_control(iscsi_ibft_ctl_t *ctl_hdr, 324*6cefaae1SJack Meng ushort_t *iscsi_offset_buf) 325*6cefaae1SJack Meng { 326*6cefaae1SJack Meng int i = 0; 327*6cefaae1SJack Meng ushort_t *offsetp = NULL; 328*6cefaae1SJack Meng 329*6cefaae1SJack Meng if (ctl_hdr == NULL) { 330*6cefaae1SJack Meng return (IBFT_STATUS_BADHDR); 331*6cefaae1SJack Meng } 332*6cefaae1SJack Meng 333*6cefaae1SJack Meng if (ctl_hdr->header.Structure_id != Control) { 334*6cefaae1SJack Meng return (IBFT_STATUS_BADCID); 335*6cefaae1SJack Meng } 336*6cefaae1SJack Meng 337*6cefaae1SJack Meng /* 338*6cefaae1SJack Meng * Copy the offsets to offset buffer. 339*6cefaae1SJack Meng */ 340*6cefaae1SJack Meng for (offsetp = &(ctl_hdr->Initiator_offset); i < IBFT_OFFSET_BUF_LEN; 341*6cefaae1SJack Meng offsetp++) { 342*6cefaae1SJack Meng iscsi_offset_buf[i++] = *offsetp; 343*6cefaae1SJack Meng } 344*6cefaae1SJack Meng 345*6cefaae1SJack Meng return (IBFT_STATUS_OK); 346*6cefaae1SJack Meng } 347*6cefaae1SJack Meng 348*6cefaae1SJack Meng /* 349*6cefaae1SJack Meng * We only copy the "Firmare Boot Selseted" and valid initiator 350*6cefaae1SJack Meng * to the boot property. 351*6cefaae1SJack Meng */ 352*6cefaae1SJack Meng static ibft_status_t 353*6cefaae1SJack Meng iscsi_parse_ibft_initiator(char *begin_of_ibft, 354*6cefaae1SJack Meng iscsi_ibft_initiator_t *initiator) 355*6cefaae1SJack Meng { 356*6cefaae1SJack Meng if (initiator == NULL) { 357*6cefaae1SJack Meng return (IBFT_STATUS_ERR); 358*6cefaae1SJack Meng } 359*6cefaae1SJack Meng 360*6cefaae1SJack Meng if (initiator->header.Structure_id != Initiator) { 361*6cefaae1SJack Meng return (IBFT_STATUS_BADHDR); 362*6cefaae1SJack Meng } 363*6cefaae1SJack Meng 364*6cefaae1SJack Meng if ((initiator->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) && 365*6cefaae1SJack Meng (initiator->header.Flags & IBFT_BLOCK_VALID_YES)) { 366*6cefaae1SJack Meng /* 367*6cefaae1SJack Meng * If the initiator name exists, we will copy it to our own 368*6cefaae1SJack Meng * property structure 369*6cefaae1SJack Meng */ 370*6cefaae1SJack Meng if (initiator->ini_name_len != 0) { 371*6cefaae1SJack Meng boot_property.boot_init.ini_name = 372*6cefaae1SJack Meng (uchar_t *)kmem_zalloc( 373*6cefaae1SJack Meng initiator->ini_name_len + 1, KM_SLEEP); 374*6cefaae1SJack Meng (void) snprintf( 375*6cefaae1SJack Meng (char *)boot_property.boot_init.ini_name, 376*6cefaae1SJack Meng initiator->ini_name_len + 1, "%s", 377*6cefaae1SJack Meng begin_of_ibft + initiator->ini_name_offset); 378*6cefaae1SJack Meng } 379*6cefaae1SJack Meng } 380*6cefaae1SJack Meng return (IBFT_STATUS_OK); 381*6cefaae1SJack Meng } 382*6cefaae1SJack Meng 383*6cefaae1SJack Meng static ibft_status_t 384*6cefaae1SJack Meng iscsi_parse_ipaddr(uchar_t *source, char *dest, int *af) 385*6cefaae1SJack Meng { 386*6cefaae1SJack Meng int i = 0; 387*6cefaae1SJack Meng 388*6cefaae1SJack Meng if (source == NULL) { 389*6cefaae1SJack Meng return (IBFT_STATUS_ERR); 390*6cefaae1SJack Meng } 391*6cefaae1SJack Meng 392*6cefaae1SJack Meng if (source[0] == 0x00 && source[1] == 0x00 && 393*6cefaae1SJack Meng source[2] == 0x00 && source[3] == 0x00 && 394*6cefaae1SJack Meng source[4] == 0x00 && source[5] == 0x00 && 395*6cefaae1SJack Meng source[6] == 0x00 && source[7] == 0x00 && 396*6cefaae1SJack Meng source[8] == 0x00 && source[9] == 0x00 && 397*6cefaae1SJack Meng (source[10] == 0xff) && (source[11] == 0xff)) { 398*6cefaae1SJack Meng /* 399*6cefaae1SJack Meng * IPv4 address 400*6cefaae1SJack Meng */ 401*6cefaae1SJack Meng if (dest != NULL) { 402*6cefaae1SJack Meng (void) sprintf(dest, "%d.%d.%d.%d", 403*6cefaae1SJack Meng source[12], source[13], source[14], source[15]); 404*6cefaae1SJack Meng } 405*6cefaae1SJack Meng if (af != NULL) { 406*6cefaae1SJack Meng *af = AF_INET; 407*6cefaae1SJack Meng } 408*6cefaae1SJack Meng } else { 409*6cefaae1SJack Meng if (dest != NULL) { 410*6cefaae1SJack Meng for (i = 0; i < 14; i = i + 2) { 411*6cefaae1SJack Meng (void) sprintf(dest, "%02x%02x:", source[i], 412*6cefaae1SJack Meng source[i+1]); 413*6cefaae1SJack Meng dest = dest + 5; 414*6cefaae1SJack Meng } 415*6cefaae1SJack Meng (void) sprintf(dest, "%02x%02x", 416*6cefaae1SJack Meng source[i], source[i+1]); 417*6cefaae1SJack Meng } 418*6cefaae1SJack Meng if (af != NULL) { 419*6cefaae1SJack Meng *af = AF_INET6; 420*6cefaae1SJack Meng } 421*6cefaae1SJack Meng } 422*6cefaae1SJack Meng 423*6cefaae1SJack Meng return (IBFT_STATUS_OK); 424*6cefaae1SJack Meng } 425*6cefaae1SJack Meng 426*6cefaae1SJack Meng /* 427*6cefaae1SJack Meng * Copy the ip address from ibft. If IPv4 is used, we should copy 428*6cefaae1SJack Meng * the address from 12th byte. 429*6cefaae1SJack Meng */ 430*6cefaae1SJack Meng static ibft_status_t 431*6cefaae1SJack Meng iscsi_copy_ibft_ipaddr(uchar_t *source, void *dest, int *af) 432*6cefaae1SJack Meng { 433*6cefaae1SJack Meng ibft_status_t ret = IBFT_STATUS_OK; 434*6cefaae1SJack Meng int sin_family = 0; 435*6cefaae1SJack Meng 436*6cefaae1SJack Meng if (source == NULL || dest == NULL) { 437*6cefaae1SJack Meng return (IBFT_STATUS_ERR); 438*6cefaae1SJack Meng } 439*6cefaae1SJack Meng ret = iscsi_parse_ipaddr(source, NULL, &sin_family); 440*6cefaae1SJack Meng if (ret != 0) { 441*6cefaae1SJack Meng return (IBFT_STATUS_BADIP); 442*6cefaae1SJack Meng } 443*6cefaae1SJack Meng 444*6cefaae1SJack Meng if (sin_family == AF_INET) { 445*6cefaae1SJack Meng bcopy(source+IPV4_OFFSET, dest, sizeof (struct in_addr)); 446*6cefaae1SJack Meng } else if (sin_family == AF_INET6) { 447*6cefaae1SJack Meng bcopy(source, dest, sizeof (struct in6_addr)); 448*6cefaae1SJack Meng } else { 449*6cefaae1SJack Meng return (IBFT_STATUS_BADAF); 450*6cefaae1SJack Meng } 451*6cefaae1SJack Meng 452*6cefaae1SJack Meng if (af != NULL) { 453*6cefaae1SJack Meng *af = sin_family; 454*6cefaae1SJack Meng } 455*6cefaae1SJack Meng return (IBFT_STATUS_OK); 456*6cefaae1SJack Meng } 457*6cefaae1SJack Meng 458*6cefaae1SJack Meng /* 459*6cefaae1SJack Meng * Maybe there are multiply NICs are available. We only copy the 460*6cefaae1SJack Meng * "Firmare Boot Selseted" and valid one to the boot property. 461*6cefaae1SJack Meng */ 462*6cefaae1SJack Meng static ibft_status_t 463*6cefaae1SJack Meng iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp) 464*6cefaae1SJack Meng { 465*6cefaae1SJack Meng ibft_status_t ret = IBFT_STATUS_OK; 466*6cefaae1SJack Meng int af = 0; 467*6cefaae1SJack Meng 468*6cefaae1SJack Meng if (nicp == NULL) { 469*6cefaae1SJack Meng return (IBFT_STATUS_ERR); 470*6cefaae1SJack Meng } 471*6cefaae1SJack Meng 472*6cefaae1SJack Meng if (nicp->header.Structure_id != Nic) { 473*6cefaae1SJack Meng return (IBFT_STATUS_ERR); 474*6cefaae1SJack Meng } 475*6cefaae1SJack Meng 476*6cefaae1SJack Meng if ((nicp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) && 477*6cefaae1SJack Meng (nicp->header.Flags & IBFT_BLOCK_VALID_YES)) { 478*6cefaae1SJack Meng ret = iscsi_copy_ibft_ipaddr(nicp->ip_addr, 479*6cefaae1SJack Meng &boot_property.boot_nic.nic_ip_u, &af); 480*6cefaae1SJack Meng if (ret != IBFT_STATUS_OK) { 481*6cefaae1SJack Meng return (ret); 482*6cefaae1SJack Meng } 483*6cefaae1SJack Meng 484*6cefaae1SJack Meng boot_property.boot_nic.sin_family = af; 485*6cefaae1SJack Meng 486*6cefaae1SJack Meng ret = iscsi_copy_ibft_ipaddr(nicp->Gateway, 487*6cefaae1SJack Meng &boot_property.boot_nic.nic_gw_u, NULL); 488*6cefaae1SJack Meng if (ret != IBFT_STATUS_OK) { 489*6cefaae1SJack Meng return (ret); 490*6cefaae1SJack Meng } 491*6cefaae1SJack Meng 492*6cefaae1SJack Meng ret = iscsi_copy_ibft_ipaddr(nicp->dhcp, 493*6cefaae1SJack Meng &boot_property.boot_nic.nic_dhcp_u, NULL); 494*6cefaae1SJack Meng if (ret != IBFT_STATUS_OK) { 495*6cefaae1SJack Meng return (ret); 496*6cefaae1SJack Meng } 497*6cefaae1SJack Meng 498*6cefaae1SJack Meng bcopy(nicp->mac, boot_property.boot_nic.nic_mac, 6); 499*6cefaae1SJack Meng boot_property.boot_nic.sub_mask_prefix = 500*6cefaae1SJack Meng nicp->Subnet_Mask_Prefix; 501*6cefaae1SJack Meng } 502*6cefaae1SJack Meng 503*6cefaae1SJack Meng return (IBFT_STATUS_OK); 504*6cefaae1SJack Meng } 505*6cefaae1SJack Meng 506*6cefaae1SJack Meng /* 507*6cefaae1SJack Meng * Maybe there are multiply targets are available. We only copy the 508*6cefaae1SJack Meng * "Firmare Boot Selseted" and valid one to the boot property. 509*6cefaae1SJack Meng */ 510*6cefaae1SJack Meng static ibft_status_t 511*6cefaae1SJack Meng iscsi_parse_ibft_target(char *begin_of_ibft, iscsi_ibft_tgt_t *tgtp) 512*6cefaae1SJack Meng { 513*6cefaae1SJack Meng char *tmp = NULL; 514*6cefaae1SJack Meng int af = 0; 515*6cefaae1SJack Meng ibft_status_t ret = IBFT_STATUS_OK; 516*6cefaae1SJack Meng 517*6cefaae1SJack Meng if (tgtp == NULL) { 518*6cefaae1SJack Meng return (IBFT_STATUS_ERR); 519*6cefaae1SJack Meng } 520*6cefaae1SJack Meng 521*6cefaae1SJack Meng if (tgtp->header.Structure_id != Target) { 522*6cefaae1SJack Meng return (IBFT_STATUS_BADHDR); 523*6cefaae1SJack Meng } 524*6cefaae1SJack Meng 525*6cefaae1SJack Meng if ((tgtp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) && 526*6cefaae1SJack Meng (tgtp->header.Flags & IBFT_BLOCK_VALID_YES)) { 527*6cefaae1SJack Meng /* 528*6cefaae1SJack Meng * Get Target Address 529*6cefaae1SJack Meng */ 530*6cefaae1SJack Meng ret = iscsi_copy_ibft_ipaddr(tgtp->ip_addr, 531*6cefaae1SJack Meng &boot_property.boot_tgt.tgt_ip_u, &af); 532*6cefaae1SJack Meng if (ret != IBFT_STATUS_OK) { 533*6cefaae1SJack Meng return (ret); 534*6cefaae1SJack Meng } 535*6cefaae1SJack Meng boot_property.boot_tgt.sin_family = af; 536*6cefaae1SJack Meng /* 537*6cefaae1SJack Meng * Get Target Name 538*6cefaae1SJack Meng */ 539*6cefaae1SJack Meng if (tgtp->target_name_len != 0) { 540*6cefaae1SJack Meng boot_property.boot_tgt.tgt_name = 541*6cefaae1SJack Meng (uchar_t *)kmem_zalloc(tgtp->target_name_len + 1, 542*6cefaae1SJack Meng KM_SLEEP); 543*6cefaae1SJack Meng (void) snprintf( 544*6cefaae1SJack Meng (char *)boot_property.boot_tgt.tgt_name, 545*6cefaae1SJack Meng tgtp->target_name_len + 1, "%s", 546*6cefaae1SJack Meng begin_of_ibft + tgtp->target_name_offset); 547*6cefaae1SJack Meng } else { 548*6cefaae1SJack Meng boot_property.boot_tgt.tgt_name = NULL; 549*6cefaae1SJack Meng } 550*6cefaae1SJack Meng 551*6cefaae1SJack Meng /* Get Dest Port */ 552*6cefaae1SJack Meng boot_property.boot_tgt.tgt_port = tgtp->port; 553*6cefaae1SJack Meng 554*6cefaae1SJack Meng boot_property.boot_tgt.lun_online = 0; 555*6cefaae1SJack Meng 556*6cefaae1SJack Meng /* 557*6cefaae1SJack Meng * Get CHAP secret and name. 558*6cefaae1SJack Meng */ 559*6cefaae1SJack Meng if (tgtp->chap_type != NO_CHAP) { 560*6cefaae1SJack Meng if (tgtp->chap_name_len != 0) { 561*6cefaae1SJack Meng boot_property.boot_init.ini_chap_name = 562*6cefaae1SJack Meng (uchar_t *)kmem_zalloc( 563*6cefaae1SJack Meng tgtp->chap_name_len + 1, 564*6cefaae1SJack Meng KM_SLEEP); 565*6cefaae1SJack Meng tmp = (char *) 566*6cefaae1SJack Meng boot_property.boot_init.ini_chap_name; 567*6cefaae1SJack Meng (void) snprintf( 568*6cefaae1SJack Meng tmp, 569*6cefaae1SJack Meng tgtp->chap_name_len + 1, "%s", 570*6cefaae1SJack Meng begin_of_ibft + tgtp->chap_name_offset); 571*6cefaae1SJack Meng } else { 572*6cefaae1SJack Meng /* 573*6cefaae1SJack Meng * Just set NULL, initiator is able to deal 574*6cefaae1SJack Meng * with this 575*6cefaae1SJack Meng */ 576*6cefaae1SJack Meng boot_property.boot_init.ini_chap_name = NULL; 577*6cefaae1SJack Meng } 578*6cefaae1SJack Meng 579*6cefaae1SJack Meng if (tgtp->chap_secret_len != 0) { 580*6cefaae1SJack Meng boot_property.boot_init.ini_chap_sec = 581*6cefaae1SJack Meng (uchar_t *)kmem_zalloc( 582*6cefaae1SJack Meng tgtp->chap_secret_len + 1, 583*6cefaae1SJack Meng KM_SLEEP); 584*6cefaae1SJack Meng bcopy(begin_of_ibft + 585*6cefaae1SJack Meng tgtp->chap_secret_offset, 586*6cefaae1SJack Meng boot_property.boot_init.ini_chap_sec, 587*6cefaae1SJack Meng tgtp->chap_secret_len); 588*6cefaae1SJack Meng } else { 589*6cefaae1SJack Meng boot_property.boot_init.ini_chap_sec = NULL; 590*6cefaae1SJack Meng return (IBFT_STATUS_ERR); 591*6cefaae1SJack Meng } 592*6cefaae1SJack Meng 593*6cefaae1SJack Meng if (tgtp->chap_type == Mutual_CHAP) { 594*6cefaae1SJack Meng if (tgtp->rev_chap_name_len != 0) { 595*6cefaae1SJack Meng boot_property.boot_tgt.tgt_chap_name = 596*6cefaae1SJack Meng (uchar_t *)kmem_zalloc( 597*6cefaae1SJack Meng tgtp->chap_name_len + 1, 598*6cefaae1SJack Meng KM_SLEEP); 599*6cefaae1SJack Meng #define TGT_CHAP_NAME boot_property.boot_tgt.tgt_chap_name 600*6cefaae1SJack Meng tmp = (char *)TGT_CHAP_NAME; 601*6cefaae1SJack Meng #undef TGT_CHAP_NAME 602*6cefaae1SJack Meng (void) snprintf( 603*6cefaae1SJack Meng tmp, 604*6cefaae1SJack Meng tgtp->chap_name_len + 1, 605*6cefaae1SJack Meng "%s", 606*6cefaae1SJack Meng begin_of_ibft + 607*6cefaae1SJack Meng tgtp->rev_chap_name_offset); 608*6cefaae1SJack Meng } else { 609*6cefaae1SJack Meng /* 610*6cefaae1SJack Meng * Just set NULL, initiator is able 611*6cefaae1SJack Meng * to deal with this 612*6cefaae1SJack Meng */ 613*6cefaae1SJack Meng boot_property.boot_tgt.tgt_chap_name = 614*6cefaae1SJack Meng NULL; 615*6cefaae1SJack Meng } 616*6cefaae1SJack Meng 617*6cefaae1SJack Meng if (tgtp->rev_chap_secret_len != 0) { 618*6cefaae1SJack Meng boot_property.boot_tgt.tgt_chap_sec = 619*6cefaae1SJack Meng (uchar_t *)kmem_zalloc( 620*6cefaae1SJack Meng tgtp->rev_chap_secret_len + 1, 621*6cefaae1SJack Meng KM_SLEEP); 622*6cefaae1SJack Meng tmp = (char *) 623*6cefaae1SJack Meng boot_property.boot_tgt.tgt_chap_sec; 624*6cefaae1SJack Meng (void) snprintf( 625*6cefaae1SJack Meng tmp, 626*6cefaae1SJack Meng tgtp->rev_chap_secret_len + 1, 627*6cefaae1SJack Meng "%s", 628*6cefaae1SJack Meng begin_of_ibft + 629*6cefaae1SJack Meng tgtp->chap_secret_offset); 630*6cefaae1SJack Meng } else { 631*6cefaae1SJack Meng boot_property.boot_tgt.tgt_chap_sec = 632*6cefaae1SJack Meng NULL; 633*6cefaae1SJack Meng return (IBFT_STATUS_BADCHAPSEC); 634*6cefaae1SJack Meng } 635*6cefaae1SJack Meng } 636*6cefaae1SJack Meng } else { 637*6cefaae1SJack Meng boot_property.boot_init.ini_chap_name = NULL; 638*6cefaae1SJack Meng boot_property.boot_init.ini_chap_sec = NULL; 639*6cefaae1SJack Meng } 640*6cefaae1SJack Meng 641*6cefaae1SJack Meng /* 642*6cefaae1SJack Meng * Get Boot LUN 643*6cefaae1SJack Meng */ 644*6cefaae1SJack Meng (void) bcopy(tgtp->boot_lun, 645*6cefaae1SJack Meng boot_property.boot_tgt.tgt_boot_lun, 8); 646*6cefaae1SJack Meng } 647*6cefaae1SJack Meng 648*6cefaae1SJack Meng return (IBFT_STATUS_OK); 649*6cefaae1SJack Meng } 650*6cefaae1SJack Meng 651*6cefaae1SJack Meng /* 652*6cefaae1SJack Meng * This function is used for scanning iBFT from the physical memory. 653*6cefaae1SJack Meng * Return Value: 654*6cefaae1SJack Meng * IBFT_STATUS_OK 655*6cefaae1SJack Meng * IBFT_STATUS_ERR 656*6cefaae1SJack Meng */ 657*6cefaae1SJack Meng static ibft_status_t 658*6cefaae1SJack Meng iscsi_scan_ibft_tbl(char *ibft_tbl_buf) 659*6cefaae1SJack Meng { 660*6cefaae1SJack Meng int start; 661*6cefaae1SJack Meng void *va = NULL; 662*6cefaae1SJack Meng int *len = NULL; 663*6cefaae1SJack Meng ibft_status_t ret = IBFT_STATUS_NOTABLE; 664*6cefaae1SJack Meng 665*6cefaae1SJack Meng for (start = ISCSI_IBFT_LOWER_ADDR; start < ISCSI_IBFT_HIGHER_ADDR; 666*6cefaae1SJack Meng start = start + ISCSI_IBFT_ALIGNED) { 667*6cefaae1SJack Meng va = (void *)psm_map((paddr_t)(start&0xffffffff), 668*6cefaae1SJack Meng ISCSI_IBFT_SIGNATURE_LEN, 669*6cefaae1SJack Meng PROT_READ); 670*6cefaae1SJack Meng 671*6cefaae1SJack Meng if (va == NULL) { 672*6cefaae1SJack Meng continue; 673*6cefaae1SJack Meng } 674*6cefaae1SJack Meng if (memcmp(va, ISCSI_IBFT_SIGNATRUE, 675*6cefaae1SJack Meng ISCSI_IBFT_SIGNATURE_LEN) == 0) { 676*6cefaae1SJack Meng ret = IBFT_STATUS_ERR; 677*6cefaae1SJack Meng /* Acquire table length */ 678*6cefaae1SJack Meng len = (int *)psm_map( 679*6cefaae1SJack Meng (paddr_t)((start+\ 680*6cefaae1SJack Meng ISCSI_IBFT_SIGNATURE_LEN)&0xffffffff), 681*6cefaae1SJack Meng ISCSI_IBFT_SIGNATURE_LEN, PROT_READ); 682*6cefaae1SJack Meng if (len == NULL) { 683*6cefaae1SJack Meng psm_unmap((caddr_t)va, 684*6cefaae1SJack Meng ISCSI_IBFT_SIGNATURE_LEN); 685*6cefaae1SJack Meng continue; 686*6cefaae1SJack Meng } 687*6cefaae1SJack Meng if (ISCSI_IBFT_LOWER_ADDR + *len < 688*6cefaae1SJack Meng ISCSI_IBFT_HIGHER_ADDR - 1) { 689*6cefaae1SJack Meng psm_unmap(va, 690*6cefaae1SJack Meng ISCSI_IBFT_SIGNATURE_LEN); 691*6cefaae1SJack Meng va = psm_map((paddr_t)(start&0xffffffff), 692*6cefaae1SJack Meng *len, 693*6cefaae1SJack Meng PROT_READ); 694*6cefaae1SJack Meng if (va != NULL) { 695*6cefaae1SJack Meng /* 696*6cefaae1SJack Meng * Copy data to our own buffer 697*6cefaae1SJack Meng */ 698*6cefaae1SJack Meng bcopy(va, ibft_tbl_buf, *len); 699*6cefaae1SJack Meng ret = IBFT_STATUS_OK; 700*6cefaae1SJack Meng } 701*6cefaae1SJack Meng psm_unmap((caddr_t)va, *len); 702*6cefaae1SJack Meng psm_unmap((caddr_t)len, 703*6cefaae1SJack Meng ISCSI_IBFT_SIGNATURE_LEN); 704*6cefaae1SJack Meng break; 705*6cefaae1SJack Meng } else { 706*6cefaae1SJack Meng psm_unmap((caddr_t)va, 707*6cefaae1SJack Meng ISCSI_IBFT_SIGNATURE_LEN); 708*6cefaae1SJack Meng psm_unmap((caddr_t)len, 709*6cefaae1SJack Meng ISCSI_IBFT_SIGNATURE_LEN); 710*6cefaae1SJack Meng } 711*6cefaae1SJack Meng } else { 712*6cefaae1SJack Meng psm_unmap((caddr_t)va, ISCSI_IBFT_SIGNATURE_LEN); 713*6cefaae1SJack Meng } 714*6cefaae1SJack Meng } 715*6cefaae1SJack Meng 716*6cefaae1SJack Meng return (ret); 717*6cefaae1SJack Meng } 718*6cefaae1SJack Meng 719*6cefaae1SJack Meng /* 720*6cefaae1SJack Meng * Scan the ibft table and store the iSCSI boot properties 721*6cefaae1SJack Meng * If there is a valid table then set the iscsiboot_prop 722*6cefaae1SJack Meng * iBF should be off if the host is not intended 723*6cefaae1SJack Meng * to be booted from iSCSI disk 724*6cefaae1SJack Meng */ 725*6cefaae1SJack Meng void 726*6cefaae1SJack Meng ld_ib_prop() 727*6cefaae1SJack Meng { 728*6cefaae1SJack Meng ibft_status_t ret = IBFT_STATUS_OK; 729*6cefaae1SJack Meng char *ibft_tbl_buf; 730*6cefaae1SJack Meng 731*6cefaae1SJack Meng ibft_tbl_buf = (char *)kmem_zalloc(ISCSI_IBFT_TBL_BUF_LEN, 732*6cefaae1SJack Meng KM_SLEEP); 733*6cefaae1SJack Meng 734*6cefaae1SJack Meng if (!ibft_tbl_buf) { 735*6cefaae1SJack Meng /* Unlikely to happen */ 736*6cefaae1SJack Meng cmn_err(CE_NOTE, IBFT_INVALID_MSG, 737*6cefaae1SJack Meng IBFT_STATUS_LOWMEM); 738*6cefaae1SJack Meng return; 739*6cefaae1SJack Meng } 740*6cefaae1SJack Meng 741*6cefaae1SJack Meng (void) memset(&boot_property, 0, sizeof (boot_property)); 742*6cefaae1SJack Meng if ((ret = iscsi_scan_ibft_tbl(ibft_tbl_buf)) == 743*6cefaae1SJack Meng IBFT_STATUS_OK) { 744*6cefaae1SJack Meng ret = iscsi_parse_ibft_tbl( 745*6cefaae1SJack Meng (iscsi_ibft_tbl_hdr_t *)ibft_tbl_buf); 746*6cefaae1SJack Meng if (ret == IBFT_STATUS_OK) { 747*6cefaae1SJack Meng iscsiboot_prop = &boot_property; 748*6cefaae1SJack Meng iscsi_print_boot_property(); 749*6cefaae1SJack Meng } else { 750*6cefaae1SJack Meng cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret); 751*6cefaae1SJack Meng } 752*6cefaae1SJack Meng } else if (ret != IBFT_STATUS_NOTABLE) { 753*6cefaae1SJack Meng cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret); 754*6cefaae1SJack Meng } 755*6cefaae1SJack Meng 756*6cefaae1SJack Meng kmem_free(ibft_tbl_buf, ISCSI_IBFT_TBL_BUF_LEN); 757*6cefaae1SJack Meng } 758