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 boot_property.boot_init.ini_name_len = 378 initiator->ini_name_len + 1; 379 (void) snprintf( 380 (char *)boot_property.boot_init.ini_name, 381 initiator->ini_name_len + 1, "%s", 382 begin_of_ibft + initiator->ini_name_offset); 383 } 384 } 385 return (IBFT_STATUS_OK); 386 } 387 388 static ibft_status_t 389 iscsi_parse_ipaddr(uchar_t *source, char *dest, int *af) 390 { 391 int i = 0; 392 393 if (source == NULL) { 394 return (IBFT_STATUS_ERR); 395 } 396 397 if (source[0] == 0x00 && source[1] == 0x00 && 398 source[2] == 0x00 && source[3] == 0x00 && 399 source[4] == 0x00 && source[5] == 0x00 && 400 source[6] == 0x00 && source[7] == 0x00 && 401 source[8] == 0x00 && source[9] == 0x00 && 402 (source[10] == 0xff) && (source[11] == 0xff)) { 403 /* 404 * IPv4 address 405 */ 406 if (dest != NULL) { 407 (void) sprintf(dest, "%d.%d.%d.%d", 408 source[12], source[13], source[14], source[15]); 409 } 410 if (af != NULL) { 411 *af = AF_INET; 412 } 413 } else { 414 if (dest != NULL) { 415 for (i = 0; i < 14; i = i + 2) { 416 (void) sprintf(dest, "%02x%02x:", source[i], 417 source[i+1]); 418 dest = dest + 5; 419 } 420 (void) sprintf(dest, "%02x%02x", 421 source[i], source[i+1]); 422 } 423 if (af != NULL) { 424 *af = AF_INET6; 425 } 426 } 427 428 return (IBFT_STATUS_OK); 429 } 430 431 /* 432 * Copy the ip address from ibft. If IPv4 is used, we should copy 433 * the address from 12th byte. 434 */ 435 static ibft_status_t 436 iscsi_copy_ibft_ipaddr(uchar_t *source, void *dest, int *af) 437 { 438 ibft_status_t ret = IBFT_STATUS_OK; 439 int sin_family = 0; 440 441 if (source == NULL || dest == NULL) { 442 return (IBFT_STATUS_ERR); 443 } 444 ret = iscsi_parse_ipaddr(source, NULL, &sin_family); 445 if (ret != 0) { 446 return (IBFT_STATUS_BADIP); 447 } 448 449 if (sin_family == AF_INET) { 450 bcopy(source+IPV4_OFFSET, dest, sizeof (struct in_addr)); 451 } else if (sin_family == AF_INET6) { 452 bcopy(source, dest, sizeof (struct in6_addr)); 453 } else { 454 return (IBFT_STATUS_BADAF); 455 } 456 457 if (af != NULL) { 458 *af = sin_family; 459 } 460 return (IBFT_STATUS_OK); 461 } 462 463 /* 464 * Maybe there are multiply NICs are available. We only copy the 465 * "Firmare Boot Selseted" and valid one to the boot property. 466 */ 467 static ibft_status_t 468 iscsi_parse_ibft_NIC(iscsi_ibft_nic_t *nicp) 469 { 470 ibft_status_t ret = IBFT_STATUS_OK; 471 int af = 0; 472 473 if (nicp == NULL) { 474 return (IBFT_STATUS_ERR); 475 } 476 477 if (nicp->header.Structure_id != Nic) { 478 return (IBFT_STATUS_ERR); 479 } 480 481 if ((nicp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) && 482 (nicp->header.Flags & IBFT_BLOCK_VALID_YES)) { 483 ret = iscsi_copy_ibft_ipaddr(nicp->ip_addr, 484 &boot_property.boot_nic.nic_ip_u, &af); 485 if (ret != IBFT_STATUS_OK) { 486 return (ret); 487 } 488 489 boot_property.boot_nic.sin_family = af; 490 491 ret = iscsi_copy_ibft_ipaddr(nicp->Gateway, 492 &boot_property.boot_nic.nic_gw_u, NULL); 493 if (ret != IBFT_STATUS_OK) { 494 return (ret); 495 } 496 497 ret = iscsi_copy_ibft_ipaddr(nicp->dhcp, 498 &boot_property.boot_nic.nic_dhcp_u, NULL); 499 if (ret != IBFT_STATUS_OK) { 500 return (ret); 501 } 502 503 bcopy(nicp->mac, boot_property.boot_nic.nic_mac, 6); 504 boot_property.boot_nic.sub_mask_prefix = 505 nicp->Subnet_Mask_Prefix; 506 } 507 508 return (IBFT_STATUS_OK); 509 } 510 511 /* 512 * Maybe there are multiply targets are available. We only copy the 513 * "Firmare Boot Selseted" and valid one to the boot property. 514 */ 515 static ibft_status_t 516 iscsi_parse_ibft_target(char *begin_of_ibft, iscsi_ibft_tgt_t *tgtp) 517 { 518 char *tmp = NULL; 519 int af = 0; 520 ibft_status_t ret = IBFT_STATUS_OK; 521 522 if (tgtp == NULL) { 523 return (IBFT_STATUS_ERR); 524 } 525 526 if (tgtp->header.Structure_id != Target) { 527 return (IBFT_STATUS_BADHDR); 528 } 529 530 if ((tgtp->header.Flags & IBFT_FIRMWARE_BOOT_SELECTED) && 531 (tgtp->header.Flags & IBFT_BLOCK_VALID_YES)) { 532 /* 533 * Get Target Address 534 */ 535 ret = iscsi_copy_ibft_ipaddr(tgtp->ip_addr, 536 &boot_property.boot_tgt.tgt_ip_u, &af); 537 if (ret != IBFT_STATUS_OK) { 538 return (ret); 539 } 540 boot_property.boot_tgt.sin_family = af; 541 /* 542 * Get Target Name 543 */ 544 if (tgtp->target_name_len != 0) { 545 boot_property.boot_tgt.tgt_name = 546 (uchar_t *)kmem_zalloc(tgtp->target_name_len + 1, 547 KM_SLEEP); 548 boot_property.boot_tgt.tgt_name_len = 549 tgtp->target_name_len + 1; 550 (void) snprintf( 551 (char *)boot_property.boot_tgt.tgt_name, 552 tgtp->target_name_len + 1, "%s", 553 begin_of_ibft + tgtp->target_name_offset); 554 } else { 555 boot_property.boot_tgt.tgt_name = NULL; 556 } 557 558 /* Get Dest Port */ 559 boot_property.boot_tgt.tgt_port = tgtp->port; 560 561 boot_property.boot_tgt.lun_online = 0; 562 563 /* 564 * Get CHAP secret and name. 565 */ 566 if (tgtp->chap_type != NO_CHAP) { 567 if (tgtp->chap_name_len != 0) { 568 boot_property.boot_init.ini_chap_name = 569 (uchar_t *)kmem_zalloc( 570 tgtp->chap_name_len + 1, 571 KM_SLEEP); 572 boot_property.boot_init.ini_chap_name_len = 573 tgtp->chap_name_len + 1; 574 tmp = (char *) 575 boot_property.boot_init.ini_chap_name; 576 (void) snprintf( 577 tmp, 578 tgtp->chap_name_len + 1, "%s", 579 begin_of_ibft + tgtp->chap_name_offset); 580 } else { 581 /* 582 * Just set NULL, initiator is able to deal 583 * with this 584 */ 585 boot_property.boot_init.ini_chap_name = NULL; 586 } 587 588 if (tgtp->chap_secret_len != 0) { 589 boot_property.boot_init.ini_chap_sec = 590 (uchar_t *)kmem_zalloc( 591 tgtp->chap_secret_len + 1, 592 KM_SLEEP); 593 boot_property.boot_init.ini_chap_sec_len = 594 tgtp->chap_secret_len + 1; 595 bcopy(begin_of_ibft + 596 tgtp->chap_secret_offset, 597 boot_property.boot_init.ini_chap_sec, 598 tgtp->chap_secret_len); 599 } else { 600 boot_property.boot_init.ini_chap_sec = NULL; 601 return (IBFT_STATUS_ERR); 602 } 603 604 if (tgtp->chap_type == Mutual_CHAP) { 605 if (tgtp->rev_chap_name_len != 0) { 606 boot_property.boot_tgt.tgt_chap_name = 607 (uchar_t *)kmem_zalloc( 608 tgtp->rev_chap_name_len + 1, 609 KM_SLEEP); 610 boot_property.boot_tgt.tgt_chap_name_len 611 = tgtp->rev_chap_name_len + 1; 612 #define TGT_CHAP_NAME boot_property.boot_tgt.tgt_chap_name 613 tmp = (char *)TGT_CHAP_NAME; 614 #undef TGT_CHAP_NAME 615 (void) snprintf( 616 tmp, 617 tgtp->rev_chap_name_len + 1, 618 "%s", 619 begin_of_ibft + 620 tgtp->rev_chap_name_offset); 621 } else { 622 /* 623 * Just set NULL, initiator is able 624 * to deal with this 625 */ 626 boot_property.boot_tgt.tgt_chap_name = 627 NULL; 628 } 629 630 if (tgtp->rev_chap_secret_len != 0) { 631 boot_property.boot_tgt.tgt_chap_sec = 632 (uchar_t *)kmem_zalloc( 633 tgtp->rev_chap_secret_len + 1, 634 KM_SLEEP); 635 boot_property.boot_tgt.tgt_chap_sec_len 636 = tgtp->rev_chap_secret_len + 1; 637 tmp = (char *) 638 boot_property.boot_tgt.tgt_chap_sec; 639 (void) snprintf( 640 tmp, 641 tgtp->rev_chap_secret_len + 1, 642 "%s", 643 begin_of_ibft + 644 tgtp->chap_secret_offset); 645 } else { 646 boot_property.boot_tgt.tgt_chap_sec = 647 NULL; 648 return (IBFT_STATUS_BADCHAPSEC); 649 } 650 } 651 } else { 652 boot_property.boot_init.ini_chap_name = NULL; 653 boot_property.boot_init.ini_chap_sec = NULL; 654 } 655 656 /* 657 * Get Boot LUN 658 */ 659 (void) bcopy(tgtp->boot_lun, 660 boot_property.boot_tgt.tgt_boot_lun, 8); 661 } 662 663 return (IBFT_STATUS_OK); 664 } 665 666 /* 667 * This function is used for scanning iBFT from the physical memory. 668 * Return Value: 669 * IBFT_STATUS_OK 670 * IBFT_STATUS_ERR 671 */ 672 static ibft_status_t 673 iscsi_scan_ibft_tbl(char *ibft_tbl_buf) 674 { 675 int start; 676 void *va = NULL; 677 int *len = NULL; 678 ibft_status_t ret = IBFT_STATUS_NOTABLE; 679 680 for (start = ISCSI_IBFT_LOWER_ADDR; start < ISCSI_IBFT_HIGHER_ADDR; 681 start = start + ISCSI_IBFT_ALIGNED) { 682 va = (void *)psm_map((paddr_t)(start&0xffffffff), 683 ISCSI_IBFT_SIGNATURE_LEN, 684 PROT_READ); 685 686 if (va == NULL) { 687 continue; 688 } 689 if (memcmp(va, ISCSI_IBFT_SIGNATRUE, 690 ISCSI_IBFT_SIGNATURE_LEN) == 0) { 691 ret = IBFT_STATUS_ERR; 692 /* Acquire table length */ 693 len = (int *)psm_map( 694 (paddr_t)((start+\ 695 ISCSI_IBFT_SIGNATURE_LEN)&0xffffffff), 696 ISCSI_IBFT_SIGNATURE_LEN, PROT_READ); 697 if (len == NULL) { 698 psm_unmap((caddr_t)va, 699 ISCSI_IBFT_SIGNATURE_LEN); 700 continue; 701 } 702 if (ISCSI_IBFT_LOWER_ADDR + *len < 703 ISCSI_IBFT_HIGHER_ADDR - 1) { 704 psm_unmap(va, 705 ISCSI_IBFT_SIGNATURE_LEN); 706 va = psm_map((paddr_t)(start&0xffffffff), 707 *len, 708 PROT_READ); 709 if (va != NULL) { 710 /* 711 * Copy data to our own buffer 712 */ 713 bcopy(va, ibft_tbl_buf, *len); 714 ret = IBFT_STATUS_OK; 715 } 716 psm_unmap((caddr_t)va, *len); 717 psm_unmap((caddr_t)len, 718 ISCSI_IBFT_SIGNATURE_LEN); 719 break; 720 } else { 721 psm_unmap((caddr_t)va, 722 ISCSI_IBFT_SIGNATURE_LEN); 723 psm_unmap((caddr_t)len, 724 ISCSI_IBFT_SIGNATURE_LEN); 725 } 726 } else { 727 psm_unmap((caddr_t)va, ISCSI_IBFT_SIGNATURE_LEN); 728 } 729 } 730 731 return (ret); 732 } 733 734 /* 735 * Scan the ibft table and store the iSCSI boot properties 736 * If there is a valid table then set the iscsiboot_prop 737 * iBF should be off if the host is not intended 738 * to be booted from iSCSI disk 739 */ 740 void 741 ld_ib_prop() 742 { 743 ibft_status_t ret = IBFT_STATUS_OK; 744 char *ibft_tbl_buf; 745 746 if (do_bsys_getproplen(NULL, "ibft-noprobe") > 0) 747 ibft_noprobe = 1; 748 749 if (ibft_noprobe != 0) { 750 /* 751 * Scanning for iBFT may conflict with devices which use memory 752 * in 640-1024KB of physical address space. The iBFT 753 * specification suggests use of low RAM method - scanning 754 * physical memory 512-1024 KB for iBFT table. However, the 755 * Upper Memory Area (UMA) 640-1024 KB may contain device 756 * memory or memory mapped I/O. Although reading from I/O area 757 * is usually fine, the actual behavior depends on device 758 * implementation. In some cases, the user may want to disable 759 * low RAM method and prevent reading from device I/O area. 760 * 761 * To disable low RAM method: 762 * 1) pass "-B ibft-noprobe=1" on kernel command line 763 * 2) add line "set ibft_noprobe=1" in /etc/system 764 */ 765 cmn_err(CE_NOTE, IBFT_NOPROBE_MSG); 766 return; 767 } 768 769 ibft_tbl_buf = (char *)kmem_zalloc(ISCSI_IBFT_TBL_BUF_LEN, 770 KM_SLEEP); 771 772 if (!ibft_tbl_buf) { 773 /* Unlikely to happen */ 774 cmn_err(CE_NOTE, IBFT_INVALID_MSG, 775 IBFT_STATUS_LOWMEM); 776 return; 777 } 778 779 (void) memset(&boot_property, 0, sizeof (boot_property)); 780 if ((ret = iscsi_scan_ibft_tbl(ibft_tbl_buf)) == 781 IBFT_STATUS_OK) { 782 ret = iscsi_parse_ibft_tbl( 783 (iscsi_ibft_tbl_hdr_t *)ibft_tbl_buf); 784 if (ret == IBFT_STATUS_OK) { 785 iscsiboot_prop = &boot_property; 786 iscsi_print_boot_property(); 787 } else { 788 cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret); 789 } 790 } else if (ret != IBFT_STATUS_NOTABLE) { 791 cmn_err(CE_NOTE, IBFT_INVALID_MSG, ret); 792 } 793 794 kmem_free(ibft_tbl_buf, ISCSI_IBFT_TBL_BUF_LEN); 795 } 796