2 * Copyright (C) IBM Corporation. 2007
3 * Author: Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
4 * Copyright (C) Red Hat, Inc. All rights reserved. 2008
5 * Copyright (C) Mike Christie 2008
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #define _XOPEN_SOURCE 500
30 #include <sys/types.h>
33 #include "fw_context.h"
38 #define IBFT_SYSFS_ROOT "/sys/firmware/ibft/"
39 #define IBFT_SUBSYS "ibft"
41 static char *target_list
[IBFT_MAX
];
42 static char *nic_list
[IBFT_MAX
];
46 static int file_exist(const char *file
)
48 struct stat bootpath_stat
;
50 return !stat(file
, &bootpath_stat
);
54 * Finds the etherrnetX and targetX under the sysfs directory.
56 static int find_sysfs_dirs(const char *fpath
, const struct stat
*sb
,
57 int tflag
, struct FTW
*ftw
)
59 if (tflag
== FTW_D
&& (strstr(fpath
+ ftw
->base
, "target"))) {
60 if (tgt_cnt
== IBFT_MAX
) {
61 printf("Too many targets found in IBFT data."
62 "Max number of targets %d\n", IBFT_MAX
);
65 target_list
[tgt_cnt
++] = strdup(strstr(fpath
, "target"));
68 if (tflag
== FTW_D
&& (strstr(fpath
+ ftw
->base
, "ethernet"))) {
69 if (nic_cnt
== IBFT_MAX
) {
70 printf("Too many nics found in IBFT data."
71 "Max number of nics %d\n", IBFT_MAX
);
74 nic_list
[nic_cnt
++] = strdup(strstr(fpath
, "ethernet"));
80 static int get_iface_from_device(char *id
, struct boot_context
*context
)
82 char dev_dir
[FILENAMESZ
];
87 memset(dev_dir
, 0, FILENAMESZ
);
88 snprintf(dev_dir
, FILENAMESZ
, IBFT_SYSFS_ROOT
"/%s/device", id
);
90 if (!file_exist(dev_dir
))
93 dirfd
= opendir(dev_dir
);
97 while ((dent
= readdir(dirfd
))) {
98 if (!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, "..") ||
99 strncmp(dent
->d_name
, "net", 3))
102 if (!strncmp(dent
->d_name
, "net:", 4)) {
103 if ((strlen(dent
->d_name
) - 4) >
104 (sizeof(context
->iface
) - 1)) {
106 printf("Net device %s too big for iface "
107 "buffer.\n", dent
->d_name
);
111 if (sscanf(dent
->d_name
, "net:%s", context
->iface
) != 1)
116 printf("Could not read ethernet to net link\n.");
127 /* If not found try again with newer kernel networkdev sysfs layout */
128 strlcat(dev_dir
, "/net", FILENAMESZ
);
130 if (!file_exist(dev_dir
))
133 dirfd
= opendir(dev_dir
);
137 while ((dent
= readdir(dirfd
))) {
138 if (!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
141 /* Take the first "regular" directory entry */
142 if (strlen(dent
->d_name
) > (sizeof(context
->iface
) - 1)) {
144 printf("Net device %s too big for iface buffer.\n",
149 strcpy(context
->iface
, dent
->d_name
);
160 * Routines to fill in the context values.
162 static int fill_nic_context(char *id
, struct boot_context
*context
)
166 rc
= sysfs_get_str(id
, IBFT_SUBSYS
, "mac", context
->mac
,
167 sizeof(context
->mac
));
171 rc
= get_iface_from_device(id
, context
);
175 sysfs_get_str(id
, IBFT_SUBSYS
, "ip-addr", context
->ipaddr
,
176 sizeof(context
->ipaddr
));
177 sysfs_get_str(id
, IBFT_SUBSYS
, "vlan", context
->vlan
,
178 sizeof(context
->vlan
));
179 sysfs_get_str(id
, IBFT_SUBSYS
, "subnet-mask", context
->mask
,
180 sizeof(context
->mask
));
181 sysfs_get_str(id
, IBFT_SUBSYS
, "gateway", context
->gateway
,
182 sizeof(context
->gateway
));
183 sysfs_get_str(id
, IBFT_SUBSYS
, "primary-dns", context
->primary_dns
,
184 sizeof(context
->primary_dns
));
185 sysfs_get_str(id
, IBFT_SUBSYS
, "secondary-dns", context
->secondary_dns
,
186 sizeof(context
->secondary_dns
));
187 sysfs_get_str(id
, IBFT_SUBSYS
, "dhcp", context
->dhcp
,
188 sizeof(context
->dhcp
));
192 static void fill_initiator_context(struct boot_context
*context
)
194 sysfs_get_str("initiator", IBFT_SUBSYS
, "initiator-name",
195 context
->initiatorname
,
196 sizeof(context
->initiatorname
));
197 sysfs_get_str("initiator", IBFT_SUBSYS
, "isid", context
->isid
,
198 sizeof(context
->isid
));
200 static int fill_tgt_context(char *id
, struct boot_context
*context
)
204 rc
= sysfs_get_str(id
, IBFT_SUBSYS
, "target-name", context
->targetname
,
205 sizeof(context
->targetname
));
209 rc
= sysfs_get_str(id
, IBFT_SUBSYS
, "ip-addr", context
->target_ipaddr
,
210 sizeof(context
->target_ipaddr
));
215 * We can live without the rest of they do not exist. If we
216 * failed to get them we will figure it out when we login.
218 if (sysfs_get_int(id
, IBFT_SUBSYS
, "port", &context
->target_port
))
219 context
->target_port
= ISCSI_LISTEN_PORT
;
221 sysfs_get_str(id
, IBFT_SUBSYS
, "lun", context
->lun
,
222 sizeof(context
->lun
));
223 sysfs_get_str(id
, IBFT_SUBSYS
, "chap-name", context
->chap_name
,
224 sizeof(context
->chap_name
));
225 sysfs_get_str(id
, IBFT_SUBSYS
, "chap-secret",
226 context
->chap_password
,
227 sizeof(context
->chap_password
));
228 sysfs_get_str(id
, IBFT_SUBSYS
, "rev-chap-name",
229 context
->chap_name_in
,
230 sizeof(context
->chap_name_in
));
231 sysfs_get_str(id
, IBFT_SUBSYS
, "rev-chap-name-secret",
232 context
->chap_password_in
,
233 sizeof(context
->chap_password_in
));
237 #define IBFT_SYSFS_FLAG_FW_SEL_BOOT 2
239 static int find_boot_flag(char *list
[], ssize_t size
, int *boot_idx
)
244 for (i
= 0; i
< size
; i
++, flag
= -1) {
245 rc
= sysfs_get_int(list
[i
], IBFT_SUBSYS
, "flags", &flag
);
249 if (flag
& IBFT_SYSFS_FLAG_FW_SEL_BOOT
) {
262 static void deallocate_lists(void)
266 for (i
= 0; i
< nic_cnt
; i
++)
270 for (i
= 0; i
< tgt_cnt
; i
++)
271 free(target_list
[i
]);
277 int fwparam_ibft_sysfs_boot_info(struct boot_context
*context
)
279 char initiator_dir
[FILENAMESZ
];
281 int nic_idx
= -1, tgt_idx
= -1;
283 memset(&initiator_dir
, 0 , FILENAMESZ
);
284 snprintf(initiator_dir
, FILENAMESZ
, "%sinitiator",
289 if (file_exist(initiator_dir
)) {
290 /* Find the target's and the ethernet's */
291 rc
= nftw(IBFT_SYSFS_ROOT
, find_sysfs_dirs
, 20, 1);
293 /* Find wihch target and which ethernet have
294 the boot flag set. */
295 rc
= find_boot_flag(nic_list
, nic_cnt
, &nic_idx
);
299 rc
= find_boot_flag(target_list
, tgt_cnt
, &tgt_idx
);
303 /* Fill in the context values */
304 rc
= fill_nic_context(nic_list
[nic_idx
], context
);
305 rc
|= fill_tgt_context(target_list
[tgt_idx
], context
);
306 fill_initiator_context(context
);
313 int fwparam_ibft_sysfs_get_targets(struct list_head
*list
)
315 struct boot_context
*context
;
316 int rc
= 0, i
, nic_idx
, nic
;
317 char initiator_dir
[FILENAMESZ
];
319 memset(&initiator_dir
, 0 , FILENAMESZ
);
320 snprintf(initiator_dir
, FILENAMESZ
, "%sinitiator",
323 if (!file_exist(initiator_dir
))
329 /* Find the target's and the ethernet's */
330 nftw(IBFT_SYSFS_ROOT
, find_sysfs_dirs
, 20, 1);
331 for (i
= 0; i
< tgt_cnt
; i
++) {
332 context
= calloc(1, sizeof(*context
));
338 rc
= fill_tgt_context(target_list
[i
], context
);
342 rc
= sysfs_get_int(target_list
[i
], IBFT_SUBSYS
, "nic-assoc",
347 for (nic
= 0; nic
< nic_cnt
; nic
++) {
350 rc
= sysfs_get_int(nic_list
[nic
], IBFT_SUBSYS
, "index",
352 if (!rc
&& (id
== nic_idx
))
356 if (nic
== nic_cnt
) {
357 printf("Invalid nic-assoc of %d. Max id %d.\n",
362 rc
= fill_nic_context(nic_list
[nic
], context
);
366 fill_initiator_context(context
);
367 list_add_tail(&context
->list
, list
);
373 fw_free_targets(list
);