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