Print this page
5255 uts shouldn't open-code ISP2
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/ib/adapters/hermon/hermon_qpmod.c
+++ new/usr/src/uts/common/io/ib/adapters/hermon/hermon_qpmod.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
26 26 /*
27 27 * hermon_qpmod.c
28 28 * Hermon Queue Pair Modify Routines
29 29 *
30 30 * This contains all the routines necessary to implement the
31 31 * ModifyQP() verb. This includes all the code for legal
32 32 * transitions to and from Reset, Init, RTR, RTS, SQD, SQErr,
33 33 * and Error.
34 34 */
35 35
36 +#include <sys/sysmacros.h>
36 37 #include <sys/types.h>
37 38 #include <sys/conf.h>
38 39 #include <sys/ddi.h>
39 40 #include <sys/sunddi.h>
40 41 #include <sys/modctl.h>
41 42 #include <sys/bitmap.h>
42 43
43 44 #include <sys/ib/adapters/hermon/hermon.h>
44 45 #include <sys/ib/ib_pkt_hdrs.h>
45 46
46 47 static int hermon_qp_reset2init(hermon_state_t *state, hermon_qphdl_t qp,
47 48 ibt_qp_info_t *info_p);
48 49 static int hermon_qp_init2init(hermon_state_t *state, hermon_qphdl_t qp,
49 50 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
50 51 static int hermon_qp_init2rtr(hermon_state_t *state, hermon_qphdl_t qp,
51 52 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
52 53 static int hermon_qp_rtr2rts(hermon_state_t *state, hermon_qphdl_t qp,
53 54 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
54 55 static int hermon_qp_rts2rts(hermon_state_t *state, hermon_qphdl_t qp,
55 56 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
56 57 #ifdef HERMON_NOTNOW
57 58 static int hermon_qp_rts2sqd(hermon_state_t *state, hermon_qphdl_t qp,
58 59 ibt_cep_modify_flags_t flags);
59 60 #endif
60 61 static int hermon_qp_sqd2rts(hermon_state_t *state, hermon_qphdl_t qp,
61 62 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
62 63 static int hermon_qp_sqd2sqd(hermon_state_t *state, hermon_qphdl_t qp,
63 64 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
64 65 static int hermon_qp_sqerr2rts(hermon_state_t *state, hermon_qphdl_t qp,
65 66 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
66 67 static int hermon_qp_to_error(hermon_state_t *state, hermon_qphdl_t qp);
67 68 static int hermon_qp_reset2err(hermon_state_t *state, hermon_qphdl_t qp);
68 69
69 70 static uint_t hermon_check_rdma_enable_flags(ibt_cep_modify_flags_t flags,
70 71 ibt_qp_info_t *info_p, hermon_hw_qpc_t *qpc);
71 72 static int hermon_qp_validate_resp_rsrc(hermon_state_t *state,
72 73 ibt_qp_rc_attr_t *rc, uint_t *rra_max);
73 74 static int hermon_qp_validate_init_depth(hermon_state_t *state,
74 75 ibt_qp_rc_attr_t *rc, uint_t *sra_max);
75 76 static int hermon_qp_validate_mtu(hermon_state_t *state, uint_t mtu);
76 77
77 78 /*
78 79 * hermon_qp_modify()
79 80 * Context: Can be called from interrupt or base context.
80 81 */
81 82 /* ARGSUSED */
82 83 int
83 84 hermon_qp_modify(hermon_state_t *state, hermon_qphdl_t qp,
84 85 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p,
85 86 ibt_queue_sizes_t *actual_sz)
86 87 {
87 88 ibt_cep_state_t cur_state, mod_state;
88 89 ibt_cep_modify_flags_t okflags;
89 90 int status;
90 91
91 92 /*
92 93 * TODO add support for SUSPEND and RESUME
93 94 */
94 95
95 96 /*
96 97 * Lock the QP so that we can modify it atomically. After grabbing
97 98 * the lock, get the current QP state. We will use this current QP
98 99 * state to determine the legal transitions (and the checks that need
99 100 * to be performed.)
100 101 * Below is a case for every possible QP state. In each case, we
101 102 * check that no flags are set which are not valid for the possible
102 103 * transitions from that state. If these tests pass and the
103 104 * state transition we are attempting is legal, then we call one
104 105 * of the helper functions. Each of these functions does some
105 106 * additional setup before posting the firmware command for the
106 107 * appropriate state transition.
107 108 */
108 109 mutex_enter(&qp->qp_lock);
109 110
110 111 /*
111 112 * Verify that the transport type matches between the serv_type and the
112 113 * qp_trans. A caller to IBT must specify the qp_trans field as
113 114 * IBT_UD_SRV, IBT_RC_SRV, or IBT_UC_SRV, depending on the QP. We
114 115 * check here that the correct value was specified, based on our
115 116 * understanding of the QP serv type.
116 117 *
117 118 * Because callers specify part of a 'union' based on what QP type they
118 119 * think they're working with, this ensures that we do not pickup bogus
119 120 * data if the caller thought they were working with a different QP
120 121 * type.
121 122 */
122 123 if (!(HERMON_QP_TYPE_VALID(info_p->qp_trans, qp->qp_serv_type))) {
123 124 mutex_exit(&qp->qp_lock);
124 125 return (IBT_QP_SRV_TYPE_INVALID);
125 126 }
126 127
127 128 /*
128 129 * If this is a transition to RTS (which is valid from RTR, RTS,
129 130 * SQError, and SQ Drain) then we should honor the "current QP state"
130 131 * specified by the consumer. This means converting the IBTF QP state
131 132 * in "info_p->qp_current_state" to an Hermon QP state. Otherwise, we
132 133 * assume that we already know the current state (i.e. whatever it was
133 134 * last modified to or queried as - in "qp->qp_state").
134 135 */
135 136 mod_state = info_p->qp_state;
136 137
137 138 if (flags & IBT_CEP_SET_RTR_RTS) {
138 139 cur_state = HERMON_QP_RTR; /* Ready to Receive */
139 140
140 141 } else if ((flags & IBT_CEP_SET_STATE) &&
141 142 (mod_state == IBT_STATE_RTS)) {
142 143
143 144 /* Convert the current IBTF QP state to an Hermon QP state */
144 145 switch (info_p->qp_current_state) {
145 146 case IBT_STATE_RTR:
146 147 cur_state = HERMON_QP_RTR; /* Ready to Receive */
147 148 break;
148 149 case IBT_STATE_RTS:
149 150 cur_state = HERMON_QP_RTS; /* Ready to Send */
150 151 break;
151 152 case IBT_STATE_SQE:
152 153 cur_state = HERMON_QP_SQERR; /* Send Queue Error */
153 154 break;
154 155 case IBT_STATE_SQD:
155 156 cur_state = HERMON_QP_SQD; /* SQ Drained */
156 157 break;
157 158 default:
158 159 mutex_exit(&qp->qp_lock);
159 160 return (IBT_QP_STATE_INVALID);
160 161 }
161 162 } else {
162 163 cur_state = qp->qp_state;
163 164 }
164 165
165 166 switch (cur_state) {
166 167 case HERMON_QP_RESET:
167 168 okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RESET_INIT |
168 169 IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
169 170 IBT_CEP_SET_ATOMIC | IBT_CEP_SET_PKEY_IX |
170 171 IBT_CEP_SET_PORT | IBT_CEP_SET_QKEY);
171 172
172 173 /*
173 174 * Check for attempts to modify invalid attributes from the
174 175 * "Reset" state
175 176 */
176 177 if (flags & ~okflags) {
177 178 mutex_exit(&qp->qp_lock);
178 179 status = IBT_QP_ATTR_RO;
179 180 goto qpmod_fail;
180 181 }
181 182
182 183 /*
183 184 * Verify state transition is to either "Init", back to
184 185 * "Reset", or to "Error".
185 186 */
186 187 if ((flags & IBT_CEP_SET_RESET_INIT) &&
187 188 (flags & IBT_CEP_SET_STATE) &&
188 189 (mod_state != IBT_STATE_INIT)) {
189 190 /* Invalid transition - ambiguous flags */
190 191 mutex_exit(&qp->qp_lock);
191 192 status = IBT_QP_STATE_INVALID;
192 193 goto qpmod_fail;
193 194
194 195 } else if ((flags & IBT_CEP_SET_RESET_INIT) ||
195 196 ((flags & IBT_CEP_SET_STATE) &&
196 197 (mod_state == IBT_STATE_INIT))) {
197 198 /*
198 199 * Attempt to transition from "Reset" to "Init"
199 200 */
200 201 status = hermon_qp_reset2init(state, qp, info_p);
201 202 if (status != DDI_SUCCESS) {
202 203 mutex_exit(&qp->qp_lock);
203 204 goto qpmod_fail;
204 205 }
205 206 qp->qp_state = HERMON_QP_INIT;
206 207 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_INIT);
207 208
208 209 } else if ((flags & IBT_CEP_SET_STATE) &&
209 210 (mod_state == IBT_STATE_RESET)) {
210 211 /*
211 212 * Attempt to transition from "Reset" back to "Reset"
212 213 * Nothing to do here really... just drop the lock
213 214 * and return success. The qp->qp_state should
214 215 * already be set to HERMON_QP_RESET.
215 216 *
216 217 * Note: We return here because we do not want to fall
217 218 * through to the hermon_wrid_from_reset_handling()
218 219 * routine below (since we are not really moving
219 220 * _out_ of the "Reset" state.
220 221 */
221 222 mutex_exit(&qp->qp_lock);
222 223 return (DDI_SUCCESS);
223 224
224 225 } else if ((flags & IBT_CEP_SET_STATE) &&
225 226 (mod_state == IBT_STATE_ERROR)) {
226 227 /*
227 228 * Attempt to transition from "Reset" to "Error"
228 229 */
229 230 status = hermon_qp_reset2err(state, qp);
230 231 if (status != DDI_SUCCESS) {
231 232 mutex_exit(&qp->qp_lock);
232 233 goto qpmod_fail;
233 234 }
234 235 qp->qp_state = HERMON_QP_ERR;
235 236 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
236 237
237 238 } else {
238 239 /* Invalid transition - return error */
239 240 mutex_exit(&qp->qp_lock);
240 241 status = IBT_QP_STATE_INVALID;
241 242 goto qpmod_fail;
242 243 }
243 244
244 245 /*
245 246 * Do any additional handling necessary here for the transition
246 247 * from the "Reset" state (e.g. re-initialize the workQ WRID
247 248 * lists). Note: If hermon_wrid_from_reset_handling() fails,
248 249 * then we attempt to transition the QP back to the "Reset"
249 250 * state. If that fails, then it is an indication of a serious
250 251 * problem (either HW or SW). So we print out a warning
251 252 * message and return failure.
252 253 */
253 254 status = hermon_wrid_from_reset_handling(state, qp);
254 255 if (status != DDI_SUCCESS) {
255 256 if (hermon_qp_to_reset(state, qp) != DDI_SUCCESS) {
256 257 HERMON_WARNING(state, "failed to reset QP");
257 258 }
258 259 qp->qp_state = HERMON_QP_RESET;
259 260 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
260 261
261 262 mutex_exit(&qp->qp_lock);
262 263 goto qpmod_fail;
263 264 }
264 265 break;
265 266
266 267 case HERMON_QP_INIT:
267 268 okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_INIT_RTR |
268 269 IBT_CEP_SET_ADDS_VECT | IBT_CEP_SET_RDMARA_IN |
269 270 IBT_CEP_SET_MIN_RNR_NAK | IBT_CEP_SET_ALT_PATH |
270 271 IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
271 272 IBT_CEP_SET_ATOMIC | IBT_CEP_SET_PKEY_IX |
272 273 IBT_CEP_SET_QKEY | IBT_CEP_SET_PORT);
273 274
274 275 /*
275 276 * Check for attempts to modify invalid attributes from the
276 277 * "Init" state
277 278 */
278 279 if (flags & ~okflags) {
279 280 mutex_exit(&qp->qp_lock);
280 281 status = IBT_QP_ATTR_RO;
281 282 goto qpmod_fail;
282 283 }
283 284
284 285 /*
285 286 * Verify state transition is to either "RTR", back to "Init",
286 287 * to "Reset", or to "Error"
287 288 */
288 289 if ((flags & IBT_CEP_SET_INIT_RTR) &&
289 290 (flags & IBT_CEP_SET_STATE) &&
290 291 (mod_state != IBT_STATE_RTR)) {
291 292 /* Invalid transition - ambiguous flags */
292 293 mutex_exit(&qp->qp_lock);
293 294 status = IBT_QP_STATE_INVALID;
294 295 goto qpmod_fail;
295 296
296 297 } else if ((flags & IBT_CEP_SET_INIT_RTR) ||
297 298 ((flags & IBT_CEP_SET_STATE) &&
298 299 (mod_state == IBT_STATE_RTR))) {
299 300 /*
300 301 * Attempt to transition from "Init" to "RTR"
301 302 */
302 303 status = hermon_qp_init2rtr(state, qp, flags, info_p);
303 304 if (status != DDI_SUCCESS) {
304 305 mutex_exit(&qp->qp_lock);
305 306 goto qpmod_fail;
306 307 }
307 308 qp->qp_state = HERMON_QP_RTR;
308 309 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTR);
309 310
310 311 } else if ((flags & IBT_CEP_SET_STATE) &&
311 312 (mod_state == IBT_STATE_INIT)) {
312 313 /*
313 314 * Attempt to transition from "Init" to "Init"
314 315 */
315 316 status = hermon_qp_init2init(state, qp, flags, info_p);
316 317 if (status != DDI_SUCCESS) {
317 318 mutex_exit(&qp->qp_lock);
318 319 goto qpmod_fail;
319 320 }
320 321 qp->qp_state = HERMON_QP_INIT;
321 322 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_INIT);
322 323
323 324 } else if ((flags & IBT_CEP_SET_STATE) &&
324 325 (mod_state == IBT_STATE_RESET)) {
325 326 /*
326 327 * Attempt to transition from "Init" to "Reset"
327 328 */
328 329 status = hermon_qp_to_reset(state, qp);
329 330 if (status != DDI_SUCCESS) {
330 331 mutex_exit(&qp->qp_lock);
331 332 goto qpmod_fail;
332 333 }
333 334 qp->qp_state = HERMON_QP_RESET;
334 335 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
335 336
336 337 /*
337 338 * Do any additional handling necessary for the
338 339 * transition _to_ the "Reset" state (e.g. update the
339 340 * workQ WRID lists)
340 341 */
341 342 status = hermon_wrid_to_reset_handling(state, qp);
342 343 if (status != IBT_SUCCESS) {
343 344 mutex_exit(&qp->qp_lock);
344 345 goto qpmod_fail;
345 346 }
346 347
347 348 } else if ((flags & IBT_CEP_SET_STATE) &&
348 349 (mod_state == IBT_STATE_ERROR)) {
349 350 /*
350 351 * Attempt to transition from "Init" to "Error"
351 352 */
352 353 status = hermon_qp_to_error(state, qp);
353 354 if (status != DDI_SUCCESS) {
354 355 mutex_exit(&qp->qp_lock);
355 356 goto qpmod_fail;
356 357 }
357 358 qp->qp_state = HERMON_QP_ERR;
358 359 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
359 360
360 361 } else {
361 362 /* Invalid transition - return error */
362 363 mutex_exit(&qp->qp_lock);
363 364 status = IBT_QP_STATE_INVALID;
364 365 goto qpmod_fail;
365 366 }
366 367 break;
367 368
368 369 case HERMON_QP_RTR:
369 370 okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RTR_RTS |
370 371 IBT_CEP_SET_TIMEOUT | IBT_CEP_SET_RETRY |
371 372 IBT_CEP_SET_RNR_NAK_RETRY | IBT_CEP_SET_RDMARA_OUT |
372 373 IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
373 374 IBT_CEP_SET_ATOMIC | IBT_CEP_SET_QKEY |
374 375 IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_MIG |
375 376 IBT_CEP_SET_MIN_RNR_NAK);
376 377
377 378 /*
378 379 * Check for attempts to modify invalid attributes from the
379 380 * "RTR" state
380 381 */
381 382 if (flags & ~okflags) {
382 383 mutex_exit(&qp->qp_lock);
383 384 status = IBT_QP_ATTR_RO;
384 385 goto qpmod_fail;
385 386 }
386 387
387 388 /*
388 389 * Verify state transition is to either "RTS", "Reset",
389 390 * or "Error"
390 391 */
391 392 if ((flags & IBT_CEP_SET_RTR_RTS) &&
392 393 (flags & IBT_CEP_SET_STATE) &&
393 394 (mod_state != IBT_STATE_RTS)) {
394 395 /* Invalid transition - ambiguous flags */
395 396 mutex_exit(&qp->qp_lock);
396 397 status = IBT_QP_STATE_INVALID;
397 398 goto qpmod_fail;
398 399
399 400 } else if ((flags & IBT_CEP_SET_RTR_RTS) ||
400 401 ((flags & IBT_CEP_SET_STATE) &&
401 402 (mod_state == IBT_STATE_RTS))) {
402 403 /*
403 404 * Attempt to transition from "RTR" to "RTS"
404 405 */
405 406 status = hermon_qp_rtr2rts(state, qp, flags, info_p);
406 407 if (status != DDI_SUCCESS) {
407 408 mutex_exit(&qp->qp_lock);
408 409 goto qpmod_fail;
409 410 }
410 411 qp->qp_state = HERMON_QP_RTS;
411 412 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
412 413
413 414 } else if ((flags & IBT_CEP_SET_STATE) &&
414 415 (mod_state == IBT_STATE_RESET)) {
415 416 /*
416 417 * Attempt to transition from "RTR" to "Reset"
417 418 */
418 419 status = hermon_qp_to_reset(state, qp);
419 420 if (status != DDI_SUCCESS) {
420 421 mutex_exit(&qp->qp_lock);
421 422 goto qpmod_fail;
422 423 }
423 424 qp->qp_state = HERMON_QP_RESET;
424 425 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
425 426
426 427 /*
427 428 * Do any additional handling necessary for the
428 429 * transition _to_ the "Reset" state (e.g. update the
429 430 * workQ WRID lists)
430 431 */
431 432 status = hermon_wrid_to_reset_handling(state, qp);
432 433 if (status != IBT_SUCCESS) {
433 434 mutex_exit(&qp->qp_lock);
434 435 goto qpmod_fail;
435 436 }
436 437
437 438 } else if ((flags & IBT_CEP_SET_STATE) &&
438 439 (mod_state == IBT_STATE_ERROR)) {
439 440 /*
440 441 * Attempt to transition from "RTR" to "Error"
441 442 */
442 443 status = hermon_qp_to_error(state, qp);
443 444 if (status != DDI_SUCCESS) {
444 445 mutex_exit(&qp->qp_lock);
445 446 goto qpmod_fail;
446 447 }
447 448 qp->qp_state = HERMON_QP_ERR;
448 449 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
449 450
450 451 } else {
451 452 /* Invalid transition - return error */
452 453 mutex_exit(&qp->qp_lock);
453 454 status = IBT_QP_STATE_INVALID;
454 455 goto qpmod_fail;
455 456 }
456 457 break;
457 458
458 459 case HERMON_QP_RTS:
459 460 okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RDMA_R |
460 461 IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC |
461 462 IBT_CEP_SET_QKEY | IBT_CEP_SET_ALT_PATH |
462 463 IBT_CEP_SET_MIG | IBT_CEP_SET_MIN_RNR_NAK |
463 464 IBT_CEP_SET_SQD_EVENT);
464 465
465 466 /*
466 467 * Check for attempts to modify invalid attributes from the
467 468 * "RTS" state
468 469 */
469 470 if (flags & ~okflags) {
470 471 mutex_exit(&qp->qp_lock);
471 472 status = IBT_QP_ATTR_RO;
472 473 goto qpmod_fail;
473 474 }
474 475
475 476 /*
476 477 * Verify state transition is to either "RTS", "SQD", "Reset",
477 478 * or "Error"
478 479 */
479 480 if ((flags & IBT_CEP_SET_STATE) &&
480 481 (mod_state == IBT_STATE_RTS)) {
481 482 /*
482 483 * Attempt to transition from "RTS" to "RTS"
483 484 */
484 485 status = hermon_qp_rts2rts(state, qp, flags, info_p);
485 486 if (status != DDI_SUCCESS) {
486 487 mutex_exit(&qp->qp_lock);
487 488 goto qpmod_fail;
488 489 }
489 490 qp->qp_state = HERMON_QP_RTS;
490 491 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
491 492
492 493 } else if ((flags & IBT_CEP_SET_STATE) &&
493 494 (mod_state == IBT_STATE_SQD)) {
494 495 #ifdef HERMON_NOTNOW
495 496 /*
496 497 * Attempt to transition from "RTS" to "SQD"
497 498 */
498 499 status = hermon_qp_rts2sqd(state, qp, flags);
499 500 if (status != DDI_SUCCESS) {
500 501 mutex_exit(&qp->qp_lock);
501 502 goto qpmod_fail;
502 503 }
503 504 qp->qp_state = HERMON_QP_SQD;
504 505 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
505 506 #else
506 507 /* hack because of the lack of fw support for SQD */
507 508 mutex_exit(&qp->qp_lock);
508 509 status = IBT_QP_STATE_INVALID;
509 510 goto qpmod_fail;
510 511 #endif
511 512
512 513 } else if ((flags & IBT_CEP_SET_STATE) &&
513 514 (mod_state == IBT_STATE_RESET)) {
514 515 /*
515 516 * Attempt to transition from "RTS" to "Reset"
516 517 */
517 518 status = hermon_qp_to_reset(state, qp);
518 519 if (status != DDI_SUCCESS) {
519 520 mutex_exit(&qp->qp_lock);
520 521 goto qpmod_fail;
521 522 }
522 523 qp->qp_state = HERMON_QP_RESET;
523 524 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
524 525
525 526 /*
526 527 * Do any additional handling necessary for the
527 528 * transition _to_ the "Reset" state (e.g. update the
528 529 * workQ WRID lists)
529 530 */
530 531 status = hermon_wrid_to_reset_handling(state, qp);
531 532 if (status != IBT_SUCCESS) {
532 533 mutex_exit(&qp->qp_lock);
533 534 goto qpmod_fail;
534 535 }
535 536
536 537 } else if ((flags & IBT_CEP_SET_STATE) &&
537 538 (mod_state == IBT_STATE_ERROR)) {
538 539 /*
539 540 * Attempt to transition from "RTS" to "Error"
540 541 */
541 542 status = hermon_qp_to_error(state, qp);
542 543 if (status != DDI_SUCCESS) {
543 544 mutex_exit(&qp->qp_lock);
544 545 goto qpmod_fail;
545 546 }
546 547 qp->qp_state = HERMON_QP_ERR;
547 548 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
548 549
549 550 } else {
550 551 /* Invalid transition - return error */
551 552 mutex_exit(&qp->qp_lock);
552 553 status = IBT_QP_STATE_INVALID;
553 554 goto qpmod_fail;
554 555 }
555 556 break;
556 557
557 558 case HERMON_QP_SQERR:
558 559 okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RDMA_R |
559 560 IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC |
560 561 IBT_CEP_SET_QKEY | IBT_CEP_SET_MIN_RNR_NAK);
561 562
562 563 /*
563 564 * Check for attempts to modify invalid attributes from the
564 565 * "SQErr" state
565 566 */
566 567 if (flags & ~okflags) {
567 568 mutex_exit(&qp->qp_lock);
568 569 status = IBT_QP_ATTR_RO;
569 570 goto qpmod_fail;
570 571 }
571 572
572 573 /*
573 574 * Verify state transition is to either "RTS", "Reset", or
574 575 * "Error"
575 576 */
576 577 if ((flags & IBT_CEP_SET_STATE) &&
577 578 (mod_state == IBT_STATE_RTS)) {
578 579 /*
579 580 * Attempt to transition from "SQErr" to "RTS"
580 581 */
581 582 status = hermon_qp_sqerr2rts(state, qp, flags, info_p);
582 583 if (status != DDI_SUCCESS) {
583 584 mutex_exit(&qp->qp_lock);
584 585 goto qpmod_fail;
585 586 }
586 587 qp->qp_state = HERMON_QP_RTS;
587 588 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
588 589
589 590 } else if ((flags & IBT_CEP_SET_STATE) &&
590 591 (mod_state == IBT_STATE_RESET)) {
591 592 /*
592 593 * Attempt to transition from "SQErr" to "Reset"
593 594 */
594 595 status = hermon_qp_to_reset(state, qp);
595 596 if (status != DDI_SUCCESS) {
596 597 mutex_exit(&qp->qp_lock);
597 598 goto qpmod_fail;
598 599 }
599 600 qp->qp_state = HERMON_QP_RESET;
600 601 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
601 602
602 603 /*
603 604 * Do any additional handling necessary for the
604 605 * transition _to_ the "Reset" state (e.g. update the
605 606 * workQ WRID lists)
606 607 */
607 608 status = hermon_wrid_to_reset_handling(state, qp);
608 609 if (status != IBT_SUCCESS) {
609 610 mutex_exit(&qp->qp_lock);
610 611 goto qpmod_fail;
611 612 }
612 613
613 614 } else if ((flags & IBT_CEP_SET_STATE) &&
614 615 (mod_state == IBT_STATE_ERROR)) {
615 616 /*
616 617 * Attempt to transition from "SQErr" to "Error"
617 618 */
618 619 status = hermon_qp_to_error(state, qp);
619 620 if (status != DDI_SUCCESS) {
620 621 mutex_exit(&qp->qp_lock);
621 622 goto qpmod_fail;
622 623 }
623 624 qp->qp_state = HERMON_QP_ERR;
624 625 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
625 626
626 627 } else {
627 628 /* Invalid transition - return error */
628 629 mutex_exit(&qp->qp_lock);
629 630 status = IBT_QP_STATE_INVALID;
630 631 goto qpmod_fail;
631 632 }
632 633 break;
633 634
634 635 case HERMON_QP_SQD:
635 636 okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_ADDS_VECT |
636 637 IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_MIG |
637 638 IBT_CEP_SET_RDMARA_OUT | IBT_CEP_SET_RDMARA_IN |
638 639 IBT_CEP_SET_QKEY | IBT_CEP_SET_PKEY_IX |
639 640 IBT_CEP_SET_TIMEOUT | IBT_CEP_SET_RETRY |
640 641 IBT_CEP_SET_RNR_NAK_RETRY | IBT_CEP_SET_PORT |
641 642 IBT_CEP_SET_MIN_RNR_NAK | IBT_CEP_SET_RDMA_R |
642 643 IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC);
643 644
644 645 /*
645 646 * Check for attempts to modify invalid attributes from the
646 647 * "SQD" state
647 648 */
648 649 if (flags & ~okflags) {
649 650 mutex_exit(&qp->qp_lock);
650 651 status = IBT_QP_ATTR_RO;
651 652 goto qpmod_fail;
652 653 }
653 654
654 655 /*
655 656 * Verify state transition is to either "SQD", "RTS", "Reset",
656 657 * or "Error"
657 658 */
658 659
659 660 if ((flags & IBT_CEP_SET_STATE) &&
660 661 (mod_state == IBT_STATE_SQD)) {
661 662 /*
662 663 * Attempt to transition from "SQD" to "SQD"
663 664 */
664 665 status = hermon_qp_sqd2sqd(state, qp, flags, info_p);
665 666 if (status != DDI_SUCCESS) {
666 667 mutex_exit(&qp->qp_lock);
667 668 goto qpmod_fail;
668 669 }
669 670 qp->qp_state = HERMON_QP_SQD;
670 671 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
671 672
672 673 } else if ((flags & IBT_CEP_SET_STATE) &&
673 674 (mod_state == IBT_STATE_RTS)) {
674 675 /*
675 676 * If still draining SQ, then fail transition attempt
676 677 * to RTS, even though this is now done is two steps
677 678 * (see below) if the consumer has tried this before
678 679 * it's drained, let him fail and wait appropriately
679 680 */
680 681 if (qp->qp_sqd_still_draining) {
681 682 mutex_exit(&qp->qp_lock);
682 683 goto qpmod_fail;
683 684 }
684 685 /*
685 686 * IBA 1.2 has changed - most/all the things that were
686 687 * done in SQD2RTS can be done in SQD2SQD. So make this
687 688 * a 2-step process. First, set any attributes requsted
688 689 * w/ SQD2SQD, but no real transition.
689 690 *
690 691 * First, Attempt to transition from "SQD" to "SQD"
691 692 */
692 693 status = hermon_qp_sqd2sqd(state, qp, flags, info_p);
693 694 if (status != DDI_SUCCESS) {
694 695 mutex_exit(&qp->qp_lock);
695 696 goto qpmod_fail;
696 697 }
697 698 qp->qp_state = HERMON_QP_SQD;
698 699 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
699 700
700 701 /*
701 702 * The, attempt to transition from "SQD" to "RTS", but
702 703 * request only the state transition, no attributes
703 704 */
704 705
705 706 status = hermon_qp_sqd2rts(state, qp,
706 707 IBT_CEP_SET_STATE, info_p);
707 708 if (status != DDI_SUCCESS) {
708 709 mutex_exit(&qp->qp_lock);
709 710 goto qpmod_fail;
710 711 }
711 712 qp->qp_state = HERMON_QP_RTS;
712 713 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
713 714
714 715 } else if ((flags & IBT_CEP_SET_STATE) &&
715 716 (mod_state == IBT_STATE_RESET)) {
716 717 /*
717 718 * Attempt to transition from "SQD" to "Reset"
718 719 */
719 720 status = hermon_qp_to_reset(state, qp);
720 721 if (status != DDI_SUCCESS) {
721 722 mutex_exit(&qp->qp_lock);
722 723 goto qpmod_fail;
723 724 }
724 725 qp->qp_state = HERMON_QP_RESET;
725 726 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
726 727
727 728 /*
728 729 * Do any additional handling necessary for the
729 730 * transition _to_ the "Reset" state (e.g. update the
730 731 * workQ WRID lists)
731 732 */
732 733 status = hermon_wrid_to_reset_handling(state, qp);
733 734 if (status != IBT_SUCCESS) {
734 735 mutex_exit(&qp->qp_lock);
735 736 goto qpmod_fail;
736 737 }
737 738
738 739 } else if ((flags & IBT_CEP_SET_STATE) &&
739 740 (mod_state == IBT_STATE_ERROR)) {
740 741 /*
741 742 * Attempt to transition from "SQD" to "Error"
742 743 */
743 744 status = hermon_qp_to_error(state, qp);
744 745 if (status != DDI_SUCCESS) {
745 746 mutex_exit(&qp->qp_lock);
746 747 goto qpmod_fail;
747 748 }
748 749 qp->qp_state = HERMON_QP_ERR;
749 750 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
750 751
751 752 } else {
752 753 /* Invalid transition - return error */
753 754 mutex_exit(&qp->qp_lock);
754 755 status = IBT_QP_STATE_INVALID;
755 756 goto qpmod_fail;
756 757 }
757 758 break;
758 759
759 760 case HERMON_QP_ERR:
760 761 /*
761 762 * Verify state transition is to either "Reset" or back to
762 763 * "Error"
763 764 */
764 765 if ((flags & IBT_CEP_SET_STATE) &&
765 766 (mod_state == IBT_STATE_RESET)) {
766 767 /*
767 768 * Attempt to transition from "Error" to "Reset"
768 769 */
769 770 status = hermon_qp_to_reset(state, qp);
770 771 if (status != DDI_SUCCESS) {
771 772 mutex_exit(&qp->qp_lock);
772 773 goto qpmod_fail;
773 774 }
774 775 qp->qp_state = HERMON_QP_RESET;
775 776 HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
776 777
777 778 /*
778 779 * Do any additional handling necessary for the
779 780 * transition _to_ the "Reset" state (e.g. update the
780 781 * workQ WRID lists)
781 782 */
782 783 status = hermon_wrid_to_reset_handling(state, qp);
783 784 if (status != IBT_SUCCESS) {
784 785 mutex_exit(&qp->qp_lock);
785 786 goto qpmod_fail;
786 787 }
787 788
788 789 } else if ((flags & IBT_CEP_SET_STATE) &&
789 790 (mod_state == IBT_STATE_ERROR)) {
790 791 /*
791 792 * Attempt to transition from "Error" back to "Error"
792 793 * Nothing to do here really... just drop the lock
793 794 * and return success. The qp->qp_state should
794 795 * already be set to HERMON_QP_ERR.
795 796 *
796 797 */
797 798 mutex_exit(&qp->qp_lock);
798 799 return (DDI_SUCCESS);
799 800
800 801 } else {
801 802 /* Invalid transition - return error */
802 803 mutex_exit(&qp->qp_lock);
803 804 status = IBT_QP_STATE_INVALID;
804 805 goto qpmod_fail;
805 806 }
806 807 break;
807 808
808 809 default:
809 810 /*
810 811 * Invalid QP state. If we got here then it's a warning of
811 812 * a probably serious problem. So print a message and return
812 813 * failure
813 814 */
814 815 mutex_exit(&qp->qp_lock);
815 816 HERMON_WARNING(state, "unknown QP state in modify");
816 817 status = IBT_QP_STATE_INVALID;
817 818 goto qpmod_fail;
818 819 }
819 820
820 821 mutex_exit(&qp->qp_lock);
821 822 return (DDI_SUCCESS);
822 823
823 824 qpmod_fail:
824 825 return (status);
825 826 }
826 827
827 828
828 829 /*
829 830 * hermon_qp_reset2init()
830 831 * Context: Can be called from interrupt or base context.
831 832 */
832 833 static int
833 834 hermon_qp_reset2init(hermon_state_t *state, hermon_qphdl_t qp,
834 835 ibt_qp_info_t *info_p)
835 836 {
836 837 hermon_hw_qpc_t *qpc;
837 838 ibt_qp_rc_attr_t *rc;
838 839 ibt_qp_ud_attr_t *ud;
839 840 ibt_qp_uc_attr_t *uc;
840 841 uint_t portnum, pkeyindx;
841 842 int status;
842 843 uint32_t cqnmask;
843 844 int qp_srq_en;
844 845
845 846 ASSERT(MUTEX_HELD(&qp->qp_lock));
846 847
847 848 /*
848 849 * Grab the temporary QPC entry from QP software state
849 850 */
850 851 qpc = &qp->qpc;
851 852
852 853 /*
853 854 * Fill in the common fields in the QPC
854 855 */
855 856
856 857 if (qp->qp_is_special) {
857 858 qpc->serv_type = HERMON_QP_MLX;
858 859 } else {
859 860 qpc->serv_type = qp->qp_serv_type;
860 861 }
861 862 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
862 863
863 864 qpc->pd = qp->qp_pdhdl->pd_pdnum;
864 865
865 866 qpc->log_sq_stride = qp->qp_sq_log_wqesz - 4;
866 867 qpc->log_rq_stride = qp->qp_rq_log_wqesz - 4;
867 868 qpc->sq_no_prefetch = qp->qp_no_prefetch;
868 869 qpc->log_sq_size = highbit(qp->qp_sq_bufsz) - 1;
869 870 qpc->log_rq_size = highbit(qp->qp_rq_bufsz) - 1;
870 871
871 872 qpc->usr_page = qp->qp_uarpg;
872 873
873 874 cqnmask = (1 << state->hs_cfg_profile->cp_log_num_cq) - 1;
874 875 qpc->cqn_snd =
875 876 (qp->qp_sq_cqhdl == NULL) ? 0 : qp->qp_sq_cqhdl->cq_cqnum & cqnmask;
876 877 qpc->page_offs = qp->qp_wqinfo.qa_pgoffs >> 6;
877 878 qpc->cqn_rcv =
878 879 (qp->qp_rq_cqhdl == NULL) ? 0 : qp->qp_rq_cqhdl->cq_cqnum & cqnmask;
879 880
880 881 /* dbr is now an address, not an index */
881 882 qpc->dbr_addrh = ((uint64_t)qp->qp_rq_pdbr >> 32);
882 883 qpc->dbr_addrl = ((uint64_t)qp->qp_rq_pdbr & 0xFFFFFFFC) >> 2;
883 884 qpc->sq_wqe_counter = 0;
884 885 qpc->rq_wqe_counter = 0;
885 886 /*
886 887 * HERMON:
887 888 * qpc->wqe_baseaddr is replaced by LKey from the cMPT, and
888 889 * page_offset, mtt_base_addr_h/l, and log2_page_size will
889 890 * be used to map the WQE buffer
890 891 * NOTE that the cMPT is created implicitly when the QP is
891 892 * transitioned from reset to init
892 893 */
893 894 qpc->log2_pgsz = qp->qp_mrhdl->mr_log2_pgsz;
894 895 qpc->mtt_base_addrl = (qp->qp_mrhdl->mr_mttaddr) >> 3;
895 896 qpc->mtt_base_addrh = (uint32_t)((qp->qp_mrhdl->mr_mttaddr >> 32) &
896 897 0xFF);
897 898 qp_srq_en = (qp->qp_alloc_flags & IBT_QP_USES_SRQ) != 0;
898 899 qpc->srq_en = qp_srq_en;
899 900
900 901 if (qp_srq_en) {
901 902 qpc->srq_number = qp->qp_srqhdl->srq_srqnum;
902 903 } else {
903 904 qpc->srq_number = 0;
904 905 }
905 906
906 907 /*
907 908 * Fast Registration Work Requests and Reserved Lkey are enabled
908 909 * with the single IBT bit stored in qp_rlky.
909 910 */
910 911 qpc->fre = qp->qp_rlky;
911 912 qpc->rlky = qp->qp_rlky;
912 913
913 914 /* 1.2 verbs extensions disabled for now */
914 915 qpc->header_sep = 0; /* disable header separation for now */
915 916 qpc->rss = qp->qp_alloc_flags & IBT_QP_USES_RSS ? 1 : 0;
916 917 qpc->inline_scatter = 0; /* disable inline scatter for now */
917 918
918 919 /*
919 920 * Now fill in the QPC fields which are specific to transport type
920 921 */
921 922 if (qp->qp_type == IBT_UD_RQP) {
922 923 int my_fc_id_idx, exch_base;
923 924
924 925 ud = &info_p->qp_transport.ud;
925 926
926 927 /* Set the QKey */
927 928 qpc->qkey = ud->ud_qkey;
928 929
929 930 /*
930 931 * Set MTU and message max. Hermon checks the QPC
931 932 * MTU settings rather than just the port MTU,
932 933 * so set it to maximum size.
933 934 */
934 935 qpc->mtu = HERMON_MAX_MTU;
935 936 if (qp->qp_uses_lso)
936 937 qpc->msg_max = state->hs_devlim.log_max_gso_sz;
937 938 else if (qp->qp_is_special)
938 939 qpc->msg_max = HERMON_MAX_MTU + 6;
939 940 else
940 941 qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
941 942
942 943 /* Check for valid port number and fill it in */
943 944 portnum = ud->ud_port;
944 945 if (hermon_portnum_is_valid(state, portnum)) {
945 946 qp->qp_portnum = portnum - 1;
946 947 qpc->pri_addr_path.sched_q =
947 948 HERMON_QP_SCHEDQ_GET(portnum - 1,
948 949 0, qp->qp_is_special);
949 950 } else {
950 951 return (IBT_HCA_PORT_INVALID);
951 952 }
952 953
953 954
954 955 /* Check for valid PKey index and fill it in */
955 956 pkeyindx = ud->ud_pkey_ix;
956 957 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
957 958 qpc->pri_addr_path.pkey_indx = pkeyindx;
958 959 qp->qp_pkeyindx = pkeyindx;
959 960 } else {
960 961 return (IBT_PKEY_IX_ILLEGAL);
961 962 }
962 963
963 964 /* fill in the RSS fields */
964 965 if (qpc->rss) {
965 966 struct hermon_hw_rss_s *rssp;
966 967 ibt_rss_flags_t flags = ud->ud_rss.rss_flags;
967 968
968 969 rssp = (struct hermon_hw_rss_s *)&qpc->pri_addr_path;
969 970 rssp->log2_tbl_sz = ud->ud_rss.rss_log2_table;
970 971 rssp->base_qpn = ud->ud_rss.rss_base_qpn;
971 972 rssp->default_qpn = ud->ud_rss.rss_def_qpn;
972 973 if (flags & IBT_RSS_ALG_XOR)
973 974 rssp->hash_fn = 0; /* XOR Hash Function */
974 975 else if (flags & IBT_RSS_ALG_TPL)
975 976 rssp->hash_fn = 1; /* Toeplitz Hash Fn */
976 977 else
977 978 return (IBT_INVALID_PARAM);
978 979 rssp->ipv4 = (flags & IBT_RSS_HASH_IPV4) != 0;
979 980 rssp->tcp_ipv4 = (flags & IBT_RSS_HASH_TCP_IPV4) != 0;
980 981 rssp->ipv6 = (flags & IBT_RSS_HASH_IPV6) != 0;
981 982 rssp->tcp_ipv4 = (flags & IBT_RSS_HASH_TCP_IPV6) != 0;
982 983 bcopy(ud->ud_rss.rss_toe_key, rssp->rss_key, 40);
983 984 } else if (qp->qp_serv_type == HERMON_QP_RFCI) {
984 985 status = hermon_fcoib_set_id(state, portnum,
985 986 qp->qp_qpnum, ud->ud_fc.fc_src_id);
986 987 if (status != DDI_SUCCESS)
987 988 return (status);
988 989 qp->qp_fc_attr = ud->ud_fc;
989 990 } else if (qp->qp_serv_type == HERMON_QP_FEXCH) {
990 991 my_fc_id_idx = hermon_fcoib_get_id_idx(state,
991 992 portnum, &ud->ud_fc);
992 993 if (my_fc_id_idx == -1)
993 994 return (IBT_INVALID_PARAM);
994 995 qpc->my_fc_id_idx = my_fc_id_idx;
995 996
996 997 status = hermon_fcoib_fexch_mkey_init(state,
997 998 qp->qp_pdhdl, ud->ud_fc.fc_hca_port,
998 999 qp->qp_qpnum, HERMON_CMD_NOSLEEP_SPIN);
999 1000 if (status != DDI_SUCCESS)
1000 1001 return (status);
1001 1002 qp->qp_fc_attr = ud->ud_fc;
1002 1003 } else if (qp->qp_serv_type == HERMON_QP_FCMND) {
1003 1004 my_fc_id_idx = hermon_fcoib_get_id_idx(state,
1004 1005 portnum, &ud->ud_fc);
1005 1006 if (my_fc_id_idx == -1)
1006 1007 return (IBT_INVALID_PARAM);
1007 1008 qpc->my_fc_id_idx = my_fc_id_idx;
1008 1009 exch_base = hermon_fcoib_check_exch_base_off(state,
1009 1010 portnum, &ud->ud_fc);
1010 1011 if (exch_base == -1)
1011 1012 return (IBT_INVALID_PARAM);
1012 1013 qpc->exch_base = exch_base;
1013 1014 qpc->exch_size = ud->ud_fc.fc_exch_log2_sz;
1014 1015 qp->qp_fc_attr = ud->ud_fc;
1015 1016 }
1016 1017
1017 1018 } else if (qp->qp_serv_type == HERMON_QP_RC) {
1018 1019 rc = &info_p->qp_transport.rc;
1019 1020
1020 1021 /* Set the RDMA (recv) enable/disable flags */
1021 1022 qpc->rre = (info_p->qp_flags & IBT_CEP_RDMA_RD) ? 1 : 0;
1022 1023 qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
1023 1024 qpc->rae = (info_p->qp_flags & IBT_CEP_ATOMIC) ? 1 : 0;
1024 1025
1025 1026 /* Check for valid port number and fill it in */
1026 1027 portnum = rc->rc_path.cep_hca_port_num;
1027 1028 if (hermon_portnum_is_valid(state, portnum)) {
1028 1029 qp->qp_portnum = portnum - 1;
1029 1030 qpc->pri_addr_path.sched_q =
1030 1031 HERMON_QP_SCHEDQ_GET(portnum - 1,
1031 1032 0, qp->qp_is_special);
1032 1033 } else {
1033 1034 return (IBT_HCA_PORT_INVALID);
1034 1035 }
1035 1036
1036 1037 /* Check for valid PKey index and fill it in */
1037 1038 pkeyindx = rc->rc_path.cep_pkey_ix;
1038 1039 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1039 1040 qpc->pri_addr_path.pkey_indx = pkeyindx;
1040 1041 } else {
1041 1042 return (IBT_PKEY_IX_ILLEGAL);
1042 1043 }
1043 1044
1044 1045 } else if (qp->qp_serv_type == HERMON_QP_UC) {
1045 1046 uc = &info_p->qp_transport.uc;
1046 1047
1047 1048 /*
1048 1049 * Set the RDMA (recv) enable/disable flags. Note: RDMA Read
1049 1050 * and Atomic are ignored by default.
1050 1051 */
1051 1052 qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
1052 1053
1053 1054 /* Check for valid port number and fill it in */
1054 1055 portnum = uc->uc_path.cep_hca_port_num;
1055 1056 if (hermon_portnum_is_valid(state, portnum)) {
1056 1057 qp->qp_portnum = portnum - 1;
1057 1058 qpc->pri_addr_path.sched_q =
1058 1059 HERMON_QP_SCHEDQ_GET(portnum - 1,
1059 1060 0, qp->qp_is_special);
1060 1061 } else {
1061 1062 return (IBT_HCA_PORT_INVALID);
1062 1063 }
1063 1064
1064 1065 /* Check for valid PKey index and fill it in */
1065 1066 pkeyindx = uc->uc_path.cep_pkey_ix;
1066 1067 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1067 1068 qpc->pri_addr_path.pkey_indx = pkeyindx;
1068 1069 } else {
1069 1070 return (IBT_PKEY_IX_ILLEGAL);
1070 1071 }
1071 1072
1072 1073 } else {
1073 1074 /*
1074 1075 * Invalid QP transport type. If we got here then it's a
1075 1076 * warning of a probably serious problem. So print a message
1076 1077 * and return failure
1077 1078 */
1078 1079 HERMON_WARNING(state, "unknown QP transport type in rst2init");
1079 1080 return (ibc_get_ci_failure(0));
1080 1081 }
1081 1082
1082 1083 /*
1083 1084 * Post the RST2INIT_QP command to the Hermon firmware
1084 1085 *
1085 1086 * We do a HERMON_NOSLEEP here because we are still holding the
1086 1087 * "qp_lock". If we got raised to interrupt level by priority
1087 1088 * inversion, we do not want to block in this routine waiting for
1088 1089 * success.
1089 1090 */
1090 1091 status = hermon_cmn_qp_cmd_post(state, RST2INIT_QP, qpc, qp->qp_qpnum,
1091 1092 0, HERMON_CMD_NOSLEEP_SPIN);
1092 1093 if (status != HERMON_CMD_SUCCESS) {
1093 1094 cmn_err(CE_NOTE, "hermon%d: RST2INIT_QP command failed: %08x\n",
1094 1095 state->hs_instance, status);
1095 1096 if (status == HERMON_CMD_INVALID_STATUS) {
1096 1097 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
1097 1098 }
1098 1099 return (ibc_get_ci_failure(0));
1099 1100 }
1100 1101
1101 1102 return (DDI_SUCCESS);
1102 1103 }
1103 1104
1104 1105
1105 1106 /*
1106 1107 * hermon_qp_init2init()
1107 1108 * Context: Can be called from interrupt or base context.
1108 1109 */
1109 1110 static int
1110 1111 hermon_qp_init2init(hermon_state_t *state, hermon_qphdl_t qp,
1111 1112 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
1112 1113 {
1113 1114 hermon_hw_qpc_t *qpc;
1114 1115 ibt_qp_rc_attr_t *rc;
1115 1116 ibt_qp_ud_attr_t *ud;
1116 1117 ibt_qp_uc_attr_t *uc;
1117 1118 uint_t portnum, pkeyindx;
1118 1119 uint32_t opmask = 0;
1119 1120 int status;
1120 1121
1121 1122 ASSERT(MUTEX_HELD(&qp->qp_lock));
1122 1123
1123 1124 /*
1124 1125 * Grab the temporary QPC entry from QP software state
1125 1126 */
1126 1127 qpc = &qp->qpc;
1127 1128
1128 1129 /*
1129 1130 * Since there are no common fields to be filled in for this command,
1130 1131 * we begin with the QPC fields which are specific to transport type.
1131 1132 */
1132 1133 if (qp->qp_type == IBT_UD_RQP) {
1133 1134 ud = &info_p->qp_transport.ud;
1134 1135
1135 1136 /*
1136 1137 * If we are attempting to modify the port for this QP, then
1137 1138 * check for valid port number and fill it in. Also set the
1138 1139 * appropriate flag in the "opmask" parameter.
1139 1140 */
1140 1141 /*
1141 1142 * set port is not supported in init2init - however, in init2rtr it will
1142 1143 * take the entire qpc, including the embedded sched_q in the path
1143 1144 * structure - so, we can just skip setting the opmask for it explicitly
1144 1145 * and allow it to be set later on
1145 1146 */
1146 1147 if (flags & IBT_CEP_SET_PORT) {
1147 1148 portnum = ud->ud_port;
1148 1149 if (hermon_portnum_is_valid(state, portnum)) {
1149 1150 qp->qp_portnum = portnum - 1; /* save it away */
1150 1151 qpc->pri_addr_path.sched_q =
1151 1152 HERMON_QP_SCHEDQ_GET(portnum - 1,
1152 1153 0, qp->qp_is_special);
1153 1154 } else {
1154 1155 return (IBT_HCA_PORT_INVALID);
1155 1156 }
1156 1157 }
1157 1158
1158 1159 /*
1159 1160 * If we are attempting to modify the PKey index for this QP,
1160 1161 * then check for valid PKey index and fill it in. Also set
1161 1162 * the appropriate flag in the "opmask" parameter.
1162 1163 */
1163 1164 if (flags & IBT_CEP_SET_PKEY_IX) {
1164 1165 pkeyindx = ud->ud_pkey_ix;
1165 1166 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1166 1167 qpc->pri_addr_path.pkey_indx = pkeyindx;
1167 1168 opmask |= HERMON_CMD_OP_PKEYINDX;
1168 1169 qp->qp_pkeyindx = pkeyindx;
1169 1170 } else {
1170 1171 return (IBT_PKEY_IX_ILLEGAL);
1171 1172 }
1172 1173 }
1173 1174
1174 1175 /*
1175 1176 * If we are attempting to modify the QKey for this QP, then
1176 1177 * fill it in and set the appropriate flag in the "opmask"
1177 1178 * parameter.
1178 1179 */
1179 1180 if (flags & IBT_CEP_SET_QKEY) {
1180 1181 qpc->qkey = ud->ud_qkey;
1181 1182 opmask |= HERMON_CMD_OP_QKEY;
1182 1183 }
1183 1184
1184 1185 } else if (qp->qp_serv_type == HERMON_QP_RC) {
1185 1186 rc = &info_p->qp_transport.rc;
1186 1187
1187 1188 /*
1188 1189 * If we are attempting to modify the port for this QP, then
1189 1190 * check for valid port number and fill it in. Also set the
1190 1191 * appropriate flag in the "opmask" parameter.
1191 1192 */
1192 1193 if (flags & IBT_CEP_SET_PORT) {
1193 1194 portnum = rc->rc_path.cep_hca_port_num;
1194 1195 if (hermon_portnum_is_valid(state, portnum)) {
1195 1196 qp->qp_portnum = portnum - 1;
1196 1197 qpc->pri_addr_path.sched_q =
1197 1198 HERMON_QP_SCHEDQ_GET(portnum - 1,
1198 1199 0, qp->qp_is_special);
1199 1200 } else {
1200 1201 return (IBT_HCA_PORT_INVALID);
1201 1202 }
1202 1203
1203 1204 }
1204 1205
1205 1206 /*
1206 1207 * If we are attempting to modify the PKey index for this QP,
1207 1208 * then check for valid PKey index and fill it in. Also set
1208 1209 * the appropriate flag in the "opmask" parameter.
1209 1210 */
1210 1211 if (flags & IBT_CEP_SET_PKEY_IX) {
1211 1212 pkeyindx = rc->rc_path.cep_pkey_ix;
1212 1213 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1213 1214 qpc->pri_addr_path.pkey_indx = pkeyindx;
1214 1215 opmask |= HERMON_CMD_OP_PKEYINDX;
1215 1216 } else {
1216 1217 return (IBT_PKEY_IX_ILLEGAL);
1217 1218 }
1218 1219 }
1219 1220
1220 1221 /*
1221 1222 * Check if any of the flags indicate a change in the RDMA
1222 1223 * (recv) enable/disable flags and set the appropriate flag in
1223 1224 * the "opmask" parameter
1224 1225 */
1225 1226 opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
1226 1227
1227 1228 } else if (qp->qp_serv_type == HERMON_QP_UC) {
1228 1229 uc = &info_p->qp_transport.uc;
1229 1230
1230 1231 /*
1231 1232 * If we are attempting to modify the port for this QP, then
1232 1233 * check for valid port number and fill it in. Also set the
1233 1234 * appropriate flag in the "opmask" parameter.
1234 1235 */
1235 1236 if (flags & IBT_CEP_SET_PORT) {
1236 1237 portnum = uc->uc_path.cep_hca_port_num;
1237 1238 if (hermon_portnum_is_valid(state, portnum)) {
1238 1239 qp->qp_portnum = portnum - 1;
1239 1240 qpc->pri_addr_path.sched_q =
1240 1241 HERMON_QP_SCHEDQ_GET(portnum - 1,
1241 1242 0, qp->qp_is_special);
1242 1243 } else {
1243 1244 return (IBT_HCA_PORT_INVALID);
1244 1245 }
1245 1246 /* port# cannot be set in this transition - defer to init2rtr */
1246 1247 }
1247 1248
1248 1249 /*
1249 1250 * If we are attempting to modify the PKey index for this QP,
1250 1251 * then check for valid PKey index and fill it in. Also set
1251 1252 * the appropriate flag in the "opmask" parameter.
1252 1253 */
1253 1254 if (flags & IBT_CEP_SET_PKEY_IX) {
1254 1255 pkeyindx = uc->uc_path.cep_pkey_ix;
1255 1256 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1256 1257 qpc->pri_addr_path.pkey_indx = pkeyindx;
1257 1258 opmask |= HERMON_CMD_OP_PKEYINDX;
1258 1259 } else {
1259 1260 return (IBT_PKEY_IX_ILLEGAL);
1260 1261 }
1261 1262 }
1262 1263
1263 1264 /*
1264 1265 * Check if any of the flags indicate a change in the RDMA
1265 1266 * Write (recv) enable/disable and set the appropriate flag
1266 1267 * in the "opmask" parameter. Note: RDMA Read and Atomic are
1267 1268 * not valid for UC transport.
1268 1269 */
1269 1270 if (flags & IBT_CEP_SET_RDMA_W) {
1270 1271 qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
1271 1272 opmask |= HERMON_CMD_OP_RWE;
1272 1273 }
1273 1274 } else {
1274 1275 /*
1275 1276 * Invalid QP transport type. If we got here then it's a
1276 1277 * warning of a probably serious problem. So print a message
1277 1278 * and return failure
1278 1279 */
1279 1280 HERMON_WARNING(state, "unknown QP transport type in init2init");
1280 1281 return (ibc_get_ci_failure(0));
1281 1282 }
1282 1283
1283 1284 /*
1284 1285 * Post the INIT2INIT_QP command to the Hermon firmware
1285 1286 *
1286 1287 * We do a HERMON_NOSLEEP here because we are still holding the
1287 1288 * "qp_lock". If we got raised to interrupt level by priority
1288 1289 * inversion, we do not want to block in this routine waiting for
1289 1290 * success.
1290 1291 */
1291 1292 status = hermon_cmn_qp_cmd_post(state, INIT2INIT_QP, qpc, qp->qp_qpnum,
1292 1293 opmask, HERMON_CMD_NOSLEEP_SPIN);
1293 1294 if (status != HERMON_CMD_SUCCESS) {
1294 1295 if (status != HERMON_CMD_BAD_QP_STATE) {
1295 1296 cmn_err(CE_NOTE, "hermon%d: INIT2INIT_QP command "
1296 1297 "failed: %08x\n", state->hs_instance, status);
1297 1298 if (status == HERMON_CMD_INVALID_STATUS) {
1298 1299 hermon_fm_ereport(state, HCA_SYS_ERR,
1299 1300 HCA_ERR_SRV_LOST);
1300 1301 }
1301 1302 return (ibc_get_ci_failure(0));
1302 1303 } else {
1303 1304 return (IBT_QP_STATE_INVALID);
1304 1305 }
1305 1306 }
1306 1307
1307 1308 return (DDI_SUCCESS);
1308 1309 }
1309 1310
1310 1311
1311 1312 /*
1312 1313 * hermon_qp_init2rtr()
1313 1314 * Context: Can be called from interrupt or base context.
1314 1315 */
1315 1316 static int
1316 1317 hermon_qp_init2rtr(hermon_state_t *state, hermon_qphdl_t qp,
1317 1318 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
1318 1319 {
1319 1320 hermon_hw_qpc_t *qpc;
1320 1321 ibt_qp_rc_attr_t *rc;
1321 1322 ibt_qp_ud_attr_t *ud;
1322 1323 ibt_qp_uc_attr_t *uc;
1323 1324 hermon_hw_addr_path_t *qpc_path;
1324 1325 ibt_adds_vect_t *adds_vect;
1325 1326 uint_t portnum, pkeyindx, rra_max;
1326 1327 uint_t mtu;
1327 1328 uint32_t opmask = 0;
1328 1329 int status;
1329 1330
1330 1331 ASSERT(MUTEX_HELD(&qp->qp_lock));
1331 1332
1332 1333 /*
1333 1334 * Grab the temporary QPC entry from QP software state
1334 1335 */
1335 1336 qpc = &qp->qpc;
1336 1337
1337 1338 /*
1338 1339 * Since there are few common fields to be filled in for this command,
1339 1340 * we just do the QPC fields that are specific to transport type.
1340 1341 */
1341 1342 if (qp->qp_type == IBT_UD_RQP) {
1342 1343 ud = &info_p->qp_transport.ud;
1343 1344
1344 1345 /*
1345 1346 * If this UD QP is also a "special QP" (QP0 or QP1), then
1346 1347 * the MTU is 256 bytes. However, Hermon checks the QPC
1347 1348 * MTU settings rather than just the port MTU, so we will
1348 1349 * set it to maximum size for all UD.
1349 1350 */
1350 1351 qpc->mtu = HERMON_MAX_MTU;
1351 1352 if (qp->qp_uses_lso)
1352 1353 qpc->msg_max = state->hs_devlim.log_max_gso_sz;
1353 1354 else
1354 1355 qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
1355 1356
1356 1357 /*
1357 1358 * Save away the MTU value. This is used in future sqd2sqd
1358 1359 * transitions, as the MTU must remain the same in future
1359 1360 * changes.
1360 1361 */
1361 1362 qp->qp_save_mtu = qpc->mtu;
1362 1363
1363 1364 /*
1364 1365 * If we are attempting to modify the PKey index for this QP,
1365 1366 * then check for valid PKey index and fill it in. Also set
1366 1367 * the appropriate flag in the "opmask" parameter.
1367 1368 */
1368 1369 if (flags & IBT_CEP_SET_PKEY_IX) {
1369 1370 pkeyindx = ud->ud_pkey_ix;
1370 1371 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1371 1372 qpc->pri_addr_path.pkey_indx = pkeyindx;
1372 1373 opmask |= HERMON_CMD_OP_PKEYINDX;
1373 1374 qp->qp_pkeyindx = pkeyindx;
1374 1375 } else {
1375 1376 return (IBT_PKEY_IX_ILLEGAL);
1376 1377 }
1377 1378 }
1378 1379
1379 1380 /*
1380 1381 * If we are attempting to modify the QKey for this QP, then
1381 1382 * fill it in and set the appropriate flag in the "opmask"
1382 1383 * parameter.
1383 1384 */
1384 1385 if (flags & IBT_CEP_SET_QKEY) {
1385 1386 qpc->qkey = ud->ud_qkey;
1386 1387 opmask |= HERMON_CMD_OP_QKEY;
1387 1388 }
1388 1389
1389 1390 } else if (qp->qp_serv_type == HERMON_QP_RC) {
1390 1391 rc = &info_p->qp_transport.rc;
1391 1392 qpc_path = &qpc->pri_addr_path;
1392 1393 adds_vect = &rc->rc_path.cep_adds_vect;
1393 1394
1394 1395 /*
1395 1396 * Set the common primary address path fields
1396 1397 */
1397 1398 status = hermon_set_addr_path(state, adds_vect, qpc_path,
1398 1399 HERMON_ADDRPATH_QP);
1399 1400 if (status != DDI_SUCCESS) {
1400 1401 return (status);
1401 1402 }
1402 1403 /* set the primary port number/sched_q */
1403 1404 portnum = qp->qp_portnum + 1;
1404 1405 if (hermon_portnum_is_valid(state, portnum)) {
1405 1406 qpc->pri_addr_path.sched_q =
1406 1407 HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
1407 1408 adds_vect->av_srvl, qp->qp_is_special);
1408 1409 } else {
1409 1410 return (IBT_HCA_PORT_INVALID);
1410 1411 }
1411 1412
1412 1413 /*
1413 1414 * The following values are apparently "required" here (as
1414 1415 * they are part of the IBA-defined "Remote Node Address
1415 1416 * Vector"). However, they are also going to be "required"
1416 1417 * later - at RTR2RTS_QP time. Not sure why. But we set
1417 1418 * them here anyway.
1418 1419 */
1419 1420 qpc->rnr_retry = rc->rc_rnr_retry_cnt;
1420 1421 qpc->retry_cnt = rc->rc_retry_cnt;
1421 1422 qpc_path->ack_timeout = rc->rc_path.cep_timeout;
1422 1423
1423 1424 /*
1424 1425 * Setup the destination QP, recv PSN, MTU, max msg size,etc.
1425 1426 * Note max message size is defined to be the maximum IB
1426 1427 * allowed message size (which is 2^31 bytes). Also max
1427 1428 * MTU is defined by HCA port properties.
1428 1429 */
1429 1430 qpc->rem_qpn = rc->rc_dst_qpn;
1430 1431 qpc->next_rcv_psn = rc->rc_rq_psn;
1431 1432 qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
1432 1433 qpc->ric = 0;
1433 1434 mtu = rc->rc_path_mtu;
1434 1435
1435 1436 if (hermon_qp_validate_mtu(state, mtu) != DDI_SUCCESS) {
1436 1437 return (IBT_HCA_PORT_MTU_EXCEEDED);
1437 1438 }
1438 1439 qpc->mtu = mtu;
1439 1440
1440 1441 /*
1441 1442 * Save away the MTU value. This is used in future sqd2sqd
1442 1443 * transitions, as the MTU must remain the same in future
1443 1444 * changes.
1444 1445 */
1445 1446 qp->qp_save_mtu = qpc->mtu;
1446 1447
1447 1448 /*
1448 1449 * Though it is a "required" parameter, "min_rnr_nak" is
1449 1450 * optionally specifiable in Hermon. So we force the
1450 1451 * optional flag here.
1451 1452 */
1452 1453 qpc->min_rnr_nak = rc->rc_min_rnr_nak;
1453 1454 opmask |= HERMON_CMD_OP_MINRNRNAK;
1454 1455
1455 1456 /*
1456 1457 * Check that the number of specified "incoming RDMA resources"
1457 1458 * is valid. And if it is, then setup the "rra_max
1458 1459 */
1459 1460 if (hermon_qp_validate_resp_rsrc(state, rc, &rra_max) !=
1460 1461 DDI_SUCCESS) {
1461 1462 return (IBT_INVALID_PARAM);
1462 1463 }
1463 1464 qpc->rra_max = rra_max;
1464 1465
1465 1466 /* don't need to set up ra_buff_indx, implicit for hermon */
1466 1467
1467 1468 /*
1468 1469 * If we are attempting to modify the PKey index for this QP,
1469 1470 * then check for valid PKey index and fill it in. Also set
1470 1471 * the appropriate flag in the "opmask" parameter.
1471 1472 */
1472 1473 if (flags & IBT_CEP_SET_PKEY_IX) {
1473 1474 pkeyindx = rc->rc_path.cep_pkey_ix;
1474 1475 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1475 1476 qpc->pri_addr_path.pkey_indx = pkeyindx;
1476 1477 opmask |= HERMON_CMD_OP_PKEYINDX;
1477 1478 } else {
1478 1479 return (IBT_PKEY_IX_ILLEGAL);
1479 1480 }
1480 1481 }
1481 1482
1482 1483 /*
1483 1484 * Check if any of the flags indicate a change in the RDMA
1484 1485 * (recv) enable/disable flags and set the appropriate flag in
1485 1486 * the "opmask" parameter
1486 1487 */
1487 1488 opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
1488 1489
1489 1490 /*
1490 1491 * Check for optional alternate path and fill in the
1491 1492 * appropriate QPC fields if one is specified
1492 1493 */
1493 1494 if (flags & IBT_CEP_SET_ALT_PATH) {
1494 1495 qpc_path = &qpc->alt_addr_path;
1495 1496 adds_vect = &rc->rc_alt_path.cep_adds_vect;
1496 1497
1497 1498 /* Set the common alternate address path fields */
1498 1499 status = hermon_set_addr_path(state, adds_vect,
1499 1500 qpc_path, HERMON_ADDRPATH_QP);
1500 1501 if (status != DDI_SUCCESS) {
1501 1502 return (status);
1502 1503 }
1503 1504 qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
1504 1505
1505 1506
1506 1507 /*
1507 1508 * Check for valid alternate path port number and fill
1508 1509 * it in
1509 1510 */
1510 1511 portnum = rc->rc_alt_path.cep_hca_port_num;
1511 1512 if (hermon_portnum_is_valid(state, portnum)) {
1512 1513 qp->qp_portnum_alt = portnum - 1;
1513 1514 qpc->alt_addr_path.sched_q =
1514 1515 HERMON_QP_SCHEDQ_GET(portnum - 1,
1515 1516 adds_vect->av_srvl, qp->qp_is_special);
1516 1517 } else {
1517 1518 return (IBT_HCA_PORT_INVALID);
1518 1519 }
1519 1520 /*
1520 1521 * Check for valid alternate path PKey index and fill
1521 1522 * it in
1522 1523 */
1523 1524 pkeyindx = rc->rc_alt_path.cep_pkey_ix;
1524 1525 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1525 1526 qpc->alt_addr_path.pkey_indx = pkeyindx;
1526 1527 } else {
1527 1528 return (IBT_PKEY_IX_ILLEGAL);
1528 1529 }
1529 1530 opmask |= HERMON_CMD_OP_ALT_PATH;
1530 1531 }
1531 1532
1532 1533 } else if (qp->qp_serv_type == HERMON_QP_UC) {
1533 1534 uc = &info_p->qp_transport.uc;
1534 1535 qpc_path = &qpc->pri_addr_path;
1535 1536 adds_vect = &uc->uc_path.cep_adds_vect;
1536 1537
1537 1538 /*
1538 1539 * Set the common primary address path fields
1539 1540 */
1540 1541 status = hermon_set_addr_path(state, adds_vect, qpc_path,
1541 1542 HERMON_ADDRPATH_QP);
1542 1543 if (status != DDI_SUCCESS) {
1543 1544 return (status);
1544 1545 }
1545 1546
1546 1547 /* set the primary port num/schedq */
1547 1548 portnum = qp->qp_portnum + 1;
1548 1549 if (hermon_portnum_is_valid(state, portnum)) {
1549 1550 qpc->pri_addr_path.sched_q =
1550 1551 HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
1551 1552 adds_vect->av_srvl, qp->qp_is_special);
1552 1553 } else {
1553 1554 return (IBT_HCA_PORT_INVALID);
1554 1555 }
1555 1556
1556 1557 /*
1557 1558 * Setup the destination QP, recv PSN, MTU, max msg size,etc.
1558 1559 * Note max message size is defined to be the maximum IB
1559 1560 * allowed message size (which is 2^31 bytes). Also max
1560 1561 * MTU is defined by HCA port properties.
1561 1562 */
1562 1563 qpc->rem_qpn = uc->uc_dst_qpn;
1563 1564 qpc->next_rcv_psn = uc->uc_rq_psn;
1564 1565 qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
1565 1566 mtu = uc->uc_path_mtu;
1566 1567 if (hermon_qp_validate_mtu(state, mtu) != DDI_SUCCESS) {
1567 1568 return (IBT_HCA_PORT_MTU_EXCEEDED);
1568 1569 }
1569 1570 qpc->mtu = mtu;
1570 1571
1571 1572 /*
1572 1573 * Save away the MTU value. This is used in future sqd2sqd
1573 1574 * transitions, as the MTU must remain the same in future
1574 1575 * changes.
1575 1576 */
1576 1577 qp->qp_save_mtu = qpc->mtu;
1577 1578
1578 1579 /*
1579 1580 * If we are attempting to modify the PKey index for this QP,
1580 1581 * then check for valid PKey index and fill it in. Also set
1581 1582 * the appropriate flag in the "opmask" parameter.
1582 1583 */
1583 1584 if (flags & IBT_CEP_SET_PKEY_IX) {
1584 1585 pkeyindx = uc->uc_path.cep_pkey_ix;
1585 1586 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1586 1587 qpc->pri_addr_path.pkey_indx = pkeyindx;
1587 1588 opmask |= HERMON_CMD_OP_PKEYINDX;
1588 1589 } else {
1589 1590 return (IBT_PKEY_IX_ILLEGAL);
1590 1591 }
1591 1592 }
1592 1593
1593 1594 /*
1594 1595 * Check if any of the flags indicate a change in the RDMA
1595 1596 * Write (recv) enable/disable and set the appropriate flag
1596 1597 * in the "opmask" parameter. Note: RDMA Read and Atomic are
1597 1598 * not valid for UC transport.
1598 1599 */
1599 1600 if (flags & IBT_CEP_SET_RDMA_W) {
1600 1601 qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
1601 1602 opmask |= HERMON_CMD_OP_RWE;
1602 1603 }
1603 1604
1604 1605 /*
1605 1606 * Check for optional alternate path and fill in the
1606 1607 * appropriate QPC fields if one is specified
1607 1608 */
1608 1609 if (flags & IBT_CEP_SET_ALT_PATH) {
1609 1610 qpc_path = &qpc->alt_addr_path;
1610 1611 adds_vect = &uc->uc_alt_path.cep_adds_vect;
1611 1612
1612 1613 /* Set the common alternate address path fields */
1613 1614 status = hermon_set_addr_path(state, adds_vect,
1614 1615 qpc_path, HERMON_ADDRPATH_QP);
1615 1616 if (status != DDI_SUCCESS) {
1616 1617 return (status);
1617 1618 }
1618 1619
1619 1620 qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
1620 1621
1621 1622 /*
1622 1623 * Check for valid alternate path port number and fill
1623 1624 * it in
1624 1625 */
1625 1626 portnum = uc->uc_alt_path.cep_hca_port_num;
1626 1627 if (hermon_portnum_is_valid(state, portnum)) {
1627 1628 qp->qp_portnum_alt = portnum - 1;
1628 1629 qpc->alt_addr_path.sched_q =
1629 1630 HERMON_QP_SCHEDQ_GET(portnum - 1,
1630 1631 adds_vect->av_srvl, qp->qp_is_special);
1631 1632 } else {
1632 1633 return (IBT_HCA_PORT_INVALID);
1633 1634 }
1634 1635
1635 1636 /*
1636 1637 * Check for valid alternate path PKey index and fill
1637 1638 * it in
1638 1639 */
1639 1640 pkeyindx = uc->uc_alt_path.cep_pkey_ix;
1640 1641 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1641 1642 qpc->alt_addr_path.pkey_indx = pkeyindx;
1642 1643 } else {
1643 1644 return (IBT_PKEY_IX_ILLEGAL);
1644 1645 }
1645 1646 opmask |= HERMON_CMD_OP_ALT_PATH;
1646 1647 }
1647 1648 } else {
1648 1649 /*
1649 1650 * Invalid QP transport type. If we got here then it's a
1650 1651 * warning of a probably serious problem. So print a message
1651 1652 * and return failure
1652 1653 */
1653 1654 HERMON_WARNING(state, "unknown QP transport type in init2rtr");
1654 1655 return (ibc_get_ci_failure(0));
1655 1656 }
1656 1657
1657 1658 /*
1658 1659 * Post the INIT2RTR_QP command to the Hermon firmware
1659 1660 *
1660 1661 * We do a HERMON_NOSLEEP here because we are still holding the
1661 1662 * "qp_lock". If we got raised to interrupt level by priority
1662 1663 * inversion, we do not want to block in this routine waiting for
1663 1664 * success.
1664 1665 */
1665 1666 status = hermon_cmn_qp_cmd_post(state, INIT2RTR_QP, qpc, qp->qp_qpnum,
1666 1667 opmask, HERMON_CMD_NOSLEEP_SPIN);
1667 1668 if (status != HERMON_CMD_SUCCESS) {
1668 1669 if (status != HERMON_CMD_BAD_QP_STATE) {
1669 1670 cmn_err(CE_NOTE, "hermon%d: INIT2RTR_QP command "
1670 1671 "failed: %08x\n", state->hs_instance, status);
1671 1672 if (status == HERMON_CMD_INVALID_STATUS) {
1672 1673 hermon_fm_ereport(state, HCA_SYS_ERR,
1673 1674 HCA_ERR_SRV_LOST);
1674 1675 }
1675 1676 return (ibc_get_ci_failure(0));
1676 1677 } else {
1677 1678 return (IBT_QP_STATE_INVALID);
1678 1679 }
1679 1680 }
1680 1681
1681 1682 return (DDI_SUCCESS);
1682 1683 }
1683 1684
1684 1685
1685 1686 /*
1686 1687 * hermon_qp_rtr2rts()
1687 1688 * Context: Can be called from interrupt or base context.
1688 1689 */
1689 1690 static int
1690 1691 hermon_qp_rtr2rts(hermon_state_t *state, hermon_qphdl_t qp,
1691 1692 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
1692 1693 {
1693 1694 hermon_hw_qpc_t *qpc;
1694 1695 ibt_qp_rc_attr_t *rc;
1695 1696 ibt_qp_ud_attr_t *ud;
1696 1697 ibt_qp_uc_attr_t *uc;
1697 1698 hermon_hw_addr_path_t *qpc_path;
1698 1699 ibt_adds_vect_t *adds_vect;
1699 1700 uint_t portnum, pkeyindx, sra_max;
1700 1701 uint32_t opmask = 0;
1701 1702 int status;
1702 1703
1703 1704 ASSERT(MUTEX_HELD(&qp->qp_lock));
1704 1705
1705 1706 /*
1706 1707 * Grab the temporary QPC entry from QP software state
1707 1708 */
1708 1709 qpc = &qp->qpc;
1709 1710
1710 1711 /*
1711 1712 * Now fill in the QPC fields which are specific to transport type
1712 1713 */
1713 1714 if (qp->qp_type == IBT_UD_RQP) {
1714 1715 ud = &info_p->qp_transport.ud;
1715 1716
1716 1717 /* Set the send PSN */
1717 1718 qpc->next_snd_psn = ud->ud_sq_psn;
1718 1719
1719 1720 /*
1720 1721 * If we are attempting to modify the QKey for this QP, then
1721 1722 * fill it in and set the appropriate flag in the "opmask"
1722 1723 * parameter.
1723 1724 */
1724 1725 if (flags & IBT_CEP_SET_QKEY) {
1725 1726 qpc->qkey = ud->ud_qkey;
1726 1727 opmask |= HERMON_CMD_OP_QKEY;
1727 1728 }
1728 1729
1729 1730 } else if (qp->qp_serv_type == HERMON_QP_RC) {
1730 1731 rc = &info_p->qp_transport.rc;
1731 1732 qpc_path = &qpc->pri_addr_path;
1732 1733
1733 1734 /*
1734 1735 * Setup the send PSN, ACK timeout, and retry counts
1735 1736 */
1736 1737 qpc->next_snd_psn = rc->rc_sq_psn;
1737 1738 qpc_path->ack_timeout = rc->rc_path.cep_timeout;
1738 1739 qpc->rnr_retry = rc->rc_rnr_retry_cnt;
1739 1740 /* in qpc now, not path */
1740 1741 qpc->retry_cnt = rc->rc_retry_cnt;
1741 1742
1742 1743 /*
1743 1744 * Set "ack_req_freq" based on the configuration variable
1744 1745 */
1745 1746 qpc->ack_req_freq = state->hs_cfg_profile->cp_ackreq_freq;
1746 1747
1747 1748 /*
1748 1749 * Check that the number of specified "outgoing RDMA resources"
1749 1750 * is valid. And if it is, then setup the "sra_max"
1750 1751 * appropriately
1751 1752 */
1752 1753 if (hermon_qp_validate_init_depth(state, rc, &sra_max) !=
1753 1754 DDI_SUCCESS) {
1754 1755 return (IBT_INVALID_PARAM);
1755 1756 }
1756 1757 qpc->sra_max = sra_max;
1757 1758
1758 1759
1759 1760 /*
1760 1761 * Check if any of the flags indicate a change in the RDMA
1761 1762 * (recv) enable/disable flags and set the appropriate flag in
1762 1763 * the "opmask" parameter
1763 1764 */
1764 1765 opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
1765 1766
1766 1767 /*
1767 1768 * If we are attempting to modify the path migration state for
1768 1769 * this QP, then check for valid state and fill it in. Also
1769 1770 * set the appropriate flag in the "opmask" parameter.
1770 1771 */
1771 1772 if (flags & IBT_CEP_SET_MIG) {
1772 1773 if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
1773 1774 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
1774 1775 } else if (rc->rc_mig_state == IBT_STATE_REARMED) {
1775 1776 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
1776 1777 } else {
1777 1778 return (IBT_QP_APM_STATE_INVALID);
1778 1779 }
1779 1780 opmask |= HERMON_CMD_OP_PM_STATE;
1780 1781 }
1781 1782
1782 1783 /*
1783 1784 * If we are attempting to modify the "Minimum RNR NAK" value
1784 1785 * for this QP, then fill it in and set the appropriate flag
1785 1786 * in the "opmask" parameter.
1786 1787 */
1787 1788 if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
1788 1789 qpc->min_rnr_nak = rc->rc_min_rnr_nak;
1789 1790 opmask |= HERMON_CMD_OP_MINRNRNAK;
1790 1791 }
1791 1792
1792 1793 /*
1793 1794 * Check for optional alternate path and fill in the
1794 1795 * appropriate QPC fields if one is specified
1795 1796 */
1796 1797 if (flags & IBT_CEP_SET_ALT_PATH) {
1797 1798 qpc_path = &qpc->alt_addr_path;
1798 1799 adds_vect = &rc->rc_alt_path.cep_adds_vect;
1799 1800
1800 1801 /* Set the common alternate address path fields */
1801 1802 status = hermon_set_addr_path(state, adds_vect,
1802 1803 qpc_path, HERMON_ADDRPATH_QP);
1803 1804 if (status != DDI_SUCCESS) {
1804 1805 return (status);
1805 1806 }
1806 1807
1807 1808 qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
1808 1809
1809 1810 /*
1810 1811 * Check for valid alternate path port number and fill
1811 1812 * it in
1812 1813 */
1813 1814 portnum = rc->rc_alt_path.cep_hca_port_num;
1814 1815 if (hermon_portnum_is_valid(state, portnum)) {
1815 1816 qp->qp_portnum_alt = portnum - 1;
1816 1817 qpc->alt_addr_path.sched_q =
1817 1818 HERMON_QP_SCHEDQ_GET(portnum - 1,
1818 1819 adds_vect->av_srvl, qp->qp_is_special);
1819 1820 } else {
1820 1821 return (IBT_HCA_PORT_INVALID);
1821 1822 }
1822 1823
1823 1824 /*
1824 1825 * Check for valid alternate path PKey index and fill
1825 1826 * it in
1826 1827 */
1827 1828 pkeyindx = rc->rc_alt_path.cep_pkey_ix;
1828 1829 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1829 1830 qpc->alt_addr_path.pkey_indx = pkeyindx;
1830 1831 } else {
1831 1832 return (IBT_PKEY_IX_ILLEGAL);
1832 1833 }
1833 1834 opmask |= HERMON_CMD_OP_ALT_PATH;
1834 1835 }
1835 1836
1836 1837 } else if (qp->qp_serv_type == HERMON_QP_UC) {
1837 1838 uc = &info_p->qp_transport.uc;
1838 1839
1839 1840 /* Set the send PSN */
1840 1841 qpc->next_snd_psn = uc->uc_sq_psn;
1841 1842
1842 1843 /*
1843 1844 * Configure the QP to allow (sending of) all types of allowable
1844 1845 * UC traffic (i.e. RDMA Write).
1845 1846 */
1846 1847
1847 1848
1848 1849 /*
1849 1850 * Check if any of the flags indicate a change in the RDMA
1850 1851 * Write (recv) enable/disable and set the appropriate flag
1851 1852 * in the "opmask" parameter. Note: RDMA Read and Atomic are
1852 1853 * not valid for UC transport.
1853 1854 */
1854 1855 if (flags & IBT_CEP_SET_RDMA_W) {
1855 1856 qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
1856 1857 opmask |= HERMON_CMD_OP_RWE;
1857 1858 }
1858 1859
1859 1860 /*
1860 1861 * If we are attempting to modify the path migration state for
1861 1862 * this QP, then check for valid state and fill it in. Also
1862 1863 * set the appropriate flag in the "opmask" parameter.
1863 1864 */
1864 1865 if (flags & IBT_CEP_SET_MIG) {
1865 1866 if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
1866 1867 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
1867 1868 } else if (uc->uc_mig_state == IBT_STATE_REARMED) {
1868 1869 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
1869 1870 } else {
1870 1871 return (IBT_QP_APM_STATE_INVALID);
1871 1872 }
1872 1873 opmask |= HERMON_CMD_OP_PM_STATE;
1873 1874 }
1874 1875
1875 1876 /*
1876 1877 * Check for optional alternate path and fill in the
1877 1878 * appropriate QPC fields if one is specified
1878 1879 */
1879 1880 if (flags & IBT_CEP_SET_ALT_PATH) {
1880 1881 qpc_path = &qpc->alt_addr_path;
1881 1882 adds_vect = &uc->uc_alt_path.cep_adds_vect;
1882 1883
1883 1884 /* Set the common alternate address path fields */
1884 1885 status = hermon_set_addr_path(state, adds_vect,
1885 1886 qpc_path, HERMON_ADDRPATH_QP);
1886 1887 if (status != DDI_SUCCESS) {
1887 1888 return (status);
1888 1889 }
1889 1890 qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
1890 1891
1891 1892 /*
1892 1893 * Check for valid alternate path port number and fill
1893 1894 * it in
1894 1895 */
1895 1896 portnum = uc->uc_alt_path.cep_hca_port_num;
1896 1897 if (hermon_portnum_is_valid(state, portnum)) {
1897 1898 qpc->alt_addr_path.sched_q =
1898 1899 HERMON_QP_SCHEDQ_GET(portnum - 1,
1899 1900 adds_vect->av_srvl, qp->qp_is_special);
1900 1901 } else {
1901 1902 return (IBT_HCA_PORT_INVALID);
1902 1903 }
1903 1904
1904 1905 /*
1905 1906 * Check for valid alternate path PKey index and fill
1906 1907 * it in
1907 1908 */
1908 1909 pkeyindx = uc->uc_alt_path.cep_pkey_ix;
1909 1910 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1910 1911 qpc->alt_addr_path.pkey_indx = pkeyindx;
1911 1912 } else {
1912 1913 return (IBT_PKEY_IX_ILLEGAL);
1913 1914 }
1914 1915 opmask |= HERMON_CMD_OP_ALT_PATH;
1915 1916 }
1916 1917 } else {
1917 1918 /*
1918 1919 * Invalid QP transport type. If we got here then it's a
1919 1920 * warning of a probably serious problem. So print a message
1920 1921 * and return failure
1921 1922 */
1922 1923 HERMON_WARNING(state, "unknown QP transport type in rtr2rts");
1923 1924 return (ibc_get_ci_failure(0));
1924 1925 }
1925 1926
1926 1927 /*
1927 1928 * Post the RTR2RTS_QP command to the Hermon firmware
1928 1929 *
1929 1930 * We do a HERMON_NOSLEEP here because we are still holding the
1930 1931 * "qp_lock". If we got raised to interrupt level by priority
1931 1932 * inversion, we do not want to block in this routine waiting for
1932 1933 * success.
1933 1934 */
1934 1935 status = hermon_cmn_qp_cmd_post(state, RTR2RTS_QP, qpc, qp->qp_qpnum,
1935 1936 opmask, HERMON_CMD_NOSLEEP_SPIN);
1936 1937 if (status != HERMON_CMD_SUCCESS) {
1937 1938 if (status != HERMON_CMD_BAD_QP_STATE) {
1938 1939 cmn_err(CE_NOTE, "hermon%d: RTR2RTS_QP command failed: "
1939 1940 "%08x\n", state->hs_instance, status);
1940 1941 if (status == HERMON_CMD_INVALID_STATUS) {
1941 1942 hermon_fm_ereport(state, HCA_SYS_ERR,
1942 1943 HCA_ERR_SRV_LOST);
1943 1944 }
1944 1945 return (ibc_get_ci_failure(0));
1945 1946 } else {
1946 1947 return (IBT_QP_STATE_INVALID);
1947 1948 }
1948 1949 }
1949 1950
1950 1951 return (DDI_SUCCESS);
1951 1952 }
1952 1953
1953 1954
1954 1955 /*
1955 1956 * hermon_qp_rts2rts()
1956 1957 * Context: Can be called from interrupt or base context.
1957 1958 */
1958 1959 static int
1959 1960 hermon_qp_rts2rts(hermon_state_t *state, hermon_qphdl_t qp,
1960 1961 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
1961 1962 {
1962 1963 hermon_hw_qpc_t *qpc;
1963 1964 ibt_qp_rc_attr_t *rc;
1964 1965 ibt_qp_ud_attr_t *ud;
1965 1966 ibt_qp_uc_attr_t *uc;
1966 1967 hermon_hw_addr_path_t *qpc_path;
1967 1968 ibt_adds_vect_t *adds_vect;
1968 1969 uint_t portnum, pkeyindx;
1969 1970 uint32_t opmask = 0;
1970 1971 int status;
1971 1972
1972 1973 ASSERT(MUTEX_HELD(&qp->qp_lock));
1973 1974
1974 1975 /*
1975 1976 * Grab the temporary QPC entry from QP software state
1976 1977 */
1977 1978
1978 1979 qpc = &qp->qpc;
1979 1980
1980 1981 /*
1981 1982 * Since there are no common fields to be filled in for this command,
1982 1983 * we begin with the QPC fields which are specific to transport type.
1983 1984 */
1984 1985 if (qp->qp_type == IBT_UD_RQP) {
1985 1986 ud = &info_p->qp_transport.ud;
1986 1987
1987 1988 /*
1988 1989 * If we are attempting to modify the QKey for this QP, then
1989 1990 * fill it in and set the appropriate flag in the "opmask"
1990 1991 * parameter.
1991 1992 */
1992 1993 if (flags & IBT_CEP_SET_QKEY) {
1993 1994 qpc->qkey = ud->ud_qkey;
1994 1995 opmask |= HERMON_CMD_OP_QKEY;
1995 1996 }
1996 1997
1997 1998 } else if (qp->qp_serv_type == HERMON_QP_RC) {
1998 1999 rc = &info_p->qp_transport.rc;
1999 2000
2000 2001 /*
2001 2002 * Check if any of the flags indicate a change in the RDMA
2002 2003 * (recv) enable/disable flags and set the appropriate flag in
2003 2004 * the "opmask" parameter
2004 2005 */
2005 2006 opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
2006 2007
2007 2008 /*
2008 2009 * If we are attempting to modify the path migration state for
2009 2010 * this QP, then check for valid state and fill it in. Also
2010 2011 * set the appropriate flag in the "opmask" parameter.
2011 2012 */
2012 2013 if (flags & IBT_CEP_SET_MIG) {
2013 2014 if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
2014 2015 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
2015 2016 } else if (rc->rc_mig_state == IBT_STATE_REARMED) {
2016 2017 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
2017 2018 } else {
2018 2019 return (IBT_QP_APM_STATE_INVALID);
2019 2020 }
2020 2021 opmask |= HERMON_CMD_OP_PM_STATE;
2021 2022 }
2022 2023
2023 2024 /*
2024 2025 * If we are attempting to modify the "Minimum RNR NAK" value
2025 2026 * for this QP, then fill it in and set the appropriate flag
2026 2027 * in the "opmask" parameter.
2027 2028 */
2028 2029 if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
2029 2030 qpc->min_rnr_nak = rc->rc_min_rnr_nak;
2030 2031 opmask |= HERMON_CMD_OP_MINRNRNAK;
2031 2032 }
2032 2033
2033 2034 /*
2034 2035 * Check for optional alternate path and fill in the
2035 2036 * appropriate QPC fields if one is specified
2036 2037 */
2037 2038 if (flags & IBT_CEP_SET_ALT_PATH) {
2038 2039 qpc_path = &qpc->alt_addr_path;
2039 2040 adds_vect = &rc->rc_alt_path.cep_adds_vect;
2040 2041
2041 2042 /* Set the common alternate address path fields */
2042 2043 status = hermon_set_addr_path(state, adds_vect,
2043 2044 qpc_path, HERMON_ADDRPATH_QP);
2044 2045 if (status != DDI_SUCCESS) {
2045 2046 return (status);
2046 2047 }
2047 2048 qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
2048 2049
2049 2050 /*
2050 2051 * Check for valid alternate path port number and fill
2051 2052 * it in
2052 2053 */
2053 2054 portnum = rc->rc_alt_path.cep_hca_port_num;
2054 2055 if (hermon_portnum_is_valid(state, portnum)) {
2055 2056 qp->qp_portnum_alt = portnum - 1;
2056 2057 qpc->alt_addr_path.sched_q =
2057 2058 HERMON_QP_SCHEDQ_GET(portnum - 1,
2058 2059 adds_vect->av_srvl, qp->qp_is_special);
2059 2060 } else {
2060 2061 return (IBT_HCA_PORT_INVALID);
2061 2062 }
2062 2063
2063 2064 /*
2064 2065 * Check for valid alternate path PKey index and fill
2065 2066 * it in
2066 2067 */
2067 2068 pkeyindx = rc->rc_alt_path.cep_pkey_ix;
2068 2069 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2069 2070 qpc->alt_addr_path.pkey_indx = pkeyindx;
2070 2071 } else {
2071 2072 return (IBT_PKEY_IX_ILLEGAL);
2072 2073 }
2073 2074 opmask |= HERMON_CMD_OP_ALT_PATH;
2074 2075 }
2075 2076
2076 2077 } else if (qp->qp_serv_type == HERMON_QP_UC) {
2077 2078 uc = &info_p->qp_transport.uc;
2078 2079
2079 2080 /*
2080 2081 * Check if any of the flags indicate a change in the RDMA
2081 2082 * Write (recv) enable/disable and set the appropriate flag
2082 2083 * in the "opmask" parameter. Note: RDMA Read and Atomic are
2083 2084 * not valid for UC transport.
2084 2085 */
2085 2086 if (flags & IBT_CEP_SET_RDMA_W) {
2086 2087 qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
2087 2088 opmask |= HERMON_CMD_OP_RWE;
2088 2089 }
2089 2090
2090 2091 /*
2091 2092 * If we are attempting to modify the path migration state for
2092 2093 * this QP, then check for valid state and fill it in. Also
2093 2094 * set the appropriate flag in the "opmask" parameter.
2094 2095 */
2095 2096 if (flags & IBT_CEP_SET_MIG) {
2096 2097 if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
2097 2098 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
2098 2099 } else if (uc->uc_mig_state == IBT_STATE_REARMED) {
2099 2100 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
2100 2101 } else {
2101 2102 return (IBT_QP_APM_STATE_INVALID);
2102 2103 }
2103 2104 opmask |= HERMON_CMD_OP_PM_STATE;
2104 2105 }
2105 2106
2106 2107 /*
2107 2108 * Check for optional alternate path and fill in the
2108 2109 * appropriate QPC fields if one is specified
2109 2110 */
2110 2111 if (flags & IBT_CEP_SET_ALT_PATH) {
2111 2112 qpc_path = &qpc->alt_addr_path;
2112 2113 adds_vect = &uc->uc_alt_path.cep_adds_vect;
2113 2114
2114 2115 /* Set the common alternate address path fields */
2115 2116 status = hermon_set_addr_path(state, adds_vect,
2116 2117 qpc_path, HERMON_ADDRPATH_QP);
2117 2118 if (status != DDI_SUCCESS) {
2118 2119 return (status);
2119 2120 }
2120 2121
2121 2122 /*
2122 2123 * Check for valid alternate path port number and fill
2123 2124 * it in
2124 2125 */
2125 2126 portnum = uc->uc_alt_path.cep_hca_port_num;
2126 2127 if (hermon_portnum_is_valid(state, portnum)) {
2127 2128 qp->qp_portnum_alt = portnum - 1;
2128 2129 qpc->alt_addr_path.sched_q =
2129 2130 HERMON_QP_SCHEDQ_GET(portnum - 1,
2130 2131 adds_vect->av_srvl, qp->qp_is_special);
2131 2132 } else {
2132 2133 return (IBT_HCA_PORT_INVALID);
2133 2134 }
2134 2135
2135 2136 /*
2136 2137 * Check for valid alternate path PKey index and fill
2137 2138 * it in
2138 2139 */
2139 2140 pkeyindx = uc->uc_alt_path.cep_pkey_ix;
2140 2141 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2141 2142 qpc->alt_addr_path.pkey_indx = pkeyindx;
2142 2143 } else {
2143 2144 return (IBT_PKEY_IX_ILLEGAL);
2144 2145 }
2145 2146 opmask |= HERMON_CMD_OP_ALT_PATH;
2146 2147 }
2147 2148 } else {
2148 2149 /*
2149 2150 * Invalid QP transport type. If we got here then it's a
2150 2151 * warning of a probably serious problem. So print a message
2151 2152 * and return failure
2152 2153 */
2153 2154 HERMON_WARNING(state, "unknown QP transport type in rts2rts");
2154 2155 return (ibc_get_ci_failure(0));
2155 2156 }
2156 2157
2157 2158 /*
2158 2159 * Post the RTS2RTS_QP command to the Hermon firmware
2159 2160 *
2160 2161 * We do a HERMON_NOSLEEP here because we are still holding the
2161 2162 * "qp_lock". If we got raised to interrupt level by priority
2162 2163 * inversion, we do not want to block in this routine waiting for
2163 2164 * success.
2164 2165 */
2165 2166 status = hermon_cmn_qp_cmd_post(state, RTS2RTS_QP, qpc, qp->qp_qpnum,
2166 2167 opmask, HERMON_CMD_NOSLEEP_SPIN);
2167 2168 if (status != HERMON_CMD_SUCCESS) {
2168 2169 if (status != HERMON_CMD_BAD_QP_STATE) {
2169 2170 cmn_err(CE_NOTE, "hermon%d: RTS2RTS_QP command failed: "
2170 2171 "%08x\n", state->hs_instance, status);
2171 2172 if (status == HERMON_CMD_INVALID_STATUS) {
2172 2173 hermon_fm_ereport(state, HCA_SYS_ERR,
2173 2174 HCA_ERR_SRV_LOST);
2174 2175 }
2175 2176 return (ibc_get_ci_failure(0));
2176 2177 } else {
2177 2178 return (IBT_QP_STATE_INVALID);
2178 2179 }
2179 2180 }
2180 2181
2181 2182 return (DDI_SUCCESS);
2182 2183 }
2183 2184
2184 2185
2185 2186 #ifdef HERMON_NOTNOW
2186 2187 /*
2187 2188 * hermon_qp_rts2sqd()
2188 2189 * Context: Can be called from interrupt or base context.
2189 2190 */
2190 2191 static int
2191 2192 hermon_qp_rts2sqd(hermon_state_t *state, hermon_qphdl_t qp,
2192 2193 ibt_cep_modify_flags_t flags)
2193 2194 {
2194 2195 int status;
2195 2196
2196 2197 ASSERT(MUTEX_HELD(&qp->qp_lock));
2197 2198
2198 2199 /*
2199 2200 * Set a flag to indicate whether or not the consumer is interested
2200 2201 * in receiving the SQ drained event. Since we are going to always
2201 2202 * request hardware generation of the SQD event, we use the value in
2202 2203 * "qp_forward_sqd_event" to determine whether or not to pass the event
2203 2204 * to the IBTF or to silently consume it.
2204 2205 */
2205 2206 qp->qp_forward_sqd_event = (flags & IBT_CEP_SET_SQD_EVENT) ? 1 : 0;
2206 2207
2207 2208 /*
2208 2209 * Post the RTS2SQD_QP command to the Hermon firmware
2209 2210 *
2210 2211 * We do a HERMON_NOSLEEP here because we are still holding the
2211 2212 * "qp_lock". If we got raised to interrupt level by priority
2212 2213 * inversion, we do not want to block in this routine waiting for
2213 2214 * success.
2214 2215 */
2215 2216 status = hermon_cmn_qp_cmd_post(state, RTS2SQD_QP, NULL, qp->qp_qpnum,
2216 2217 0, HERMON_CMD_NOSLEEP_SPIN);
2217 2218 if (status != HERMON_CMD_SUCCESS) {
2218 2219 if (status != HERMON_CMD_BAD_QP_STATE) {
2219 2220 cmn_err(CE_NOTE, "hermon%d: RTS2SQD_QP command failed: "
2220 2221 "%08x\n", state->hs_instance, status);
2221 2222 if (status == HERMON_CMD_INVALID_STATUS) {
2222 2223 hermon_fm_ereport(state, HCA_SYS_ERR,
2223 2224 HCA_ERR_SRV_LOST);
2224 2225 }
2225 2226 return (ibc_get_ci_failure(0));
2226 2227 } else {
2227 2228 return (IBT_QP_STATE_INVALID);
2228 2229 }
2229 2230 }
2230 2231
2231 2232 /*
2232 2233 * Mark the current QP state as "SQ Draining". This allows us to
2233 2234 * distinguish between the two underlying states in SQD. (see QueryQP()
2234 2235 * code in hermon_qp.c)
2235 2236 */
2236 2237 qp->qp_sqd_still_draining = 1;
2237 2238
2238 2239 return (DDI_SUCCESS);
2239 2240 }
2240 2241 #endif
2241 2242
2242 2243
2243 2244 /*
2244 2245 * hermon_qp_sqd2rts()
2245 2246 * Context: Can be called from interrupt or base context.
2246 2247 */
2247 2248 static int
2248 2249 hermon_qp_sqd2rts(hermon_state_t *state, hermon_qphdl_t qp,
2249 2250 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
2250 2251 {
2251 2252 hermon_hw_qpc_t *qpc;
2252 2253 ibt_qp_rc_attr_t *rc;
2253 2254 ibt_qp_ud_attr_t *ud;
2254 2255 ibt_qp_uc_attr_t *uc;
2255 2256 hermon_hw_addr_path_t *qpc_path;
2256 2257 ibt_adds_vect_t *adds_vect;
2257 2258 uint_t portnum, pkeyindx;
2258 2259 uint_t rra_max, sra_max;
2259 2260 uint32_t opmask = 0;
2260 2261 int status;
2261 2262
2262 2263 ASSERT(MUTEX_HELD(&qp->qp_lock));
2263 2264
2264 2265 /*
2265 2266 * Grab the temporary QPC entry from QP software state
2266 2267 */
2267 2268 qpc = &qp->qpc;
2268 2269
2269 2270 /*
2270 2271 * Fill in the common fields in the QPC
2271 2272 */
2272 2273
2273 2274 /*
2274 2275 * Now fill in the QPC fields which are specific to transport type
2275 2276 */
2276 2277 if (qp->qp_type == IBT_UD_RQP) {
2277 2278 ud = &info_p->qp_transport.ud;
2278 2279
2279 2280 /*
2280 2281 * If we are attempting to modify the port for this QP, then
2281 2282 * check for valid port number and fill it in. Also set the
2282 2283 * appropriate flag in the "opmask" parameter.
2283 2284 */
2284 2285 if (flags & IBT_CEP_SET_PORT) {
2285 2286 portnum = ud->ud_port;
2286 2287 if (hermon_portnum_is_valid(state, portnum)) {
2287 2288 qp->qp_portnum = portnum - 1;
2288 2289 qpc->pri_addr_path.sched_q =
2289 2290 HERMON_QP_SCHEDQ_GET(portnum - 1,
2290 2291 0, qp->qp_is_special);
2291 2292 } else {
2292 2293 return (IBT_HCA_PORT_INVALID);
2293 2294 }
2294 2295 opmask |= HERMON_CMD_OP_PRIM_PORT;
2295 2296 }
2296 2297
2297 2298 /*
2298 2299 * If we are attempting to modify the PKey index for this QP,
2299 2300 * then check for valid PKey index and fill it in. Also set
2300 2301 * the appropriate flag in the "opmask" parameter.
2301 2302 */
2302 2303 if (flags & IBT_CEP_SET_PKEY_IX) {
2303 2304 pkeyindx = ud->ud_pkey_ix;
2304 2305 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2305 2306 qpc->pri_addr_path.pkey_indx = pkeyindx;
2306 2307 opmask |= HERMON_CMD_OP_PKEYINDX;
2307 2308 qp->qp_pkeyindx = pkeyindx;
2308 2309 } else {
2309 2310 return (IBT_PKEY_IX_ILLEGAL);
2310 2311 }
2311 2312 }
2312 2313
2313 2314 /*
2314 2315 * If we are attempting to modify the QKey for this QP, then
2315 2316 * fill it in and set the appropriate flag in the "opmask"
2316 2317 * parameter.
2317 2318 */
2318 2319 if (flags & IBT_CEP_SET_QKEY) {
2319 2320 qpc->qkey = ud->ud_qkey;
2320 2321 opmask |= HERMON_CMD_OP_QKEY;
2321 2322 }
2322 2323
2323 2324 } else if (qp->qp_serv_type == HERMON_QP_RC) {
2324 2325 rc = &info_p->qp_transport.rc;
2325 2326
2326 2327 /*
2327 2328 * Check if any of the flags indicate a change in the RDMA
2328 2329 * (recv) enable/disable flags and set the appropriate flag in
2329 2330 * the "opmask" parameter
2330 2331 */
2331 2332 opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
2332 2333
2333 2334 qpc->retry_cnt = rc->rc_retry_cnt;
2334 2335
2335 2336 /*
2336 2337 * If we are attempting to modify the path migration state for
2337 2338 * this QP, then check for valid state and fill it in. Also
2338 2339 * set the appropriate flag in the "opmask" parameter.
2339 2340 */
2340 2341 if (flags & IBT_CEP_SET_MIG) {
2341 2342 if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
2342 2343 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
2343 2344 } else if (rc->rc_mig_state == IBT_STATE_REARMED) {
2344 2345 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
2345 2346 } else {
2346 2347 return (IBT_QP_APM_STATE_INVALID);
2347 2348 }
2348 2349 opmask |= HERMON_CMD_OP_PM_STATE;
2349 2350 }
2350 2351
2351 2352 /*
2352 2353 * Check for optional alternate path and fill in the
2353 2354 * appropriate QPC fields if one is specified
2354 2355 */
2355 2356 if (flags & IBT_CEP_SET_ALT_PATH) {
2356 2357 qpc_path = &qpc->alt_addr_path;
2357 2358 adds_vect = &rc->rc_alt_path.cep_adds_vect;
2358 2359
2359 2360 /* Set the common alternate address path fields */
2360 2361 status = hermon_set_addr_path(state, adds_vect,
2361 2362 qpc_path, HERMON_ADDRPATH_QP);
2362 2363 if (status != DDI_SUCCESS) {
2363 2364 return (status);
2364 2365 }
2365 2366 qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
2366 2367 /*
2367 2368 * Check for valid alternate path port number and fill
2368 2369 * it in
2369 2370 */
2370 2371 portnum = rc->rc_alt_path.cep_hca_port_num;
2371 2372 if (hermon_portnum_is_valid(state, portnum)) {
2372 2373 qp->qp_portnum_alt = portnum - 1;
2373 2374 qpc->alt_addr_path.sched_q =
2374 2375 HERMON_QP_SCHEDQ_GET(portnum - 1,
2375 2376 adds_vect->av_srvl, qp->qp_is_special);
2376 2377 } else {
2377 2378 return (IBT_HCA_PORT_INVALID);
2378 2379 }
2379 2380
2380 2381 /*
2381 2382 * Check for valid alternate path PKey index and fill
2382 2383 * it in
2383 2384 */
2384 2385 pkeyindx = rc->rc_alt_path.cep_pkey_ix;
2385 2386 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2386 2387 qpc->alt_addr_path.pkey_indx = pkeyindx;
2387 2388 } else {
2388 2389 return (IBT_PKEY_IX_ILLEGAL);
2389 2390 }
2390 2391 opmask |= HERMON_CMD_OP_ALT_PATH;
2391 2392 }
2392 2393
2393 2394 /*
2394 2395 * If we are attempting to modify the number of "outgoing
2395 2396 * RDMA resources" for this QP, then check for valid value and
2396 2397 * fill it in. Also set the appropriate flag in the "opmask"
2397 2398 * parameter.
2398 2399 */
2399 2400 if (flags & IBT_CEP_SET_RDMARA_OUT) {
2400 2401 if (hermon_qp_validate_init_depth(state, rc,
2401 2402 &sra_max) != DDI_SUCCESS) {
2402 2403 return (IBT_INVALID_PARAM);
2403 2404 }
2404 2405 qpc->sra_max = sra_max;
2405 2406 opmask |= HERMON_CMD_OP_SRA_SET;
2406 2407 }
2407 2408
2408 2409 /*
2409 2410 * If we are attempting to modify the number of "incoming
2410 2411 * RDMA resources" for this QP, then check for valid value and
2411 2412 * update the "rra_max" and "ra_buf_index" fields in the QPC to
2412 2413 * point to the pre-allocated RDB resources (in DDR). Also set
2413 2414 * the appropriate flag in the "opmask" parameter.
2414 2415 */
2415 2416 if (flags & IBT_CEP_SET_RDMARA_IN) {
2416 2417 if (hermon_qp_validate_resp_rsrc(state, rc,
2417 2418 &rra_max) != DDI_SUCCESS) {
2418 2419 return (IBT_INVALID_PARAM);
2419 2420 }
2420 2421 qpc->rra_max = rra_max;
2421 2422 opmask |= HERMON_CMD_OP_RRA_SET;
2422 2423 }
2423 2424
2424 2425
2425 2426 /*
2426 2427 * If we are attempting to modify the "Minimum RNR NAK" value
2427 2428 * for this QP, then fill it in and set the appropriate flag
2428 2429 * in the "opmask" parameter.
2429 2430 */
2430 2431 if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
2431 2432 qpc->min_rnr_nak = rc->rc_min_rnr_nak;
2432 2433 opmask |= HERMON_CMD_OP_MINRNRNAK;
2433 2434 }
2434 2435
2435 2436 } else if (qp->qp_serv_type == HERMON_QP_UC) {
2436 2437 uc = &info_p->qp_transport.uc;
2437 2438
2438 2439 /*
2439 2440 * Check if any of the flags indicate a change in the RDMA
2440 2441 * Write (recv) enable/disable and set the appropriate flag
2441 2442 * in the "opmask" parameter. Note: RDMA Read and Atomic are
2442 2443 * not valid for UC transport.
2443 2444 */
2444 2445 if (flags & IBT_CEP_SET_RDMA_W) {
2445 2446 qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
2446 2447 opmask |= HERMON_CMD_OP_RWE;
2447 2448 }
2448 2449
2449 2450 /*
2450 2451 * If we are attempting to modify the path migration state for
2451 2452 * this QP, then check for valid state and fill it in. Also
2452 2453 * set the appropriate flag in the "opmask" parameter.
2453 2454 */
2454 2455 if (flags & IBT_CEP_SET_MIG) {
2455 2456 if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
2456 2457 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
2457 2458 } else if (uc->uc_mig_state == IBT_STATE_REARMED) {
2458 2459 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
2459 2460 } else {
2460 2461 return (IBT_QP_APM_STATE_INVALID);
2461 2462 }
2462 2463 opmask |= HERMON_CMD_OP_PM_STATE;
2463 2464 }
2464 2465
2465 2466 /*
2466 2467 * Check for optional alternate path and fill in the
2467 2468 * appropriate QPC fields if one is specified
2468 2469 */
2469 2470 if (flags & IBT_CEP_SET_ALT_PATH) {
2470 2471 qpc_path = &qpc->alt_addr_path;
2471 2472 adds_vect = &uc->uc_alt_path.cep_adds_vect;
2472 2473
2473 2474 /* Set the common alternate address path fields */
2474 2475 status = hermon_set_addr_path(state, adds_vect,
2475 2476 qpc_path, HERMON_ADDRPATH_QP);
2476 2477 if (status != DDI_SUCCESS) {
2477 2478 return (status);
2478 2479 }
2479 2480
2480 2481 /*
2481 2482 * Check for valid alternate path port number and fill
2482 2483 * it in
2483 2484 */
2484 2485 portnum = uc->uc_alt_path.cep_hca_port_num;
2485 2486 if (hermon_portnum_is_valid(state, portnum)) {
2486 2487 qp->qp_portnum_alt = portnum - 1;
2487 2488 qpc->alt_addr_path.sched_q =
2488 2489 HERMON_QP_SCHEDQ_GET(portnum - 1,
2489 2490 adds_vect->av_srvl, qp->qp_is_special);
2490 2491 } else {
2491 2492 return (IBT_HCA_PORT_INVALID);
2492 2493 }
2493 2494
2494 2495 /*
2495 2496 * Check for valid alternate path PKey index and fill
2496 2497 * it in
2497 2498 */
2498 2499 pkeyindx = uc->uc_alt_path.cep_pkey_ix;
2499 2500 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2500 2501 qpc->alt_addr_path.pkey_indx = pkeyindx;
2501 2502 } else {
2502 2503 return (IBT_PKEY_IX_ILLEGAL);
2503 2504 }
2504 2505 opmask |= HERMON_CMD_OP_ALT_PATH;
2505 2506 }
2506 2507 } else {
2507 2508 /*
2508 2509 * Invalid QP transport type. If we got here then it's a
2509 2510 * warning of a probably serious problem. So print a message
2510 2511 * and return failure
2511 2512 */
2512 2513 HERMON_WARNING(state, "unknown QP transport type in sqd2rts");
2513 2514 return (ibc_get_ci_failure(0));
2514 2515 }
2515 2516
2516 2517 /*
2517 2518 * Post the SQD2RTS_QP command to the Hermon firmware
2518 2519 *
2519 2520 * We do a HERMON_NOSLEEP here because we are still holding the
2520 2521 * "qp_lock". If we got raised to interrupt level by priority
2521 2522 * inversion, we do not want to block in this routine waiting for
2522 2523 * success.
2523 2524 */
2524 2525 status = hermon_cmn_qp_cmd_post(state, SQD2RTS_QP, qpc, qp->qp_qpnum,
2525 2526 opmask, HERMON_CMD_NOSLEEP_SPIN);
2526 2527 if (status != HERMON_CMD_SUCCESS) {
2527 2528 if (status != HERMON_CMD_BAD_QP_STATE) {
2528 2529 cmn_err(CE_NOTE, "hermon%d: SQD2RTS_QP command failed: "
2529 2530 "%08x\n", state->hs_instance, status);
2530 2531 if (status == HERMON_CMD_INVALID_STATUS) {
2531 2532 hermon_fm_ereport(state, HCA_SYS_ERR,
2532 2533 HCA_ERR_SRV_LOST);
2533 2534 }
2534 2535 return (ibc_get_ci_failure(0));
2535 2536 } else {
2536 2537 return (IBT_QP_STATE_INVALID);
2537 2538 }
2538 2539 }
2539 2540
2540 2541 return (DDI_SUCCESS);
2541 2542 }
2542 2543
2543 2544
2544 2545 /*
2545 2546 * hermon_qp_sqd2sqd()
2546 2547 * Context: Can be called from interrupt or base context.
2547 2548 */
2548 2549 static int
2549 2550 hermon_qp_sqd2sqd(hermon_state_t *state, hermon_qphdl_t qp,
2550 2551 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
2551 2552 {
2552 2553 hermon_hw_qpc_t *qpc;
2553 2554 ibt_qp_rc_attr_t *rc;
2554 2555 ibt_qp_ud_attr_t *ud;
2555 2556 ibt_qp_uc_attr_t *uc;
2556 2557 hermon_hw_addr_path_t *qpc_path;
2557 2558 ibt_adds_vect_t *adds_vect;
2558 2559 uint_t portnum, pkeyindx;
2559 2560 uint_t rra_max, sra_max;
2560 2561 uint32_t opmask = 0;
2561 2562 int status;
2562 2563
2563 2564 ASSERT(MUTEX_HELD(&qp->qp_lock));
2564 2565
2565 2566 /*
2566 2567 * Grab the temporary QPC entry from QP software state
2567 2568 */
2568 2569 qpc = &qp->qpc;
2569 2570
2570 2571 /*
2571 2572 * Fill in the common fields in the QPC
2572 2573 */
2573 2574
2574 2575 /*
2575 2576 * Now fill in the QPC fields which are specific to transport type
2576 2577 */
2577 2578 if (qp->qp_type == IBT_UD_RQP) {
2578 2579 ud = &info_p->qp_transport.ud;
2579 2580
2580 2581 /*
2581 2582 * If we are attempting to modify the port for this QP, then
2582 2583 * check for valid port number and fill it in. Also set the
2583 2584 * appropriate flag in the "opmask" parameter.
2584 2585 */
2585 2586 if (flags & IBT_CEP_SET_PORT) {
2586 2587 portnum = ud->ud_port;
2587 2588 if (hermon_portnum_is_valid(state, portnum)) {
2588 2589 qp->qp_portnum = portnum - 1;
2589 2590 qpc->pri_addr_path.sched_q =
2590 2591 HERMON_QP_SCHEDQ_GET(portnum - 1,
2591 2592 0, qp->qp_is_special);
2592 2593 } else {
2593 2594 return (IBT_HCA_PORT_INVALID);
2594 2595 }
2595 2596 opmask |= HERMON_CMD_OP_SCHEDQUEUE;
2596 2597 }
2597 2598
2598 2599 /*
2599 2600 * If we are attempting to modify the PKey index for this QP,
2600 2601 * then check for valid PKey index and fill it in. Also set
2601 2602 * the appropriate flag in the "opmask" parameter.
2602 2603 */
2603 2604 if (flags & IBT_CEP_SET_PKEY_IX) {
2604 2605 pkeyindx = ud->ud_pkey_ix;
2605 2606 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2606 2607 qpc->pri_addr_path.pkey_indx = pkeyindx;
2607 2608 opmask |= HERMON_CMD_OP_PKEYINDX;
2608 2609 qp->qp_pkeyindx = pkeyindx;
2609 2610 } else {
2610 2611 return (IBT_PKEY_IX_ILLEGAL);
2611 2612 }
2612 2613 }
2613 2614
2614 2615 /*
2615 2616 * If we are attempting to modify the QKey for this QP, then
2616 2617 * fill it in and set the appropriate flag in the "opmask"
2617 2618 * parameter.
2618 2619 */
2619 2620 if (flags & IBT_CEP_SET_QKEY) {
2620 2621 qpc->qkey = ud->ud_qkey;
2621 2622 opmask |= HERMON_CMD_OP_QKEY;
2622 2623 }
2623 2624
2624 2625 } else if (qp->qp_serv_type == HERMON_QP_RC) {
2625 2626 rc = &info_p->qp_transport.rc;
2626 2627
2627 2628 /*
2628 2629 * Check if any of the flags indicate a change in the RDMA
2629 2630 * (recv) enable/disable flags and set the appropriate flag in
2630 2631 * the "opmask" parameter
2631 2632 */
2632 2633 opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
2633 2634
2634 2635 /*
2635 2636 * Check for optional primary path and fill in the
2636 2637 * appropriate QPC fields if one is specified
2637 2638 */
2638 2639 if (flags & IBT_CEP_SET_ADDS_VECT) {
2639 2640 qpc_path = &qpc->pri_addr_path;
2640 2641 adds_vect = &rc->rc_path.cep_adds_vect;
2641 2642
2642 2643 /* Set the common primary address path fields */
2643 2644 status = hermon_set_addr_path(state, adds_vect,
2644 2645 qpc_path, HERMON_ADDRPATH_QP);
2645 2646 if (status != DDI_SUCCESS) {
2646 2647 return (status);
2647 2648 }
2648 2649 qpc->rnr_retry = rc->rc_rnr_retry_cnt;
2649 2650 qpc_path->ack_timeout = rc->rc_path.cep_timeout;
2650 2651 qpc->retry_cnt = rc->rc_retry_cnt;
2651 2652
2652 2653 portnum = qp->qp_portnum + 1;
2653 2654 if (hermon_portnum_is_valid(state, portnum)) {
2654 2655 qpc->pri_addr_path.sched_q =
2655 2656 HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
2656 2657 adds_vect->av_srvl, qp->qp_is_special);
2657 2658 } else {
2658 2659 return (IBT_HCA_PORT_INVALID);
2659 2660 }
2660 2661
2661 2662 /*
2662 2663 * MTU changes as part of sqd2sqd are not allowed.
2663 2664 * Simply keep the same MTU value here, stored in the
2664 2665 * qphdl from init2rtr time.
2665 2666 */
2666 2667 qpc->mtu = qp->qp_save_mtu;
2667 2668
2668 2669 opmask |= (HERMON_CMD_OP_PRIM_PATH |
2669 2670 HERMON_CMD_OP_RETRYCNT | HERMON_CMD_OP_ACKTIMEOUT |
2670 2671 HERMON_CMD_OP_PRIM_RNRRETRY);
2671 2672 }
2672 2673
2673 2674 /*
2674 2675 * If we are attempting to modify the path migration state for
2675 2676 * this QP, then check for valid state and fill it in. Also
2676 2677 * set the appropriate flag in the "opmask" parameter.
2677 2678 */
2678 2679 if (flags & IBT_CEP_SET_MIG) {
2679 2680 if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
2680 2681 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
2681 2682 } else if (rc->rc_mig_state == IBT_STATE_REARMED) {
2682 2683 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
2683 2684 } else {
2684 2685 return (IBT_QP_APM_STATE_INVALID);
2685 2686 }
2686 2687 opmask |= HERMON_CMD_OP_PM_STATE;
2687 2688 }
2688 2689
2689 2690 /*
2690 2691 * If we are attempting to modify the PKey index for this QP,
2691 2692 * then check for valid PKey index and fill it in. Also set
2692 2693 * the appropriate flag in the "opmask" parameter.
2693 2694 */
2694 2695 if (flags & IBT_CEP_SET_PKEY_IX) {
2695 2696 pkeyindx = rc->rc_path.cep_pkey_ix;
2696 2697 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2697 2698 qpc->pri_addr_path.pkey_indx = pkeyindx;
2698 2699 opmask |= HERMON_CMD_OP_PKEYINDX;
2699 2700 } else {
2700 2701 return (IBT_PKEY_IX_ILLEGAL);
2701 2702 }
2702 2703 }
2703 2704
2704 2705 /*
2705 2706 * If we are attempting to modify the port for this QP, then
2706 2707 * check for valid port number and fill it in. Also set the
2707 2708 * appropriate flag in the "opmask" parameter.
2708 2709 */
2709 2710 if (flags & IBT_CEP_SET_PORT) {
2710 2711 portnum = rc->rc_path.cep_hca_port_num;
2711 2712 if (hermon_portnum_is_valid(state, portnum)) {
2712 2713 qp->qp_portnum = portnum - 1;
2713 2714 qpc->pri_addr_path.sched_q =
2714 2715 HERMON_QP_SCHEDQ_GET(portnum - 1,
2715 2716 adds_vect->av_srvl, qp->qp_is_special);
2716 2717 } else {
2717 2718 return (IBT_HCA_PORT_INVALID);
2718 2719 }
2719 2720 opmask |= HERMON_CMD_OP_SCHEDQUEUE;
2720 2721 }
2721 2722
2722 2723 /*
2723 2724 * Check for optional alternate path and fill in the
2724 2725 * appropriate QPC fields if one is specified
2725 2726 */
2726 2727 if (flags & IBT_CEP_SET_ALT_PATH) {
2727 2728 qpc_path = &qpc->alt_addr_path;
2728 2729 adds_vect = &rc->rc_alt_path.cep_adds_vect;
2729 2730
2730 2731 /* Set the common alternate address path fields */
2731 2732 status = hermon_set_addr_path(state, adds_vect,
2732 2733 qpc_path, HERMON_ADDRPATH_QP);
2733 2734 if (status != DDI_SUCCESS) {
2734 2735 return (status);
2735 2736 }
2736 2737 qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
2737 2738
2738 2739 /*
2739 2740 * Check for valid alternate path port number and fill
2740 2741 * it in
2741 2742 */
2742 2743 portnum = rc->rc_alt_path.cep_hca_port_num;
2743 2744 if (hermon_portnum_is_valid(state, portnum)) {
2744 2745 qp->qp_portnum_alt = portnum - 1;
2745 2746 qpc->alt_addr_path.sched_q =
2746 2747 HERMON_QP_SCHEDQ_GET(portnum - 1,
2747 2748 adds_vect->av_srvl, qp->qp_is_special);
2748 2749 } else {
2749 2750 return (IBT_HCA_PORT_INVALID);
2750 2751 }
2751 2752
2752 2753 /*
2753 2754 * Check for valid alternate path PKey index and fill
2754 2755 * it in
2755 2756 */
2756 2757 pkeyindx = rc->rc_alt_path.cep_pkey_ix;
2757 2758 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2758 2759 qpc->alt_addr_path.pkey_indx = pkeyindx;
2759 2760 } else {
2760 2761 return (IBT_PKEY_IX_ILLEGAL);
2761 2762 }
2762 2763 opmask |= HERMON_CMD_OP_ALT_PATH;
2763 2764 }
2764 2765
2765 2766 /*
2766 2767 * If we are attempting to modify the number of "outgoing
2767 2768 * RDMA resources" for this QP, then check for valid value and
2768 2769 * fill it in. Also set the appropriate flag in the "opmask"
2769 2770 * parameter.
2770 2771 */
2771 2772 if (flags & IBT_CEP_SET_RDMARA_OUT) {
2772 2773 if (hermon_qp_validate_init_depth(state, rc,
2773 2774 &sra_max) != DDI_SUCCESS) {
2774 2775 return (IBT_INVALID_PARAM);
2775 2776 }
2776 2777 qpc->sra_max = sra_max;
2777 2778 opmask |= HERMON_CMD_OP_SRA_SET;
2778 2779 }
2779 2780
2780 2781 /*
2781 2782 * If we are attempting to modify the number of "incoming
2782 2783 * RDMA resources" for this QP, then check for valid value and
2783 2784 * update the "rra_max" and "ra_buf_index" fields in the QPC to
2784 2785 * point to the pre-allocated RDB resources (in DDR). Also set
2785 2786 * the appropriate flag in the "opmask" parameter.
2786 2787 */
2787 2788 if (flags & IBT_CEP_SET_RDMARA_IN) {
2788 2789 if (hermon_qp_validate_resp_rsrc(state, rc,
2789 2790 &rra_max) != DDI_SUCCESS) {
2790 2791 return (IBT_INVALID_PARAM);
2791 2792 }
2792 2793 qpc->rra_max = rra_max;
2793 2794 opmask |= HERMON_CMD_OP_RRA_SET;
2794 2795 }
2795 2796
2796 2797 /*
2797 2798 * If we are attempting to modify the "Local Ack Timeout" value
2798 2799 * for this QP, then fill it in and set the appropriate flag in
2799 2800 * the "opmask" parameter.
2800 2801 */
2801 2802 if (flags & IBT_CEP_SET_TIMEOUT) {
2802 2803 qpc_path = &qpc->pri_addr_path;
2803 2804 qpc_path->ack_timeout = rc->rc_path.cep_timeout;
2804 2805 opmask |= HERMON_CMD_OP_ACKTIMEOUT;
2805 2806 }
2806 2807
2807 2808 /*
2808 2809 * If we are attempting to modify the "Retry Count" for this QP,
2809 2810 * then fill it in and set the appropriate flag in the "opmask"
2810 2811 * parameter.
2811 2812 */
2812 2813 if (flags & IBT_CEP_SET_RETRY) {
2813 2814 qpc->retry_cnt = rc->rc_retry_cnt;
2814 2815 opmask |= HERMON_CMD_OP_PRIM_RNRRETRY;
2815 2816 }
2816 2817
2817 2818 /*
2818 2819 * If we are attempting to modify the "RNR Retry Count" for this
2819 2820 * QP, then fill it in and set the appropriate flag in the
2820 2821 * "opmask" parameter.
2821 2822 */
2822 2823 if (flags & IBT_CEP_SET_RNR_NAK_RETRY) {
2823 2824 qpc_path = &qpc->pri_addr_path;
2824 2825 qpc->rnr_retry = rc->rc_rnr_retry_cnt;
2825 2826 opmask |= HERMON_CMD_OP_RETRYCNT;
2826 2827 }
2827 2828
2828 2829 /*
2829 2830 * If we are attempting to modify the "Minimum RNR NAK" value
2830 2831 * for this QP, then fill it in and set the appropriate flag
2831 2832 * in the "opmask" parameter.
2832 2833 */
2833 2834 if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
2834 2835 qpc->min_rnr_nak = rc->rc_min_rnr_nak;
2835 2836 opmask |= HERMON_CMD_OP_MINRNRNAK;
2836 2837 }
2837 2838
2838 2839 } else if (qp->qp_serv_type == HERMON_QP_UC) {
2839 2840 uc = &info_p->qp_transport.uc;
2840 2841
2841 2842 /*
2842 2843 * Check if any of the flags indicate a change in the RDMA
2843 2844 * Write (recv) enable/disable and set the appropriate flag
2844 2845 * in the "opmask" parameter. Note: RDMA Read and Atomic are
2845 2846 * not valid for UC transport.
2846 2847 */
2847 2848 if (flags & IBT_CEP_SET_RDMA_W) {
2848 2849 qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
2849 2850 opmask |= HERMON_CMD_OP_RWE;
2850 2851 }
2851 2852
2852 2853 /*
2853 2854 * Check for optional primary path and fill in the
2854 2855 * appropriate QPC fields if one is specified
2855 2856 */
2856 2857 if (flags & IBT_CEP_SET_ADDS_VECT) {
2857 2858 qpc_path = &qpc->pri_addr_path;
2858 2859 adds_vect = &uc->uc_path.cep_adds_vect;
2859 2860
2860 2861 /* Set the common primary address path fields */
2861 2862 status = hermon_set_addr_path(state, adds_vect,
2862 2863 qpc_path, HERMON_ADDRPATH_QP);
2863 2864 if (status != DDI_SUCCESS) {
2864 2865 return (status);
2865 2866 }
2866 2867 portnum = qp->qp_portnum + 1;
2867 2868 if (hermon_portnum_is_valid(state, portnum)) {
2868 2869 qpc->pri_addr_path.sched_q =
2869 2870 HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
2870 2871 adds_vect->av_srvl, qp->qp_is_special);
2871 2872 } else {
2872 2873 return (IBT_HCA_PORT_INVALID);
2873 2874 }
2874 2875
2875 2876 /*
2876 2877 * MTU changes as part of sqd2sqd are not allowed.
2877 2878 * Simply keep the same MTU value here, stored in the
2878 2879 * qphdl from init2rtr time.
2879 2880 */
2880 2881 qpc->mtu = qp->qp_save_mtu;
2881 2882
2882 2883 opmask |= HERMON_CMD_OP_PRIM_PATH;
2883 2884 }
2884 2885
2885 2886 /*
2886 2887 * If we are attempting to modify the path migration state for
2887 2888 * this QP, then check for valid state and fill it in. Also
2888 2889 * set the appropriate flag in the "opmask" parameter.
2889 2890 */
2890 2891 if (flags & IBT_CEP_SET_MIG) {
2891 2892 if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
2892 2893 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
2893 2894 } else if (uc->uc_mig_state == IBT_STATE_REARMED) {
2894 2895 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
2895 2896 } else {
2896 2897 return (IBT_QP_APM_STATE_INVALID);
2897 2898 }
2898 2899 opmask |= HERMON_CMD_OP_PM_STATE;
2899 2900 }
2900 2901
2901 2902 /*
2902 2903 * If we are attempting to modify the PKey index for this QP,
2903 2904 * then check for valid PKey index and fill it in. Also set
2904 2905 * the appropriate flag in the "opmask" parameter.
2905 2906 */
2906 2907 if (flags & IBT_CEP_SET_PKEY_IX) {
2907 2908 pkeyindx = uc->uc_path.cep_pkey_ix;
2908 2909 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2909 2910 qpc->pri_addr_path.pkey_indx = pkeyindx;
2910 2911 opmask |= HERMON_CMD_OP_PKEYINDX;
2911 2912 } else {
2912 2913 return (IBT_PKEY_IX_ILLEGAL);
2913 2914 }
2914 2915 }
2915 2916
2916 2917 /*
2917 2918 * Check for optional alternate path and fill in the
2918 2919 * appropriate QPC fields if one is specified
2919 2920 */
2920 2921 if (flags & IBT_CEP_SET_ALT_PATH) {
2921 2922 qpc_path = &qpc->alt_addr_path;
2922 2923 adds_vect = &uc->uc_alt_path.cep_adds_vect;
2923 2924
2924 2925 /* Set the common alternate address path fields */
2925 2926 status = hermon_set_addr_path(state, adds_vect,
2926 2927 qpc_path, HERMON_ADDRPATH_QP);
2927 2928 if (status != DDI_SUCCESS) {
2928 2929 return (status);
2929 2930 }
2930 2931
2931 2932 /*
2932 2933 * Check for valid alternate path port number and fill
2933 2934 * it in
2934 2935 */
2935 2936 portnum = uc->uc_alt_path.cep_hca_port_num;
2936 2937 if (hermon_portnum_is_valid(state, portnum)) {
2937 2938 qp->qp_portnum_alt = portnum - 1;
2938 2939 qpc->alt_addr_path.sched_q =
2939 2940 HERMON_QP_SCHEDQ_GET(portnum - 1,
2940 2941 adds_vect->av_srvl, qp->qp_is_special);
2941 2942 } else {
2942 2943 return (IBT_HCA_PORT_INVALID);
2943 2944 }
2944 2945
2945 2946 /*
2946 2947 * Check for valid alternate path PKey index and fill
2947 2948 * it in
2948 2949 */
2949 2950 pkeyindx = uc->uc_alt_path.cep_pkey_ix;
2950 2951 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2951 2952 qpc->alt_addr_path.pkey_indx = pkeyindx;
2952 2953 } else {
2953 2954 return (IBT_PKEY_IX_ILLEGAL);
2954 2955 }
2955 2956 opmask |= HERMON_CMD_OP_ALT_PATH;
2956 2957 }
2957 2958 } else {
2958 2959 /*
2959 2960 * Invalid QP transport type. If we got here then it's a
2960 2961 * warning of a probably serious problem. So print a message
2961 2962 * and return failure
2962 2963 */
2963 2964 HERMON_WARNING(state, "unknown QP transport type in sqd2sqd");
2964 2965 return (ibc_get_ci_failure(0));
2965 2966 }
2966 2967
2967 2968 /*
2968 2969 * Post the SQD2SQD_QP command to the Hermon firmware
2969 2970 *
2970 2971 * We do a HERMON_NOSLEEP here because we are still holding the
2971 2972 * "qp_lock". If we got raised to interrupt level by priority
2972 2973 * inversion, we do not want to block in this routine waiting for
2973 2974 * success.
2974 2975 */
2975 2976 status = hermon_cmn_qp_cmd_post(state, SQD2SQD_QP, qpc, qp->qp_qpnum,
2976 2977 opmask, HERMON_CMD_NOSLEEP_SPIN);
2977 2978 if (status != HERMON_CMD_SUCCESS) {
2978 2979 if (status != HERMON_CMD_BAD_QP_STATE) {
2979 2980 cmn_err(CE_NOTE, "hermon%d: SQD2SQD_QP command failed: "
2980 2981 "%08x\n", state->hs_instance, status);
2981 2982 if (status == HERMON_CMD_INVALID_STATUS) {
2982 2983 hermon_fm_ereport(state, HCA_SYS_ERR,
2983 2984 HCA_ERR_SRV_LOST);
2984 2985 }
2985 2986 return (ibc_get_ci_failure(0));
2986 2987 } else {
2987 2988 return (IBT_QP_STATE_INVALID);
2988 2989 }
2989 2990 }
2990 2991
2991 2992 return (DDI_SUCCESS);
2992 2993 }
2993 2994
2994 2995
2995 2996 /*
2996 2997 * hermon_qp_sqerr2rts()
2997 2998 * Context: Can be called from interrupt or base context.
2998 2999 */
2999 3000 static int
3000 3001 hermon_qp_sqerr2rts(hermon_state_t *state, hermon_qphdl_t qp,
3001 3002 ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
3002 3003 {
3003 3004 hermon_hw_qpc_t *qpc;
3004 3005 ibt_qp_ud_attr_t *ud;
3005 3006 uint32_t opmask = 0;
3006 3007 int status;
3007 3008
3008 3009 ASSERT(MUTEX_HELD(&qp->qp_lock));
3009 3010
3010 3011 /*
3011 3012 * Grab the temporary QPC entry from QP software state
3012 3013 */
3013 3014 qpc = &qp->qpc;
3014 3015
3015 3016 /*
3016 3017 * Since there are no common fields to be filled in for this command,
3017 3018 * we begin with the QPC fields which are specific to transport type.
3018 3019 */
3019 3020 if (qp->qp_type == IBT_UD_RQP) {
3020 3021 ud = &info_p->qp_transport.ud;
3021 3022
3022 3023 /*
3023 3024 * If we are attempting to modify the QKey for this QP, then
3024 3025 * fill it in and set the appropriate flag in the "opmask"
3025 3026 * parameter.
3026 3027 */
3027 3028 if (flags & IBT_CEP_SET_QKEY) {
3028 3029 qpc->qkey = ud->ud_qkey;
3029 3030 opmask |= HERMON_CMD_OP_QKEY;
3030 3031 }
3031 3032
3032 3033 } else if (qp->qp_serv_type == HERMON_QP_UC) {
3033 3034
3034 3035 /*
3035 3036 * Check if any of the flags indicate a change in the RDMA
3036 3037 * Write (recv) enable/disable and set the appropriate flag
3037 3038 * in the "opmask" parameter. Note: RDMA Read and Atomic are
3038 3039 * not valid for UC transport.
3039 3040 */
3040 3041 if (flags & IBT_CEP_SET_RDMA_W) {
3041 3042 qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
3042 3043 opmask |= HERMON_CMD_OP_RWE;
3043 3044 }
3044 3045 } else {
3045 3046 /*
3046 3047 * Invalid QP transport type. If we got here then it's a
3047 3048 * warning of a probably serious problem. So print a message
3048 3049 * and return failure
3049 3050 */
3050 3051 HERMON_WARNING(state, "unknown QP transport type in sqerr2rts");
3051 3052 return (ibc_get_ci_failure(0));
3052 3053 }
3053 3054
3054 3055 /*
3055 3056 * Post the SQERR2RTS_QP command to the Hermon firmware
3056 3057 *
3057 3058 * We do a HERMON_NOSLEEP here because we are still holding the
3058 3059 * "qp_lock". If we got raised to interrupt level by priority
3059 3060 * inversion, we do not want to block in this routine waiting for
3060 3061 * success.
3061 3062 */
3062 3063 status = hermon_cmn_qp_cmd_post(state, SQERR2RTS_QP, qpc, qp->qp_qpnum,
3063 3064 opmask, HERMON_CMD_NOSLEEP_SPIN);
3064 3065 if (status != HERMON_CMD_SUCCESS) {
3065 3066 if (status != HERMON_CMD_BAD_QP_STATE) {
3066 3067 cmn_err(CE_NOTE, "hermon%d: SQERR2RTS_QP command "
3067 3068 "failed: %08x\n", state->hs_instance, status);
3068 3069 if (status == HERMON_CMD_INVALID_STATUS) {
3069 3070 hermon_fm_ereport(state, HCA_SYS_ERR,
3070 3071 HCA_ERR_SRV_LOST);
3071 3072 }
3072 3073 return (ibc_get_ci_failure(0));
3073 3074 } else {
3074 3075 return (IBT_QP_STATE_INVALID);
3075 3076 }
3076 3077 }
3077 3078
3078 3079 return (DDI_SUCCESS);
3079 3080 }
3080 3081
3081 3082
3082 3083 /*
3083 3084 * hermon_qp_to_error()
3084 3085 * Context: Can be called from interrupt or base context.
3085 3086 */
3086 3087 static int
3087 3088 hermon_qp_to_error(hermon_state_t *state, hermon_qphdl_t qp)
3088 3089 {
3089 3090 int status;
3090 3091
3091 3092 ASSERT(MUTEX_HELD(&qp->qp_lock));
3092 3093
3093 3094 /*
3094 3095 * Post the TOERR_QP command to the Hermon firmware
3095 3096 *
3096 3097 * We do a HERMON_NOSLEEP here because we are still holding the
3097 3098 * "qp_lock". If we got raised to interrupt level by priority
3098 3099 * inversion, we do not want to block in this routine waiting for
3099 3100 * success.
3100 3101 */
3101 3102 status = hermon_cmn_qp_cmd_post(state, TOERR_QP, NULL, qp->qp_qpnum,
3102 3103 0, HERMON_CMD_NOSLEEP_SPIN);
3103 3104 if (status != HERMON_CMD_SUCCESS) {
3104 3105 cmn_err(CE_NOTE, "hermon%d: TOERR_QP command failed: %08x\n",
3105 3106 state->hs_instance, status);
3106 3107 if (status == HERMON_CMD_INVALID_STATUS) {
3107 3108 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
3108 3109 }
3109 3110 return (ibc_get_ci_failure(0));
3110 3111 }
3111 3112
3112 3113 return (DDI_SUCCESS);
3113 3114 }
3114 3115
3115 3116
3116 3117 /*
3117 3118 * hermon_qp_to_reset()
3118 3119 * Context: Can be called from interrupt or base context.
3119 3120 */
3120 3121 int
3121 3122 hermon_qp_to_reset(hermon_state_t *state, hermon_qphdl_t qp)
3122 3123 {
3123 3124 hermon_hw_qpc_t *qpc;
3124 3125 int status;
3125 3126
3126 3127 ASSERT(MUTEX_HELD(&qp->qp_lock));
3127 3128
3128 3129 /*
3129 3130 * Grab the temporary QPC entry from QP software state
3130 3131 */
3131 3132 qpc = &qp->qpc;
3132 3133
3133 3134 /*
3134 3135 * Post the TORST_QP command to the Hermon firmware
3135 3136 *
3136 3137 * We do a HERMON_NOSLEEP here because we are still holding the
3137 3138 * "qp_lock". If we got raised to interrupt level by priority
3138 3139 * inversion, we do not want to block in this routine waiting for
3139 3140 * success.
3140 3141 */
3141 3142 status = hermon_cmn_qp_cmd_post(state, TORST_QP, qpc, qp->qp_qpnum,
3142 3143 0, HERMON_CMD_NOSLEEP_SPIN);
3143 3144 if (status != HERMON_CMD_SUCCESS) {
3144 3145 cmn_err(CE_NOTE, "hermon%d: TORST_QP command failed: %08x\n",
3145 3146 state->hs_instance, status);
3146 3147 if (status == HERMON_CMD_INVALID_STATUS) {
3147 3148 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
3148 3149 }
3149 3150 return (ibc_get_ci_failure(0));
3150 3151 }
3151 3152 if (qp->qp_serv_type == HERMON_QP_FEXCH) {
3152 3153 status = hermon_fcoib_fexch_mkey_fini(state, qp->qp_pdhdl,
3153 3154 qp->qp_qpnum, HERMON_CMD_NOSLEEP_SPIN);
3154 3155 if (status != DDI_SUCCESS)
3155 3156 cmn_err(CE_NOTE, "hermon%d: fexch_mkey_fini failed "
3156 3157 "%08x\n", state->hs_instance, status);
3157 3158 }
3158 3159 return (DDI_SUCCESS);
3159 3160 }
3160 3161
3161 3162
3162 3163 /*
3163 3164 * hermon_qp_reset2err()
3164 3165 * Context: Can be called from interrupt or base context.
3165 3166 */
3166 3167 static int
3167 3168 hermon_qp_reset2err(hermon_state_t *state, hermon_qphdl_t qp)
3168 3169 {
3169 3170 hermon_hw_qpc_t *qpc;
3170 3171 int status;
3171 3172 uint32_t cqnmask;
3172 3173
3173 3174 ASSERT(MUTEX_HELD(&qp->qp_lock));
3174 3175
3175 3176 /*
3176 3177 * In order to implement the transition from "Reset" directly to the
3177 3178 * "Error" state, it is necessary to first give ownership of the QP
3178 3179 * context to the Hermon hardware. This is accomplished by
3179 3180 * transitioning the QP to "Init" as an intermediate step and then,
3180 3181 * immediately transitioning to "Error".
3181 3182 *
3182 3183 * When this function returns success, the QP context will be owned by
3183 3184 * the Hermon hardware and will be in the "Error" state.
3184 3185 */
3185 3186
3186 3187 /*
3187 3188 * Grab the temporary QPC entry from QP software state
3188 3189 */
3189 3190 qpc = &qp->qpc;
3190 3191
3191 3192 /*
3192 3193 * Fill in the common fields in the QPC
3193 3194 */
3194 3195 if (qp->qp_is_special) {
3195 3196 qpc->serv_type = HERMON_QP_MLX;
3196 3197 } else {
3197 3198 qpc->serv_type = qp->qp_serv_type;
3198 3199 }
3199 3200 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
3200 3201 qpc->usr_page = qp->qp_uarpg;
3201 3202 /* dbr is now an address, not an index */
3202 3203 qpc->dbr_addrh = ((uint64_t)qp->qp_rq_pdbr >> 32);
3203 3204 qpc->dbr_addrl = ((uint64_t)qp->qp_rq_pdbr & 0xFFFFFFFC) >> 2;
3204 3205 qpc->pd = qp->qp_pdhdl->pd_pdnum;
3205 3206 /*
3206 3207 * HERMON:
3207 3208 * qpc->wqe_baseaddr is replaced by LKey from the cMPT, and
3208 3209 * page_offset, mtt_base_addr_h/l, and log2_page_size will
3209 3210 * be used to map the WQE buffer
3210 3211 * NOTE that the cMPT is created implicitly when the QP is
3211 3212 * transitioned from reset to init
3212 3213 */
3213 3214 qpc->log2_pgsz = qp->qp_mrhdl->mr_log2_pgsz;
3214 3215 qpc->mtt_base_addrh = (qp->qp_mrhdl->mr_mttaddr) >> 32 & 0xFF;
3215 3216 qpc->mtt_base_addrl = (qp->qp_mrhdl->mr_mttaddr) >> 3 & 0xFFFFFFFF;
3216 3217 cqnmask = (1 << state->hs_cfg_profile->cp_log_num_cq) - 1;
3217 3218 qpc->cqn_snd =
3218 3219 (qp->qp_sq_cqhdl == NULL) ? 0 : qp->qp_sq_cqhdl->cq_cqnum & cqnmask;
3219 3220 qpc->page_offs = qp->qp_wqinfo.qa_pgoffs >> 6;
3220 3221 qpc->cqn_rcv =
3221 3222 (qp->qp_rq_cqhdl == NULL) ? 0 : qp->qp_rq_cqhdl->cq_cqnum & cqnmask;
3222 3223
3223 3224 qpc->sq_wqe_counter = 0;
3224 3225 qpc->rq_wqe_counter = 0;
3225 3226 qpc->log_sq_stride = qp->qp_sq_log_wqesz - 4;
3226 3227 qpc->log_rq_stride = qp->qp_rq_log_wqesz - 4;
3227 3228 qpc->log_sq_size = highbit(qp->qp_sq_bufsz) - 1;
3228 3229 qpc->log_rq_size = highbit(qp->qp_rq_bufsz) - 1;
3229 3230 qpc->srq_en = (qp->qp_alloc_flags & IBT_QP_USES_SRQ) != 0;
3230 3231 qpc->sq_no_prefetch = qp->qp_no_prefetch;
3231 3232
3232 3233 if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
3233 3234 qpc->srq_number = qp->qp_srqhdl->srq_srqnum;
3234 3235 } else {
3235 3236 qpc->srq_number = 0;
3236 3237 }
3237 3238
3238 3239 qpc->fre = 0; /* default disable fast registration WR */
3239 3240 qpc->rlky = 0; /* default disable reserved lkey */
3240 3241
3241 3242 /*
3242 3243 * Now fill in the QPC fields which are specific to transport type
3243 3244 */
3244 3245 if (qp->qp_type == IBT_UD_RQP) {
3245 3246 /* Set the UD parameters to an invalid default */
3246 3247 qpc->qkey = 0;
3247 3248 qpc->pri_addr_path.sched_q =
3248 3249 HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
3249 3250 qpc->pri_addr_path.pkey_indx = 0;
3250 3251
3251 3252 } else if (qp->qp_serv_type == HERMON_QP_RC) {
3252 3253 /* Set the RC parameters to invalid default */
3253 3254 qpc->rre = 0;
3254 3255 qpc->rwe = 0;
3255 3256 qpc->rae = 0;
3256 3257 qpc->alt_addr_path.sched_q =
3257 3258 HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
3258 3259 qpc->pri_addr_path.pkey_indx = 0;
3259 3260
3260 3261 } else if (qp->qp_serv_type == HERMON_QP_UC) {
3261 3262 /* Set the UC parameters to invalid default */
3262 3263 qpc->rwe = 0;
3263 3264 qpc->alt_addr_path.sched_q =
3264 3265 HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
3265 3266 qpc->pri_addr_path.pkey_indx = 0;
3266 3267
3267 3268 } else {
3268 3269 /*
3269 3270 * Invalid QP transport type. If we got here then it's a
3270 3271 * warning of a probably serious problem. So print a message
3271 3272 * and return failure
3272 3273 */
3273 3274 HERMON_WARNING(state, "unknown QP transport type in rst2err");
3274 3275 return (ibc_get_ci_failure(0));
3275 3276 }
3276 3277
3277 3278 /*
3278 3279 * Post the RST2INIT_QP command to the Hermon firmware
3279 3280 *
3280 3281 * We do a HERMON_NOSLEEP here because we are still holding the
3281 3282 * "qp_lock". If we got raised to interrupt level by priority
3282 3283 * inversion, we do not want to block in this routine waiting for
3283 3284 * success.
3284 3285 */
3285 3286 status = hermon_cmn_qp_cmd_post(state, RST2INIT_QP, qpc, qp->qp_qpnum,
3286 3287 0, HERMON_CMD_NOSLEEP_SPIN);
3287 3288 if (status != HERMON_CMD_SUCCESS) {
3288 3289 cmn_err(CE_NOTE, "hermon%d: RST2INIT_QP command failed: %08x\n",
3289 3290 state->hs_instance, status);
3290 3291 if (status == HERMON_CMD_INVALID_STATUS) {
3291 3292 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
3292 3293 }
3293 3294 return (ibc_get_ci_failure(0));
3294 3295 }
3295 3296
3296 3297 /*
3297 3298 * Now post the TOERR_QP command to the Hermon firmware
3298 3299 *
3299 3300 * We still do a HERMON_NOSLEEP here because we are still holding the
3300 3301 * "qp_lock". Note: If this fails (which it really never should),
3301 3302 * it indicates a serious problem in the HW or SW. We try to move
3302 3303 * the QP back to the "Reset" state if possible and print a warning
3303 3304 * message if not. In any case, we return an error here.
3304 3305 */
3305 3306 status = hermon_cmn_qp_cmd_post(state, TOERR_QP, NULL, qp->qp_qpnum,
3306 3307 0, HERMON_CMD_NOSLEEP_SPIN);
3307 3308 if (status != HERMON_CMD_SUCCESS) {
3308 3309 cmn_err(CE_NOTE, "hermon%d: TOERR_QP command failed: %08x\n",
3309 3310 state->hs_instance, status);
3310 3311 if (status == HERMON_CMD_INVALID_STATUS) {
3311 3312 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
3312 3313 }
3313 3314 if (hermon_qp_to_reset(state, qp) != DDI_SUCCESS) {
3314 3315 HERMON_WARNING(state, "failed to reset QP context");
3315 3316 }
3316 3317 return (ibc_get_ci_failure(0));
3317 3318 }
3318 3319
3319 3320 return (DDI_SUCCESS);
3320 3321 }
3321 3322
3322 3323
3323 3324 /*
3324 3325 * hermon_check_rdma_enable_flags()
3325 3326 * Context: Can be called from interrupt or base context.
3326 3327 */
3327 3328 static uint_t
3328 3329 hermon_check_rdma_enable_flags(ibt_cep_modify_flags_t flags,
3329 3330 ibt_qp_info_t *info_p, hermon_hw_qpc_t *qpc)
3330 3331 {
3331 3332 uint_t opmask = 0;
3332 3333
3333 3334 if (flags & IBT_CEP_SET_RDMA_R) {
3334 3335 qpc->rre = (info_p->qp_flags & IBT_CEP_RDMA_RD) ? 1 : 0;
3335 3336 opmask |= HERMON_CMD_OP_RRE;
3336 3337 }
3337 3338
3338 3339 if (flags & IBT_CEP_SET_RDMA_W) {
3339 3340 qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
3340 3341 opmask |= HERMON_CMD_OP_RWE;
3341 3342 }
3342 3343
3343 3344 if (flags & IBT_CEP_SET_ATOMIC) {
3344 3345 qpc->rae = (info_p->qp_flags & IBT_CEP_ATOMIC) ? 1 : 0;
3345 3346 opmask |= HERMON_CMD_OP_RAE;
3346 3347 }
3347 3348
3348 3349 return (opmask);
3349 3350 }
3350 3351
3351 3352 /*
3352 3353 * hermon_qp_validate_resp_rsrc()
3353 3354 * Context: Can be called from interrupt or base context.
3354 3355 */
3355 3356 static int
3356 3357 hermon_qp_validate_resp_rsrc(hermon_state_t *state, ibt_qp_rc_attr_t *rc,
3357 3358 uint_t *rra_max)
3358 3359 {
3359 3360 uint_t rdma_ra_in;
3360 3361
3361 3362 rdma_ra_in = rc->rc_rdma_ra_in;
3362 3363
3363 3364 /*
3364 3365 * Check if number of responder resources is too large. Return an
3365 3366 * error if it is
3366 3367 */
3367 3368 if (rdma_ra_in > state->hs_cfg_profile->cp_hca_max_rdma_in_qp) {
↓ open down ↓ |
3322 lines elided |
↑ open up ↑ |
3368 3369 return (IBT_INVALID_PARAM);
3369 3370 }
3370 3371
3371 3372 /*
3372 3373 * If the number of responder resources is too small, round it up.
3373 3374 * Then find the next highest power-of-2
3374 3375 */
3375 3376 if (rdma_ra_in == 0) {
3376 3377 rdma_ra_in = 1;
3377 3378 }
3378 - if ((rdma_ra_in & (rdma_ra_in - 1)) == 0) {
3379 + if (ISP2(rdma_ra_in)) {
3379 3380 *rra_max = highbit(rdma_ra_in) - 1;
3380 3381 } else {
3381 3382 *rra_max = highbit(rdma_ra_in);
3382 3383 }
3383 3384 return (DDI_SUCCESS);
3384 3385 }
3385 3386
3386 3387
3387 3388 /*
3388 3389 * hermon_qp_validate_init_depth()
3389 3390 * Context: Can be called from interrupt or base context.
3390 3391 */
3391 3392 static int
3392 3393 hermon_qp_validate_init_depth(hermon_state_t *state, ibt_qp_rc_attr_t *rc,
3393 3394 uint_t *sra_max)
3394 3395 {
3395 3396 uint_t rdma_ra_out;
3396 3397
3397 3398 rdma_ra_out = rc->rc_rdma_ra_out;
3398 3399
3399 3400 /*
3400 3401 * Check if requested initiator depth is too large. Return an error
3401 3402 * if it is
3402 3403 */
3403 3404 if (rdma_ra_out > state->hs_cfg_profile->cp_hca_max_rdma_out_qp) {
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
3404 3405 return (IBT_INVALID_PARAM);
3405 3406 }
3406 3407
3407 3408 /*
3408 3409 * If the requested initiator depth is too small, round it up.
3409 3410 * Then find the next highest power-of-2
3410 3411 */
3411 3412 if (rdma_ra_out == 0) {
3412 3413 rdma_ra_out = 1;
3413 3414 }
3414 - if ((rdma_ra_out & (rdma_ra_out - 1)) == 0) {
3415 + if (ISP2(rdma_ra_out)) {
3415 3416 *sra_max = highbit(rdma_ra_out) - 1;
3416 3417 } else {
3417 3418 *sra_max = highbit(rdma_ra_out);
3418 3419 }
3419 3420 return (DDI_SUCCESS);
3420 3421 }
3421 3422
3422 3423
3423 3424 /*
3424 3425 * hermon_qp_validate_mtu()
3425 3426 * Context: Can be called from interrupt or base context.
3426 3427 */
3427 3428 static int
3428 3429 hermon_qp_validate_mtu(hermon_state_t *state, uint_t mtu)
3429 3430 {
3430 3431 /*
3431 3432 * Check for invalid MTU values (i.e. zero or any value larger than
3432 3433 * the HCA's port maximum).
3433 3434 */
3434 3435 if ((mtu == 0) || (mtu > state->hs_cfg_profile->cp_max_mtu)) {
3435 3436 return (IBT_HCA_PORT_MTU_EXCEEDED);
3436 3437 }
3437 3438 return (DDI_SUCCESS);
3438 3439 }
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX