2
* Copyright(c) 2009 Intel Corporation. All rights reserved.
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.
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
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.
17
* Maintained at www.Open-FCoE.org
32
#include <arpa/inet.h>
33
#include <sys/types.h>
34
#include <sys/ioctl.h>
36
#include <linux/types.h>
41
#include <linux/bsg.h>
43
#include <scsi/fc/fc_els.h>
44
#include <scsi/scsi_bsg_fc.h>
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 }
49
#define SYSFS_FC_RPORTS "/sys/class/fc_remote_ports"
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__));
70
struct fc_els_lesb fs3;
71
struct fcoe_fc_els_lesb bb5;
72
} __attribute__((__packed__));
79
} __attribute__((__packed__));
86
} __attribute__((__packed__));
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",
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",
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",
161
* :: - has optional arg
162
* ; - arg is long opt
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 },
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.",
180
#define bsg_error(format...) \
182
fprintf(stderr, "ERROR: " format); \
185
#define bsg_debug(format...) \
188
printf("DEBUG: " format); \
191
static char *els_rjt2str(int type, int code)
195
str = (type == 0) ? rjt_reason : rjt_explan;
206
static int els_print_lesb(struct fcoe_fc_els_lesb *lesb)
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));
225
static int els_print_rjt(struct rls_rjt *rjt)
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",
238
static int bsg_rport_els(int bsg, u8 els_code, void *req, int req_len,
239
void *rsp, int rsp_len)
243
struct fc_bsg_reply *reply = (struct fc_bsg_reply *)sense;
244
struct fc_bsg_request cdb = {
245
.msgcode = FC_BSG_RPT_ELS,
247
.els_code = els_code,
251
struct sg_io_v4 sgio = {
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),
265
memset(sense, 0, sizeof(sense));
266
rc = ioctl(bsg, SG_IO, &sgio);
267
bsg_debug("ioctl returned %d: bsg_reply result=%d\n",
272
static int bsg_rport_els_rls(int bsg, struct rport_info *rpi)
275
struct fc_els_rls rls = {
277
.rls_port_id = hton24(rpi->port_id),
281
memset(&rsp, 0, sizeof(rsp));
282
rc = bsg_rport_els(bsg, ELS_RLS, &rls, sizeof(rls), &rsp, sizeof(rsp));
284
bsg_error("bsg_rport_els(ELS_RLS) failed\n");
287
if (rsp.rls_cmd == ELS_LS_ACC)
288
return els_print_lesb(&rsp.acc.bb5);
290
if (rsp.rls_cmd == ELS_LS_RJT)
291
return els_print_rjt(&rsp.rjt);
293
bsg_error("Unknow response!\n");
297
static int rport_getid(struct rport_info *rpi)
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");
308
bsg_error("failed to fopen(%s)!\n", rp_sysfs);
311
if (1 != fscanf(f, "0x%6x", &rpi->port_id)) {
312
bsg_error("failed to fscanf(%s)\n", rp_sysfs);
316
if (rpi->port_id & 0xff000000) {
317
bsg_error("rport %s:invalid fcid 0x%x\n", rp_sysfs,
328
* parse a string in format of rport-%d:%d-%d, and get the
329
* corresponding rport info.
332
static int rport_parse(const char *s, struct rport_info *rpi)
336
memset(rpi, 0, sizeof(*rpi));
337
if (3 != sscanf(s, "rport-%d:%d-%d", &rpi->host_no, &rpi->channel,
340
if (rport_getid(rpi))
345
#define RPORT_ONLINE "Online"
346
static int rport_check_state(struct rport_info *rpi)
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);
359
f = fopen(rp_sysfs, "ro");
361
bsg_error("failed to fopen(%s)!\n", rp_sysfs);
364
if (!fgets(rp_state, sizeof(rp_state), f)) {
365
bsg_error("failed to fgets(%s)!\n", rp_sysfs);
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);
379
/* locate rport by fcid */
380
static int rport_find(struct rport_info *rpi)
383
struct dirent **namelist;
384
struct rport_info rpii;
392
n = scandir(SYSFS_FC_RPORTS, &namelist, 0, alphasort);
394
bsg_error("failed to scandir %s\n", SYSFS_FC_RPORTS);
398
if (namelist[n]->d_type != DT_DIR)
400
if (rport_parse(namelist[n]->d_name, &rpii))
402
if (rpi->port_id != rpii.port_id)
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,
416
static void bsg_usage(int status)
421
bsg_error("Failed! %s (Errno %d)!\n", strerror(status), status);
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]);
431
int main(int argc, char *argv[])
437
char *bsg_name = NULL;
438
struct rport_info rpi;
441
while ((opt = getopt_long(argc, argv, "", lopt, NULL)) != -1) {
444
if (rport_parse(optarg, &rpi)) {
445
bsg_error("%s format incorrect, must be:"
446
"rport-host:channel-number\n", optarg);
453
rpi.port_id = strtoull(optarg, &endptr, 16);
454
if (*endptr != '\0') {
455
bsg_error("%s has no valid FCID\n", optarg);
458
if (rport_find(&rpi)) {
459
bsg_error("%s is not a rport\n", optarg);
472
/* bsg device name */
476
if (asprintf(&bsg_name, "/dev/bsg/rport-%d:%d-%d",
477
rpi.host_no, rpi.channel, rpi.number) < 0) {
479
bsg_error("not enough memory!\n");
482
/* open bsg device */
483
bsg_dev = open(bsg_name, O_RDWR);
485
bsg_error("failed to open %s!\n", bsg_name);
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);
494
rc = bsg_rport_els_rls(bsg_dev, &rpi);
496
bsg_error("Faild to bsg_rport_els_rls\n");