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