Print this page
8368 remove warlock leftovers from usr/src/uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/ib/adapters/hermon/hermon_cmd.c
+++ new/usr/src/uts/common/io/ib/adapters/hermon/hermon_cmd.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
26 26 /*
27 27 * hermon_cmd.c
28 28 * Hermon Firmware Command Routines
29 29 *
30 30 * Implements all the routines necessary for allocating, posting, and
31 31 * freeing commands for the Hermon firmware. These routines manage a
32 32 * preallocated list of command mailboxes and provide interfaces to post
33 33 * each of the several dozen commands to the Hermon firmware.
34 34 */
35 35
36 36 #include <sys/types.h>
37 37 #include <sys/conf.h>
38 38 #include <sys/ddi.h>
39 39 #include <sys/sunddi.h>
40 40 #include <sys/modctl.h>
41 41 #include <sys/bitmap.h>
42 42
43 43 #include <sys/ib/adapters/hermon/hermon.h>
44 44
45 45 static int hermon_impl_mbox_alloc(hermon_state_t *state,
46 46 hermon_mboxlist_t *mblist, hermon_mbox_t **mb, uint_t mbox_wait);
47 47 static void hermon_impl_mbox_free(hermon_mboxlist_t *mblist,
48 48 hermon_mbox_t **mb);
49 49 static int hermon_impl_mboxlist_init(hermon_state_t *state,
50 50 hermon_mboxlist_t *mblist, uint_t num_mbox, hermon_rsrc_type_t type);
51 51 static void hermon_impl_mboxlist_fini(hermon_state_t *state,
52 52 hermon_mboxlist_t *mblist);
53 53 static int hermon_outstanding_cmd_alloc(hermon_state_t *state,
54 54 hermon_cmd_t **cmd_ptr, uint_t cmd_wait);
55 55 static void hermon_outstanding_cmd_free(hermon_state_t *state,
56 56 hermon_cmd_t **cmd_ptr);
57 57 static int hermon_write_hcr(hermon_state_t *state, hermon_cmd_post_t *cmdpost,
58 58 uint16_t token, int *hwerr);
59 59 static void hermon_mbox_sync(hermon_mbox_t *mbox, uint_t offset,
60 60 uint_t length, uint_t flag);
61 61 static void hermon_cmd_check_status(hermon_state_t *state, int status);
62 62
63 63 /*
64 64 * hermon_cmd_post()
65 65 * Context: Can be called from interrupt or base context.
66 66 *
67 67 * The "cp_flags" field in cmdpost
↓ open down ↓ |
67 lines elided |
↑ open up ↑ |
68 68 * is used to determine whether to wait for an available
69 69 * outstanding command (if necessary) or to return error.
70 70 */
71 71 int
72 72 hermon_cmd_post(hermon_state_t *state, hermon_cmd_post_t *cmdpost)
73 73 {
74 74 hermon_cmd_t *cmdptr;
75 75 int status, retry_cnt, retry_cnt2, hw_err;
76 76 uint16_t token;
77 77
78 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdpost))
79 -
80 78 /* Determine if we are going to spin until completion */
81 79 if (cmdpost->cp_flags == HERMON_CMD_NOSLEEP_SPIN) {
82 80
83 81 /* Write the command to the HCR */
84 82 retry_cnt = HCA_PIO_RETRY_CNT;
85 83 do {
86 84 status = hermon_write_hcr(state, cmdpost, 0, &hw_err);
87 85 } while (status == HERMON_CMD_INTERNAL_ERR && retry_cnt-- > 0);
88 86
89 87 /* Check if there is an error status in hermon_write_hcr() */
90 88 if (status != HERMON_CMD_SUCCESS) {
91 89 /*
92 90 * If there is a HW error, call hermon_cmd_retry_ok()
93 91 * to check the side-effect of the operation retry.
94 92 */
95 93 if ((retry_cnt == HCA_PIO_RETRY_CNT &&
96 94 hw_err == HCA_PIO_OK) ||
97 95 !hermon_cmd_retry_ok(cmdpost, status)) {
98 96 hermon_cmd_check_status(state, status);
99 97 return (status);
100 98 }
101 99 /* Check if there is a transient internal error */
102 100 } else if (retry_cnt != HCA_PIO_RETRY_CNT) {
103 101 hermon_fm_ereport(state, HCA_IBA_ERR,
104 102 HCA_ERR_TRANSIENT);
105 103 }
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
106 104
107 105 } else { /* "HERMON_CMD_SLEEP_NOSPIN" */
108 106 ASSERT(HERMON_SLEEPFLAG_FOR_CONTEXT() != HERMON_NOSLEEP);
109 107
110 108 /* NOTE: Expect threads to be waiting in here */
111 109 status = hermon_outstanding_cmd_alloc(state, &cmdptr,
112 110 cmdpost->cp_flags);
113 111 if (status != HERMON_CMD_SUCCESS) {
114 112 return (status);
115 113 }
116 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr))
117 114
118 115 retry_cnt = HCA_PIO_RETRY_CNT;
119 116 retry:
120 117 /*
121 118 * Set status to "HERMON_CMD_INVALID_STATUS". It is
122 119 * appropriate to do this here without the "cmd_comp_lock"
123 120 * because this register is overloaded. Later it will be
124 121 * used to indicate - through a change from this invalid
125 122 * value to some other value - that the condition variable
126 123 * has been signaled. Once it has, status will then contain
127 124 * the _real_ completion status
128 125 */
129 126 cmdptr->cmd_status = HERMON_CMD_INVALID_STATUS;
130 127
131 128 /* Write the command to the HCR */
132 129 token = (uint16_t)cmdptr->cmd_indx;
133 130 retry_cnt2 = HCA_PIO_RETRY_CNT;
134 131 do {
135 132 status = hermon_write_hcr(state, cmdpost, token,
136 133 &hw_err);
137 134 } while (status == HERMON_CMD_INTERNAL_ERR && retry_cnt2-- > 0);
138 135
139 136 /* Check if there is an error status in hermon_write_hcr() */
140 137 if (status != HERMON_CMD_SUCCESS) {
141 138 /*
142 139 * If there is a HW error, call hermon_cmd_retry_ok()
143 140 * to check the side-effect of the operation retry.
144 141 */
145 142 if ((retry_cnt == HCA_PIO_RETRY_CNT &&
146 143 hw_err == HCA_PIO_OK) ||
147 144 !hermon_cmd_retry_ok(cmdpost, status)) {
148 145 hermon_cmd_check_status(state, status);
149 146 hermon_outstanding_cmd_free(state, &cmdptr);
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
150 147 return (status);
151 148 }
152 149 /* Check if there is a transient internal error */
153 150 } else if (retry_cnt2 != HCA_PIO_RETRY_CNT) {
154 151 hermon_fm_ereport(state, HCA_IBA_ERR,
155 152 HCA_ERR_TRANSIENT);
156 153 }
157 154
158 155 /*
159 156 * cv_wait() on the "command_complete" condition variable.
160 - * Note: We have the "__lock_lint" here to workaround warlock.
161 - * Since warlock doesn't know that other parts of the Hermon
162 - * may occasionally call this routine while holding their own
163 - * locks, it complains about this cv_wait. In reality,
164 - * however, the rest of the driver never calls this routine
165 - * with a lock held unless they pass HERMON_CMD_NOSLEEP.
166 157 */
167 - _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cmdptr))
168 158 mutex_enter(&cmdptr->cmd_comp_lock);
169 159 while (cmdptr->cmd_status == HERMON_CMD_INVALID_STATUS) {
170 -#ifndef __lock_lint
171 - cv_wait(&cmdptr->cmd_comp_cv, &cmdptr->cmd_comp_lock);
172 160 /* NOTE: EXPECT SEVERAL THREADS TO BE WAITING HERE */
173 -#endif
161 + cv_wait(&cmdptr->cmd_comp_cv, &cmdptr->cmd_comp_lock);
174 162 }
175 163 mutex_exit(&cmdptr->cmd_comp_lock);
176 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr))
177 164
178 165 /*
179 166 * Wake up after command completes (cv_signal). Read status
180 167 * from the command (success, fail, etc.). It is appropriate
181 168 * here (as above) to read the status field without the
182 169 * "cmd_comp_lock" because it is no longer being used to
183 170 * indicate whether the condition variable has been signaled
184 171 * (i.e. at this point we are certain that it already has).
185 172 */
186 173 status = cmdptr->cmd_status;
187 174
188 175 /* retry the operation if an internal error occurs */
189 176 if (status == HERMON_CMD_INTERNAL_ERR && retry_cnt-- > 0)
190 177 goto retry;
191 178
192 179 /* Save the "outparam" values into the cmdpost struct */
193 180 cmdpost->cp_outparm = cmdptr->cmd_outparm;
194 181
195 182 /*
196 183 * Add the command back to the "outstanding commands list".
197 184 * Signal the "cmd_list" condition variable, if necessary.
198 185 */
199 186 hermon_outstanding_cmd_free(state, &cmdptr);
200 187
201 188 /* Check if there is an error status in hermon_write_hcr() */
202 189 if (status != HERMON_CMD_SUCCESS) {
203 190 /*
204 191 * If there is a HW error, call hermon_cmd_retry_ok()
205 192 * to check the side-effect of the operation retry.
206 193 */
207 194 if ((retry_cnt == HCA_PIO_RETRY_CNT &&
208 195 hw_err == HCA_PIO_OK) ||
209 196 !hermon_cmd_retry_ok(cmdpost, status)) {
210 197 hermon_cmd_check_status(state, status);
211 198 cmn_err(CE_NOTE, "hermon%d: post cmd failed "
212 199 "opcode (0x%x) status (0x%x)\n",
213 200 state->hs_instance, cmdpost->cp_opcode,
214 201 status);
215 202 return (status);
216 203 }
217 204 /* Check if there is a transient internal error */
218 205 } else if (retry_cnt != HCA_PIO_RETRY_CNT) {
219 206 hermon_fm_ereport(state, HCA_IBA_ERR,
220 207 HCA_ERR_TRANSIENT);
221 208 }
222 209 }
223 210
224 211 return (HERMON_CMD_SUCCESS);
225 212 }
226 213
227 214 /*
228 215 * hermon_cmd_check_status()
229 216 * Context: Can be called from interrupt or base
230 217 *
231 218 * checks the status returned from write_hcr and does the right
232 219 * notice to the console, if any
233 220 */
234 221 static void
235 222 hermon_cmd_check_status(hermon_state_t *state, int status)
236 223 {
237 224 switch (status) {
238 225 case HERMON_CMD_TIMEOUT_TOGGLE:
239 226 HERMON_FMANOTE(state, HERMON_FMA_TOTOG);
240 227 hermon_fm_ereport(state, HCA_IBA_ERR,
241 228 HCA_ERR_NON_FATAL);
242 229 break;
243 230
244 231 case HERMON_CMD_TIMEOUT_GOBIT:
245 232 HERMON_FMANOTE(state, HERMON_FMA_GOBIT);
246 233 hermon_fm_ereport(state, HCA_IBA_ERR,
247 234 HCA_ERR_NON_FATAL);
248 235 break;
249 236
250 237 case HERMON_CMD_INSUFF_RSRC:
251 238 HERMON_FMANOTE(state, HERMON_FMA_RSRC);
252 239 break;
253 240
254 241 case HERMON_CMD_INVALID_STATUS:
255 242 HERMON_FMANOTE(state, HERMON_FMA_CMDINV);
256 243 hermon_fm_ereport(state, HCA_IBA_ERR,
257 244 HCA_ERR_NON_FATAL);
258 245 break;
259 246
260 247 case HERMON_CMD_INTERNAL_ERR:
261 248 HERMON_FMANOTE(state, HERMON_FMA_HCRINT);
262 249 hermon_fm_ereport(state, HCA_IBA_ERR,
263 250 HCA_ERR_NON_FATAL);
264 251 break;
265 252
266 253 case HERMON_CMD_BAD_NVMEM:
267 254 /*
268 255 * No need of an ereport here since this case
269 256 * is treated as a degradation later.
270 257 */
271 258 HERMON_FMANOTE(state, HERMON_FMA_NVMEM);
272 259 break;
273 260
274 261 default:
275 262 break;
276 263 }
277 264 }
278 265
279 266 /*
280 267 * hermon_mbox_alloc()
281 268 * Context: Can be called from interrupt or base context.
282 269 *
283 270 * The "mbox_wait" parameter is used to determine whether to
284 271 * wait for a mailbox to become available or not.
285 272 */
286 273 int
287 274 hermon_mbox_alloc(hermon_state_t *state, hermon_mbox_info_t *mbox_info,
288 275 uint_t mbox_wait)
289 276 {
290 277 int status;
291 278 uint_t sleep_context;
292 279
293 280 sleep_context = HERMON_SLEEPFLAG_FOR_CONTEXT();
294 281
295 282 /* Allocate an "In" mailbox */
296 283 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_INMBOX) {
297 284 /* Determine correct mboxlist based on calling context */
298 285 if (sleep_context == HERMON_NOSLEEP) {
299 286 status = hermon_impl_mbox_alloc(state,
300 287 &state->hs_in_intr_mblist,
301 288 &mbox_info->mbi_in, mbox_wait);
302 289
303 290 ASSERT(status == HERMON_CMD_SUCCESS);
304 291 } else {
305 292 /* NOTE: Expect threads to be waiting in here */
306 293 status = hermon_impl_mbox_alloc(state,
307 294 &state->hs_in_mblist, &mbox_info->mbi_in,
308 295 mbox_wait);
309 296 if (status != HERMON_CMD_SUCCESS) {
310 297 return (status);
311 298 }
312 299 }
313 300
314 301 }
315 302
316 303 /* Allocate an "Out" mailbox */
317 304 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_OUTMBOX) {
318 305 /* Determine correct mboxlist based on calling context */
319 306 if (sleep_context == HERMON_NOSLEEP) {
320 307 status = hermon_impl_mbox_alloc(state,
321 308 &state->hs_out_intr_mblist,
322 309 &mbox_info->mbi_out, mbox_wait);
323 310
324 311 ASSERT(status == HERMON_CMD_SUCCESS);
325 312 } else {
326 313 /* NOTE: Expect threads to be waiting in here */
327 314 status = hermon_impl_mbox_alloc(state,
328 315 &state->hs_out_mblist, &mbox_info->mbi_out,
329 316 mbox_wait);
330 317 if (status != HERMON_CMD_SUCCESS) {
331 318 /* If we allocated an "In" mailbox, free it */
332 319 if (mbox_info->mbi_alloc_flags &
333 320 HERMON_ALLOC_INMBOX) {
↓ open down ↓ |
147 lines elided |
↑ open up ↑ |
334 321 hermon_impl_mbox_free(
335 322 &state->hs_in_mblist,
336 323 &mbox_info->mbi_in);
337 324 }
338 325 return (status);
339 326 }
340 327 }
341 328 }
342 329
343 330 /* Store appropriate context in mbox_info */
344 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context))
345 331 mbox_info->mbi_sleep_context = sleep_context;
346 332
347 333 return (HERMON_CMD_SUCCESS);
348 334 }
349 335
350 336
351 337 /*
352 338 * hermon_mbox_free()
353 339 * Context: Can be called from interrupt or base context.
354 340 */
355 341 void
356 342 hermon_mbox_free(hermon_state_t *state, hermon_mbox_info_t *mbox_info)
357 343 {
358 344 /*
359 345 * The mailbox has to be freed in the same context from which it was
360 346 * allocated. The context is stored in the mbox_info at
361 347 * hermon_mbox_alloc() time. We check the stored context against the
362 348 * current context here.
363 349 */
364 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context))
365 350 ASSERT(mbox_info->mbi_sleep_context == HERMON_SLEEPFLAG_FOR_CONTEXT());
366 351
367 352 /* Determine correct mboxlist based on calling context */
368 353 if (mbox_info->mbi_sleep_context == HERMON_NOSLEEP) {
369 354 /* Free the intr "In" mailbox */
370 355 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_INMBOX) {
371 356 hermon_impl_mbox_free(&state->hs_in_intr_mblist,
372 357 &mbox_info->mbi_in);
373 358 }
374 359
375 360 /* Free the intr "Out" mailbox */
376 361 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_OUTMBOX) {
377 362 hermon_impl_mbox_free(&state->hs_out_intr_mblist,
378 363 &mbox_info->mbi_out);
379 364 }
380 365 } else {
381 366 /* Free the "In" mailbox */
382 367 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_INMBOX) {
383 368 hermon_impl_mbox_free(&state->hs_in_mblist,
384 369 &mbox_info->mbi_in);
385 370 }
386 371
387 372 /* Free the "Out" mailbox */
388 373 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_OUTMBOX) {
389 374 hermon_impl_mbox_free(&state->hs_out_mblist,
390 375 &mbox_info->mbi_out);
391 376 }
392 377 }
393 378 }
394 379
395 380
396 381
397 382 /*
398 383 * hermon_cmd_complete_handler()
399 384 * Context: Called only from interrupt context.
400 385 */
401 386 /* ARGSUSED */
402 387 int
403 388 hermon_cmd_complete_handler(hermon_state_t *state, hermon_eqhdl_t eq,
404 389 hermon_hw_eqe_t *eqe)
405 390 {
406 391 hermon_cmd_t *cmdp;
407 392
408 393 /*
409 394 * Find the outstanding command pointer based on value returned
410 395 * in "token"
411 396 */
412 397 cmdp = &state->hs_cmd_list.cml_cmd[HERMON_EQE_CMDTOKEN_GET(eq, eqe)];
413 398
414 399 /* Signal the waiting thread */
415 400 mutex_enter(&cmdp->cmd_comp_lock);
416 401 cmdp->cmd_outparm = ((uint64_t)HERMON_EQE_CMDOUTP0_GET(eq, eqe) << 32) |
417 402 HERMON_EQE_CMDOUTP1_GET(eq, eqe);
418 403 cmdp->cmd_status = HERMON_EQE_CMDSTATUS_GET(eq, eqe);
419 404
420 405 cv_signal(&cmdp->cmd_comp_cv);
421 406 mutex_exit(&cmdp->cmd_comp_lock);
422 407
423 408 return (DDI_SUCCESS);
424 409 }
425 410
426 411
427 412 /*
428 413 * hermon_inmbox_list_init()
429 414 * Context: Only called from attach() path context
430 415 */
431 416 int
432 417 hermon_inmbox_list_init(hermon_state_t *state)
433 418 {
434 419 int status;
435 420 uint_t num_inmbox;
436 421
437 422 /* Initialize the "In" mailbox list */
438 423 num_inmbox = (1 << state->hs_cfg_profile->cp_log_num_inmbox);
439 424 status = hermon_impl_mboxlist_init(state, &state->hs_in_mblist,
440 425 num_inmbox, HERMON_IN_MBOX);
441 426 if (status != DDI_SUCCESS) {
442 427 return (DDI_FAILURE);
443 428 }
444 429
445 430 return (DDI_SUCCESS);
446 431 }
447 432
448 433
449 434 /*
450 435 * hermon_intr_inmbox_list_init()
451 436 * Context: Only called from attach() path context
452 437 */
453 438 int
454 439 hermon_intr_inmbox_list_init(hermon_state_t *state)
455 440 {
456 441 int status;
457 442 uint_t num_inmbox;
458 443
459 444 /* Initialize the interrupt "In" mailbox list */
460 445 num_inmbox = (1 << state->hs_cfg_profile->cp_log_num_intr_inmbox);
461 446 status = hermon_impl_mboxlist_init(state, &state->hs_in_intr_mblist,
462 447 num_inmbox, HERMON_INTR_IN_MBOX);
463 448 if (status != DDI_SUCCESS) {
464 449 return (DDI_FAILURE);
465 450 }
466 451
467 452 return (DDI_SUCCESS);
468 453 }
469 454
470 455
471 456 /*
472 457 * hermon_outmbox_list_init()
473 458 * Context: Only called from attach() path context
474 459 */
475 460 int
476 461 hermon_outmbox_list_init(hermon_state_t *state)
477 462 {
478 463 int status;
479 464 uint_t num_outmbox;
480 465
481 466 /* Initialize the "Out" mailbox list */
482 467 num_outmbox = (1 << state->hs_cfg_profile->cp_log_num_outmbox);
483 468 status = hermon_impl_mboxlist_init(state, &state->hs_out_mblist,
484 469 num_outmbox, HERMON_OUT_MBOX);
485 470 if (status != DDI_SUCCESS) {
486 471 return (DDI_FAILURE);
487 472 }
488 473
489 474 return (DDI_SUCCESS);
490 475 }
491 476
492 477
493 478 /*
494 479 * hermon_intr_outmbox_list_init()
495 480 * Context: Only called from attach() path context
496 481 */
497 482 int
498 483 hermon_intr_outmbox_list_init(hermon_state_t *state)
499 484 {
500 485 int status;
501 486 uint_t num_outmbox;
502 487
503 488 /* Initialize the interrupts "Out" mailbox list */
504 489 num_outmbox = (1 << state->hs_cfg_profile->cp_log_num_intr_outmbox);
505 490 status = hermon_impl_mboxlist_init(state, &state->hs_out_intr_mblist,
506 491 num_outmbox, HERMON_INTR_OUT_MBOX);
507 492 if (status != DDI_SUCCESS) {
508 493 return (DDI_FAILURE);
509 494 }
510 495
511 496 return (DDI_SUCCESS);
512 497 }
513 498
514 499
515 500 /*
516 501 * hermon_inmbox_list_fini()
517 502 * Context: Only called from attach() and/or detach() path contexts
518 503 */
519 504 void
520 505 hermon_inmbox_list_fini(hermon_state_t *state)
521 506 {
522 507 /* Free up the "In" mailbox list */
523 508 hermon_impl_mboxlist_fini(state, &state->hs_in_mblist);
524 509 }
525 510
526 511
527 512 /*
528 513 * hermon_intr_inmbox_list_fini()
529 514 * Context: Only called from attach() and/or detach() path contexts
530 515 */
531 516 void
532 517 hermon_intr_inmbox_list_fini(hermon_state_t *state)
533 518 {
534 519 /* Free up the interupts "In" mailbox list */
535 520 hermon_impl_mboxlist_fini(state, &state->hs_in_intr_mblist);
536 521 }
537 522
538 523
539 524 /*
540 525 * hermon_outmbox_list_fini()
541 526 * Context: Only called from attach() and/or detach() path contexts
542 527 */
543 528 void
544 529 hermon_outmbox_list_fini(hermon_state_t *state)
545 530 {
546 531 /* Free up the "Out" mailbox list */
547 532 hermon_impl_mboxlist_fini(state, &state->hs_out_mblist);
548 533 }
549 534
550 535
551 536 /*
552 537 * hermon_intr_outmbox_list_fini()
553 538 * Context: Only called from attach() and/or detach() path contexts
554 539 */
555 540 void
556 541 hermon_intr_outmbox_list_fini(hermon_state_t *state)
557 542 {
558 543 /* Free up the interrupt "Out" mailbox list */
559 544 hermon_impl_mboxlist_fini(state, &state->hs_out_intr_mblist);
560 545 }
561 546
562 547
563 548 /*
564 549 * hermon_impl_mbox_alloc()
565 550 * Context: Can be called from interrupt or base context.
566 551 */
567 552 static int
568 553 hermon_impl_mbox_alloc(hermon_state_t *state, hermon_mboxlist_t *mblist,
569 554 hermon_mbox_t **mb, uint_t mbox_wait)
570 555 {
571 556 hermon_mbox_t *mbox_ptr;
572 557 uint_t index, next, prev;
573 558 uint_t count, countmax;
574 559
575 560 /*
576 561 * If the mailbox list is empty, then wait (if appropriate in the
577 562 * current context). Otherwise, grab the next available mailbox.
578 563 */
579 564 if (mbox_wait == HERMON_NOSLEEP) {
580 565 count = 0;
581 566 countmax = state->hs_cfg_profile->cp_cmd_poll_max;
582 567
583 568 mutex_enter(&mblist->mbl_lock);
584 569 mblist->mbl_pollers++;
585 570 while (mblist->mbl_entries_free == 0) {
586 571 mutex_exit(&mblist->mbl_lock);
587 572 /* Delay loop polling for an available mbox */
588 573 if (++count > countmax) {
589 574 return (HERMON_CMD_INSUFF_RSRC);
590 575 }
591 576
592 577 /* Delay before polling for mailbox again */
593 578 drv_usecwait(state->hs_cfg_profile->cp_cmd_poll_delay);
594 579 mutex_enter(&mblist->mbl_lock);
595 580 }
↓ open down ↓ |
221 lines elided |
↑ open up ↑ |
596 581 mblist->mbl_pollers--;
597 582
598 583 /* HERMON_SLEEP */
599 584 } else {
600 585 /*
601 586 * Grab lock here as we prepare to cv_wait if needed.
602 587 */
603 588 mutex_enter(&mblist->mbl_lock);
604 589 while (mblist->mbl_entries_free == 0) {
605 590 /*
606 - * Wait (on cv) for a mailbox to become free. Note:
607 - * Just as we do above in hermon_cmd_post(), we also
608 - * have the "__lock_lint" here to workaround warlock.
609 - * Warlock doesn't know that other parts of the Hermon
610 - * may occasionally call this routine while holding
611 - * their own locks, so it complains about this cv_wait.
612 - * In reality, however, the rest of the driver never
613 - * calls this routine with a lock held unless they pass
614 - * HERMON_CMD_NOSLEEP.
591 + * Wait (on cv) for a mailbox to become free.
615 592 */
616 593 mblist->mbl_waiters++;
617 -#ifndef __lock_lint
618 594 cv_wait(&mblist->mbl_cv, &mblist->mbl_lock);
619 -#endif
620 595 }
621 596 }
622 597
623 598 /* Grab the next available mailbox from list */
624 599 mbox_ptr = mblist->mbl_mbox;
625 600 index = mblist->mbl_head_indx;
626 601 next = mbox_ptr[index].mb_next;
627 602 prev = mbox_ptr[index].mb_prev;
628 603
629 604 /* Remove it from the mailbox list */
630 605 mblist->mbl_mbox[next].mb_prev = prev;
631 606 mblist->mbl_mbox[prev].mb_next = next;
632 607 mblist->mbl_head_indx = next;
633 608
634 609 /* Update the "free" count and return the mailbox pointer */
635 610 mblist->mbl_entries_free--;
636 611 *mb = &mbox_ptr[index];
637 612
638 613 mutex_exit(&mblist->mbl_lock);
639 614
640 615 return (HERMON_CMD_SUCCESS);
641 616 }
642 617
643 618
644 619 /*
645 620 * hermon_impl_mbox_free()
646 621 * Context: Can be called from interrupt or base context.
647 622 */
648 623 static void
649 624 hermon_impl_mbox_free(hermon_mboxlist_t *mblist, hermon_mbox_t **mb)
650 625 {
651 626 uint_t mbox_indx;
652 627
653 628 mutex_enter(&mblist->mbl_lock);
654 629
655 630 /* Pull the "index" from mailbox entry */
656 631 mbox_indx = (*mb)->mb_indx;
657 632
658 633 /*
659 634 * If mailbox list is not empty, then insert the entry. Otherwise,
660 635 * this is the only entry. So update the pointers appropriately.
661 636 */
662 637 if (mblist->mbl_entries_free++ != 0) {
663 638 /* Update the current mailbox */
664 639 (*mb)->mb_next = mblist->mbl_head_indx;
665 640 (*mb)->mb_prev = mblist->mbl_tail_indx;
666 641
667 642 /* Update head and tail mailboxes */
668 643 mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev = mbox_indx;
669 644 mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next = mbox_indx;
670 645
671 646 /* Update tail index */
672 647 mblist->mbl_tail_indx = mbox_indx;
673 648
674 649 } else {
675 650 /* Update the current mailbox */
676 651 (*mb)->mb_next = mbox_indx;
677 652 (*mb)->mb_prev = mbox_indx;
678 653
679 654 /* Update head and tail indexes */
680 655 mblist->mbl_tail_indx = mbox_indx;
681 656 mblist->mbl_head_indx = mbox_indx;
682 657 }
683 658
684 659 /*
685 660 * Because we can have both waiters (SLEEP treads waiting for a
686 661 * cv_signal to continue processing) and pollers (NOSLEEP treads
687 662 * polling for a mailbox to become available), we try to share CPU time
688 663 * between them. We do this by signalling the waiters only every other
689 664 * call to mbox_free. This gives the pollers a chance to get some CPU
690 665 * time to do their command. If we signalled every time, the pollers
691 666 * would have a much harder time getting CPU time.
692 667 *
693 668 * If there are waiters and no pollers, then we signal always.
694 669 *
695 670 * Otherwise, if there are either no waiters, there may in fact be
696 671 * pollers, so we do not signal in that case.
697 672 */
698 673 if (mblist->mbl_pollers > 0 && mblist->mbl_waiters > 0) {
699 674 /* flip the signal value */
700 675 mblist->mbl_signal = (mblist->mbl_signal + 1) % 2;
701 676 } else if (mblist->mbl_waiters > 0) {
702 677 mblist->mbl_signal = 1;
703 678 } else {
704 679 mblist->mbl_signal = 0;
705 680 }
706 681
707 682 /*
708 683 * Depending on the conditions in the previous check, we signal only if
709 684 * we are supposed to.
710 685 */
711 686 if (mblist->mbl_signal) {
712 687 mblist->mbl_waiters--;
713 688 cv_signal(&mblist->mbl_cv);
714 689 }
715 690
716 691 /* Clear out the mailbox entry pointer */
717 692 *mb = NULL;
718 693
719 694 mutex_exit(&mblist->mbl_lock);
720 695 }
721 696
722 697
723 698 /*
724 699 * hermon_impl_mboxlist_init()
725 700 * Context: Only called from attach() path context
726 701 */
727 702 static int
728 703 hermon_impl_mboxlist_init(hermon_state_t *state, hermon_mboxlist_t *mblist,
729 704 uint_t num_mbox, hermon_rsrc_type_t type)
730 705 {
731 706 hermon_rsrc_t *rsrc;
732 707 ddi_dma_cookie_t dma_cookie;
733 708 uint_t dma_cookiecnt;
734 709 int status, i;
735 710
736 711 /* Allocate the memory for the mailbox entries list */
737 712 mblist->mbl_list_sz = num_mbox;
738 713 mblist->mbl_mbox = kmem_zalloc(mblist->mbl_list_sz *
739 714 sizeof (hermon_mbox_t), KM_SLEEP);
740 715
741 716 /* Initialize the mailbox entries list */
742 717 mblist->mbl_head_indx = 0;
743 718 mblist->mbl_tail_indx = mblist->mbl_list_sz - 1;
744 719 mblist->mbl_entries_free = mblist->mbl_list_sz;
745 720 mblist->mbl_waiters = 0;
746 721 mblist->mbl_num_alloc = 0;
747 722
748 723 /* Set up the mailbox list's cv and mutex */
749 724 mutex_init(&mblist->mbl_lock, NULL, MUTEX_DRIVER,
750 725 DDI_INTR_PRI(state->hs_intrmsi_pri));
751 726 cv_init(&mblist->mbl_cv, NULL, CV_DRIVER, NULL);
752 727
753 728 /* Initialize the mailbox list entries */
754 729 for (i = 0; i < mblist->mbl_list_sz; i++) {
755 730 /* Allocate resources for the mailbox */
756 731 status = hermon_rsrc_alloc(state, type, 1, HERMON_SLEEP,
757 732 &rsrc);
758 733 if (status != DDI_SUCCESS) {
759 734 /* Jump to cleanup and return error */
760 735 goto mboxlist_init_fail;
761 736 }
762 737
763 738 /* Save away the mailbox resource info */
764 739 mblist->mbl_mbox[i].mb_rsrcptr = rsrc;
765 740 mblist->mbl_mbox[i].mb_addr = rsrc->hr_addr;
766 741 mblist->mbl_mbox[i].mb_acchdl = rsrc->hr_acchdl;
767 742
768 743 /*
769 744 * Get a PCI mapped address for each mailbox. Note: this
770 745 * uses the ddi_dma_handle return from the resource
771 746 * allocation routine
772 747 */
773 748 status = ddi_dma_addr_bind_handle(rsrc->hr_dmahdl, NULL,
774 749 rsrc->hr_addr, rsrc->hr_len,
775 750 (DDI_DMA_RDWR | DDI_DMA_CONSISTENT),
776 751 DDI_DMA_SLEEP, NULL, &dma_cookie, &dma_cookiecnt);
777 752 if (status != DDI_SUCCESS) {
778 753 /* Jump to cleanup and return error */
779 754 hermon_rsrc_free(state, &rsrc);
780 755 goto mboxlist_init_fail;
781 756 }
782 757
783 758 /* Save away the mapped address for the mailbox */
784 759 mblist->mbl_mbox[i].mb_mapaddr = dma_cookie.dmac_laddress;
785 760
786 761 /* Make each entry point to the "next" and "prev" entries */
787 762 mblist->mbl_mbox[i].mb_next = i+1;
788 763 mblist->mbl_mbox[i].mb_prev = i-1;
789 764 mblist->mbl_mbox[i].mb_indx = i;
790 765 mblist->mbl_num_alloc = i + 1;
791 766 }
792 767
793 768 /* Make the "head" and "tail" entries point to each other */
794 769 mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev =
795 770 mblist->mbl_tail_indx;
796 771 mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next =
797 772 mblist->mbl_head_indx;
798 773
799 774 return (DDI_SUCCESS);
800 775
801 776 mboxlist_init_fail:
802 777 hermon_impl_mboxlist_fini(state, mblist);
803 778
804 779 return (DDI_FAILURE);
805 780 }
806 781
807 782
808 783 /*
809 784 * hermon_impl_mboxlist_fini()
810 785 * Context: Only called from attach() and/or detach() path contexts
811 786 */
812 787 static void
813 788 hermon_impl_mboxlist_fini(hermon_state_t *state, hermon_mboxlist_t *mblist)
814 789 {
815 790 hermon_rsrc_t *rsrc;
816 791 int i, status;
817 792
818 793 /* Release the resources for each of the mailbox list entries */
819 794 for (i = 0; i < mblist->mbl_num_alloc; i++) {
820 795 rsrc = mblist->mbl_mbox[i].mb_rsrcptr;
821 796
822 797 /*
823 798 * First, unbind the DMA memory for the mailbox
824 799 *
825 800 * Note: The only way ddi_dma_unbind_handle() currently
826 801 * can return an error is if the handle passed in is invalid.
827 802 * Since this should never happen, we choose to return void
828 803 * from this function! If this does return an error,
829 804 * however, then we print a warning message to the console.
830 805 */
831 806 status = ddi_dma_unbind_handle(rsrc->hr_dmahdl);
832 807 if (status != DDI_SUCCESS) {
833 808 HERMON_WARNING(state, "failed to unbind DMA mapping");
834 809 return;
835 810 }
836 811
837 812 /* Next, free the mailbox resource */
838 813 hermon_rsrc_free(state, &rsrc);
839 814 }
840 815
841 816 /* Destroy the mailbox list mutex and cv */
842 817 mutex_destroy(&mblist->mbl_lock);
843 818 cv_destroy(&mblist->mbl_cv);
844 819
845 820 /* Free up the memory for tracking the mailbox list */
846 821 kmem_free(mblist->mbl_mbox, mblist->mbl_list_sz *
847 822 sizeof (hermon_mbox_t));
848 823 }
849 824
850 825
851 826 /*
852 827 * hermon_outstanding_cmd_alloc()
853 828 * Context: Can be called only from base context.
854 829 */
855 830 static int
856 831 hermon_outstanding_cmd_alloc(hermon_state_t *state, hermon_cmd_t **cmd_ptr,
857 832 uint_t cmd_wait)
858 833 {
859 834 hermon_cmdlist_t *cmd_list;
860 835 uint_t next, prev, head;
861 836
862 837 cmd_list = &state->hs_cmd_list;
863 838 mutex_enter(&cmd_list->cml_lock);
864 839
865 840 /* Ensure that outstanding commands are supported */
866 841 ASSERT(cmd_list->cml_num_alloc != 0);
867 842
868 843 /*
869 844 * If the outstanding command list is empty, then wait (if
870 845 * appropriate in the current context). Otherwise, grab the
↓ open down ↓ |
241 lines elided |
↑ open up ↑ |
871 846 * next available command.
872 847 */
873 848 while (cmd_list->cml_entries_free == 0) {
874 849 /* No free commands */
875 850 if (cmd_wait == HERMON_NOSLEEP) {
876 851 mutex_exit(&cmd_list->cml_lock);
877 852 return (HERMON_CMD_INSUFF_RSRC);
878 853 }
879 854
880 855 /*
881 - * Wait (on cv) for a command to become free. Note: Just
882 - * as we do above in hermon_cmd_post(), we also have the
883 - * "__lock_lint" here to workaround warlock. Warlock doesn't
884 - * know that other parts of the Hermon may occasionally call
885 - * this routine while holding their own locks, so it complains
886 - * about this cv_wait. In reality, however, the rest of the
887 - * driver never calls this routine with a lock held unless
888 - * they pass HERMON_CMD_NOSLEEP.
856 + * Wait (on cv) for a command to become free.
889 857 */
890 858 cmd_list->cml_waiters++;
891 -#ifndef __lock_lint
892 859 cv_wait(&cmd_list->cml_cv, &cmd_list->cml_lock);
893 -#endif
894 860 }
895 861
896 862 /* Grab the next available command from the list */
897 863 head = cmd_list->cml_head_indx;
898 864 *cmd_ptr = &cmd_list->cml_cmd[head];
899 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(**cmd_ptr))
900 865 next = (*cmd_ptr)->cmd_next;
901 866 prev = (*cmd_ptr)->cmd_prev;
902 867 (*cmd_ptr)->cmd_status = HERMON_CMD_INVALID_STATUS;
903 868
904 869 /* Remove it from the command list */
905 870 cmd_list->cml_cmd[next].cmd_prev = prev;
906 871 cmd_list->cml_cmd[prev].cmd_next = next;
907 872 cmd_list->cml_head_indx = next;
908 873
909 874 /* Update the "free" count and return */
910 875 cmd_list->cml_entries_free--;
911 876
912 877 mutex_exit(&cmd_list->cml_lock);
913 878
914 879 return (HERMON_CMD_SUCCESS);
915 880 }
916 881
917 882
918 883 /*
919 884 * hermon_outstanding_cmd_free()
920 885 * Context: Can be called only from base context.
921 886 */
922 887 static void
923 888 hermon_outstanding_cmd_free(hermon_state_t *state, hermon_cmd_t **cmd_ptr)
924 889 {
925 890 hermon_cmdlist_t *cmd_list;
926 891 uint_t cmd_indx;
927 892
928 893 cmd_list = &state->hs_cmd_list;
929 894 mutex_enter(&cmd_list->cml_lock);
930 895
931 896 /* Pull the "index" from command entry */
932 897 cmd_indx = (*cmd_ptr)->cmd_indx;
933 898
934 899 /*
935 900 * If outstanding command list is not empty, then insert the entry.
936 901 * Otherwise, this is the only entry. So update the pointers
937 902 * appropriately.
938 903 */
939 904 if (cmd_list->cml_entries_free++ != 0) {
940 905 /* Update the current command */
941 906 (*cmd_ptr)->cmd_next = cmd_list->cml_head_indx;
942 907 (*cmd_ptr)->cmd_prev = cmd_list->cml_tail_indx;
943 908
944 909 /* Update head and tail commands */
945 910 cmd_list->cml_cmd[cmd_list->cml_head_indx].cmd_prev = cmd_indx;
946 911 cmd_list->cml_cmd[cmd_list->cml_tail_indx].cmd_next = cmd_indx;
947 912
948 913 /* Update tail index */
949 914 cmd_list->cml_tail_indx = cmd_indx;
950 915
951 916 } else {
952 917 /* Update the current command */
953 918 (*cmd_ptr)->cmd_next = cmd_indx;
954 919 (*cmd_ptr)->cmd_prev = cmd_indx;
955 920
956 921 /* Update head and tail indexes */
957 922 cmd_list->cml_head_indx = cmd_indx;
958 923 cmd_list->cml_tail_indx = cmd_indx;
959 924 }
960 925
961 926 /* If there are threads waiting, signal one of them */
962 927 if (cmd_list->cml_waiters > 0) {
963 928 cmd_list->cml_waiters--;
964 929 cv_signal(&cmd_list->cml_cv);
965 930 }
966 931
967 932 /* Clear out the command entry pointer */
968 933 *cmd_ptr = NULL;
969 934
970 935 mutex_exit(&cmd_list->cml_lock);
971 936 }
972 937
973 938
974 939 /*
975 940 * hermon_write_hcr()
976 941 * Context: Can be called from interrupt or base context.
977 942 */
978 943 static int
979 944 hermon_write_hcr(hermon_state_t *state, hermon_cmd_post_t *cmdpost,
980 945 uint16_t token, int *hw_err)
981 946 {
982 947 hermon_hw_hcr_t *hcr;
983 948 uint_t status, count, countmax;
984 949 uint64_t hcrreg;
985 950 uint64_t togmask;
986 951 ddi_acc_handle_t cmdhdl = hermon_get_cmdhdl(state);
987 952 boolean_t hw_error = B_FALSE;
↓ open down ↓ |
78 lines elided |
↑ open up ↑ |
988 953
989 954 /* initialize the FMA retry loop */
990 955 hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
991 956
992 957 /*
993 958 * Grab the "HCR access" lock if the driver is not in
994 959 * fastreboot. In fastreboot, this function is called
995 960 * with the single thread but in high interrupt context
996 961 * (so that this mutex lock cannot be used).
997 962 */
998 -#ifdef __lock_lint
999 - mutex_enter(&state->hs_cmd_regs.hcr_lock);
1000 -#else
1001 963 if (!HERMON_IN_FASTREBOOT(state)) {
1002 964 mutex_enter(&state->hs_cmd_regs.hcr_lock);
1003 965 }
1004 -#endif
1005 966 hcr = state->hs_cmd_regs.hcr;
1006 967
1007 968 /*
1008 969 * First, check the "go" bit to see if any previous hcr usage is
1009 970 * complete. As long as it is set then we must continue to poll.
1010 971 */
1011 972
1012 973 countmax = state->hs_cfg_profile->cp_cmd_poll_max;
1013 974 togmask = (state->hs_cmd_toggle & 0x01) << HERMON_HCR_CMD_T_SHFT;
1014 975
1015 976 /* the FMA retry loop starts. */
1016 977 hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1017 978 fm_test);
1018 979
1019 980 count = 0;
1020 981 for (;;) {
1021 982 hcrreg = ddi_get32(cmdhdl, &hcr->cmd);
1022 983
1023 984 /* If "go" bit is clear and toggle reset, then done */
1024 985 if (((hcrreg & HERMON_HCR_CMD_GO_MASK) == 0) &&
1025 986 ((hcrreg & HERMON_HCR_CMD_T_MASK) == togmask)) {
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
1026 987 break;
1027 988 }
1028 989 /* Delay before polling the "go" bit again */
1029 990 drv_usecwait(state->hs_cfg_profile->cp_cmd_poll_delay);
1030 991
1031 992 /*
1032 993 * If we poll more than the maximum number of times, then
1033 994 * return a "timeout" error.
1034 995 */
1035 996 if (++count > countmax) {
1036 -#ifdef __lock_lint
1037 - mutex_exit(&state->hs_cmd_regs.hcr_lock);
1038 -#else
1039 997 if (!HERMON_IN_FASTREBOOT(state)) {
1040 998 mutex_exit(&state->hs_cmd_regs.hcr_lock);
1041 999 }
1042 -#endif
1043 1000 cmn_err(CE_NOTE, "write_hcr: cannot start cmd");
1044 1001 return (HERMON_CMD_TIMEOUT_GOBIT);
1045 1002 }
1046 1003 }
1047 1004
1048 1005 /* the FMA retry loop ends. */
1049 1006 hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1050 1007 fm_test);
1051 1008
1052 1009 /* check if there is a transient error */
1053 1010 if (fm_loop_cnt != HCA_PIO_RETRY_CNT) {
1054 1011 hw_error = B_TRUE;
1055 1012 }
1056 1013
1057 1014 /* succeeded, so update the cmd counter for this cmd's completion */
1058 1015 state->hs_cmd_toggle++;
1059 1016 togmask = (state->hs_cmd_toggle & 0x01) << HERMON_HCR_CMD_T_SHFT;
1060 1017
1061 1018 /* the FMA retry loop starts. */
1062 1019 hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1063 1020 fm_test);
1064 1021
1065 1022 /* Write "inparam" as a 64-bit quantity */
1066 1023 ddi_put64(cmdhdl, (uint64_t *)(void *)&hcr->in_param0,
1067 1024 cmdpost->cp_inparm);
1068 1025
1069 1026 /* Write "inmod" and 32-bits of "outparam" as 64-bit */
1070 1027 hcrreg = ((uint64_t)cmdpost->cp_inmod << 32);
1071 1028 hcrreg = hcrreg | (cmdpost->cp_outparm >> 32);
1072 1029
1073 1030 ddi_put64(cmdhdl, (uint64_t *)(void *)&hcr->input_modifier, hcrreg);
1074 1031
1075 1032 /* Write the other 32-bits of "outparam" and "token" as 64-bit */
1076 1033 hcrreg = (cmdpost->cp_outparm << 32);
1077 1034 hcrreg = hcrreg | ((uint32_t)token << HERMON_HCR_TOKEN_SHIFT);
1078 1035
1079 1036 ddi_put64(cmdhdl, (uint64_t *)(void *)&hcr->out_param1, hcrreg);
1080 1037
1081 1038 /* Then setup the final hcrreg to hit doorbell (i.e. "go" bit) */
1082 1039 hcrreg = HERMON_HCR_CMD_GO_MASK;
1083 1040 /* Then set the toggle bit for this command */
1084 1041 hcrreg |= (state->hs_cmd_toggle & 0x01) << HERMON_HCR_CMD_T_SHFT;
1085 1042 if (cmdpost->cp_flags == HERMON_CMD_SLEEP_NOSPIN) {
1086 1043 hcrreg = hcrreg | HERMON_HCR_CMD_E_MASK;
1087 1044 }
1088 1045 hcrreg = hcrreg | (cmdpost->cp_opmod << HERMON_HCR_CMD_OPMOD_SHFT);
1089 1046 hcrreg = hcrreg | (cmdpost->cp_opcode);
1090 1047
1091 1048 /* Write the doorbell to the HCR */
1092 1049 ddi_put32(cmdhdl, &hcr->cmd, hcrreg);
1093 1050
1094 1051 /* the FMA retry loop ends. */
1095 1052 hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1096 1053 fm_test);
1097 1054
1098 1055 /* check if there is a transient error */
1099 1056 if (fm_loop_cnt != HCA_PIO_RETRY_CNT) {
1100 1057 hw_error = B_TRUE;
1101 1058 }
1102 1059
1103 1060 /*
1104 1061 * In the SPIN case we read the HCR and check the "go" bit. For the
1105 1062 * NOSPIN case we do not have to poll, we simply release the HCR lock
1106 1063 * and return.
1107 1064 */
1108 1065 if (cmdpost->cp_flags == HERMON_CMD_NOSLEEP_SPIN) {
1109 1066
1110 1067 countmax = (state->hs_cfg_profile->cp_cmd_poll_max << 4);
1111 1068
1112 1069 /* the FMA retry loop starts. */
1113 1070 hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt,
1114 1071 fm_status, fm_test);
1115 1072
1116 1073 count = 0;
1117 1074 for (;;) {
1118 1075 hcrreg = ddi_get32(cmdhdl, &hcr->cmd);
1119 1076
1120 1077 /* If "go" bit is clear and toggle reset, then done */
1121 1078 if (((hcrreg & HERMON_HCR_CMD_GO_MASK) == 0) &&
1122 1079 ((hcrreg & HERMON_HCR_CMD_T_MASK) == togmask)) {
↓ open down ↓ |
70 lines elided |
↑ open up ↑ |
1123 1080 break;
1124 1081 }
1125 1082 /* Delay before polling the "go" bit again */
1126 1083 drv_usecwait(state->hs_cfg_profile->cp_cmd_poll_delay);
1127 1084
1128 1085 /*
1129 1086 * If we poll more than the maximum number of times,
1130 1087 * then return a "timeout" error.
1131 1088 */
1132 1089 if (++count > countmax) {
1133 -#ifdef __lock_lint
1134 - mutex_exit(&state-> hs_cmd_regs.hcr_lock);
1135 -#else
1136 1090 if (!HERMON_IN_FASTREBOOT(state)) {
1137 1091 mutex_exit(&state->
1138 1092 hs_cmd_regs.hcr_lock);
1139 1093 }
1140 -#endif
1141 1094 cmn_err(CE_NOTE,
1142 1095 "write_hcr: cannot complete cmd");
1143 1096 return (HERMON_CMD_TIMEOUT_GOBIT);
1144 1097 }
1145 1098 }
1146 1099
1147 1100 /* Pull out the "status" bits from the HCR */
1148 1101 status = (hcrreg >> HERMON_HCR_CMD_STATUS_SHFT);
1149 1102
1150 1103 /*
1151 1104 * Read the "outparam" value. Note: we have to read "outparam"
1152 1105 * as two separate 32-bit reads because the field in the HCR is
1153 1106 * not 64-bit aligned.
1154 1107 */
1155 1108 hcrreg = ddi_get32(cmdhdl, &hcr->out_param0);
1156 1109 cmdpost->cp_outparm = hcrreg << 32;
1157 1110 hcrreg = ddi_get32(cmdhdl, &hcr->out_param1);
1158 1111 cmdpost->cp_outparm |= hcrreg;
1159 1112
1160 1113 /* the FMA retry loop ends. */
1161 1114 hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1162 1115 fm_test);
1163 1116
1164 1117 /* check if there is a transient error */
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
1165 1118 if (fm_loop_cnt != HCA_PIO_RETRY_CNT) {
1166 1119 hw_error = B_TRUE;
1167 1120 }
1168 1121
1169 1122 /* END SPIN */
1170 1123 } else { /* NOSPIN */
1171 1124 status = HERMON_CMD_SUCCESS;
1172 1125 }
1173 1126
1174 1127 /* Drop the "HCR access" lock */
1175 -#ifdef __lock_lint
1176 - mutex_exit(&state->hs_cmd_regs.hcr_lock);
1177 -#else
1178 1128 if (!HERMON_IN_FASTREBOOT(state)) {
1179 1129 mutex_exit(&state->hs_cmd_regs.hcr_lock);
1180 1130 }
1181 -#endif
1182 1131 if (hw_error == B_TRUE) {
1183 1132 *hw_err = HCA_PIO_TRANSIENT;
1184 1133 } else {
1185 1134 *hw_err = HCA_PIO_OK;
1186 1135 }
1187 1136 #ifdef FMA_TEST
1188 1137 if (hermon_test_num == -3) {
1189 1138 status = HERMON_CMD_INTERNAL_ERR;
1190 1139 }
1191 1140 #endif
1192 1141 return (status);
1193 1142
1194 1143 pio_error:
1195 -#ifdef __lock_lint
1196 - mutex_exit(&state->hs_cmd_regs.hcr_lock);
1197 -#else
1198 1144 if (!HERMON_IN_FASTREBOOT(state)) {
1199 1145 mutex_exit(&state->hs_cmd_regs.hcr_lock);
1200 1146 }
1201 -#endif
1202 1147 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_NON_FATAL);
1203 1148 *hw_err = HCA_PIO_PERSISTENT;
1204 1149 return (HERMON_CMD_INVALID_STATUS);
1205 1150 }
1206 1151
1207 1152
1208 1153 /*
1209 1154 * hermon_outstanding_cmdlist_init()
1210 1155 * Context: Only called from attach() path context
1211 1156 */
1212 1157 int
1213 1158 hermon_outstanding_cmdlist_init(hermon_state_t *state)
1214 1159 {
1215 1160 uint_t num_outstanding_cmds, head, tail;
1216 1161 int i;
1217 1162
1218 1163 /*
1219 1164 * Determine the number of the outstanding commands supported
1220 1165 * by the Hermon device (obtained from the QUERY_FW command). Note:
1221 1166 * Because we handle both SLEEP and NOSLEEP cases around the hermon HCR,
1222 1167 * we know that when an interrupt comes in it will be next on the
1223 1168 * command register, and will at most have to wait one commands time.
1224 1169 * We do not have to reserve an outstanding command here for
1225 1170 * interrupts.
1226 1171 */
1227 1172 num_outstanding_cmds = (1 << state->hs_fw.log_max_cmd);
1228 1173
1229 1174 /* Initialize the outstanding command list */
1230 1175 state->hs_cmd_list.cml_list_sz = num_outstanding_cmds;
1231 1176 state->hs_cmd_list.cml_head_indx = 0;
1232 1177 state->hs_cmd_list.cml_tail_indx = state->hs_cmd_list.cml_list_sz - 1;
1233 1178 state->hs_cmd_list.cml_entries_free = state->hs_cmd_list.cml_list_sz;
1234 1179 state->hs_cmd_list.cml_waiters = 0;
1235 1180 state->hs_cmd_list.cml_num_alloc = 0;
1236 1181
1237 1182 /* Allocate the memory for the outstanding command list */
1238 1183 if (num_outstanding_cmds) {
1239 1184 state->hs_cmd_list.cml_cmd =
1240 1185 kmem_zalloc(state->hs_cmd_list.cml_list_sz *
1241 1186 sizeof (hermon_cmd_t), KM_SLEEP);
1242 1187 }
1243 1188 mutex_init(&state->hs_cmd_list.cml_lock, NULL, MUTEX_DRIVER,
1244 1189 DDI_INTR_PRI(state->hs_intrmsi_pri));
1245 1190 cv_init(&state->hs_cmd_list.cml_cv, NULL, CV_DRIVER, NULL);
1246 1191
1247 1192 /* Initialize the individual outstanding command list entries */
1248 1193 for (i = 0; i < state->hs_cmd_list.cml_list_sz; i++) {
1249 1194 mutex_init(&state->hs_cmd_list.cml_cmd[i].cmd_comp_lock,
1250 1195 NULL, MUTEX_DRIVER, DDI_INTR_PRI(state->hs_intrmsi_pri));
1251 1196 cv_init(&state->hs_cmd_list.cml_cmd[i].cmd_comp_cv, NULL,
1252 1197 CV_DRIVER, NULL);
1253 1198
1254 1199 state->hs_cmd_list.cml_cmd[i].cmd_next = i+1;
1255 1200 state->hs_cmd_list.cml_cmd[i].cmd_prev = i-1;
1256 1201 state->hs_cmd_list.cml_cmd[i].cmd_indx = i;
1257 1202 state->hs_cmd_list.cml_num_alloc = i + 1;
1258 1203 }
1259 1204 if (num_outstanding_cmds) {
1260 1205 head = state->hs_cmd_list.cml_head_indx;
1261 1206 tail = state->hs_cmd_list.cml_tail_indx;
1262 1207 state->hs_cmd_list.cml_cmd[head].cmd_prev =
1263 1208 state->hs_cmd_list.cml_tail_indx;
1264 1209 state->hs_cmd_list.cml_cmd[tail].cmd_next =
1265 1210 state->hs_cmd_list.cml_head_indx;
1266 1211 }
1267 1212
1268 1213 return (DDI_SUCCESS);
1269 1214 }
1270 1215
1271 1216
1272 1217 /*
1273 1218 * hermon_outstanding_cmdlist_fini()
1274 1219 * Context: Only called from attach() and/or detach() path contexts
1275 1220 */
1276 1221 void
1277 1222 hermon_outstanding_cmdlist_fini(hermon_state_t *state)
1278 1223 {
1279 1224 int i;
1280 1225
1281 1226 /* Destroy the outstanding command list entries */
1282 1227 for (i = 0; i < state->hs_cmd_list.cml_num_alloc; i++) {
1283 1228 mutex_destroy(&state->hs_cmd_list.cml_cmd[i].cmd_comp_lock);
1284 1229 cv_destroy(&state->hs_cmd_list.cml_cmd[i].cmd_comp_cv);
1285 1230 }
1286 1231
1287 1232 /* Destroy the lock (and cv) and free up memory for list */
1288 1233 mutex_destroy(&state->hs_cmd_list.cml_lock);
1289 1234 cv_destroy(&state->hs_cmd_list.cml_cv);
1290 1235 if (state->hs_cmd_list.cml_num_alloc) {
1291 1236 kmem_free(state->hs_cmd_list.cml_cmd,
1292 1237 state->hs_cmd_list.cml_list_sz * sizeof (hermon_cmd_t));
1293 1238 }
1294 1239 }
1295 1240
1296 1241
1297 1242 /*
1298 1243 * hermon_mbox_sync()
1299 1244 */
1300 1245 static void
1301 1246 hermon_mbox_sync(hermon_mbox_t *mbox, uint_t offset, uint_t length,
1302 1247 uint_t flag)
1303 1248 {
1304 1249 ddi_dma_handle_t dmahdl;
1305 1250 int status;
1306 1251
1307 1252 /* Get the DMA handle from mailbox */
1308 1253 dmahdl = mbox->mb_rsrcptr->hr_dmahdl;
1309 1254
1310 1255 /* Calculate offset into mailbox */
1311 1256 status = ddi_dma_sync(dmahdl, (off_t)offset, (size_t)length, flag);
1312 1257 if (status != DDI_SUCCESS) {
1313 1258 return;
1314 1259 }
1315 1260 }
1316 1261
1317 1262
1318 1263 /*
1319 1264 * hermon_init_hca_cmd_post()
1320 1265 * Context: Can be called from interrupt or base context.
1321 1266 * (Currently called only from attach() path context)
1322 1267 */
1323 1268 int
1324 1269 hermon_init_hca_cmd_post(hermon_state_t *state,
1325 1270 hermon_hw_initqueryhca_t *inithca, uint_t sleepflag)
1326 1271 {
1327 1272 hermon_mbox_info_t mbox_info;
1328 1273 hermon_cmd_post_t cmd;
1329 1274 uint64_t data;
1330 1275 uint_t size;
1331 1276 int status, i;
1332 1277
1333 1278 /* Make sure we are called with the correct flag */
1334 1279 ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN);
1335 1280
1336 1281 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1337 1282
1338 1283 /* Get an "In" mailbox for the command */
1339 1284 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
1340 1285 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
1341 1286 if (status != HERMON_CMD_SUCCESS) {
1342 1287 return (status);
1343 1288 }
1344 1289
1345 1290 /* Copy the Hermon "INIT_HCA" command into the mailbox */
1346 1291 size = sizeof (hermon_hw_initqueryhca_t);
1347 1292 for (i = 0; i < (size >> 3); i++) {
1348 1293 data = ((uint64_t *)inithca)[i];
1349 1294 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1350 1295 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
1351 1296 }
1352 1297
1353 1298 /* Sync the mailbox for the device to read */
1354 1299 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1355 1300
1356 1301 /* Setup and post the Hermon "INIT_HCA" command */
1357 1302 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
1358 1303 cmd.cp_outparm = 0;
1359 1304 cmd.cp_inmod = 0;
1360 1305 cmd.cp_opcode = INIT_HCA;
1361 1306 cmd.cp_opmod = 0;
1362 1307 cmd.cp_flags = sleepflag;
1363 1308 status = hermon_cmd_post(state, &cmd);
1364 1309
1365 1310 /* Free the mailbox */
1366 1311 hermon_mbox_free(state, &mbox_info);
1367 1312 return (status);
1368 1313 }
1369 1314
1370 1315
1371 1316 /*
1372 1317 * hermon_close_hca_cmd_post()
1373 1318 * Context: Can be called from interrupt or base context.
1374 1319 * (Currently called only from attach() and/or detach() path contexts)
1375 1320 */
1376 1321 int
1377 1322 hermon_close_hca_cmd_post(hermon_state_t *state, uint_t sleepflag)
1378 1323 {
1379 1324 hermon_cmd_post_t cmd;
1380 1325 int status;
1381 1326
1382 1327 /* Make sure we are called with the correct flag */
1383 1328 ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN);
1384 1329
1385 1330 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1386 1331
1387 1332
1388 1333 /* Setup and post the Hermon "CLOSE_HCA" command */
1389 1334 cmd.cp_inparm = 0;
1390 1335 cmd.cp_outparm = 0;
1391 1336 cmd.cp_inmod = 0;
1392 1337 cmd.cp_opcode = CLOSE_HCA;
1393 1338 cmd.cp_opmod = 0;
1394 1339 cmd.cp_flags = sleepflag;
1395 1340 status = hermon_cmd_post(state, &cmd);
1396 1341 return (status);
1397 1342 }
1398 1343
1399 1344
1400 1345 /*
1401 1346 * hermon_set_port_cmd_post()
1402 1347 * Context: Can be called from interrupt or base context.
1403 1348 * (Currently called only from attach() path context)
1404 1349 */
1405 1350 int
1406 1351 hermon_set_port_cmd_post(hermon_state_t *state, hermon_hw_set_port_t *initport,
1407 1352 uint_t port, uint_t sleepflag)
1408 1353 {
1409 1354 hermon_mbox_info_t mbox_info;
1410 1355 hermon_cmd_post_t cmd;
1411 1356 uint64_t data;
1412 1357 uint_t size;
1413 1358 int status, i;
1414 1359
1415 1360 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1416 1361
1417 1362 /* Get an "In" mailbox for the command */
1418 1363 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
1419 1364 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
1420 1365 if (status != HERMON_CMD_SUCCESS) {
1421 1366 return (status);
1422 1367 }
1423 1368
1424 1369 /* Copy the Hermon "INIT_PORT" command into the mailbox */
1425 1370 size = sizeof (hermon_hw_set_port_t);
1426 1371 for (i = 0; i < (size >> 3); i++) {
1427 1372 data = ((uint64_t *)initport)[i];
1428 1373 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1429 1374 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
1430 1375 }
1431 1376
1432 1377 /* Sync the mailbox for the device to read */
1433 1378 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1434 1379
1435 1380 /* Setup and post the Hermon "SET_PORT" command */
1436 1381 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
1437 1382 cmd.cp_outparm = 0;
1438 1383 cmd.cp_inmod = port;
1439 1384 cmd.cp_opcode = SET_PORT;
1440 1385 cmd.cp_opmod = 0;
1441 1386 cmd.cp_flags = sleepflag;
1442 1387 status = hermon_cmd_post(state, &cmd);
1443 1388
1444 1389 /* Free the mailbox */
1445 1390 hermon_mbox_free(state, &mbox_info);
1446 1391 return (status);
1447 1392 }
1448 1393
1449 1394
1450 1395 /*
1451 1396 * hermon_init_port_cmd_post()
1452 1397 * Context: Can be called from interrupt or base context.
1453 1398 * (Currently called only from attach() and/or detach() path contexts)
1454 1399 */
1455 1400 int
1456 1401 hermon_init_port_cmd_post(hermon_state_t *state, uint_t port, uint_t sleepflag)
1457 1402 {
1458 1403 hermon_cmd_post_t cmd;
1459 1404 int status;
1460 1405
1461 1406 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1462 1407
1463 1408 /* Setup and post the Hermon "INIT_PORT" command */
1464 1409 cmd.cp_inparm = 0;
1465 1410 cmd.cp_outparm = 0;
1466 1411 cmd.cp_inmod = port;
1467 1412 cmd.cp_opcode = INIT_PORT;
1468 1413 cmd.cp_opmod = 0;
1469 1414 cmd.cp_flags = sleepflag;
1470 1415 status = hermon_cmd_post(state, &cmd);
1471 1416
1472 1417 return (status);
1473 1418 }
1474 1419
1475 1420
1476 1421 /*
1477 1422 * hermon_close_port_cmd_post()
1478 1423 * Context: Can be called from interrupt or base context.
1479 1424 * (Currently called only from attach() and/or detach() path contexts)
1480 1425 */
1481 1426 int
1482 1427 hermon_close_port_cmd_post(hermon_state_t *state, uint_t port, uint_t sleepflag)
1483 1428 {
1484 1429 hermon_cmd_post_t cmd;
1485 1430 int status;
1486 1431
1487 1432 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1488 1433
1489 1434 /* Setup and post the Hermon "CLOSE_PORT" command */
1490 1435 cmd.cp_inparm = 0;
1491 1436 cmd.cp_outparm = 0;
1492 1437 cmd.cp_inmod = port;
1493 1438 cmd.cp_opcode = CLOSE_PORT;
1494 1439 cmd.cp_opmod = 0;
1495 1440 cmd.cp_flags = sleepflag;
1496 1441 status = hermon_cmd_post(state, &cmd);
1497 1442 return (status);
1498 1443 }
1499 1444
1500 1445
1501 1446 /*
1502 1447 * hermon_mod_stat_cfg_cmd_post()
1503 1448 * Context: Can be called only from attach() path
1504 1449 *
1505 1450 * This routine was initially implemented to enable SRQ. That's no longer needed
1506 1451 * in hermon, and the code is conditionally compiled OUT, but left here because
1507 1452 * there are other static configuration parameters we might one day want to set
1508 1453 */
1509 1454 #ifdef HERMON_NO_MOD_STAT_CFG
1510 1455 int
1511 1456 hermon_mod_stat_cfg_cmd_post(hermon_state_t *state)
1512 1457 {
1513 1458 hermon_mbox_info_t mbox_info;
1514 1459 hermon_cmd_post_t cmd;
1515 1460 hermon_hw_mod_stat_cfg_t *mod;
1516 1461 hermon_hw_msg_in_mod_t inmod;
1517 1462 uint64_t data;
1518 1463 uint_t size;
1519 1464 int status, i;
1520 1465
1521 1466 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1522 1467
1523 1468 /*
1524 1469 * "MOD_STAT_CFG" needs an INMBOX parameter, to specify what operations
1525 1470 * to do. However, at the point in time that we call this command, the
1526 1471 * DDR has not yet been initialized, and all INMBOX'es are located in
1527 1472 * DDR. Because we want to call MOD_STAT_CFG before QUERY_DEVLIM is
1528 1473 * called, and thus call it before DDR is setup, we simply use an
1529 1474 * OUTMBOX memory location here as our INMBOX parameter.
1530 1475 */
1531 1476 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
1532 1477 status = hermon_mbox_alloc(state, &mbox_info, HERMON_NOSLEEP);
1533 1478 if (status != HERMON_CMD_SUCCESS) {
1534 1479 return (status);
1535 1480 }
1536 1481
1537 1482 /*
1538 1483 * Allocate on the heap our 'mod_stat_cfg' structure. We want to
1539 1484 * ideally move all of this on to the stack in the future, but this
1540 1485 * works well for now.
1541 1486 */
1542 1487 mod = (hermon_hw_mod_stat_cfg_t *)kmem_zalloc(
1543 1488 sizeof (hermon_hw_mod_stat_cfg_t), KM_SLEEP);
1544 1489
1545 1490 /* Setup "MOD_STAT_CFG" settings */
1546 1491 mod->srq_m = 1;
1547 1492 mod->srq = state->hs_cfg_profile->cp_srq_enable;
1548 1493
1549 1494 if (mod->srq) {
1550 1495 /* use DEV_LIMS num srq */
1551 1496 mod->log_max_srq = state->hs_cfg_profile->cp_log_num_srq;
1552 1497 } else {
1553 1498 mod->log_max_srq = 0;
1554 1499 }
1555 1500
1556 1501 /* Copy the "MOD_STAT_CFG" command into the "In" mailbox */
1557 1502 size = sizeof (hermon_hw_mod_stat_cfg_t);
1558 1503 for (i = 0; i < (size >> 3); i++) {
1559 1504 data = ((uint64_t *)mod)[i];
1560 1505 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1561 1506 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
1562 1507 }
1563 1508
1564 1509 /* Sync the mailbox for the device to read */
1565 1510 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1566 1511
1567 1512 /* Setup and post the Hermon "MOD_STAT_CFG" command */
1568 1513 cmd.cp_inparm = mbox_info.mbi_out->mb_mapaddr;
1569 1514 cmd.cp_outparm = 0;
1570 1515 cmd.cp_inmod = 0;
1571 1516 cmd.cp_opcode = MOD_STAT_CFG;
1572 1517 cmd.cp_opmod = HERMON_MOD_STAT_CFG_PTR;
1573 1518 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1574 1519 status = hermon_cmd_post(state, &cmd);
1575 1520
1576 1521 /* Free "MOD_STAT_CFG" struct */
1577 1522 kmem_free(mod, sizeof (hermon_hw_mod_stat_cfg_t));
1578 1523
1579 1524 /* Free the mailbox */
1580 1525 hermon_mbox_free(state, &mbox_info);
1581 1526 return (status);
1582 1527 }
1583 1528 #endif
1584 1529
1585 1530
1586 1531 /*
1587 1532 * hermon_map_cmd_post()
1588 1533 * Context: Can be called only from user or kernel context
1589 1534 *
1590 1535 * Generic routine to map FW, ICMA, and ICM.
1591 1536 */
1592 1537 int
1593 1538 hermon_map_cmd_post(hermon_state_t *state, hermon_dma_info_t *dma,
1594 1539 uint16_t opcode, ddi_dma_cookie_t cookie, uint_t ccount)
1595 1540 {
1596 1541 hermon_mbox_info_t mbox_info;
1597 1542 hermon_cmd_post_t cmd;
1598 1543 hermon_hw_vpm_t vpm;
1599 1544 uint64_t data;
1600 1545 uint64_t paddr, vaddr;
1601 1546 uint_t size;
1602 1547 int status, i, j, k = 0;
1603 1548 int max_mailbox_size;
1604 1549 int cookie_num_icm_pages;
1605 1550 int num_vpm_entries;
1606 1551 int log2_npages;
1607 1552 int npages;
1608 1553
1609 1554 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1610 1555
1611 1556 /* Allocate an IN mailbox */
1612 1557 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
1613 1558 status = hermon_mbox_alloc(state, &mbox_info, HERMON_SLEEP);
1614 1559 if (status != HERMON_CMD_SUCCESS) {
1615 1560 return (status);
1616 1561 }
1617 1562
1618 1563 /* Initialize cmd parameters */
1619 1564 cmd.cp_outparm = 0;
1620 1565 cmd.cp_opcode = opcode;
1621 1566 cmd.cp_opmod = 0;
1622 1567 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1623 1568
1624 1569 /*
1625 1570 * Allocate a list of VPM (Virtual Physical Mapping) structures.
1626 1571 * A VPM encodes a power-of-2 number of DMA pages that have been
1627 1572 * allocated and are passed in the dma_info. We need to break up
1628 1573 * the DMA cookies that are in the dma_info into power-of-2 page
1629 1574 * mappings. We also need to keep track of the number of VPMs we
1630 1575 * have total, as it is used as the inmod for this command.
1631 1576 */
1632 1577
1633 1578 /* Start with the ICM address passed and the first cookie */
1634 1579 vaddr = dma->icmaddr;
1635 1580
1636 1581 /* Initialize the VPM count and the VPM struct */
1637 1582 num_vpm_entries = 0;
1638 1583 size = sizeof (hermon_hw_vpm_t);
1639 1584 bzero(&vpm, size);
1640 1585
1641 1586 /*
1642 1587 * Establish a max mailbox size (in VPM entries). If we reach this,
1643 1588 * we must post a MAP command, reinitialzie num_vpm_entries, and
1644 1589 * continue.
1645 1590 */
1646 1591 max_mailbox_size = HERMON_MBOX_SIZE / size;
1647 1592
1648 1593 /*
1649 1594 * First, walk through the DMA cookies and build VPMs from them.
1650 1595 */
1651 1596 while (ccount-- > 0) {
1652 1597
1653 1598 /* Determine the number of ICM pages in this cookie. */
1654 1599 cookie_num_icm_pages = cookie.dmac_size / HERMON_PAGESIZE;
1655 1600
1656 1601 /* Initialize this set of VPM's starting physical address. */
1657 1602 paddr = cookie.dmac_laddress;
1658 1603
1659 1604 /*
1660 1605 * Now build a set of VPMs for this cookie's memory, breaking
1661 1606 * up the cookies into multiple VPMs if necessary to achieve
1662 1607 * the required power-of-2 number of pages per VPM. Once each
1663 1608 * VPM is constructed, write it out to the mailbox memory.
1664 1609 */
1665 1610 for (i = cookie_num_icm_pages; i > 0; i -= npages) {
1666 1611 log2_npages = highbit(i) - 1;
1667 1612 npages = (1 << log2_npages);
1668 1613 /* Ensure this chunk is aligned on it's own size */
1669 1614 while (((npages * HERMON_PAGESIZE - 1) & paddr) != 0) {
1670 1615 log2_npages--;
1671 1616 npages = (1 << log2_npages);
1672 1617 }
1673 1618 vpm.log2sz = log2_npages;
1674 1619
1675 1620 vpm.paddr_l = (uint32_t)(paddr >> 12);
1676 1621 vpm.paddr_h = (uint32_t)(paddr >> 32);
1677 1622 /* Increment the paddr for the next VPM */
1678 1623 paddr += npages * HERMON_PAGESIZE;
1679 1624
1680 1625 if (opcode == MAP_ICM) {
1681 1626 vpm.vaddr_l = (uint32_t)(vaddr >> 12);
1682 1627 vpm.vaddr_h = (uint32_t)(vaddr >> 32);
1683 1628 /* Increment the ICM address for the next VPM */
1684 1629 vaddr += npages * HERMON_PAGESIZE;
1685 1630 }
1686 1631
1687 1632 /*
1688 1633 * Copy this VPM into the "In" mailbox. Note we're
1689 1634 * using 'k' as the offset from mb_addr for this cmd.
1690 1635 */
1691 1636 for (j = 0; j < (size >> 3); j++, k++) {
1692 1637 data = ((uint64_t *)(void *)&vpm)[j];
1693 1638 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1694 1639 ((uint64_t *)mbox_info.mbi_in->mb_addr + k),
1695 1640 data);
1696 1641 }
1697 1642
1698 1643 /*
1699 1644 * Increment the number of VPM entries and check
1700 1645 * against max mailbox size. If we have reached
1701 1646 * the maximum mailbox size, post the map cmd.
1702 1647 */
1703 1648 if (++num_vpm_entries == max_mailbox_size) {
1704 1649
1705 1650 /* Sync the mailbox for the device to read */
1706 1651 hermon_mbox_sync(mbox_info.mbi_in, 0, (size *
1707 1652 num_vpm_entries), DDI_DMA_SYNC_FORDEV);
1708 1653
1709 1654 /* Setup and post the command */
1710 1655 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
1711 1656 cmd.cp_inmod = num_vpm_entries;
1712 1657 status = hermon_cmd_post(state, &cmd);
1713 1658 if (status != HERMON_CMD_SUCCESS) {
1714 1659 cmn_err(CE_NOTE, "hermon%d: %s cmd "
1715 1660 "failed (0x%x)", state->hs_instance,
1716 1661 opcode == MAP_FA ? "MAP_FA" :
1717 1662 opcode == MAP_ICM ? "MAP_ICM" :
1718 1663 opcode == MAP_ICM_AUX ? "MAP_ICMA" :
1719 1664 "UNKNOWN", status);
1720 1665 goto map_fail;
1721 1666 }
1722 1667
1723 1668 /*
1724 1669 * Reinitialize num_vpm_entries, and the
1725 1670 * mb_addr offset
1726 1671 */
1727 1672 num_vpm_entries = k = 0;
1728 1673 }
1729 1674 }
1730 1675
1731 1676 /* If count remains, move onto the next cookie */
1732 1677 if (ccount != 0) {
1733 1678 ddi_dma_nextcookie(dma->dma_hdl, &cookie);
1734 1679 }
1735 1680 }
1736 1681
1737 1682 if (num_vpm_entries) {
1738 1683
1739 1684 /* Sync the mailbox for the device to read */
1740 1685 hermon_mbox_sync(mbox_info.mbi_in, 0, (size * num_vpm_entries),
1741 1686 DDI_DMA_SYNC_FORDEV);
1742 1687
1743 1688 /* Setup and post the command */
1744 1689 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
1745 1690 cmd.cp_inmod = num_vpm_entries;
1746 1691 status = hermon_cmd_post(state, &cmd);
1747 1692 if (status != HERMON_CMD_SUCCESS) {
1748 1693 cmn_err(CE_NOTE, "hermon%d: %s cmd "
1749 1694 "failed (0x%x)", state->hs_instance,
1750 1695 opcode == MAP_FA ? "MAP_FA" :
1751 1696 opcode == MAP_ICM ? "MAP_ICM" :
1752 1697 opcode == MAP_ICM_AUX ? "MAP_ICMA" :
1753 1698 "UNKNOWN", status);
1754 1699 goto map_fail;
1755 1700 }
1756 1701 }
1757 1702
1758 1703 map_fail:
1759 1704 /* Free the mailbox */
1760 1705 hermon_mbox_free(state, &mbox_info);
1761 1706 return (status);
1762 1707 }
1763 1708
1764 1709
1765 1710 /*
1766 1711 * hermon_unmap_fa_cmd_post()
1767 1712 * Context: Can be called only from attach() path
1768 1713 */
1769 1714 int
1770 1715 hermon_unmap_fa_cmd_post(hermon_state_t *state)
1771 1716 {
1772 1717 hermon_cmd_post_t cmd;
1773 1718 int status;
1774 1719
1775 1720 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1776 1721
1777 1722 /* Setup and post the Hermon "UNMAP_FA" command */
1778 1723 cmd.cp_inparm = 0;
1779 1724 cmd.cp_outparm = 0;
1780 1725 cmd.cp_inmod = 0;
1781 1726 cmd.cp_opcode = UNMAP_FA;
1782 1727 cmd.cp_opmod = 0;
1783 1728 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1784 1729 status = hermon_cmd_post(state, &cmd);
1785 1730
1786 1731 return (status);
1787 1732 }
1788 1733
1789 1734
1790 1735 /*
1791 1736 * hermon_run_fw_cmd_post()
1792 1737 * Context: Can be called only from attach() path
1793 1738 */
1794 1739 int
1795 1740 hermon_run_fw_cmd_post(hermon_state_t *state)
1796 1741 {
1797 1742 hermon_cmd_post_t cmd;
1798 1743 int status;
1799 1744
1800 1745 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1801 1746
1802 1747 /* Setup and post the Hermon "RUN_FW" command */
1803 1748 cmd.cp_inparm = 0;
1804 1749 cmd.cp_outparm = 0;
1805 1750 cmd.cp_inmod = 0;
1806 1751 cmd.cp_opcode = RUN_FW;
1807 1752 cmd.cp_opmod = 0;
1808 1753 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1809 1754
1810 1755 status = hermon_cmd_post(state, &cmd);
1811 1756 #ifdef FMA_TEST
1812 1757 if (hermon_test_num == -2) {
1813 1758 status = HERMON_CMD_BAD_NVMEM;
1814 1759 /*
1815 1760 * No need of an ereport here since this case
1816 1761 * is treated as a degradation later.
1817 1762 */
1818 1763 HERMON_FMANOTE(state, HERMON_FMA_BADNVMEM);
1819 1764 }
1820 1765 #endif
1821 1766 return (status);
1822 1767 }
1823 1768
1824 1769
1825 1770 /*
1826 1771 * hermon_set_icm_size_cmd_post()
1827 1772 * Context: Can be called only from attach() path
1828 1773 */
1829 1774 int
1830 1775 hermon_set_icm_size_cmd_post(hermon_state_t *state)
1831 1776 {
1832 1777 hermon_cmd_post_t cmd;
1833 1778 int status;
1834 1779
1835 1780 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1836 1781
1837 1782 /* Setup and post the Hermon "SET_ICM_SIZE" command */
1838 1783 cmd.cp_inparm = (uint64_t)state->hs_icm_sz;
1839 1784 cmd.cp_outparm = 0;
1840 1785 cmd.cp_inmod = 0;
1841 1786 cmd.cp_opcode = SET_ICM_SIZE;
1842 1787 cmd.cp_opmod = 0;
1843 1788 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1844 1789 status = hermon_cmd_post(state, &cmd);
1845 1790
1846 1791 /*
1847 1792 * Aux ICM size in 4K pages returned in output param
1848 1793 * convert it to bytes
1849 1794 */
1850 1795 state->hs_icma_sz = (uint64_t)(cmd.cp_outparm << HERMON_PAGESHIFT);
1851 1796 return (status);
1852 1797 }
1853 1798
1854 1799
1855 1800 /*
1856 1801 * hermon_unmap_icm_aux_cmd_post()
1857 1802 * Context: Can be called only from attach() path
1858 1803 */
1859 1804 int
1860 1805 hermon_unmap_icm_aux_cmd_post(hermon_state_t *state)
1861 1806 {
1862 1807 hermon_cmd_post_t cmd;
1863 1808 int status;
1864 1809
1865 1810 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1866 1811
1867 1812 /* Setup and post the Hermon "UNMAP_ICM_AUX" command */
1868 1813 cmd.cp_inparm = 0;
1869 1814 cmd.cp_outparm = 0;
1870 1815 cmd.cp_inmod = 0;
1871 1816 cmd.cp_opcode = UNMAP_ICM_AUX;
1872 1817 cmd.cp_opmod = 0;
1873 1818 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1874 1819 status = hermon_cmd_post(state, &cmd);
1875 1820 return (status);
1876 1821 }
1877 1822
1878 1823
1879 1824 /*
1880 1825 * hermon_unmap_icm_cmd_post()
1881 1826 * Context: Can be called from base or attach context
1882 1827 */
1883 1828 int
1884 1829 hermon_unmap_icm_cmd_post(hermon_state_t *state, hermon_dma_info_t *dma_info)
1885 1830 {
1886 1831 hermon_cmd_post_t cmd;
1887 1832 uint64_t addr;
1888 1833 uint32_t npages;
1889 1834 int status;
1890 1835
1891 1836 /*
1892 1837 * Setup and post the Hermon "UNMAP_ICM" command. If a
1893 1838 * hermon_dma_info_t was passed, we want to unmap a set
1894 1839 * of pages. Otherwise, unmap all of ICM.
1895 1840 */
1896 1841 if (dma_info != NULL) {
1897 1842 addr = dma_info->icmaddr;
1898 1843 npages = dma_info->length / HERMON_PAGESIZE;
1899 1844 } else {
1900 1845 addr = 0;
1901 1846 npages = state->hs_icm_sz / HERMON_PAGESIZE;
1902 1847 }
1903 1848
1904 1849 /* Setup and post the Hermon "UNMAP_ICM" command */
1905 1850 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1906 1851 cmd.cp_inparm = addr;
1907 1852 cmd.cp_outparm = 0;
1908 1853 cmd.cp_inmod = npages;
1909 1854 cmd.cp_opcode = UNMAP_ICM;
1910 1855 cmd.cp_opmod = 0;
1911 1856 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1912 1857 status = hermon_cmd_post(state, &cmd);
1913 1858 return (status);
1914 1859 }
1915 1860
1916 1861
1917 1862 /*
1918 1863 * hermon_mad_ifc_cmd_post()
1919 1864 * Context: Can be called from interrupt or base context.
1920 1865 */
1921 1866 int
1922 1867 hermon_mad_ifc_cmd_post(hermon_state_t *state, uint_t port,
1923 1868 uint_t sleepflag, uint32_t *mad, uint32_t *resp)
1924 1869 {
1925 1870 hermon_mbox_info_t mbox_info;
1926 1871 hermon_cmd_post_t cmd;
1927 1872 uint_t size;
1928 1873 int status;
1929 1874
1930 1875 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1931 1876
1932 1877 /* Get "In" and "Out" mailboxes for the command */
1933 1878 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
1934 1879 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
1935 1880 if (status != HERMON_CMD_SUCCESS) {
1936 1881 return (status);
1937 1882 }
1938 1883
1939 1884 /* Copy the request MAD into the "In" mailbox */
1940 1885 size = HERMON_CMD_MAD_IFC_SIZE;
1941 1886 bcopy(mad, mbox_info.mbi_in->mb_addr, size);
1942 1887
1943 1888 /* Sync the mailbox for the device to read */
1944 1889 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1945 1890
1946 1891 /* Setup the Hermon "MAD_IFC" command */
1947 1892 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
1948 1893 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
1949 1894 cmd.cp_inmod = port;
1950 1895 cmd.cp_opcode = MAD_IFC;
1951 1896 cmd.cp_opmod = HERMON_CMD_MKEY_CHECK; /* Enable MKey checking */
1952 1897 cmd.cp_flags = sleepflag;
1953 1898 status = hermon_cmd_post(state, &cmd);
1954 1899 if (status != HERMON_CMD_SUCCESS) {
1955 1900 goto mad_ifc_fail;
1956 1901 }
1957 1902
1958 1903 /* Sync the mailbox to read the results */
1959 1904 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
1960 1905
1961 1906 /* Copy the response MAD into "resp" */
1962 1907 bcopy(mbox_info.mbi_out->mb_addr, resp, size);
1963 1908
1964 1909 mad_ifc_fail:
1965 1910 /* Free the mailbox */
1966 1911 hermon_mbox_free(state, &mbox_info);
1967 1912 return (status);
1968 1913 }
1969 1914
1970 1915
1971 1916 /*
1972 1917 * hermon_getportinfo_cmd_post()
1973 1918 * Context: Can be called from interrupt or base context.
1974 1919 */
1975 1920 int
1976 1921 hermon_getportinfo_cmd_post(hermon_state_t *state, uint_t port,
1977 1922 uint_t sleepflag, sm_portinfo_t *portinfo)
1978 1923 {
1979 1924 hermon_mbox_info_t mbox_info;
1980 1925 hermon_cmd_post_t cmd;
1981 1926 uint32_t *mbox;
1982 1927 uint_t size;
1983 1928 int status, i;
1984 1929
1985 1930 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1986 1931
1987 1932 /* Get "In" and "Out" mailboxes for the command */
1988 1933 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
1989 1934 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
1990 1935 if (status != HERMON_CMD_SUCCESS) {
1991 1936 return (status);
1992 1937 }
1993 1938
1994 1939 /* Build the GetPortInfo request MAD in the "In" mailbox */
1995 1940 size = HERMON_CMD_MAD_IFC_SIZE;
1996 1941 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
1997 1942 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
1998 1943 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
1999 1944 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2000 1945 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2001 1946 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PORTINFO);
2002 1947 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], port);
2003 1948 for (i = 6; i < (size >> 2); i++) {
2004 1949 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2005 1950 }
2006 1951
2007 1952 /* Sync the mailbox for the device to read */
2008 1953 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2009 1954
2010 1955 /* Setup the Hermon "MAD_IFC" command */
2011 1956 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2012 1957 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2013 1958 cmd.cp_inmod = port;
2014 1959 cmd.cp_opcode = MAD_IFC;
2015 1960 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */
2016 1961 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2017 1962 status = hermon_cmd_post(state, &cmd);
2018 1963 if (status != HERMON_CMD_SUCCESS) {
2019 1964 goto getportinfo_fail;
2020 1965 }
2021 1966
2022 1967 /* Sync the mailbox to read the results */
2023 1968 size = sizeof (sm_portinfo_t);
↓ open down ↓ |
812 lines elided |
↑ open up ↑ |
2024 1969 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2025 1970 size, DDI_DMA_SYNC_FORCPU);
2026 1971
2027 1972 /*
2028 1973 * Copy GetPortInfo response MAD into "portinfo". Do any endian
2029 1974 * swapping that may be necessary to flip any of the "portinfo"
2030 1975 * fields
2031 1976 */
2032 1977 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2033 1978 HERMON_CMD_MADDATA_OFFSET), portinfo, size);
2034 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*portinfo))
2035 1979 HERMON_GETPORTINFO_SWAP(portinfo);
2036 1980
2037 1981 getportinfo_fail:
2038 1982 /* Free the mailbox */
2039 1983 hermon_mbox_free(state, &mbox_info);
2040 1984 return (status);
2041 1985 }
2042 1986
2043 1987 /*
2044 1988 * hermon_is_ext_port_counters_supported()
2045 1989 *
2046 1990 * Determine weather extended port counters are supported or not by sending
2047 1991 * ClassPortInfo perf mgmt class MAD.
2048 1992 */
2049 1993 int
2050 1994 hermon_is_ext_port_counters_supported(hermon_state_t *state, uint_t port,
2051 1995 uint_t sleepflag, int *ext_width_supported)
2052 1996 {
2053 1997 hermon_mbox_info_t mbox_info;
2054 1998 hermon_cmd_post_t cmd;
2055 1999 uint64_t data;
2056 2000 uint32_t *mbox;
2057 2001 int status;
2058 2002
2059 2003 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2060 2004
2061 2005 /* Get "In" and "Out" mailboxes for the command */
2062 2006 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2063 2007 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2064 2008 if (status != HERMON_CMD_SUCCESS) {
2065 2009 return (status);
2066 2010 }
2067 2011
2068 2012 /* Build the ClassPortInfo request MAD in the "In" mailbox */
2069 2013 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2070 2014
2071 2015 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_PERF_GET);
2072 2016 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2073 2017 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2074 2018 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2075 2019 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4],
2076 2020 HERMON_CMD_CLASSPORTINFO);
2077 2021 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR);
2078 2022
2079 2023 /* Sync the mailbox for the device to read */
2080 2024 hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MAD_IFC_SIZE,
2081 2025 DDI_DMA_SYNC_FORDEV);
2082 2026
2083 2027 /* Setup the Hermon "MAD_IFC" command */
2084 2028 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2085 2029 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2086 2030 cmd.cp_inmod = port;
2087 2031 cmd.cp_opcode = MAD_IFC;
2088 2032 /* No MKey and BKey checking */
2089 2033 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK | HERMON_CMD_BKEY_DONTCHECK;
2090 2034 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2091 2035 status = hermon_cmd_post(state, &cmd);
2092 2036 if (status != HERMON_CMD_SUCCESS) {
2093 2037 goto fail;
2094 2038 }
2095 2039
2096 2040 /* Sync the mailbox to read the results */
2097 2041 hermon_mbox_sync(mbox_info.mbi_out, 0, HERMON_CMD_MAD_IFC_SIZE,
2098 2042 DDI_DMA_SYNC_FORCPU);
2099 2043
2100 2044 /*
2101 2045 * We can discard the MAD header and the reserved area of the
2102 2046 * perf mgmt class MAD
2103 2047 */
2104 2048 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2105 2049 ((uint64_t *)mbox_info.mbi_out->mb_addr + 8));
2106 2050 *ext_width_supported = (data & (HERMON_IS_EXT_WIDTH_SUPPORTED |
2107 2051 HERMON_IS_EXT_WIDTH_SUPPORTED_NOIETF)) ? 1 : 0;
2108 2052
2109 2053 fail:
2110 2054 /* Free the mailbox */
2111 2055 hermon_mbox_free(state, &mbox_info);
2112 2056 return (status);
2113 2057 }
2114 2058
2115 2059 /*
2116 2060 * hermon_getextpefcntr_cmd_post()
2117 2061 *
2118 2062 * Read the extended performance counters of the specified port and
2119 2063 * copy them into perfinfo.
2120 2064 */
2121 2065 int
2122 2066 hermon_getextperfcntr_cmd_post(hermon_state_t *state, uint_t port,
2123 2067 uint_t sleepflag, hermon_hw_sm_extperfcntr_t *perfinfo)
2124 2068 {
2125 2069 hermon_mbox_info_t mbox_info;
2126 2070 hermon_cmd_post_t cmd;
2127 2071 uint64_t data;
2128 2072 uint32_t *mbox;
2129 2073 int status, i;
2130 2074
2131 2075 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2132 2076
2133 2077 /* Get "In" and "Out" mailboxes for the command */
2134 2078 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2135 2079 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2136 2080 if (status != HERMON_CMD_SUCCESS) {
2137 2081 return (status);
2138 2082 }
2139 2083
2140 2084 /* Build PortCountersExtended request MAD in the "In" mailbox */
2141 2085 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2142 2086
2143 2087 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_PERF_GET);
2144 2088 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2145 2089 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2146 2090 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2147 2091 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4],
2148 2092 HERMON_CMD_EXTPERFCNTRS);
2149 2093 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR);
2150 2094 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16));
2151 2095
2152 2096 /* Sync the mailbox for the device to read */
2153 2097 hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MAD_IFC_SIZE,
2154 2098 DDI_DMA_SYNC_FORDEV);
2155 2099
2156 2100 /* Setup the Hermon "MAD_IFC" command */
2157 2101 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2158 2102 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2159 2103 cmd.cp_inmod = port;
2160 2104 cmd.cp_opcode = MAD_IFC;
2161 2105 /* No MKey and BKey checking */
2162 2106 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK | HERMON_CMD_BKEY_DONTCHECK;
2163 2107 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2164 2108 status = hermon_cmd_post(state, &cmd);
2165 2109 if (status != HERMON_CMD_SUCCESS) {
2166 2110 goto fail;
2167 2111 }
2168 2112
2169 2113 /* Sync the mailbox to read the results */
2170 2114 hermon_mbox_sync(mbox_info.mbi_out, 0, HERMON_CMD_MAD_IFC_SIZE,
2171 2115 DDI_DMA_SYNC_FORCPU);
2172 2116
2173 2117 /*
2174 2118 * Copy Perfcounters into "perfinfo". We can discard the MAD
2175 2119 * header and the reserved area of the perf mgmt class MAD.
2176 2120 */
2177 2121 for (i = 0; i < (sizeof (hermon_hw_sm_extperfcntr_t) >> 3); i++) {
2178 2122 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2179 2123 ((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8));
2180 2124 ((uint64_t *)(void *)perfinfo)[i] = data;
2181 2125 }
2182 2126
2183 2127 fail:
2184 2128 /* Free the mailbox */
2185 2129 hermon_mbox_free(state, &mbox_info);
2186 2130 return (status);
2187 2131 }
2188 2132
2189 2133 /*
2190 2134 * hermon_getpefcntr_cmd_post()
2191 2135 * Context: Can be called from interrupt or base context.
2192 2136 *
2193 2137 * If reset is zero, read the performance counters of the specified port and
2194 2138 * copy them into perfinfo.
2195 2139 * If reset is non-zero reset the performance counters of the specified port.
2196 2140 */
2197 2141 int
2198 2142 hermon_getperfcntr_cmd_post(hermon_state_t *state, uint_t port,
2199 2143 uint_t sleepflag, hermon_hw_sm_perfcntr_t *perfinfo, int reset)
2200 2144 {
2201 2145 hermon_mbox_info_t mbox_info;
2202 2146 hermon_cmd_post_t cmd;
2203 2147 uint64_t data;
2204 2148 uint32_t *mbox;
2205 2149 uint_t size;
2206 2150 int status, i;
2207 2151
2208 2152 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2209 2153
2210 2154 /* Get "In" and "Out" mailboxes for the command */
2211 2155 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2212 2156 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2213 2157 if (status != HERMON_CMD_SUCCESS) {
2214 2158 return (status);
2215 2159 }
2216 2160
2217 2161 /* Build the GetPortInfo request MAD in the "In" mailbox */
2218 2162 size = HERMON_CMD_MAD_IFC_SIZE;
2219 2163 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2220 2164
2221 2165 if (reset) {
2222 2166 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
2223 2167 HERMON_CMD_PERF_SET);
2224 2168 } else {
2225 2169 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
2226 2170 HERMON_CMD_PERF_GET);
2227 2171 }
2228 2172 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2229 2173 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2230 2174 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2231 2175 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PERFCNTRS);
2232 2176 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR);
2233 2177
2234 2178 if (reset) {
2235 2179 /* reset counters for XmitData, RcvData, XmitPkts, RcvPkts */
2236 2180 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16],
2237 2181 ((port << 16) | 0xf000));
2238 2182
2239 2183 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[22], 0);
2240 2184 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[23], 0);
2241 2185 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[24], 0);
2242 2186 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[25], 0);
2243 2187 } else
2244 2188 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16));
2245 2189
2246 2190 /* Sync the mailbox for the device to read */
2247 2191 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2248 2192
2249 2193 /* Setup the Hermon "MAD_IFC" command */
2250 2194 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2251 2195 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2252 2196 cmd.cp_inmod = port;
2253 2197 cmd.cp_opcode = MAD_IFC;
2254 2198 /* No MKey and BKey checking */
2255 2199 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK | HERMON_CMD_BKEY_DONTCHECK;
2256 2200 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2257 2201 status = hermon_cmd_post(state, &cmd);
2258 2202 if (status != HERMON_CMD_SUCCESS) {
2259 2203 goto getperfinfo_fail;
2260 2204 }
2261 2205
2262 2206 /* Sync the mailbox to read the results */
2263 2207 size = HERMON_CMD_MAD_IFC_SIZE;
2264 2208 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
2265 2209
2266 2210 if (reset == 0) {
2267 2211 size = sizeof (hermon_hw_sm_perfcntr_t); /* for the copy */
2268 2212 /*
2269 2213 * Copy Perfcounters into "perfinfo". We can discard the MAD
2270 2214 * header and the 8 Quadword reserved area of the PERM mgmt
2271 2215 * class MAD
2272 2216 */
2273 2217
2274 2218 for (i = 0; i < size >> 3; i++) {
2275 2219 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2276 2220 ((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8));
2277 2221 ((uint64_t *)(void *)perfinfo)[i] = data;
2278 2222 }
2279 2223 }
2280 2224
2281 2225 getperfinfo_fail:
2282 2226 /* Free the mailbox */
2283 2227 hermon_mbox_free(state, &mbox_info);
2284 2228 return (status);
2285 2229 }
2286 2230
2287 2231
2288 2232
2289 2233 /*
2290 2234 * hermon_getnodeinfo_cmd_post()
2291 2235 * Context: Can be called from interrupt or base context.
2292 2236 * (Currently called only from attach() and detach() path contexts)
2293 2237 */
2294 2238 int
2295 2239 hermon_getnodeinfo_cmd_post(hermon_state_t *state, uint_t sleepflag,
2296 2240 sm_nodeinfo_t *nodeinfo)
2297 2241 {
2298 2242 hermon_mbox_info_t mbox_info;
2299 2243 hermon_cmd_post_t cmd;
2300 2244 uint32_t *mbox;
2301 2245 uint_t size;
2302 2246 int status, i;
2303 2247
2304 2248 /* Make sure we are called with the correct flag */
2305 2249 ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN);
2306 2250
2307 2251 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2308 2252
2309 2253 /* Get "In" and "Out" mailboxes for the command */
2310 2254 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2311 2255 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2312 2256 if (status != HERMON_CMD_SUCCESS) {
2313 2257 return (status);
2314 2258 }
2315 2259
2316 2260 /* Build the GetNodeInfo request MAD into the "In" mailbox */
2317 2261 size = HERMON_CMD_MAD_IFC_SIZE;
2318 2262 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2319 2263 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2320 2264 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2321 2265 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2322 2266 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2323 2267 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_NODEINFO);
2324 2268 for (i = 5; i < (size >> 2); i++) {
2325 2269 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2326 2270 }
2327 2271
2328 2272 /* Sync the mailbox for the device to read */
2329 2273 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2330 2274
2331 2275 /* Setup the Hermon "MAD_IFC" command */
2332 2276 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2333 2277 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2334 2278 cmd.cp_inmod = 1; /* Get NodeInfo from port #1 */
2335 2279 cmd.cp_opcode = MAD_IFC;
2336 2280 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */
2337 2281 cmd.cp_flags = sleepflag;
2338 2282 status = hermon_cmd_post(state, &cmd);
2339 2283 if (status != HERMON_CMD_SUCCESS) {
2340 2284 goto getnodeinfo_fail;
2341 2285 }
2342 2286
2343 2287 /* Sync the mailbox to read the results */
2344 2288 size = sizeof (sm_nodeinfo_t);
↓ open down ↓ |
300 lines elided |
↑ open up ↑ |
2345 2289 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2346 2290 size, DDI_DMA_SYNC_FORCPU);
2347 2291
2348 2292 /*
2349 2293 * Copy GetNodeInfo response MAD into "nodeinfo". Do any endian
2350 2294 * swapping that may be necessary to flip any of the "nodeinfo"
2351 2295 * fields
2352 2296 */
2353 2297 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2354 2298 HERMON_CMD_MADDATA_OFFSET), nodeinfo, size);
2355 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*nodeinfo))
2356 2299 HERMON_GETNODEINFO_SWAP(nodeinfo);
2357 2300
2358 2301 getnodeinfo_fail:
2359 2302 /* Free the mailbox */
2360 2303 hermon_mbox_free(state, &mbox_info);
2361 2304 return (status);
2362 2305 }
2363 2306
2364 2307
2365 2308 /*
2366 2309 * hermon_getnodedesc_cmd_post()
2367 2310 * Context: Can be called from interrupt or base context.
2368 2311 * (Currently called only from attach() and detach() path contexts)
2369 2312 */
2370 2313 int
2371 2314 hermon_getnodedesc_cmd_post(hermon_state_t *state, uint_t sleepflag,
2372 2315 sm_nodedesc_t *nodedesc)
2373 2316 {
2374 2317 hermon_mbox_info_t mbox_info;
2375 2318 hermon_cmd_post_t cmd;
2376 2319 uint32_t *mbox;
2377 2320 uint_t size;
2378 2321 int status, i;
2379 2322
2380 2323 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2381 2324
2382 2325 /* Get "In" and "Out" mailboxes for the command */
2383 2326 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2384 2327 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2385 2328 if (status != HERMON_CMD_SUCCESS) {
2386 2329 return (status);
2387 2330 }
2388 2331
2389 2332 /* Build the GetNodeDesc request MAD into the "In" mailbox */
2390 2333 size = HERMON_CMD_MAD_IFC_SIZE;
2391 2334 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2392 2335 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2393 2336 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2394 2337 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2395 2338 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2396 2339 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_NODEDESC);
2397 2340 for (i = 5; i < (size >> 2); i++) {
2398 2341 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2399 2342 }
2400 2343
2401 2344 /* Sync the mailbox for the device to read */
2402 2345 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2403 2346
2404 2347 /* Setup the Hermon "MAD_IFC" command */
2405 2348 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2406 2349 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2407 2350 cmd.cp_inmod = 1; /* Get NodeDesc from port #1 */
2408 2351 cmd.cp_opcode = MAD_IFC;
2409 2352 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */
2410 2353 cmd.cp_flags = sleepflag;
2411 2354 status = hermon_cmd_post(state, &cmd);
2412 2355 if (status != HERMON_CMD_SUCCESS) {
2413 2356 goto getnodedesc_fail;
2414 2357 }
2415 2358
2416 2359 /* Sync the mailbox to read the results */
2417 2360 size = sizeof (sm_nodedesc_t);
2418 2361 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2419 2362 size, DDI_DMA_SYNC_FORCPU);
2420 2363
2421 2364 /* Copy GetNodeDesc response MAD into "nodedesc" */
2422 2365 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2423 2366 HERMON_CMD_MADDATA_OFFSET), nodedesc, size);
2424 2367
2425 2368 getnodedesc_fail:
2426 2369 /* Free the mailbox */
2427 2370 hermon_mbox_free(state, &mbox_info);
2428 2371 return (status);
2429 2372 }
2430 2373
2431 2374
2432 2375 /*
2433 2376 * hermon_getguidinfo_cmd_post()
2434 2377 * Context: Can be called from interrupt or base context.
2435 2378 */
2436 2379 int
2437 2380 hermon_getguidinfo_cmd_post(hermon_state_t *state, uint_t port,
2438 2381 uint_t guidblock, uint_t sleepflag, sm_guidinfo_t *guidinfo)
2439 2382 {
2440 2383 hermon_mbox_info_t mbox_info;
2441 2384 hermon_cmd_post_t cmd;
2442 2385 uint32_t *mbox;
2443 2386 uint_t size;
2444 2387 int status, i;
2445 2388
2446 2389 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2447 2390
2448 2391 /* Get "In" and "Out" mailboxes for the command */
2449 2392 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2450 2393 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2451 2394 if (status != HERMON_CMD_SUCCESS) {
2452 2395 return (status);
2453 2396 }
2454 2397
2455 2398 /* Build the GetGUIDInfo request MAD into the "In" mailbox */
2456 2399 size = HERMON_CMD_MAD_IFC_SIZE;
2457 2400 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2458 2401 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2459 2402 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2460 2403 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2461 2404 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2462 2405 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_GUIDINFO);
2463 2406 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], guidblock);
2464 2407 for (i = 6; i < (size >> 2); i++) {
2465 2408 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2466 2409 }
2467 2410
2468 2411 /* Sync the mailbox for the device to read */
2469 2412 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2470 2413
2471 2414 /* Setup the Hermon "MAD_IFC" command */
2472 2415 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2473 2416 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2474 2417 cmd.cp_inmod = port;
2475 2418 cmd.cp_opcode = MAD_IFC;
2476 2419 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */
2477 2420 cmd.cp_flags = sleepflag;
2478 2421 status = hermon_cmd_post(state, &cmd);
2479 2422 if (status != HERMON_CMD_SUCCESS) {
2480 2423 goto getguidinfo_fail;
2481 2424 }
2482 2425
2483 2426 /* Sync the mailbox to read the results */
↓ open down ↓ |
118 lines elided |
↑ open up ↑ |
2484 2427 size = sizeof (sm_guidinfo_t);
2485 2428 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2486 2429 size, DDI_DMA_SYNC_FORCPU);
2487 2430
2488 2431 /*
2489 2432 * Copy GetGUIDInfo response MAD into "guidinfo". Do any endian
2490 2433 * swapping that may be necessary to flip the "guidinfo" fields
2491 2434 */
2492 2435 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2493 2436 HERMON_CMD_MADDATA_OFFSET), guidinfo, size);
2494 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*guidinfo))
2495 2437 HERMON_GETGUIDINFO_SWAP(guidinfo);
2496 2438
2497 2439 getguidinfo_fail:
2498 2440 /* Free the mailbox */
2499 2441 hermon_mbox_free(state, &mbox_info);
2500 2442 return (status);
2501 2443 }
2502 2444
2503 2445
2504 2446 /*
2505 2447 * hermon_getpkeytable_cmd_post()
2506 2448 * Context: Can be called from interrupt or base context.
2507 2449 */
2508 2450 int
2509 2451 hermon_getpkeytable_cmd_post(hermon_state_t *state, uint_t port,
2510 2452 uint_t pkeyblock, uint_t sleepflag, sm_pkey_table_t *pkeytable)
2511 2453 {
2512 2454 hermon_mbox_info_t mbox_info;
2513 2455 hermon_cmd_post_t cmd;
2514 2456 uint32_t *mbox;
2515 2457 uint_t size;
2516 2458 int status, i;
2517 2459
2518 2460 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2519 2461
2520 2462 /* Get "In" and "Out" mailboxes for the command */
2521 2463 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2522 2464 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2523 2465 if (status != HERMON_CMD_SUCCESS) {
2524 2466 return (status);
2525 2467 }
2526 2468
2527 2469 /* Build the GetPkeyTable request MAD into the "In" mailbox */
2528 2470 size = HERMON_CMD_MAD_IFC_SIZE;
2529 2471 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2530 2472 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2531 2473 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2532 2474 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2533 2475 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2534 2476 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PKEYTBLE);
2535 2477 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], pkeyblock);
2536 2478 for (i = 6; i < (size >> 2); i++) {
2537 2479 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2538 2480 }
2539 2481
2540 2482 /* Sync the mailbox for the device to read */
2541 2483 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2542 2484
2543 2485 /* Setup the Hermon "MAD_IFC" command */
2544 2486 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2545 2487 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2546 2488 cmd.cp_inmod = port;
2547 2489 cmd.cp_opcode = MAD_IFC;
2548 2490 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */
2549 2491 cmd.cp_flags = sleepflag;
2550 2492 status = hermon_cmd_post(state, &cmd);
2551 2493 if (status != HERMON_CMD_SUCCESS) {
2552 2494 goto getpkeytable_fail;
2553 2495 }
2554 2496
2555 2497 /* Sync the mailbox to read the results */
↓ open down ↓ |
51 lines elided |
↑ open up ↑ |
2556 2498 size = sizeof (sm_pkey_table_t);
2557 2499 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2558 2500 size, DDI_DMA_SYNC_FORCPU);
2559 2501
2560 2502 /*
2561 2503 * Copy GetPKeyTable response MAD into "pkeytable". Do any endian
2562 2504 * swapping that may be necessary to flip the "pkeytable" fields
2563 2505 */
2564 2506 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2565 2507 HERMON_CMD_MADDATA_OFFSET), pkeytable, size);
2566 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pkeytable))
2567 2508 HERMON_GETPKEYTABLE_SWAP(pkeytable);
2568 2509
2569 2510 getpkeytable_fail:
2570 2511 /* Free the mailbox */
2571 2512 hermon_mbox_free(state, &mbox_info);
2572 2513 return (status);
2573 2514 }
2574 2515
2575 2516
2576 2517 /*
2577 2518 * hermon_write_mtt_cmd_post()
2578 2519 * Context: Can be called from interrupt or base context.
2579 2520 */
2580 2521 int
2581 2522 hermon_write_mtt_cmd_post(hermon_state_t *state, hermon_rsrc_t *mtt,
2582 2523 uint64_t start_addr, uint_t nummtt, uint_t sleepflag)
2583 2524 {
2584 2525 hermon_mbox_info_t mbox_info;
2585 2526 hermon_cmd_post_t cmd;
2586 2527 uint64_t data;
2587 2528 uint_t size;
2588 2529 int status;
2589 2530 int i;
2590 2531
2591 2532 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2592 2533
2593 2534 /* Get an "In" mailbox for the command */
2594 2535 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2595 2536 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2596 2537 if (status != HERMON_CMD_SUCCESS) {
2597 2538 return (status);
2598 2539 }
2599 2540
2600 2541 /*
2601 2542 * The WRITE_MTT command input parameter contains the 64-bit addr of
2602 2543 * the first target MTT, followed by 64 bits reserved, followed by an
2603 2544 * array of MTT entries.
2604 2545 *
2605 2546 */
2606 2547 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2607 2548 ((uint64_t *)mbox_info.mbi_in->mb_addr),
2608 2549 start_addr);
2609 2550
2610 2551 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2611 2552 ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), 0x0);
2612 2553
2613 2554 for (i = 0; i < nummtt; i++) {
2614 2555 data = ((uint64_t *)mtt->hr_addr)[i];
2615 2556 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2616 2557 ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 2), data);
2617 2558 }
2618 2559
2619 2560 /* Sync the mailbox for the device to read */
2620 2561 size = (nummtt << HERMON_MTT_SIZE_SHIFT) + HERMON_CMD_WRITEMTT_RSVD_SZ;
2621 2562 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2622 2563
2623 2564 /* Setup and post Hermon "WRITE_MTT" command */
2624 2565 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2625 2566 cmd.cp_outparm = 0;
2626 2567 cmd.cp_inmod = nummtt;
2627 2568 cmd.cp_opcode = WRITE_MTT;
2628 2569 cmd.cp_opmod = 0;
2629 2570 cmd.cp_flags = sleepflag;
2630 2571 status = hermon_cmd_post(state, &cmd);
2631 2572 if (status != HERMON_CMD_SUCCESS) {
2632 2573 cmn_err(CE_CONT, "WRITE_MTT failed (0x%x)\n", status);
2633 2574 }
2634 2575
2635 2576 /* Free the mailbox */
2636 2577 hermon_mbox_free(state, &mbox_info);
2637 2578 return (status);
2638 2579 }
2639 2580
2640 2581
2641 2582 /*
2642 2583 * hermon_sync_tpt_cmd_post()
2643 2584 * Context: Can be called from interrupt or base context.
2644 2585 */
2645 2586 int
2646 2587 hermon_sync_tpt_cmd_post(hermon_state_t *state, uint_t sleepflag)
2647 2588 {
2648 2589 hermon_cmd_post_t cmd;
2649 2590 int status;
2650 2591
2651 2592 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2652 2593
2653 2594 /* Setup and post the Hermon "SYNC_TPT" command */
2654 2595 cmd.cp_inparm = 0;
2655 2596 cmd.cp_outparm = 0;
2656 2597 cmd.cp_inmod = 0;
2657 2598 cmd.cp_opcode = SYNC_TPT;
2658 2599 cmd.cp_opmod = 0;
2659 2600 cmd.cp_flags = sleepflag;
2660 2601 status = hermon_cmd_post(state, &cmd);
2661 2602
2662 2603 return (status);
2663 2604 }
2664 2605
2665 2606 /*
2666 2607 * hermon_map_eq_cmd_post()
2667 2608 * Context: Can be called from interrupt or base context.
2668 2609 * (Currently called only from attach() and/or detach() path contexts)
2669 2610 */
2670 2611 int
2671 2612 hermon_map_eq_cmd_post(hermon_state_t *state, uint_t map, uint_t eqcindx,
2672 2613 uint64_t eqmapmask, uint_t sleepflag)
2673 2614 {
2674 2615 hermon_cmd_post_t cmd;
2675 2616 int status;
2676 2617
2677 2618 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2678 2619
2679 2620 /* Setup and post Hermon "MAP_EQ" command */
2680 2621 cmd.cp_inparm = eqmapmask;
2681 2622 cmd.cp_outparm = 0;
2682 2623 cmd.cp_inmod = eqcindx;
2683 2624 if (map != HERMON_CMD_MAP_EQ_EVT_MAP) {
2684 2625 cmd.cp_inmod |= HERMON_CMD_UNMAP_EQ_MASK;
2685 2626 }
2686 2627 cmd.cp_opcode = MAP_EQ;
2687 2628 cmd.cp_opmod = 0;
2688 2629 cmd.cp_flags = sleepflag;
2689 2630 status = hermon_cmd_post(state, &cmd);
2690 2631 return (status);
2691 2632 }
2692 2633
2693 2634
2694 2635 /*
2695 2636 * hermon_resize_cq_cmd_post()
2696 2637 * Context: Can be called from interrupt or base context.
2697 2638 */
2698 2639 int
2699 2640 hermon_resize_cq_cmd_post(hermon_state_t *state, hermon_hw_cqc_t *cqc,
2700 2641 uint_t cqcindx, uint32_t *prod_indx, uint_t sleepflag)
2701 2642 {
2702 2643 hermon_mbox_info_t mbox_info;
2703 2644 hermon_cmd_post_t cmd;
2704 2645 uint64_t data;
2705 2646 uint_t size;
2706 2647 int status, i;
2707 2648
2708 2649 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2709 2650
2710 2651 /* Get an "In" mailbox for the command */
2711 2652 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2712 2653 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2713 2654 if (status != HERMON_CMD_SUCCESS) {
2714 2655 return (status);
2715 2656 }
2716 2657
2717 2658 /* Copy the Hermon "MODIFY_CQ" command into mailbox */
2718 2659 size = sizeof (hermon_hw_cqc_t);
2719 2660 for (i = 0; i < (size >> 3); i++) {
2720 2661 data = ((uint64_t *)(void *)cqc)[i];
2721 2662 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2722 2663 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
2723 2664 }
2724 2665
2725 2666 /* Sync the mailbox for the device to read */
2726 2667 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2727 2668
2728 2669 /* Setup and post Hermon "MODIFY_CQ" command */
2729 2670 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2730 2671 cmd.cp_outparm = 0; /* resize cq */
2731 2672 cmd.cp_inmod = cqcindx;
2732 2673 cmd.cp_opcode = MODIFY_CQ;
2733 2674 cmd.cp_opmod = RESIZE_CQ;
2734 2675 cmd.cp_flags = sleepflag;
2735 2676 status = hermon_cmd_post(state, &cmd);
2736 2677
2737 2678 /*
2738 2679 * New "producer index" is returned in the upper 32 bits of
2739 2680 * command "outparam"
2740 2681 */
2741 2682 *prod_indx = (cmd.cp_outparm >> 32);
2742 2683
2743 2684 /* Free the mailbox */
2744 2685 hermon_mbox_free(state, &mbox_info);
2745 2686 return (status);
2746 2687 }
2747 2688
2748 2689
2749 2690 /*
2750 2691 * hermon_modify_cq_cmd_post()
2751 2692 * Context: Can be called from interrupt or base context.
2752 2693 */
2753 2694 int
2754 2695 hermon_modify_cq_cmd_post(hermon_state_t *state, hermon_hw_cqc_t *cqc,
2755 2696 uint_t cqcindx, uint_t opmod, uint_t sleepflag)
2756 2697 {
2757 2698 hermon_mbox_info_t mbox_info;
2758 2699 hermon_cmd_post_t cmd;
2759 2700 uint64_t data;
2760 2701 uint_t size;
2761 2702 int status, i;
2762 2703
2763 2704 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2764 2705
2765 2706 /* Get an "In" mailbox for the command */
2766 2707 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2767 2708 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2768 2709 if (status != HERMON_CMD_SUCCESS) {
2769 2710 return (status);
2770 2711 }
2771 2712
2772 2713 /* Copy the Hermon "MODIFY_CQ" command into mailbox */
2773 2714 size = sizeof (hermon_hw_cqc_t);
2774 2715 for (i = 0; i < (size >> 3); i++) {
2775 2716 data = ((uint64_t *)(void *)cqc)[i];
2776 2717 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2777 2718 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
2778 2719 }
2779 2720
2780 2721 /* Sync the mailbox for the device to read */
2781 2722 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2782 2723
2783 2724 /* Setup and post Hermon "MODIFY_CQ" command */
2784 2725 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2785 2726 cmd.cp_outparm = 0;
2786 2727 cmd.cp_inmod = cqcindx;
2787 2728 cmd.cp_opcode = MODIFY_CQ;
2788 2729 cmd.cp_opmod = (uint16_t)opmod;
2789 2730 cmd.cp_flags = sleepflag;
2790 2731 status = hermon_cmd_post(state, &cmd);
2791 2732
2792 2733 /* Free the mailbox */
2793 2734 hermon_mbox_free(state, &mbox_info);
2794 2735 return (status);
2795 2736 }
2796 2737
2797 2738
2798 2739 /*
2799 2740 * hermon_cmn_qp_cmd_post()
2800 2741 * Context: Can be called from interrupt or base context.
2801 2742 *
2802 2743 * This is the common function for posting all the various types of
2803 2744 * QP state transition related Hermon commands. Since some of the
2804 2745 * commands differ from the others in the number (and type) of arguments
2805 2746 * that each require, this routine does checks based on opcode type
2806 2747 * (explained in more detail below).
2807 2748 *
2808 2749 * Note: This common function should be used only with the following
2809 2750 * opcodes: RTS2SQD_QP, TOERR_QP, TORST_QP, RST2INIT_QP, INIT2INIT_QP,
2810 2751 * INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP, SQD2RTS_QP, and SQERR2RTS_QP.
2811 2752 */
2812 2753 int
2813 2754 hermon_cmn_qp_cmd_post(hermon_state_t *state, uint_t opcode,
2814 2755 hermon_hw_qpc_t *qp, uint_t qpindx, uint32_t opmask,
2815 2756 uint_t sleepflag)
2816 2757 {
2817 2758 hermon_mbox_info_t mbox_info;
2818 2759 hermon_cmd_post_t cmd;
2819 2760 uint64_t data, in_mapaddr, out_mapaddr;
2820 2761 uint_t size, flags, opmod;
2821 2762 int status, i;
2822 2763
2823 2764 /*
2824 2765 * Use the specified opcode type to set the appropriate parameters.
2825 2766 * Specifically, we need to set in_mapaddr, out_mapaddr, flags, and
2826 2767 * opmod (as necessary). Setting these parameters may also require
2827 2768 * us to allocate an "In" or "Out" mailbox depending on the command
2828 2769 * type.
2829 2770 */
2830 2771
2831 2772 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2832 2773
2833 2774 if (opcode == RTS2SQD_QP) {
2834 2775 /*
2835 2776 * Note: For RTS-to-SendQueueDrain state transitions we
2836 2777 * always want to request the event generation from the
2837 2778 * hardware. Though we may not notify the consumer of the
2838 2779 * drained event, the decision to forward (or not) is made
2839 2780 * later in the SQD event handler.
2840 2781 */
2841 2782 flags = HERMON_CMD_REQ_SQD_EVENT;
2842 2783
2843 2784 /*
2844 2785 * The RTS2SQD_QP command uses no "In" or "Out" mailboxes (and
2845 2786 * has no special opcode modifiers).
2846 2787 */
2847 2788 in_mapaddr = 0;
2848 2789 out_mapaddr = 0;
2849 2790 opmod = 0;
2850 2791
2851 2792 } else if (opcode == TOERR_QP) {
2852 2793 /*
2853 2794 * The TOERR_QP command uses no "In" or "Out" mailboxes, has no
2854 2795 * special opcode modifiers, and takes no special flags.
2855 2796 */
2856 2797 in_mapaddr = 0;
2857 2798 out_mapaddr = 0;
2858 2799 opmod = 0;
2859 2800 flags = 0;
2860 2801
2861 2802 } else if (opcode == TORST_QP) {
2862 2803 /*
2863 2804 * The TORST_QP command could take an "Out" mailbox, but we do
2864 2805 * not require it here. It also does not takes any special
2865 2806 * flags. It does however, take a HERMON_CMD_DIRECT_TO_RESET
2866 2807 * opcode modifier, which indicates that the transition to
2867 2808 * reset should happen without first moving the QP through the
2868 2809 * Error state (and, hence, without generating any unnecessary
2869 2810 * "flushed-in-error" completions).
2870 2811 */
2871 2812 in_mapaddr = 0;
2872 2813 out_mapaddr = 0;
2873 2814 opmod = HERMON_CMD_DIRECT_TO_RESET | HERMON_CMD_NO_OUTMBOX;
2874 2815 flags = 0;
2875 2816
2876 2817 } else {
2877 2818 /*
2878 2819 * All the other QP state transition commands (RST2INIT_QP,
2879 2820 * INIT2INIT_QP, INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP,
2880 2821 * SQD2RTS_QP, and SQERR2RTS_QP) require an "In" mailbox.
2881 2822 * None of these require any special flags or opcode modifiers.
2882 2823 */
2883 2824 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2884 2825 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2885 2826 if (status != HERMON_CMD_SUCCESS) {
2886 2827 return (status);
2887 2828 }
2888 2829 in_mapaddr = mbox_info.mbi_in->mb_mapaddr;
2889 2830 out_mapaddr = 0;
2890 2831 flags = 0;
2891 2832 opmod = 0;
2892 2833
2893 2834 /* Copy the Hermon command into the "In" mailbox */
2894 2835 size = sizeof (hermon_hw_qpc_t);
2895 2836 for (i = 0; i < (size >> 3); i++) {
2896 2837 data = ((uint64_t *)(void *)qp)[i];
2897 2838 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2898 2839 ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 1),
2899 2840 data);
2900 2841 }
2901 2842 ddi_put32(mbox_info.mbi_in->mb_acchdl,
2902 2843 ((uint32_t *)mbox_info.mbi_in->mb_addr), opmask);
2903 2844
2904 2845 /*
2905 2846 * Sync the mailbox for the device to read. We have to add
2906 2847 * eight bytes here to account for "opt_param_mask" and
2907 2848 * proper alignment.
2908 2849 */
2909 2850 hermon_mbox_sync(mbox_info.mbi_in, 0, size + 8,
2910 2851 DDI_DMA_SYNC_FORDEV);
2911 2852 }
2912 2853
2913 2854 /* Setup and post Hermon QP state transition command */
2914 2855 cmd.cp_inparm = in_mapaddr;
2915 2856 cmd.cp_outparm = out_mapaddr;
2916 2857 cmd.cp_inmod = qpindx | flags;
2917 2858 cmd.cp_opcode = (uint16_t)opcode;
2918 2859 cmd.cp_opmod = (uint16_t)opmod;
2919 2860 cmd.cp_flags = sleepflag;
2920 2861 status = hermon_cmd_post(state, &cmd);
2921 2862
2922 2863 /*
2923 2864 * If we allocated a mailbox (either an "In" or an "Out") above,
2924 2865 * then free it now before returning.
2925 2866 */
2926 2867 if ((opcode != RTS2SQD_QP) && (opcode != TOERR_QP) &&
2927 2868 (opcode != TORST_QP)) {
2928 2869 /* Free the mailbox */
2929 2870 hermon_mbox_free(state, &mbox_info);
2930 2871 }
2931 2872 return (status);
2932 2873 }
2933 2874
2934 2875
2935 2876 /*
2936 2877 * hermon_cmn_query_cmd_post()
2937 2878 * Context: Can be called from interrupt or base context.
2938 2879 *
2939 2880 * This is the common function for posting all the various types of
2940 2881 * Hermon query commands. All Hermon query commands require an "Out"
2941 2882 * mailbox to be allocated for the resulting queried data.
2942 2883 *
2943 2884 * Note: This common function should be used only with the following
2944 2885 * opcodes: QUERY_DEV_LIM, QUERY_FW, QUERY_DDR, QUERY_ADAPTER, QUERY_PORT
2945 2886 * QUERY_HCA, QUERY_MPT, QUERY_EQ, QUERY_CQ, and QUERY_QP.
2946 2887 * With support of FCoIB, this also supports QUERY_FC.
2947 2888 */
2948 2889 int
2949 2890 hermon_cmn_query_cmd_post(hermon_state_t *state, uint_t opcode, uint_t opmod,
2950 2891 uint_t queryindx, void *query, uint_t size, uint_t sleepflag)
2951 2892 {
2952 2893 hermon_mbox_info_t mbox_info;
2953 2894 hermon_cmd_post_t cmd;
2954 2895 uint64_t data;
2955 2896 uint_t offset;
2956 2897 int status, i;
2957 2898
2958 2899 bzero(&cmd, sizeof (hermon_cmd_post_t));
2959 2900
2960 2901 /* Get an "Out" mailbox for the command */
2961 2902 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
2962 2903 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2963 2904 if (status != HERMON_CMD_SUCCESS) {
2964 2905 return (status);
2965 2906 }
2966 2907
2967 2908 /* Setup and post the Hermon query command */
2968 2909 cmd.cp_inparm = 0;
2969 2910 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2970 2911 cmd.cp_inmod = queryindx;
2971 2912 cmd.cp_opcode = (uint16_t)opcode;
2972 2913 cmd.cp_opmod = (uint16_t)opmod;
2973 2914 cmd.cp_flags = sleepflag;
2974 2915 status = hermon_cmd_post(state, &cmd);
2975 2916 if (status != HERMON_CMD_SUCCESS) {
2976 2917 goto cmn_query_fail;
2977 2918 }
2978 2919
2979 2920 /* Sync the mailbox to read the results */
2980 2921 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
2981 2922
2982 2923 /*
2983 2924 * QUERY_QP is handled somewhat differently than the other query
2984 2925 * commands. For QUERY_QP, the actual queried data is offset into
2985 2926 * the mailbox (by one 64-bit word).
2986 2927 */
2987 2928 offset = (opcode == QUERY_QP) ? 1 : 0;
2988 2929
2989 2930 /* Copy query command results into "query" */
2990 2931 for (i = 0; i < (size >> 3); i++) {
2991 2932 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2992 2933 ((uint64_t *)mbox_info.mbi_out->mb_addr + i + offset));
2993 2934 ((uint64_t *)query)[i] = data;
2994 2935 }
2995 2936
2996 2937 cmn_query_fail:
2997 2938 /* Free the mailbox */
2998 2939 hermon_mbox_free(state, &mbox_info);
2999 2940 return (status);
3000 2941 }
3001 2942
3002 2943
3003 2944 /*
3004 2945 * hermon_cmn_ownership_cmd_post()
3005 2946 * Context: Can be called from interrupt or base context.
3006 2947 *
3007 2948 * This is the common function for posting all the various types of
3008 2949 * Hermon HW/SW resource ownership commands. Since some of the commands
3009 2950 * differ from the others in the direction of ownership change (i.e.
3010 2951 * from HW ownership to SW, or vice versa), they differ in the type of
3011 2952 * mailbox and specific handling that each requires. This routine does
3012 2953 * certain checks based on opcode type to determine the direction of
3013 2954 * the transition and to correctly handle the request.
3014 2955 *
3015 2956 * Note: This common function should be used only with the following
3016 2957 * opcodes: HW2SW_MPT, HW2SW_EQ, HW2SW_CQ, SW2HW_MPT, SW2HW_EQ, and
3017 2958 * SW2HW_CQ
3018 2959 */
3019 2960 int
3020 2961 hermon_cmn_ownership_cmd_post(hermon_state_t *state, uint_t opcode,
3021 2962 void *hwrsrc, uint_t size, uint_t hwrsrcindx, uint_t sleepflag)
3022 2963 {
3023 2964 hermon_mbox_info_t mbox_info;
3024 2965 hermon_cmd_post_t cmd;
3025 2966 uint64_t data, in_mapaddr, out_mapaddr;
3026 2967 uint_t direction, opmod;
3027 2968 int status, i;
3028 2969
3029 2970 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3030 2971
3031 2972 /*
3032 2973 * Determine the direction of the ownership transfer based on the
3033 2974 * provided opcode
3034 2975 */
3035 2976 if ((opcode == HW2SW_MPT) || (opcode == HW2SW_EQ) ||
3036 2977 (opcode == HW2SW_CQ) || (opcode == HW2SW_SRQ)) {
3037 2978 direction = HERMON_CMD_RSRC_HW2SW;
3038 2979
3039 2980 } else if ((opcode == SW2HW_MPT) || (opcode == SW2HW_EQ) ||
3040 2981 (opcode == SW2HW_CQ) || (opcode == SW2HW_SRQ)) {
3041 2982 direction = HERMON_CMD_RSRC_SW2HW;
3042 2983
3043 2984 } else {
3044 2985 return (HERMON_CMD_INVALID_STATUS);
3045 2986 }
3046 2987
3047 2988 /*
3048 2989 * If hwrsrc is NULL then we do not allocate a mailbox. This is used
3049 2990 * in the case of memory deregister where the out mailbox is not
3050 2991 * needed. In the case of re-register, we do use the hwrsrc.
3051 2992 *
3052 2993 * Otherwise, If ownership transfer is going from hardware to software,
3053 2994 * then allocate an "Out" mailbox. This will be filled in later as a
3054 2995 * result of the Hermon command.
3055 2996 *
3056 2997 * And if the ownership transfer is going from software to hardware,
3057 2998 * then we need an "In" mailbox, and we need to fill it in and sync it
3058 2999 * (if necessary). Then the mailbox can be passed to the Hermon
3059 3000 * firmware.
3060 3001 *
3061 3002 * For the HW2SW (dereg) case, we only use an out mbox if hwrsrc is !=
3062 3003 * NULL. This implies a re-reg, and the out mbox must be used. If
3063 3004 * hwrsrc is == NULL, then we can save some time and resources by not
3064 3005 * using an out mbox at all. We must set opmod to HERMON_CMD_DO_OUTMBOX
3065 3006 * and HERMON_CMD_NO_OUTMBOX appropriately in this case.
3066 3007 *
3067 3008 * For the SW2HW (reg) case, no out mbox is possible. We set opmod to
3068 3009 * 0 anyway, but this field is not used in this case.
3069 3010 */
3070 3011 if (direction == HERMON_CMD_RSRC_HW2SW) {
3071 3012 if (hwrsrc != NULL) {
3072 3013 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
3073 3014 status = hermon_mbox_alloc(state, &mbox_info,
3074 3015 sleepflag);
3075 3016 if (status != HERMON_CMD_SUCCESS) {
3076 3017 return (status);
3077 3018 }
3078 3019 in_mapaddr = 0;
3079 3020 out_mapaddr = mbox_info.mbi_out->mb_mapaddr;
3080 3021 opmod = HERMON_CMD_DO_OUTMBOX;
3081 3022 } else {
3082 3023 in_mapaddr = 0;
3083 3024 out_mapaddr = 0;
3084 3025 opmod = HERMON_CMD_NO_OUTMBOX;
3085 3026 }
3086 3027 } else { /* HERMON_CMD_RSRC_SW2HW */
3087 3028 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3088 3029 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3089 3030 if (status != HERMON_CMD_SUCCESS) {
3090 3031 return (status);
3091 3032 }
3092 3033
3093 3034 /* Copy the SW2HW ownership command into mailbox */
3094 3035 for (i = 0; i < (size >> 3); i++) {
3095 3036 data = ((uint64_t *)hwrsrc)[i];
3096 3037 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3097 3038 ((uint64_t *)mbox_info.mbi_in->mb_addr + i),
3098 3039 data);
3099 3040 }
3100 3041
3101 3042 /* Sync the mailbox for the device to read */
3102 3043 hermon_mbox_sync(mbox_info.mbi_in, 0, size,
3103 3044 DDI_DMA_SYNC_FORDEV);
3104 3045
3105 3046 in_mapaddr = mbox_info.mbi_in->mb_mapaddr;
3106 3047 out_mapaddr = 0;
3107 3048 opmod = 0;
3108 3049 }
3109 3050
3110 3051 /* Setup and post the Hermon ownership command */
3111 3052 cmd.cp_inparm = in_mapaddr;
3112 3053 cmd.cp_outparm = out_mapaddr;
3113 3054 cmd.cp_inmod = hwrsrcindx;
3114 3055 cmd.cp_opcode = (uint16_t)opcode;
3115 3056 cmd.cp_opmod = (uint16_t)opmod;
3116 3057 cmd.cp_flags = sleepflag;
3117 3058 status = hermon_cmd_post(state, &cmd);
3118 3059 if (status != HERMON_CMD_SUCCESS) {
3119 3060 goto cmn_ownership_fail;
3120 3061 }
3121 3062
3122 3063 /*
3123 3064 * As mentioned above, for HW2SW ownership transfers we need to
3124 3065 * sync (if necessary) and copy out the resulting data from the
3125 3066 * "Out" mailbox" (assuming the above command was successful).
3126 3067 */
3127 3068 if (direction == HERMON_CMD_RSRC_HW2SW && hwrsrc != NULL) {
3128 3069
3129 3070 /* Sync the mailbox to read the results */
3130 3071 hermon_mbox_sync(mbox_info.mbi_out, 0, size,
3131 3072 DDI_DMA_SYNC_FORCPU);
3132 3073
3133 3074 /* Copy HW2SW ownership command results into "hwrsrc" */
3134 3075 for (i = 0; i < (size >> 3); i++) {
3135 3076 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
3136 3077 ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
3137 3078 ((uint64_t *)hwrsrc)[i] = data;
3138 3079 }
3139 3080 }
3140 3081
3141 3082 cmn_ownership_fail:
3142 3083 if (hwrsrc != NULL) {
3143 3084 /* Free the mailbox */
3144 3085 hermon_mbox_free(state, &mbox_info);
3145 3086 }
3146 3087 return (status);
3147 3088 }
3148 3089
3149 3090
3150 3091 /*
3151 3092 * hermon_conf_special_qp_cmd_post()
3152 3093 * Context: Can be called from interrupt or base context.
3153 3094 */
3154 3095 /*ARGSUSED*/
3155 3096 int
3156 3097 hermon_conf_special_qp_cmd_post(hermon_state_t *state, uint_t qpindx,
3157 3098 uint_t qptype, uint_t sleepflag, uint_t opmod)
3158 3099 {
3159 3100 hermon_cmd_post_t cmd;
3160 3101 int status;
3161 3102
3162 3103 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3163 3104
3164 3105 /* Setup and post Hermon "CONF_SPECIAL_QP" command */
3165 3106 cmd.cp_inparm = 0;
3166 3107 cmd.cp_outparm = 0;
3167 3108 cmd.cp_inmod = qpindx & 0x00FFFFF8; /* mask off low 3 bits */
3168 3109 cmd.cp_opcode = CONF_SPECIAL_QP;
3169 3110 cmd.cp_opmod = (uint16_t)opmod;
3170 3111 cmd.cp_flags = sleepflag;
3171 3112 status = hermon_cmd_post(state, &cmd);
3172 3113
3173 3114 return (status);
3174 3115 }
3175 3116
3176 3117
3177 3118 /*
3178 3119 * hermon_get_heart_beat_rq_cmd_post()
3179 3120 * Context: Can be called only from kernel or interrupt context
3180 3121 */
3181 3122 int
3182 3123 hermon_get_heart_beat_rq_cmd_post(hermon_state_t *state, uint_t qpindx,
3183 3124 uint64_t *outparm)
3184 3125 {
3185 3126 hermon_cmd_post_t cmd;
3186 3127 int status;
3187 3128
3188 3129 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3189 3130
3190 3131 /* Setup and post the Hermon "HEART_BEAT_RQ" command */
3191 3132 cmd.cp_inparm = 0;
3192 3133 cmd.cp_outparm = 0;
3193 3134 cmd.cp_inmod = qpindx;
3194 3135 cmd.cp_opcode = HEART_BEAT_RQ;
3195 3136 cmd.cp_opmod = 0;
3196 3137 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3197 3138 status = hermon_cmd_post(state, &cmd);
3198 3139
3199 3140 /*
3200 3141 * Return immediate out param through argument pointer.
3201 3142 */
3202 3143 *outparm = cmd.cp_outparm;
3203 3144 return (status);
3204 3145 }
3205 3146
3206 3147
3207 3148 /*
3208 3149 * hermon_mgid_hash_cmd_post()
3209 3150 * Context: Can be called from interrupt or base context.
3210 3151 */
3211 3152 int
3212 3153 hermon_mgid_hash_cmd_post(hermon_state_t *state, uint64_t mgid_h,
3213 3154 uint64_t mgid_l, uint64_t *mgid_hash, uint_t sleepflag)
3214 3155 {
3215 3156 hermon_mbox_info_t mbox_info;
3216 3157 hermon_cmd_post_t cmd;
3217 3158 int status;
3218 3159
3219 3160 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3220 3161
3221 3162 /* Get an "In" mailbox for the command */
3222 3163 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3223 3164 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3224 3165 if (status != HERMON_CMD_SUCCESS) {
3225 3166 return (status);
3226 3167 }
3227 3168
3228 3169 /* Copy the Hermon "MGID_HASH" command into mailbox */
3229 3170 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3230 3171 ((uint64_t *)mbox_info.mbi_in->mb_addr + 0), mgid_h);
3231 3172 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3232 3173 ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), mgid_l);
3233 3174
3234 3175 /* Sync the mailbox for the device to read */
3235 3176 hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MGIDHASH_SZ,
3236 3177 DDI_DMA_SYNC_FORDEV);
3237 3178
3238 3179 /* Setup and post the Hermon "MGID_HASH" command */
3239 3180 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
3240 3181 cmd.cp_outparm = 0;
3241 3182 cmd.cp_inmod = 0;
3242 3183 cmd.cp_opcode = MGID_HASH;
3243 3184 cmd.cp_opmod = 0;
3244 3185 cmd.cp_flags = sleepflag;
3245 3186 status = hermon_cmd_post(state, &cmd);
3246 3187
3247 3188 /* MGID hash value is returned in command "outparam" */
3248 3189 *mgid_hash = cmd.cp_outparm;
3249 3190
3250 3191 /* Free the mailbox */
3251 3192 hermon_mbox_free(state, &mbox_info);
3252 3193 return (status);
3253 3194 }
3254 3195
3255 3196
3256 3197 /*
3257 3198 * hermon_read_mgm_cmd_post()
3258 3199 * Context: Can be called from interrupt or base context.
3259 3200 *
3260 3201 * Note: It is assumed that the "mcg" parameter is actually a pointer to a
3261 3202 * "hermon_hw_mcg_t" struct and some number of "hermon_hw_mcg_qp_list_t"
3262 3203 * structs. Combined size should be equal to result of HERMON_MCGMEM_SZ()
3263 3204 * macro.
3264 3205 */
3265 3206 int
3266 3207 hermon_read_mgm_cmd_post(hermon_state_t *state, hermon_hw_mcg_t *mcg,
3267 3208 uint_t mcgindx, uint_t sleepflag)
3268 3209 {
3269 3210 hermon_mbox_info_t mbox_info;
3270 3211 hermon_cmd_post_t cmd;
3271 3212 uint64_t data;
3272 3213 uint32_t data32;
3273 3214 uint_t size, hdrsz, qplistsz;
3274 3215 int status, i;
3275 3216
3276 3217 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3277 3218
3278 3219 /* Get an "Out" mailbox for the results */
3279 3220 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
3280 3221 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3281 3222 if (status != HERMON_CMD_SUCCESS) {
3282 3223 return (status);
3283 3224 }
3284 3225
3285 3226 /* Setup and post Hermon "READ_MGM" command */
3286 3227 cmd.cp_inparm = 0;
3287 3228 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
3288 3229 cmd.cp_inmod = mcgindx;
3289 3230 cmd.cp_opcode = READ_MGM;
3290 3231 cmd.cp_opmod = 0;
3291 3232 cmd.cp_flags = sleepflag;
3292 3233 status = hermon_cmd_post(state, &cmd);
3293 3234 if (status != HERMON_CMD_SUCCESS) {
3294 3235 goto read_mgm_fail;
3295 3236 }
3296 3237
3297 3238 /* Sync the mailbox to read the results */
3298 3239 size = HERMON_MCGMEM_SZ(state);
3299 3240 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
3300 3241
3301 3242 /* Copy the READ_MGM command results into "mcg" */
3302 3243 hdrsz = sizeof (hermon_hw_mcg_t);
3303 3244 for (i = 0; i < (hdrsz >> 3); i++) {
3304 3245 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
3305 3246 ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
3306 3247 ((uint64_t *)mcg)[i] = data;
3307 3248 }
3308 3249 qplistsz = size - hdrsz;
3309 3250 for (i = 0; i < (qplistsz >> 2); i++) {
3310 3251 data32 = ddi_get32(mbox_info.mbi_out->mb_acchdl,
3311 3252 ((uint32_t *)mbox_info.mbi_out->mb_addr + i + 8));
3312 3253 ((uint32_t *)mcg)[i + 8] = data32;
3313 3254 }
3314 3255
3315 3256 read_mgm_fail:
3316 3257 /* Free the mailbox */
3317 3258 hermon_mbox_free(state, &mbox_info);
3318 3259 return (status);
3319 3260 }
3320 3261
3321 3262
3322 3263 /*
3323 3264 * hermon_write_mgm_cmd_post()
3324 3265 * Context: Can be called from interrupt or base context.
3325 3266 *
3326 3267 * Note: It is assumed that the "mcg" parameter is actually a pointer to a
3327 3268 * "hermon_hw_mcg_t" struct and some number of "hermon_hw_mcg_qp_list_t"
3328 3269 * structs. Combined size should be equal to result of HERMON_MCGMEM_SZ()
3329 3270 * macro.
3330 3271 */
3331 3272 int
3332 3273 hermon_write_mgm_cmd_post(hermon_state_t *state, hermon_hw_mcg_t *mcg,
3333 3274 uint_t mcgindx, uint_t sleepflag)
3334 3275 {
3335 3276 hermon_mbox_info_t mbox_info;
3336 3277 hermon_cmd_post_t cmd;
3337 3278 uint64_t data;
3338 3279 uint_t size, hdrsz, qplistsz;
3339 3280 int status, i;
3340 3281
3341 3282 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3342 3283
3343 3284 /* Get an "In" mailbox for the command */
3344 3285 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3345 3286 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3346 3287 if (status != HERMON_CMD_SUCCESS) {
3347 3288 return (status);
3348 3289 }
3349 3290
3350 3291 /* Copy the Hermon "WRITE_MGM" command into mailbox */
3351 3292 size = HERMON_MCGMEM_SZ(state);
3352 3293 hdrsz = sizeof (hermon_hw_mcg_t);
3353 3294 for (i = 0; i < (hdrsz >> 3); i++) {
3354 3295 data = ((uint64_t *)mcg)[i];
3355 3296 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3356 3297 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3357 3298 }
3358 3299 qplistsz = size - hdrsz;
3359 3300 for (i = 0; i < (qplistsz >> 2); i++) {
3360 3301 data = ((uint32_t *)mcg)[i + 8];
3361 3302 ddi_put32(mbox_info.mbi_in->mb_acchdl,
3362 3303 ((uint32_t *)mbox_info.mbi_in->mb_addr + i + 8), data);
3363 3304 }
3364 3305
3365 3306 /* Sync the mailbox for the device to read */
3366 3307 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3367 3308
3368 3309 /* Setup and post Hermon "WRITE_MGM" command */
3369 3310 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
3370 3311 cmd.cp_outparm = 0;
3371 3312 cmd.cp_inmod = mcgindx;
3372 3313 cmd.cp_opcode = WRITE_MGM;
3373 3314 cmd.cp_opmod = 0;
3374 3315 cmd.cp_flags = sleepflag;
3375 3316 status = hermon_cmd_post(state, &cmd);
3376 3317
3377 3318 /* Free the mailbox */
3378 3319 hermon_mbox_free(state, &mbox_info);
3379 3320 return (status);
3380 3321 }
3381 3322
3382 3323 /*
3383 3324 * hermon_resize_srq_cmd_post()
3384 3325 * Context: Can be called from interrupt or base context.
3385 3326 */
3386 3327
3387 3328 int hermon_resize_srq_cmd_post(hermon_state_t *state, hermon_hw_srqc_t *srq,
3388 3329 uint_t srqnum, uint_t sleepflag)
3389 3330 {
3390 3331 hermon_mbox_info_t mbox_info;
3391 3332 hermon_cmd_post_t cmd;
3392 3333 uint64_t data;
3393 3334 uint_t size;
3394 3335 int status, i;
3395 3336
3396 3337 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3397 3338
3398 3339 /* Get an "In" mailbox for the command */
3399 3340 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3400 3341 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3401 3342 if (status != HERMON_CMD_SUCCESS) {
3402 3343 return (status);
3403 3344 }
3404 3345
3405 3346 /* Copy the Hermon "RESIZE_SRQ" command into mailbox */
3406 3347 size = sizeof (hermon_hw_srqc_t);
3407 3348 for (i = 0; i < (size >> 3); i++) {
3408 3349 data = ((uint64_t *)(void *)srq)[i];
3409 3350 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3410 3351 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3411 3352 }
3412 3353
3413 3354 /* Sync the mailbox for the device to read */
3414 3355 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3415 3356
3416 3357 /* Setup and post Hermon "RESIZE_SRQ" command */
3417 3358 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
3418 3359 cmd.cp_outparm = 0;
3419 3360 cmd.cp_inmod = srqnum;
3420 3361 cmd.cp_opcode = RESIZE_SRQ;
3421 3362 cmd.cp_opmod = 0;
3422 3363 cmd.cp_flags = sleepflag;
3423 3364 status = hermon_cmd_post(state, &cmd);
3424 3365
3425 3366 /* Free the mailbox */
3426 3367 hermon_mbox_free(state, &mbox_info);
3427 3368 return (status);
3428 3369 }
3429 3370 /*
3430 3371 * hermon_modify_mpt_cmd_post()
3431 3372 * Context: Can be called from interrupt or base context.
3432 3373 */
3433 3374 int
3434 3375 hermon_modify_mpt_cmd_post(hermon_state_t *state, hermon_hw_dmpt_t *mpt,
3435 3376 uint_t mptindx, uint_t flags, uint_t sleepflag)
3436 3377 {
3437 3378 hermon_mbox_info_t mbox_info;
3438 3379 hermon_cmd_post_t cmd;
3439 3380 uint64_t data;
3440 3381 uint_t size;
3441 3382 int status, i;
3442 3383
3443 3384 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3444 3385
3445 3386 /* Get an "In" mailbox for the command */
3446 3387 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3447 3388 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3448 3389 if (status != HERMON_CMD_SUCCESS) {
3449 3390 return (status);
3450 3391 }
3451 3392
3452 3393 /* Copy the Hermon "MODIFY_MPT" command into mailbox */
3453 3394 size = sizeof (hermon_hw_dmpt_t);
3454 3395 for (i = 0; i < (size >> 3); i++) {
3455 3396 data = ((uint64_t *)mpt)[i];
3456 3397 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3457 3398 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3458 3399 }
3459 3400
3460 3401 /* Sync the mailbox for the device to read */
3461 3402 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3462 3403
3463 3404 /* Setup and post Hermon "MODIFY_MPT" command */
3464 3405 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
3465 3406 cmd.cp_outparm = 0;
3466 3407 cmd.cp_inmod = mptindx;
3467 3408 cmd.cp_opcode = MODIFY_MPT;
3468 3409 cmd.cp_opmod = (uint16_t)flags;
3469 3410 cmd.cp_flags = sleepflag;
3470 3411 status = hermon_cmd_post(state, &cmd);
3471 3412
3472 3413 /* Free the mailbox */
3473 3414 hermon_mbox_free(state, &mbox_info);
3474 3415 return (status);
3475 3416 }
3476 3417
3477 3418
3478 3419 /*
3479 3420 * hermon_config_fc_cmd_post()
3480 3421 * Context: Can be called from user or kernel context.
3481 3422 * This can do either a basic config passing in
3482 3423 * *hermon_hw_config_fc_basic_s, or config the N_Port table.
3483 3424 * passing in pointer to an array of 32-bit id's
3484 3425 * Note that either one needs to be cast to void *
3485 3426 */
3486 3427 int
3487 3428 hermon_config_fc_cmd_post(hermon_state_t *state, void *cfginfo, int enable,
3488 3429 int selector, int n_ports, int portnum, uint_t sleepflag)
3489 3430 {
3490 3431 hermon_mbox_info_t mbox_info;
3491 3432 hermon_cmd_post_t cmd;
3492 3433 uint64_t data;
3493 3434 uint32_t portid;
3494 3435 uint_t size;
3495 3436 int status, i;
3496 3437
3497 3438 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3498 3439
3499 3440 /* Get an "In" mailbox for the command */
3500 3441 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3501 3442 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3502 3443 if (status != HERMON_CMD_SUCCESS) {
3503 3444 return (status);
3504 3445 }
3505 3446
3506 3447 /* Copy the appropriate info into mailbox */
3507 3448 if (selector == HERMON_HW_FC_CONF_BASIC) { /* basic info */
3508 3449 size = sizeof (hermon_hw_config_fc_basic_t);
3509 3450 for (i = 0; i < (size >> 3); i++) {
3510 3451 data = ((uint64_t *)cfginfo)[i];
3511 3452 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3512 3453 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3513 3454 }
3514 3455 } else { /* NPort config */
3515 3456 ASSERT(selector == HERMON_HW_FC_CONF_NPORT);
3516 3457 size = n_ports * sizeof (uint32_t);
3517 3458 /*
3518 3459 * n_ports must == number queried from card
3519 3460 *
3520 3461 * passed in is an array but for little endian needs to
3521 3462 * be rearranged in the mbox
3522 3463 */
3523 3464 for (i = 0; i < (size >> 3); i++) {
3524 3465 portid = ((uint32_t *)cfginfo)[i * 2];
3525 3466 data = (uint64_t)portid << 32;
3526 3467 if (i * 2 < n_ports) {
3527 3468 portid = ((uint32_t *)cfginfo)[i * 2 + 1];
3528 3469 data |= portid;
3529 3470 }
3530 3471 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3531 3472 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3532 3473 }
3533 3474 }
3534 3475
3535 3476 /* Sync the mailbox for the device to read */
3536 3477 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3537 3478
3538 3479 /* Setup and post Hermon "CONFIG_FC" command */
3539 3480 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
3540 3481 cmd.cp_outparm = 0;
3541 3482 cmd.cp_inmod = (uint32_t)(selector | portnum);
3542 3483 cmd.cp_opcode = CONFIG_FC;
3543 3484 cmd.cp_opmod = (uint16_t)enable;
3544 3485 cmd.cp_flags = sleepflag;
3545 3486 status = hermon_cmd_post(state, &cmd);
3546 3487
3547 3488 /* Free the mailbox */
3548 3489 hermon_mbox_free(state, &mbox_info);
3549 3490 return (status);
3550 3491 }
3551 3492
3552 3493 /*
3553 3494 * hermon_sense_port_post() - used to send protocol running on a port
3554 3495 * Context: Can be called from interrupt or base context
3555 3496 */
3556 3497
3557 3498 int
3558 3499 hermon_sense_port_post(hermon_state_t *state, uint_t portnum,
3559 3500 uint32_t *protocol)
3560 3501 {
3561 3502 hermon_cmd_post_t cmd;
3562 3503 int status;
3563 3504
3564 3505 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3565 3506
3566 3507 /* Setup and post Hermon "CMD_NOP" command */
3567 3508 cmd.cp_inparm = 0;
3568 3509 cmd.cp_outparm = 0;
3569 3510 cmd.cp_inmod = (uint32_t)portnum;
3570 3511 cmd.cp_opcode = SENSE_PORT;
3571 3512 cmd.cp_opmod = 0;
3572 3513 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3573 3514 status = hermon_cmd_post(state, &cmd);
3574 3515 if (status == HERMON_CMD_SUCCESS) *protocol = (uint32_t)cmd.cp_outparm;
3575 3516 return (status);
3576 3517 }
3577 3518
3578 3519
3579 3520 /*
3580 3521 * CONFIG_INT_MOD - used to configure INTERRUPT moderation
3581 3522 * if command fails, *health is invalid/undefined
3582 3523 */
3583 3524 int
3584 3525 hermon_config_int_mod(hermon_state_t *state, uint_t min_delay, uint_t vector)
3585 3526 {
3586 3527 hermon_cmd_post_t cmd;
3587 3528 int status;
3588 3529 uint64_t inparm = 0;
3589 3530
3590 3531 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3591 3532
3592 3533 /* Setup and post Hermon "CONFIG_INT_MOD" command */
3593 3534 inparm = (((uint64_t)min_delay & 0xFFFF) << 48) ||
3594 3535 (((uint64_t)vector & 0xFFFF) << 32);
3595 3536
3596 3537 cmd.cp_inparm = inparm;
3597 3538 cmd.cp_outparm = 0;
3598 3539 cmd.cp_inmod = 0;
3599 3540 cmd.cp_opcode = CONFIG_INT_MOD;
3600 3541 cmd.cp_opmod = 0;
3601 3542 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3602 3543 status = hermon_cmd_post(state, &cmd);
3603 3544 return (status);
3604 3545 }
3605 3546
3606 3547
3607 3548 int
3608 3549 hermon_nop_post(hermon_state_t *state, uint_t interval, uint_t sleep)
3609 3550 {
3610 3551 hermon_cmd_post_t cmd;
3611 3552 int status;
3612 3553
3613 3554 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3614 3555
3615 3556 /* Setup and post Hermon "CMD_NOP" command */
3616 3557 cmd.cp_inparm = 0;
3617 3558 cmd.cp_outparm = 0;
3618 3559 cmd.cp_inmod = interval;
3619 3560 cmd.cp_opcode = CMD_NOP;
3620 3561 cmd.cp_opmod = 0;
3621 3562 cmd.cp_flags = HERMON_CMD_SLEEP_NOSPIN;
3622 3563 if (sleep) cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3623 3564 status = hermon_cmd_post(state, &cmd);
3624 3565 return (status);
3625 3566 }
3626 3567
3627 3568 int
3628 3569 hermon_hw_health_check(hermon_state_t *state, int *health)
3629 3570 {
3630 3571 hermon_cmd_post_t cmd;
3631 3572 int status;
3632 3573
3633 3574 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3634 3575
3635 3576 /* Setup and post Hermon "CMD_NOP" command */
3636 3577 cmd.cp_inparm = 0;
3637 3578 cmd.cp_outparm = 0;
3638 3579 cmd.cp_inmod = 0;
3639 3580 cmd.cp_opcode = HW_HEALTH_CHECK;
3640 3581 cmd.cp_opmod = 0;
3641 3582 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3642 3583 status = hermon_cmd_post(state, &cmd);
3643 3584 *health = (int)cmd.cp_outparm;
3644 3585 return (status);
3645 3586 }
3646 3587
3647 3588 int
3648 3589 hermon_setdebug_post(hermon_state_t *state)
3649 3590 {
3650 3591 hermon_cmd_post_t cmd;
3651 3592 int status;
3652 3593
3653 3594 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3654 3595
3655 3596 /* Setup and post Hermon "CMD_NOP" command */
3656 3597 cmd.cp_inparm = 0xFFFFFFFFFFFFFFFF;
3657 3598 cmd.cp_outparm = 0;
3658 3599 cmd.cp_inmod = 0;
3659 3600 cmd.cp_opcode = SET_DEBUG_MSG;
3660 3601 cmd.cp_opmod = 0;
3661 3602 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3662 3603 status = hermon_cmd_post(state, &cmd);
3663 3604 return (status);
3664 3605 }
3665 3606
3666 3607
3667 3608 int
3668 3609 hermon_read_mtt_cmd_post(hermon_state_t *state, uint64_t mtt_addr,
3669 3610 hermon_hw_mtt_t *mtt)
3670 3611 {
3671 3612
3672 3613 hermon_cmd_post_t cmd;
3673 3614 hermon_mbox_info_t mbox_info;
3674 3615 int i, status;
3675 3616 uint_t size;
3676 3617 uint64_t data;
3677 3618
3678 3619 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3679 3620
3680 3621 /* Get an "Out" mailbox for the command */
3681 3622 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
3682 3623 status = hermon_mbox_alloc(state, &mbox_info, HERMON_CMD_SLEEP_NOSPIN);
3683 3624 if (status != HERMON_CMD_SUCCESS) {
3684 3625 return (status);
3685 3626 }
3686 3627
3687 3628 /* Setup and post the "READ_MTT" command */
3688 3629 cmd.cp_inparm = mtt_addr;
3689 3630 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
3690 3631 cmd.cp_inmod = 1;
3691 3632 cmd.cp_opcode = READ_MTT;
3692 3633 cmd.cp_opmod = 0;
3693 3634 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3694 3635 status = hermon_cmd_post(state, &cmd);
3695 3636 if (status != HERMON_CMD_SUCCESS) {
3696 3637 return (status);
3697 3638 }
3698 3639
3699 3640 /* Sync the mailbox to read the results */
3700 3641 size = sizeof (hermon_hw_mtt_t);
3701 3642 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
3702 3643
3703 3644 /* Copy mtt read out */
3704 3645 for (i = 0; i < (size >> 3); i++) {
3705 3646 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
3706 3647 ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
3707 3648 ((uint64_t *)(void *)mtt)[i] = data;
3708 3649 }
3709 3650
3710 3651 /* Free the mailbox */
3711 3652 hermon_mbox_free(state, &mbox_info);
3712 3653 return (status);
3713 3654 }
↓ open down ↓ |
1137 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX