~ubuntu-branches/ubuntu/wily/fcoe-utils/wily

« back to all changes in this revision

Viewing changes to fcrls.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2010-02-16 14:46:23 UTC
  • Revision ID: james.westby@ubuntu.com-20100216144623-n6gqxpxc5nvonv9f
Tags: upstream-1.0.9
ImportĀ upstreamĀ versionĀ 1.0.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright(c) 2009 Intel Corporation. All rights reserved.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify it
 
5
 * under the terms and conditions of the GNU General Public License,
 
6
 * version 2, as published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope it will be useful, but WITHOUT
 
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
10
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
11
 * more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License along with
 
14
 * this program; if not, write to the Free Software Foundation, Inc.,
 
15
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 
16
 *
 
17
 * Maintained at www.Open-FCoE.org
 
18
 */
 
19
 
 
20
#define _GNU_SOURCE
 
21
#include <stdio.h>
 
22
#include <stdint.h>
 
23
#include <stdlib.h>
 
24
#include <dirent.h>
 
25
#include <stdarg.h>
 
26
#include <stdbool.h>
 
27
#include <unistd.h>
 
28
#include <string.h>
 
29
#include <errno.h>
 
30
#include <fcntl.h>
 
31
#include <getopt.h>
 
32
#include <arpa/inet.h>
 
33
#include <sys/types.h>
 
34
#include <sys/ioctl.h>
 
35
#include <sys/stat.h>
 
36
#include <linux/types.h>
 
37
typedef __u8 u8;
 
38
typedef __u16 u16;
 
39
typedef __u32 u32;
 
40
typedef __u64 u64;
 
41
#include <linux/bsg.h>
 
42
#include <scsi/sg.h>
 
43
#include <scsi/fc/fc_els.h>
 
44
#include <scsi/scsi_bsg_fc.h>
 
45
 
 
46
#define ntoh24(n) (u32) ((n)[0] << 16 | (n)[1] << 8  | (n)[2])
 
47
#define hton24(h) { (h) >> 16 & 0xff, (h) >> 8 & 0xff, (h) & 0xff }
 
48
 
 
49
#define SYSFS_FC_RPORTS "/sys/class/fc_remote_ports"
 
50
 
 
51
struct rport_info {
 
52
        int host_no;
 
53
        int channel;
 
54
        u32 number;
 
55
        u32 port_id;
 
56
        bool found;
 
57
        bool online;
 
58
};
 
59
 
 
60
struct fcoe_fc_els_lesb {
 
61
        __be32 lesb_link_fail;  /* link failure count */
 
62
        __be32 lesb_vlink_fail; /* virtual link failure count */
 
63
        __be32 lesb_miss_fka;   /* missing FIP keep-alive count */
 
64
        __be32 lesb_symb_err;   /* symbol error during carrier count */
 
65
        __be32 lesb_err_block;  /* errored block count */
 
66
        __be32 lesb_fcs_error; /* frame check sequence error count */
 
67
} __attribute__((__packed__));
 
68
 
 
69
union rls_acc {
 
70
        struct fc_els_lesb fs3;
 
71
        struct fcoe_fc_els_lesb bb5;
 
72
} __attribute__((__packed__));
 
73
 
 
74
struct rls_rjt {
 
75
        u8 er_resv;
 
76
        u8 er_reason;
 
77
        u8 er_explan;
 
78
        u8 er_vendor;
 
79
} __attribute__((__packed__));
 
80
 
 
81
struct rls_rsp {
 
82
        u8 rls_cmd;
 
83
        u8 rls_resv[3];
 
84
        union rls_acc acc;
 
85
        struct rls_rjt rjt;
 
86
} __attribute__((__packed__));
 
87
 
 
88
static char *rjt_reason[] = {
 
89
        [1] = "Invalid command code",
 
90
        [2] = "Invalid version level",
 
91
        [3] = "Logical error",
 
92
        [4] = "Invalid CT_IU size",
 
93
        [5] = "Logical busy",
 
94
        [7] = "Protocol error",
 
95
        [9] = "Unable to perform command request",
 
96
        [0xB] = "Command not supported",
 
97
        [0xD] = "Server not available",
 
98
        [0xE] = "Session could not be established",
 
99
        [0xFF] = "Vendor specific",
 
100
        [0x100] = "N/A",
 
101
};
 
102
 
 
103
static char *rjt_explan[] = {
 
104
        [0] = "No additional explanation",
 
105
        [1] = "Port Identifier not registered",
 
106
        [2] = "Port Name not registered",
 
107
        [3] = "Node Name not registered",
 
108
        [4] = "Class of Service not registered",
 
109
        [6] = "Initial Process Associator not registered",
 
110
        [7] = "FC-4 Types not registered",
 
111
        [8] = "Symbolic Port Name not registered",
 
112
        [9] = "Symbolic Node Name not registered",
 
113
        [0xA] = "Port Type not registered",
 
114
        [0xC] = "Fabric Port Name not registered",
 
115
        [0xD] = "Hard Address not registered",
 
116
        [0xF] = "FC-4 Features not registered",
 
117
        [0x10] = "Access denied",
 
118
        [0x11] = "Unacceptable Port Identifier",
 
119
        [0x12] = "Data base empty",
 
120
        [0x13] = "No object registered in the specified scope",
 
121
        [0x14] = "Domain ID not present",
 
122
        [0x15] = "Port number not present",
 
123
        [0x16] = "No device attached",
 
124
        [0x17] = "invalid OX_ID-RX_ID combination",
 
125
        [0x19] = "Request already in progress",
 
126
        [0x1e] = "N_Port login required",
 
127
        [0x29] = "insufficient resources",
 
128
        [0x2a] = "unable to supply requested data",
 
129
        [0x2c] = "Request not supported",
 
130
        [0x2d] = "Invalid payload length",
 
131
        [0x44] = "Invalid Port/Node_Name",
 
132
        [0x46] = "Login Extension not supported",
 
133
        [0x48] = "Authentication required",
 
134
        [0x50] = "Periodic Scan Value not allowed",
 
135
        [0x51] = "Periodic Scanning not supported",
 
136
        [0x60] = "MAC addressing mode not supported",
 
137
        [0x61] = "Proposed MAC address incorrectly formed",
 
138
        [0xf0] = "Authorization Exception",
 
139
        [0xf1] = "Authentication Exception",
 
140
        [0xf2] = "Data base full",
 
141
        [0xf3] = "Data base empty",
 
142
        [0xf4] = "Processing request",
 
143
        [0xf5] = "Unable to verify connection",
 
144
        [0xf6] = "Devices not in a common zone",
 
145
        [0x100] = "N/A",
 
146
 
 
147
};
 
148
 
 
149
enum commands {
 
150
        NONE = 0,
 
151
        RLS_PORT,
 
152
        RLS_FCID,
 
153
        RLS_QUIET,
 
154
        RLS_HELP,
 
155
};
 
156
 
 
157
/* RLS_QUIET */
 
158
static bool quiet;
 
159
 
 
160
/* : - has arg
 
161
 * :: - has optional arg
 
162
 * ;  - arg is long opt
 
163
 */
 
164
static const struct option lopt[] = {
 
165
        { "port", required_argument, NULL, RLS_PORT },
 
166
        { "fcid", required_argument, NULL, RLS_FCID },
 
167
        { "quiet", no_argument, NULL, RLS_QUIET },
 
168
        { "help", no_argument, NULL, RLS_HELP },
 
169
        { NULL, 0, NULL, 0 },
 
170
};
 
171
 
 
172
static const char *lopt_usage[] = {
 
173
        "rport bsg name, e.g., rport-7:0-1.",
 
174
        "rport port FC_ID, e.g., 0xce000d.",
 
175
        "disable verbose output.",
 
176
        "print useage information.",
 
177
        NULL,
 
178
};
 
179
 
 
180
#define bsg_error(format...)            \
 
181
({                                      \
 
182
        fprintf(stderr, "ERROR: " format);      \
 
183
})
 
184
 
 
185
#define bsg_debug(format...)            \
 
186
({                                      \
 
187
        if (!quiet)                     \
 
188
                printf("DEBUG: " format);               \
 
189
})
 
190
 
 
191
static char *els_rjt2str(int type, int code)
 
192
{
 
193
        char **str;
 
194
 
 
195
        str = (type == 0) ? rjt_reason : rjt_explan;
 
196
 
 
197
        if (code > 0xff)
 
198
                code = 0x100;
 
199
 
 
200
        if (!str[code])
 
201
                code = 0x100;
 
202
 
 
203
        return str[code];
 
204
}
 
205
 
 
206
static int els_print_lesb(struct fcoe_fc_els_lesb *lesb)
 
207
{
 
208
        printf("RLS request accepted (LS_ACC), dumping status counters:\n"
 
209
                "\tLink Failure Count                   = %u\n"
 
210
                "\tVirtual Link Failure Count           = %u\n"
 
211
                "\tMissed Discovery Advertisement Count = %u\n"
 
212
                "\tSymbol Error During Carrier Count    = %u\n"
 
213
                "\tErrored Block Count                  = %u\n"
 
214
                "\tFrame Check Sequence Error Count     = %u\n",
 
215
                ntohl(lesb->lesb_link_fail),
 
216
                ntohl(lesb->lesb_vlink_fail),
 
217
                ntohl(lesb->lesb_miss_fka),
 
218
                ntohl(lesb->lesb_symb_err),
 
219
                ntohl(lesb->lesb_err_block),
 
220
                ntohl(lesb->lesb_fcs_error));
 
221
 
 
222
        return 0;
 
223
}
 
224
 
 
225
static int els_print_rjt(struct rls_rjt *rjt)
 
226
{
 
227
        printf("RLS request rejected (LS_RJT), check reason code below:\n"
 
228
                "\tReason Code  = 0x%02x, %s.\n"
 
229
                "\tExplain Code = 0x%02x, %s.\n",
 
230
                rjt->er_reason, els_rjt2str(0, rjt->er_reason),
 
231
                rjt->er_explan, els_rjt2str(1, rjt->er_explan));
 
232
        if (rjt->er_reason == ELS_RJT_VENDOR)
 
233
                printf("\tVendor Code  = 0x%02x (check with your vendor).\n",
 
234
                       rjt->er_vendor);
 
235
        return 0;
 
236
}
 
237
 
 
238
static int bsg_rport_els(int bsg, u8 els_code, void *req, int req_len,
 
239
                         void *rsp, int rsp_len)
 
240
{
 
241
        int rc;
 
242
        char sense[96];
 
243
        struct fc_bsg_reply *reply = (struct fc_bsg_reply *)sense;
 
244
        struct fc_bsg_request cdb = {
 
245
                .msgcode        = FC_BSG_RPT_ELS,
 
246
                .rqst_data.r_els = {
 
247
                        .els_code = els_code,
 
248
                }
 
249
        };
 
250
 
 
251
        struct sg_io_v4 sgio = {
 
252
                .guard                  = 'Q',
 
253
                .protocol               = BSG_PROTOCOL_SCSI,
 
254
                .subprotocol            = BSG_SUB_PROTOCOL_SCSI_TRANSPORT,
 
255
                .request_len            = sizeof(cdb),
 
256
                .request                = (u64)((long)&cdb),
 
257
                .dout_xfer_len          = req_len,
 
258
                .dout_xferp             = (u64)((long)req),
 
259
                .din_xfer_len           = rsp_len,
 
260
                .din_xferp              = (u64)((long)rsp),
 
261
                .max_response_len       = sizeof(sense),
 
262
                .response               = (u64)((long)&sense),
 
263
                .timeout                = 1000,
 
264
        };
 
265
        memset(sense, 0, sizeof(sense));
 
266
        rc = ioctl(bsg, SG_IO, &sgio);
 
267
        bsg_debug("ioctl returned %d: bsg_reply result=%d\n",
 
268
                 rc, reply->result);
 
269
        return rc;
 
270
}
 
271
 
 
272
static int bsg_rport_els_rls(int bsg, struct rport_info *rpi)
 
273
{
 
274
        int rc = EOPNOTSUPP;
 
275
        struct fc_els_rls rls = {
 
276
                .rls_cmd = ELS_RLS,
 
277
                .rls_port_id = hton24(rpi->port_id),
 
278
        };
 
279
        struct rls_rsp rsp;
 
280
 
 
281
        memset(&rsp, 0, sizeof(rsp));
 
282
        rc = bsg_rport_els(bsg, ELS_RLS, &rls, sizeof(rls), &rsp, sizeof(rsp));
 
283
        if (rc) {
 
284
                bsg_error("bsg_rport_els(ELS_RLS) failed\n");
 
285
                return rc;
 
286
        }
 
287
        if (rsp.rls_cmd == ELS_LS_ACC)
 
288
                return  els_print_lesb(&rsp.acc.bb5);
 
289
 
 
290
        if (rsp.rls_cmd == ELS_LS_RJT)
 
291
                return els_print_rjt(&rsp.rjt);
 
292
 
 
293
        bsg_error("Unknow response!\n");
 
294
        return EIO;
 
295
}
 
296
 
 
297
static int rport_getid(struct rport_info *rpi)
 
298
{
 
299
        FILE *f;
 
300
        char rp_sysfs[256];
 
301
 
 
302
        if (rpi->found)
 
303
                return 0;
 
304
        snprintf(rp_sysfs, sizeof(rp_sysfs), "%s/rport-%d:%d-%d/port_id",
 
305
                SYSFS_FC_RPORTS, rpi->host_no, rpi->channel, rpi->number);
 
306
        f = fopen(rp_sysfs, "ro");
 
307
        if (!f) {
 
308
                bsg_error("failed to fopen(%s)!\n", rp_sysfs);
 
309
                return ENODEV;
 
310
        }
 
311
        if (1 != fscanf(f, "0x%6x", &rpi->port_id)) {
 
312
                bsg_error("failed to fscanf(%s)\n", rp_sysfs);
 
313
                fclose(f);
 
314
                return ENODEV;
 
315
        }
 
316
        if (rpi->port_id & 0xff000000) {
 
317
                bsg_error("rport %s:invalid fcid 0x%x\n", rp_sysfs,
 
318
                          rpi->port_id);
 
319
                rpi->port_id = 0;
 
320
                fclose(f);
 
321
                return ENODEV;
 
322
        }
 
323
        fclose(f);
 
324
        return 0;
 
325
}
 
326
 
 
327
/*
 
328
 * parse a string in format of rport-%d:%d-%d, and get the
 
329
 * corresponding rport info.
 
330
 * rport-%d:%d-%d
 
331
 */
 
332
static int rport_parse(const char *s, struct rport_info *rpi)
 
333
{
 
334
        if (!s)
 
335
                return EINVAL;
 
336
        memset(rpi, 0, sizeof(*rpi));
 
337
        if (3 != sscanf(s, "rport-%d:%d-%d", &rpi->host_no, &rpi->channel,
 
338
                        &rpi->number))
 
339
                return ENODEV;
 
340
        if (rport_getid(rpi))
 
341
                return ENODEV;
 
342
        return 0;
 
343
}
 
344
 
 
345
#define RPORT_ONLINE    "Online"
 
346
static int rport_check_state(struct rport_info *rpi)
 
347
{
 
348
        FILE *f;
 
349
        char rp_sysfs[256];
 
350
        char rp_state[256];
 
351
 
 
352
        rpi->online = false;
 
353
        if (!rpi->found)
 
354
                return EINVAL;
 
355
 
 
356
        snprintf(rp_sysfs, sizeof(rp_sysfs), "%s/rport-%d:%d-%d/port_state",
 
357
                SYSFS_FC_RPORTS, rpi->host_no, rpi->channel, rpi->number);
 
358
 
 
359
        f = fopen(rp_sysfs, "ro");
 
360
        if (!f) {
 
361
                bsg_error("failed to fopen(%s)!\n", rp_sysfs);
 
362
                return ENODEV;
 
363
        }
 
364
        if (!fgets(rp_state, sizeof(rp_state), f)) {
 
365
                bsg_error("failed to fgets(%s)!\n", rp_sysfs);
 
366
                fclose(f);
 
367
                return ENODEV;
 
368
        }
 
369
        if (strncmp(rp_state, RPORT_ONLINE, strlen(RPORT_ONLINE))) {
 
370
                bsg_error("rport 0x%x %s:must be %s\n", rpi->port_id,
 
371
                        rp_state, RPORT_ONLINE);
 
372
                fclose(f);
 
373
                return ENODEV;
 
374
        }
 
375
        rpi->online = true;
 
376
        fclose(f);
 
377
        return 0;
 
378
}
 
379
/* locate rport by fcid */
 
380
static int rport_find(struct rport_info *rpi)
 
381
{
 
382
        int n;
 
383
        struct dirent **namelist;
 
384
        struct rport_info rpii;
 
385
 
 
386
        if (rpi->found)
 
387
                return 0;
 
388
 
 
389
        if (!rpi->port_id)
 
390
                return ENODEV;
 
391
 
 
392
        n = scandir(SYSFS_FC_RPORTS, &namelist, 0, alphasort);
 
393
        if (n < 0) {
 
394
                bsg_error("failed to scandir %s\n", SYSFS_FC_RPORTS);
 
395
                return ENODEV;
 
396
        }
 
397
        while (n--) {
 
398
                if (namelist[n]->d_type != DT_DIR)
 
399
                        goto free_name;
 
400
                if (rport_parse(namelist[n]->d_name, &rpii))
 
401
                        goto free_name;
 
402
                if (rpi->port_id != rpii.port_id)
 
403
                        goto free_name;
 
404
                rpii.found = true;
 
405
                memcpy(rpi, &rpii, sizeof(rpii));
 
406
                bsg_debug("found rport 0x%06x as rport-%d:%d-%d\n",
 
407
                          rpi->port_id, rpi->host_no, rpi->channel,
 
408
                          rpi->number);
 
409
free_name:
 
410
                free(namelist[n]);
 
411
        }
 
412
        free(namelist);
 
413
        return 0;
 
414
}
 
415
 
 
416
static void bsg_usage(int status)
 
417
{
 
418
        int i, n;
 
419
 
 
420
        if (status)
 
421
                bsg_error("Failed! %s (Errno %d)!\n", strerror(status), status);
 
422
 
 
423
        n = sizeof(lopt)/sizeof(struct option) - 1;
 
424
        printf("Usage: fcrls\n");
 
425
        for (i = 0; i < n; i++)
 
426
                printf("\t--%s: %s\n", lopt[i].name, lopt_usage[i]);
 
427
        exit(status);
 
428
}
 
429
 
 
430
 
 
431
int main(int argc, char *argv[])
 
432
{
 
433
        int rc = ENODEV;
 
434
        int opt;
 
435
        int bsg_dev;
 
436
        char *endptr;
 
437
        char *bsg_name = NULL;
 
438
        struct rport_info rpi;
 
439
 
 
440
        rpi.found = false;
 
441
        while ((opt = getopt_long(argc, argv, "", lopt, NULL)) != -1) {
 
442
                switch (opt) {
 
443
                case RLS_PORT:
 
444
                        if (rport_parse(optarg, &rpi)) {
 
445
                                bsg_error("%s format incorrect, must be:"
 
446
                                        "rport-host:channel-number\n", optarg);
 
447
                                bsg_usage(EINVAL);
 
448
                        }
 
449
                        rpi.found = true;
 
450
                        goto out_rls;
 
451
                case RLS_FCID:
 
452
                        rpi.found = false;
 
453
                        rpi.port_id = strtoull(optarg, &endptr, 16);
 
454
                        if (*endptr != '\0') {
 
455
                                bsg_error("%s has no valid FCID\n", optarg);
 
456
                                bsg_usage(EINVAL);
 
457
                        }
 
458
                        if (rport_find(&rpi)) {
 
459
                                bsg_error("%s is not a rport\n", optarg);
 
460
                                bsg_usage(ENODEV);
 
461
                        }
 
462
                        goto out_rls;
 
463
                case RLS_QUIET:
 
464
                        quiet = true;
 
465
                        break;
 
466
                case RLS_HELP:
 
467
                        bsg_usage(0);
 
468
                        break;
 
469
                }
 
470
        }
 
471
out_rls:
 
472
        /* bsg device name */
 
473
        if (!rpi.found)
 
474
                bsg_usage(ENODEV);
 
475
 
 
476
        if (asprintf(&bsg_name, "/dev/bsg/rport-%d:%d-%d",
 
477
                     rpi.host_no, rpi.channel, rpi.number) < 0) {
 
478
                rc = ENOMEM;
 
479
                bsg_error("not enough memory!\n");
 
480
                goto out_error;
 
481
        }
 
482
        /* open bsg device */
 
483
        bsg_dev = open(bsg_name, O_RDWR);
 
484
        if (bsg_dev < 0) {
 
485
                bsg_error("failed to open %s!\n", bsg_name);
 
486
                goto out_free;
 
487
        }
 
488
        /* check port state */
 
489
        if (rport_check_state(&rpi) || (!rpi.online)) {
 
490
                bsg_error("rport 0x%x is not online!\n", rpi.port_id);
 
491
                goto out_close;
 
492
        }
 
493
        /* send rls */
 
494
        rc = bsg_rport_els_rls(bsg_dev, &rpi);
 
495
        if (rc) {
 
496
                bsg_error("Faild to bsg_rport_els_rls\n");
 
497
                goto out_close;
 
498
        }
 
499
        rc = 0;
 
500
 
 
501
out_close:
 
502
        close(bsg_dev);
 
503
out_free:
 
504
        free(bsg_name);
 
505
out_error:
 
506
        return rc;
 
507
}