Commit | Line | Data |
---|---|---|
fab97220 HS |
1 | /* |
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | |
3 | * | |
4 | * SQP functions | |
5 | * | |
6 | * Authors: Khadija Souissi <souissi@de.ibm.com> | |
7 | * Heiko J Schick <schickhj@de.ibm.com> | |
8 | * | |
9 | * Copyright (c) 2005 IBM Corporation | |
10 | * | |
11 | * All rights reserved. | |
12 | * | |
13 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | |
14 | * BSD. | |
15 | * | |
16 | * OpenIB BSD License | |
17 | * | |
18 | * Redistribution and use in source and binary forms, with or without | |
19 | * modification, are permitted provided that the following conditions are met: | |
20 | * | |
21 | * Redistributions of source code must retain the above copyright notice, this | |
22 | * list of conditions and the following disclaimer. | |
23 | * | |
24 | * Redistributions in binary form must reproduce the above copyright notice, | |
25 | * this list of conditions and the following disclaimer in the documentation | |
26 | * and/or other materials | |
27 | * provided with the distribution. | |
28 | * | |
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
30 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
33 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
34 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
35 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | |
36 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | |
37 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
38 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
39 | * POSSIBILITY OF SUCH DAMAGE. | |
40 | */ | |
41 | ||
2b5e6b12 | 42 | #include <rdma/ib_mad.h> |
fab97220 | 43 | |
fab97220 HS |
44 | #include "ehca_classes.h" |
45 | #include "ehca_tools.h" | |
fab97220 HS |
46 | #include "ehca_iverbs.h" |
47 | #include "hcp_if.h" | |
48 | ||
9c3da099 HH |
49 | #define IB_MAD_STATUS_REDIRECT cpu_to_be16(0x0002) |
50 | #define IB_MAD_STATUS_UNSUP_VERSION cpu_to_be16(0x0004) | |
51 | #define IB_MAD_STATUS_UNSUP_METHOD cpu_to_be16(0x0008) | |
2b5e6b12 | 52 | |
9c3da099 | 53 | #define IB_PMA_CLASS_PORT_INFO cpu_to_be16(0x0001) |
fab97220 HS |
54 | |
55 | /** | |
56 | * ehca_define_sqp - Defines special queue pair 1 (GSI QP). When special queue | |
57 | * pair is created successfully, the corresponding port gets active. | |
58 | * | |
59 | * Define Special Queue pair 0 (SMI QP) is still not supported. | |
60 | * | |
61 | * @qp_init_attr: Queue pair init attributes with port and queue pair type | |
62 | */ | |
63 | ||
64 | u64 ehca_define_sqp(struct ehca_shca *shca, | |
65 | struct ehca_qp *ehca_qp, | |
66 | struct ib_qp_init_attr *qp_init_attr) | |
67 | { | |
68 | u32 pma_qp_nr, bma_qp_nr; | |
69 | u64 ret; | |
70 | u8 port = qp_init_attr->port_num; | |
71 | int counter; | |
72 | ||
73 | shca->sport[port - 1].port_state = IB_PORT_DOWN; | |
74 | ||
75 | switch (qp_init_attr->qp_type) { | |
76 | case IB_QPT_SMI: | |
77 | /* function not supported yet */ | |
78 | break; | |
79 | case IB_QPT_GSI: | |
80 | ret = hipz_h_define_aqp1(shca->ipz_hca_handle, | |
81 | ehca_qp->ipz_qp_handle, | |
82 | ehca_qp->galpas.kernel, | |
83 | (u32) qp_init_attr->port_num, | |
84 | &pma_qp_nr, &bma_qp_nr); | |
85 | ||
86 | if (ret != H_SUCCESS) { | |
87 | ehca_err(&shca->ib_device, | |
3750f605 | 88 | "Can't define AQP1 for port %x. h_ret=%lli", |
fab97220 HS |
89 | port, ret); |
90 | return ret; | |
91 | } | |
2b5e6b12 HNN |
92 | shca->sport[port - 1].pma_qp_nr = pma_qp_nr; |
93 | ehca_dbg(&shca->ib_device, "port=%x pma_qp_nr=%x", | |
94 | port, pma_qp_nr); | |
fab97220 HS |
95 | break; |
96 | default: | |
97 | ehca_err(&shca->ib_device, "invalid qp_type=%x", | |
98 | qp_init_attr->qp_type); | |
99 | return H_PARAMETER; | |
100 | } | |
101 | ||
bbdd267e HNN |
102 | if (ehca_nr_ports < 0) /* autodetect mode */ |
103 | return H_SUCCESS; | |
104 | ||
fab97220 HS |
105 | for (counter = 0; |
106 | shca->sport[port - 1].port_state != IB_PORT_ACTIVE && | |
107 | counter < ehca_port_act_time; | |
108 | counter++) { | |
109 | ehca_dbg(&shca->ib_device, "... wait until port %x is active", | |
110 | port); | |
111 | msleep_interruptible(1000); | |
112 | } | |
113 | ||
114 | if (counter == ehca_port_act_time) { | |
115 | ehca_err(&shca->ib_device, "Port %x is not active.", port); | |
116 | return H_HARDWARE; | |
117 | } | |
118 | ||
119 | return H_SUCCESS; | |
120 | } | |
2b5e6b12 HNN |
121 | |
122 | struct ib_perf { | |
123 | struct ib_mad_hdr mad_hdr; | |
124 | u8 reserved[40]; | |
125 | u8 data[192]; | |
126 | } __attribute__ ((packed)); | |
127 | ||
d706834d JF |
128 | /* TC/SL/FL packed into 32 bits, as in ClassPortInfo */ |
129 | struct tcslfl { | |
130 | u32 tc:8; | |
131 | u32 sl:4; | |
132 | u32 fl:20; | |
133 | } __attribute__ ((packed)); | |
134 | ||
135 | /* IP Version/TC/FL packed into 32 bits, as in GRH */ | |
136 | struct vertcfl { | |
137 | u32 ver:4; | |
138 | u32 tc:8; | |
139 | u32 fl:20; | |
140 | } __attribute__ ((packed)); | |
2b5e6b12 HNN |
141 | |
142 | static int ehca_process_perf(struct ib_device *ibdev, u8 port_num, | |
a97e2d86 IW |
143 | const struct ib_wc *in_wc, const struct ib_grh *in_grh, |
144 | const struct ib_mad *in_mad, struct ib_mad *out_mad) | |
2b5e6b12 | 145 | { |
a97e2d86 | 146 | const struct ib_perf *in_perf = (const struct ib_perf *)in_mad; |
2b5e6b12 HNN |
147 | struct ib_perf *out_perf = (struct ib_perf *)out_mad; |
148 | struct ib_class_port_info *poi = | |
149 | (struct ib_class_port_info *)out_perf->data; | |
d706834d JF |
150 | struct tcslfl *tcslfl = |
151 | (struct tcslfl *)&poi->redirect_tcslfl; | |
2b5e6b12 HNN |
152 | struct ehca_shca *shca = |
153 | container_of(ibdev, struct ehca_shca, ib_device); | |
154 | struct ehca_sport *sport = &shca->sport[port_num - 1]; | |
155 | ||
156 | ehca_dbg(ibdev, "method=%x", in_perf->mad_hdr.method); | |
157 | ||
158 | *out_mad = *in_mad; | |
159 | ||
160 | if (in_perf->mad_hdr.class_version != 1) { | |
161 | ehca_warn(ibdev, "Unsupported class_version=%x", | |
162 | in_perf->mad_hdr.class_version); | |
163 | out_perf->mad_hdr.status = IB_MAD_STATUS_UNSUP_VERSION; | |
164 | goto perf_reply; | |
165 | } | |
166 | ||
167 | switch (in_perf->mad_hdr.method) { | |
168 | case IB_MGMT_METHOD_GET: | |
169 | case IB_MGMT_METHOD_SET: | |
170 | /* set class port info for redirection */ | |
171 | out_perf->mad_hdr.attr_id = IB_PMA_CLASS_PORT_INFO; | |
172 | out_perf->mad_hdr.status = IB_MAD_STATUS_REDIRECT; | |
173 | memset(poi, 0, sizeof(*poi)); | |
174 | poi->base_version = 1; | |
175 | poi->class_version = 1; | |
176 | poi->resp_time_value = 18; | |
d706834d JF |
177 | |
178 | /* copy local routing information from WC where applicable */ | |
179 | tcslfl->sl = in_wc->sl; | |
180 | poi->redirect_lid = | |
181 | sport->saved_attr.lid | in_wc->dlid_path_bits; | |
182 | poi->redirect_qp = sport->pma_qp_nr; | |
2b5e6b12 | 183 | poi->redirect_qkey = IB_QP1_QKEY; |
d706834d JF |
184 | |
185 | ehca_query_pkey(ibdev, port_num, in_wc->pkey_index, | |
186 | &poi->redirect_pkey); | |
187 | ||
188 | /* if request was globally routed, copy route info */ | |
189 | if (in_grh) { | |
a97e2d86 IW |
190 | const struct vertcfl *vertcfl = |
191 | (const struct vertcfl *)&in_grh->version_tclass_flow; | |
d706834d JF |
192 | memcpy(poi->redirect_gid, in_grh->dgid.raw, |
193 | sizeof(poi->redirect_gid)); | |
194 | tcslfl->tc = vertcfl->tc; | |
195 | tcslfl->fl = vertcfl->fl; | |
196 | } else | |
197 | /* else only fill in default GID */ | |
198 | ehca_query_gid(ibdev, port_num, 0, | |
199 | (union ib_gid *)&poi->redirect_gid); | |
2b5e6b12 HNN |
200 | |
201 | ehca_dbg(ibdev, "ehca_pma_lid=%x ehca_pma_qp=%x", | |
202 | sport->saved_attr.lid, sport->pma_qp_nr); | |
203 | break; | |
204 | ||
205 | case IB_MGMT_METHOD_GET_RESP: | |
206 | return IB_MAD_RESULT_FAILURE; | |
207 | ||
208 | default: | |
209 | out_perf->mad_hdr.status = IB_MAD_STATUS_UNSUP_METHOD; | |
210 | break; | |
211 | } | |
212 | ||
213 | perf_reply: | |
214 | out_perf->mad_hdr.method = IB_MGMT_METHOD_GET_RESP; | |
215 | ||
216 | return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; | |
217 | } | |
218 | ||
219 | int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, | |
a97e2d86 IW |
220 | const struct ib_wc *in_wc, const struct ib_grh *in_grh, |
221 | const struct ib_mad *in_mad, struct ib_mad *out_mad) | |
2b5e6b12 HNN |
222 | { |
223 | int ret; | |
224 | ||
45e354e3 | 225 | if (!port_num || port_num > ibdev->phys_port_cnt || !in_wc) |
2b5e6b12 HNN |
226 | return IB_MAD_RESULT_FAILURE; |
227 | ||
228 | /* accept only pma request */ | |
229 | if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT) | |
230 | return IB_MAD_RESULT_SUCCESS; | |
231 | ||
232 | ehca_dbg(ibdev, "port_num=%x src_qp=%x", port_num, in_wc->src_qp); | |
d706834d JF |
233 | ret = ehca_process_perf(ibdev, port_num, in_wc, in_grh, |
234 | in_mad, out_mad); | |
2b5e6b12 HNN |
235 | |
236 | return ret; | |
237 | } |