11
#include <sys/types.h>
15
#include <linux/types.h>
16
#include <linux/unistd.h>
19
#include "initiator.h"
20
#include "transport.h"
23
#define ISCSI_TRANSPORT_DIR "/sys/class/iscsi_transport"
24
#define ISCSI_MAX_SYSFS_BUFFER NI_MAXHOST
26
/* tmp buffer used by sysfs functions */
27
static char sysfs_file[PATH_MAX];
28
int num_providers = 0;
29
struct qelem providers;
31
int read_sysfs_file(char *filename, void *value, char *format)
34
char buffer[ISCSI_MAX_SYSFS_BUFFER + 1], *line;
37
file = fopen(filename, "r");
39
line = fgets(buffer, sizeof(buffer), file);
41
sscanf(buffer, format, value);
43
log_debug(5, "Could not read %s.\n", filename);
48
log_debug(5, "Could not open %s.\n", filename);
54
void init_providers(void)
56
providers.q_forw = &providers;
57
providers.q_back = &providers;
60
static int trans_filter(const struct dirent *dir)
62
return strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..");
65
static int read_transports(void)
68
struct dirent **namelist;
70
int i, n, found, err = 0;
73
log_debug(7, "in %s", __FUNCTION__);
75
if (num_providers == 0)
78
n = scandir(ISCSI_TRANSPORT_DIR, &namelist, trans_filter,
81
log_error("Could not scan %s.", ISCSI_TRANSPORT_DIR);
85
for (i = 0; i < n; i++) {
88
/* copy existing pr vider to new array */
89
item = providers.q_forw;
90
while (item != &providers) {
91
p = (iscsi_provider_t *)item;
93
if (!strcmp(p->name, namelist[i]->d_name)) {
103
/* copy new provider */
104
p = malloc(sizeof(iscsi_provider_t));
108
p->sessions.q_forw = &p->sessions;
109
p->sessions.q_back = &p->sessions;
111
strncpy(p->name, namelist[i]->d_name,
112
ISCSI_TRANSPORT_NAME_MAXLEN);
114
sprintf(filename, ISCSI_TRANSPORT_DIR"/%s/handle", p->name);
115
err = read_sysfs_file(filename, &p->handle, "%llu\n");
119
sprintf(filename, ISCSI_TRANSPORT_DIR"/%s/caps", p->name);
120
err = read_sysfs_file(filename, &p->caps, "0x%x");
124
insque(&p->list, &providers);
127
for (i = 0; i < n; i++)
135
int get_sessioninfo_by_sysfs_id(int *sid, char *targetname, char *addr,
136
int *port, int *tpgt, char *session)
140
if (sscanf(session, "session%d", sid) != 1) {
141
log_error("invalid session '%s'", session);
145
memset(sysfs_file, 0, PATH_MAX);
146
sprintf(sysfs_file, "/sys/class/iscsi_session/%s/targetname", session);
147
ret = read_sysfs_file(sysfs_file, targetname, "%s\n");
149
log_error("could not read session targetname: %d", ret);
153
memset(sysfs_file, 0, PATH_MAX);
154
sprintf(sysfs_file, "/sys/class/iscsi_session/%s/tpgt", session);
155
ret = read_sysfs_file(sysfs_file, tpgt, "%u\n");
157
log_error("could not read session tpgt: %d", ret);
161
/* some HW drivers do not export addr and port */
162
memset(sysfs_file, 0, PATH_MAX);
163
sprintf(sysfs_file, "/sys/class/iscsi_connection/connection%d:0/"
164
"persistent_address", *sid);
165
memset(addr, 0, NI_MAXHOST);
166
ret = read_sysfs_file(sysfs_file, addr, "%s\n");
168
/* fall back to current address */
169
log_debug(5, "could not read pers conn addr: %d", ret);
170
memset(sysfs_file, 0, PATH_MAX);
172
"/sys/class/iscsi_connection/connection%d:0/address",
174
memset(addr, 0, NI_MAXHOST);
175
ret = read_sysfs_file(sysfs_file, addr, "%s\n");
177
log_debug(5, "could not read curr addr: %d", ret);
180
memset(sysfs_file, 0, PATH_MAX);
181
sprintf(sysfs_file, "/sys/class/iscsi_connection/connection%d:0/"
182
"persistent_port", *sid);
184
ret = read_sysfs_file(sysfs_file, port, "%u\n");
186
/* fall back to current port */
187
log_debug(5, "Could not read pers conn port %d\n", ret);
188
memset(sysfs_file, 0, PATH_MAX);
190
"/sys/class/iscsi_connection/connection%d:0/port",
193
ret = read_sysfs_file(sysfs_file, port, "%u\n");
195
log_debug(5, "Could not read curr conn port %d\n", ret);
198
log_debug(7, "found targetname %s address %s port %d\n",
199
targetname, addr ? addr : "NA", *port);
203
int sysfs_for_each_session(void *data, int *nr_found,
204
int (* fn)(void *, char *, int, char *, int, int))
208
int rc = 0, sid, port, tpgt;
209
char *targetname, *address;
211
targetname = malloc(TARGET_NAME_MAXLEN + 1);
215
address = malloc(NI_MAXHOST + 1);
221
sprintf(sysfs_file, "/sys/class/iscsi_session");
222
dirfd = opendir(sysfs_file);
228
while ((dent = readdir(dirfd))) {
229
if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
232
rc = get_sessioninfo_by_sysfs_id(&sid, targetname, address,
233
&port, &tpgt, dent->d_name);
235
log_error("could not find session info for %s",
240
rc = fn(data, targetname, tpgt, address, port, sid);
254
uint32_t get_host_no_from_sid(uint32_t sid, int *err)
256
char buf[PATH_MAX], path[PATH_MAX], *tmp;
261
memset(buf, 0, PATH_MAX);
262
memset(path, 0, PATH_MAX);
263
sprintf(path, "/sys/class/iscsi_session/session%d/device", sid);
264
if (readlink(path, buf, PATH_MAX) < 0) {
265
log_error("Could not get link for %s\n", path);
270
/* buf will be .....bus_info/hostX/sessionY */
273
tmp = strrchr(buf, '/');
276
/* find bus and increment past it */
277
tmp = strrchr(buf, '/');
280
if (sscanf(tmp, "host%u", &host_no) != 1) {
281
log_error("Could not get host for sid %u\n", sid);
289
iscsi_provider_t *get_transport_by_name(char *transport_name)
294
/* sync up kernel and userspace */
297
/* check if the transport is loaded */
298
pitem = providers.q_forw;
299
while (pitem != &providers) {
300
p = (iscsi_provider_t *)pitem;
302
if (p->handle && !strncmp(p->name, transport_name,
303
ISCSI_TRANSPORT_NAME_MAXLEN))
305
pitem = pitem->q_forw;
310
/* TODO: replace the following functions with some decent sysfs links */
311
iscsi_provider_t *get_transport_by_hba(long host_no)
313
char name[ISCSI_TRANSPORT_NAME_MAXLEN];
319
memset(sysfs_file, 0, PATH_MAX);
320
sprintf(sysfs_file, "/sys/class/scsi_host/host%lu/proc_name", host_no);
321
rc = read_sysfs_file(sysfs_file, name, "%s\n");
323
log_error("Could not read %s rc %d\n", sysfs_file, rc);
328
* stupid, stupid. We named the transports tcp or iser, but the
329
* the modules are named iscsi_tcp and iscsi_iser
331
if (strstr(name, "iscsi_"))
332
return get_transport_by_name(name + 6);
334
return get_transport_by_name(name);
337
iscsi_provider_t *get_transport_by_sid(uint32_t sid)
342
host_no = get_host_no_from_sid(sid, &err);
345
return get_transport_by_hba(host_no);
349
* For connection reinstatement we need to send the exp_statsn from
350
* the previous connection
352
* This is only called when the connection is halted so exp_statsn is safe
353
* to read without racing.
355
int set_exp_statsn(iscsi_conn_t *conn)
358
"/sys/class/iscsi_connection/connection%d:%d/exp_statsn",
359
conn->session->id, conn->id);
360
if (read_sysfs_file(sysfs_file, &conn->exp_statsn, "%u\n")) {
361
log_error("Could not read %s. Using zero fpr exp_statsn\n",
363
conn->exp_statsn = 0;
368
int sysfs_for_each_device(int host_no, uint32_t sid,
369
void (* fn)(int host_no, int lun))
375
sprintf(sysfs_file, "/sys/class/iscsi_session/session%d/device/target%d:0:0", sid, host_no);
376
dirfd = opendir(sysfs_file);
380
while ((dent = readdir(dirfd))) {
381
if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
384
if (sscanf(dent->d_name, "%d:%d:%d:%d\n", &h, &b, &t, &l) != 4)
391
void set_device_online(int hostno, int lun)
395
sprintf(sysfs_file, "/sys/bus/scsi/devices/%d:0:0:%d/state",
397
fd = open(sysfs_file, O_WRONLY);
400
log_debug(4, "online device using %s", sysfs_file);
401
if (write(fd, "running\n", 8) == -1 && errno != EINVAL)
402
/* we should read the state */
403
log_error("Could not online LUN %d err %d\n",
408
/* TODO: remove this when we fix shutdown */
409
void delete_device(int hostno, int lun)
413
sprintf(sysfs_file, "/sys/bus/scsi/devices/%d:0:0:%d/delete",
415
fd = open(sysfs_file, O_WRONLY);
418
log_debug(4, "deleting device using %s", sysfs_file);
424
* Scan a session from usersapce using sysfs
426
pid_t scan_host(iscsi_session_t *session)
428
int hostno = session->hostno;
432
sprintf(sysfs_file, "/sys/class/scsi_host/host%d/scan",
434
fd = open(sysfs_file, O_WRONLY);
436
log_error("could not scan scsi host%d\n", hostno);
443
log_debug(4, "scanning host%d using %s",hostno,
445
write(fd, "- - -", 5);
446
log_debug(4, "scanning host%d completed\n", hostno);
447
} else if (pid > 0) {
448
log_debug(4, "scanning host%d from pid %d", hostno, pid);
451
* Session is fine, so log the error and let the user
454
log_error("Could not start scanning process for host %d "
455
"err %d. Try scanning through sysfs\n", hostno,
462
iscsi_provider_t *get_transport_by_session(char *sys_session)
466
if (sscanf(sys_session, "session%u", &sid) != 1) {
467
log_error("invalid session '%s'", sys_session);
471
return get_transport_by_sid(sid);
474
void check_class_version(void)
479
if (read_sysfs_file(ISCSI_VERSION_FILE, version, "%s\n"))
482
log_warning("transport class version %s. iscsid version %s\n",
483
version, ISCSI_VERSION_STR);
485
for (i = 0; i < strlen(version); i++) {
486
if (version[i] == '-')
490
if (i == strlen(version))
494
* We want to make sure the release and interface are the same.
495
* It is ok for the svn versions to be different.
497
if (!strncmp(version, ISCSI_VERSION_STR, i) ||
499
!strncmp(version, "1.1", 3))
503
log_error("Invalid version from %s. Make sure a up to date "
504
"scsi_transport_iscsi module is loaded and a up to"
505
"date version of iscsid is running. Exiting...\n",