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
iscsi_ibft_hdr_checksum(iscsi_ibft_tbl_hdr_t * tbl_hdr)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
iscsi_parse_ibft_structure(char * begin_of_ibft,char * buf)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
iscsi_parse_ibft_tbl(iscsi_ibft_tbl_hdr_t * tbl_hdr)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
iscsi_parse_ibft_control(iscsi_ibft_ctl_t * ctl_hdr,ushort_t * iscsi_offset_buf)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
iscsi_parse_ibft_initiator(char * begin_of_ibft,iscsi_ibft_initiator_t * initiator)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
iscsi_parse_ipaddr(uchar_t * source,char * dest,int * af)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
iscsi_copy_ibft_ipaddr(uchar_t * source,void * dest,int * af)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
iscsi_parse_ibft_NIC(iscsi_ibft_nic_t * nicp)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
iscsi_parse_ibft_target(char * begin_of_ibft,iscsi_ibft_tgt_t * tgtp)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
iscsi_scan_ibft_tbl(char * ibft_tbl_buf)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
ld_ib_prop()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