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