1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * QLogic FCoE Offload Driver |
4 | * Copyright (c) 2016-2018 Cavium Inc. |
5 | */ |
6 | #include "qedf.h" |
7 | |
8 | inline bool qedf_is_vport(struct qedf_ctx *qedf) |
9 | { |
10 | return qedf->lport->vport != NULL; |
11 | } |
12 | |
13 | /* Get base qedf for physical port from vport */ |
14 | static struct qedf_ctx *qedf_get_base_qedf(struct qedf_ctx *qedf) |
15 | { |
16 | struct fc_lport *lport; |
17 | struct fc_lport *base_lport; |
18 | |
19 | if (!(qedf_is_vport(qedf))) |
20 | return NULL; |
21 | |
22 | lport = qedf->lport; |
23 | base_lport = shost_priv(vport_to_shost(lport->vport)); |
24 | return lport_priv(lport: base_lport); |
25 | } |
26 | |
27 | static ssize_t fcoe_mac_show(struct device *dev, |
28 | struct device_attribute *attr, char *buf) |
29 | { |
30 | struct fc_lport *lport = shost_priv(class_to_shost(dev)); |
31 | u32 port_id; |
32 | u8 lport_src_id[3]; |
33 | u8 fcoe_mac[6]; |
34 | |
35 | port_id = fc_host_port_id(lport->host); |
36 | lport_src_id[2] = (port_id & 0x000000FF); |
37 | lport_src_id[1] = (port_id & 0x0000FF00) >> 8; |
38 | lport_src_id[0] = (port_id & 0x00FF0000) >> 16; |
39 | fc_fcoe_set_mac(mac: fcoe_mac, did: lport_src_id); |
40 | |
41 | return scnprintf(buf, PAGE_SIZE, fmt: "%pM\n" , fcoe_mac); |
42 | } |
43 | |
44 | static ssize_t fka_period_show(struct device *dev, |
45 | struct device_attribute *attr, char *buf) |
46 | { |
47 | struct fc_lport *lport = shost_priv(class_to_shost(dev)); |
48 | struct qedf_ctx *qedf = lport_priv(lport); |
49 | int fka_period = -1; |
50 | |
51 | if (qedf_is_vport(qedf)) |
52 | qedf = qedf_get_base_qedf(qedf); |
53 | |
54 | if (qedf->ctlr.sel_fcf) |
55 | fka_period = qedf->ctlr.sel_fcf->fka_period; |
56 | |
57 | return scnprintf(buf, PAGE_SIZE, fmt: "%d\n" , fka_period); |
58 | } |
59 | |
60 | static DEVICE_ATTR_RO(fcoe_mac); |
61 | static DEVICE_ATTR_RO(fka_period); |
62 | |
63 | static struct attribute *qedf_host_attrs[] = { |
64 | &dev_attr_fcoe_mac.attr, |
65 | &dev_attr_fka_period.attr, |
66 | NULL, |
67 | }; |
68 | |
69 | static const struct attribute_group qedf_host_attr_group = { |
70 | .attrs = qedf_host_attrs |
71 | }; |
72 | |
73 | const struct attribute_group *qedf_host_groups[] = { |
74 | &qedf_host_attr_group, |
75 | NULL |
76 | }; |
77 | |
78 | extern const struct qed_fcoe_ops *qed_ops; |
79 | |
80 | void qedf_capture_grc_dump(struct qedf_ctx *qedf) |
81 | { |
82 | struct qedf_ctx *base_qedf; |
83 | |
84 | /* Make sure we use the base qedf to take the GRC dump */ |
85 | if (qedf_is_vport(qedf)) |
86 | base_qedf = qedf_get_base_qedf(qedf); |
87 | else |
88 | base_qedf = qedf; |
89 | |
90 | if (test_bit(QEDF_GRCDUMP_CAPTURE, &base_qedf->flags)) { |
91 | QEDF_INFO(&(base_qedf->dbg_ctx), QEDF_LOG_INFO, |
92 | "GRC Dump already captured.\n" ); |
93 | return; |
94 | } |
95 | |
96 | |
97 | qedf_get_grc_dump(cdev: base_qedf->cdev, common: qed_ops->common, |
98 | buf: &base_qedf->grcdump, grcsize: &base_qedf->grcdump_size); |
99 | QEDF_ERR(&(base_qedf->dbg_ctx), "GRC Dump captured.\n" ); |
100 | set_bit(QEDF_GRCDUMP_CAPTURE, addr: &base_qedf->flags); |
101 | qedf_uevent_emit(shost: base_qedf->lport->host, QEDF_UEVENT_CODE_GRCDUMP, |
102 | NULL); |
103 | } |
104 | |
105 | static ssize_t |
106 | qedf_sysfs_read_grcdump(struct file *filep, struct kobject *kobj, |
107 | struct bin_attribute *ba, char *buf, loff_t off, |
108 | size_t count) |
109 | { |
110 | ssize_t ret = 0; |
111 | struct fc_lport *lport = shost_priv(shost: dev_to_shost(container_of(kobj, |
112 | struct device, kobj))); |
113 | struct qedf_ctx *qedf = lport_priv(lport); |
114 | |
115 | if (test_bit(QEDF_GRCDUMP_CAPTURE, &qedf->flags)) { |
116 | ret = memory_read_from_buffer(to: buf, count, ppos: &off, |
117 | from: qedf->grcdump, available: qedf->grcdump_size); |
118 | } else { |
119 | QEDF_ERR(&(qedf->dbg_ctx), "GRC Dump not captured!\n" ); |
120 | } |
121 | |
122 | return ret; |
123 | } |
124 | |
125 | static ssize_t |
126 | qedf_sysfs_write_grcdump(struct file *filep, struct kobject *kobj, |
127 | struct bin_attribute *ba, char *buf, loff_t off, |
128 | size_t count) |
129 | { |
130 | struct fc_lport *lport = NULL; |
131 | struct qedf_ctx *qedf = NULL; |
132 | long reading; |
133 | int ret = 0; |
134 | |
135 | if (off != 0) |
136 | return ret; |
137 | |
138 | |
139 | lport = shost_priv(shost: dev_to_shost(container_of(kobj, |
140 | struct device, kobj))); |
141 | qedf = lport_priv(lport); |
142 | |
143 | buf[1] = 0; |
144 | ret = kstrtol(s: buf, base: 10, res: &reading); |
145 | if (ret) { |
146 | QEDF_ERR(&(qedf->dbg_ctx), "Invalid input, err(%d)\n" , ret); |
147 | return ret; |
148 | } |
149 | |
150 | switch (reading) { |
151 | case 0: |
152 | memset(qedf->grcdump, 0, qedf->grcdump_size); |
153 | clear_bit(QEDF_GRCDUMP_CAPTURE, addr: &qedf->flags); |
154 | break; |
155 | case 1: |
156 | qedf_capture_grc_dump(qedf); |
157 | break; |
158 | } |
159 | |
160 | return count; |
161 | } |
162 | |
163 | static struct bin_attribute sysfs_grcdump_attr = { |
164 | .attr = { |
165 | .name = "grcdump" , |
166 | .mode = S_IRUSR | S_IWUSR, |
167 | }, |
168 | .size = 0, |
169 | .read = qedf_sysfs_read_grcdump, |
170 | .write = qedf_sysfs_write_grcdump, |
171 | }; |
172 | |
173 | static struct sysfs_bin_attrs bin_file_entries[] = { |
174 | {"grcdump" , &sysfs_grcdump_attr}, |
175 | {NULL}, |
176 | }; |
177 | |
178 | void qedf_create_sysfs_ctx_attr(struct qedf_ctx *qedf) |
179 | { |
180 | qedf_create_sysfs_attr(shost: qedf->lport->host, iter: bin_file_entries); |
181 | } |
182 | |
183 | void qedf_remove_sysfs_ctx_attr(struct qedf_ctx *qedf) |
184 | { |
185 | qedf_remove_sysfs_attr(shost: qedf->lport->host, iter: bin_file_entries); |
186 | } |
187 | |