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