49 * command word is set or a REBOOT event is sent. If we notice a reboot 50 * via these mechanisms then wait 10ms for the status word to be set. 51 */ 52#define MCDI_STATUS_SLEEP_US 10000 53 54 void 55efx_mcdi_request_start( 56 __in efx_nic_t *enp, 57 __in efx_mcdi_req_t *emrp, 58 __in boolean_t ev_cpl) 59{ 60 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 61 efx_dword_t dword; 62 unsigned int seq; 63 unsigned int xflags; 64 unsigned int pdur; 65 unsigned int dbr; 66 unsigned int pos; 67 int state; 68 69 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 70 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 71 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 72 73 switch (emip->emi_port) { 74 case 1: 75 pdur = MCDI_P1_PDU_OFST; 76 dbr = MCDI_P1_DBL_OFST; 77 break; 78 case 2: 79 pdur = MCDI_P2_PDU_OFST; 80 dbr = MCDI_P2_DBL_OFST; 81 break; 82 default: 83 EFSYS_ASSERT(0); 84 pdur = dbr = 0; 85 }; 86 87 /* 88 * efx_mcdi_request_start() is naturally serialised against both 89 * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(), 90 * by virtue of there only being one outstanding MCDI request. 91 * Unfortunately, upper layers may also call efx_mcdi_request_abort() 92 * at any time, to timeout a pending mcdi request, That request may 93 * then subsequently complete, meaning efx_mcdi_ev_cpl() or 94 * efx_mcdi_ev_death() may end up running in parallel with 95 * efx_mcdi_request_start(). This race is handled by ensuring that 96 * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the 97 * en_eslp lock. 98 */ 99 EFSYS_LOCK(enp->en_eslp, state); 100 EFSYS_ASSERT(emip->emi_pending_req == NULL); 101 emip->emi_pending_req = emrp; 102 emip->emi_ev_cpl = ev_cpl; 103 emip->emi_poll_cnt = 0; 104 seq = emip->emi_seq++ & 0xf; 105 EFSYS_UNLOCK(enp->en_eslp, state); 106 107 xflags = 0; 108 if (ev_cpl) 109 xflags |= MCDI_HEADER_XFLAGS_EVREQ; 110 111 /* Construct the header in shared memory */ 112 EFX_POPULATE_DWORD_6(dword, 113 MCDI_HEADER_CODE, emrp->emr_cmd, 114 MCDI_HEADER_RESYNC, 1, 115 MCDI_HEADER_DATALEN, emrp->emr_in_length, 116 MCDI_HEADER_SEQ, seq, 117 MCDI_HEADER_RESPONSE, 0, 118 MCDI_HEADER_XFLAGS, xflags); 119 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_TRUE); 120 121 for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) { 122 memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos), 123 MIN(sizeof (dword), emrp->emr_in_length - pos)); 124 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, 125 pdur + 1 + (pos >> 2), &dword, B_FALSE); 126 } 127 128 /* Ring the doorbell */ 129 EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xd004be11); 130 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, dbr, &dword, B_FALSE); 131} 132 133static void 134efx_mcdi_request_copyout( 135 __in efx_nic_t *enp, 136 __in efx_mcdi_req_t *emrp) 137{ 138 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 139 unsigned int pos; 140 unsigned int pdur; 141 efx_dword_t data; 142 143 pdur = (emip->emi_port == 1) ? MCDI_P1_PDU_OFST : MCDI_P2_PDU_OFST; 144 145 /* Copy payload out if caller supplied buffer */ 146 if (emrp->emr_out_buf != NULL) { 147 size_t bytes = MIN(emrp->emr_out_length_used, 148 emrp->emr_out_length); 149 for (pos = 0; pos < bytes; pos += sizeof (efx_dword_t)) { 150 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, 151 pdur + 1 + (pos >> 2), &data, B_FALSE); 152 memcpy(MCDI_OUT(*emrp, efx_dword_t, pos), &data, 153 MIN(sizeof (data), bytes - pos)); 154 } 155 } 156} 157 158static int 159efx_mcdi_request_errcode( 160 __in unsigned int err) 161{ 162 163 switch (err) { 164 case MC_CMD_ERR_ENOENT: 165 return (ENOENT); 166 case MC_CMD_ERR_EINTR: 167 return (EINTR); 168 case MC_CMD_ERR_EACCES: 169 return (EACCES); 170 case MC_CMD_ERR_EBUSY: 171 return (EBUSY); 172 case MC_CMD_ERR_EINVAL: 173 return (EINVAL); 174 case MC_CMD_ERR_EDEADLK: 175 return (EDEADLK); 176 case MC_CMD_ERR_ENOSYS: 177 return (ENOTSUP); 178 case MC_CMD_ERR_ETIME: 179 return (ETIMEDOUT); 180#ifdef WITH_MCDI_V2 181 case MC_CMD_ERR_EAGAIN: 182 return (EAGAIN); 183 case MC_CMD_ERR_ENOSPC: 184 return (ENOSPC); 185#endif 186 default: 187 EFSYS_PROBE1(mc_pcol_error, int, err); 188 return (EIO); 189 } 190} 191 192static void 193efx_mcdi_raise_exception( 194 __in efx_nic_t *enp, 195 __in_opt efx_mcdi_req_t *emrp, 196 __in int rc) 197{ 198 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 199 const efx_mcdi_transport_t *emtp = emip->emi_mtp; 200 efx_mcdi_exception_t exception; 201 202 /* Reboot or Assertion failure only */ 203 EFSYS_ASSERT(rc == EIO || rc == EINTR); 204 205 /* 206 * If MC_CMD_REBOOT causes a reboot (dependent on parameters), 207 * then the EIO is not worthy of an exception. 208 */ 209 if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO) 210 return; 211 212 exception = (rc == EIO) 213 ? EFX_MCDI_EXCEPTION_MC_REBOOT 214 : EFX_MCDI_EXCEPTION_MC_BADASSERT; 215 216 emtp->emt_exception(emtp->emt_context, exception); 217} 218 219static int 220efx_mcdi_poll_reboot( 221 __in efx_nic_t *enp) 222{ 223 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 224 unsigned int rebootr; 225 efx_dword_t dword; 226 uint32_t value; 227 228 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2); 229 rebootr = ((emip->emi_port == 1) 230 ? MCDI_P1_REBOOT_OFST 231 : MCDI_P2_REBOOT_OFST); 232 233 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE); 234 value = EFX_DWORD_FIELD(dword, EFX_DWORD_0); 235 236 if (value == 0) 237 return (0); 238 239 EFX_ZERO_DWORD(dword); 240 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE); 241 242 if (value == MC_STATUS_DWORD_ASSERT) 243 return (EINTR); 244 else 245 return (EIO); 246} 247 248 __checkReturn boolean_t 249efx_mcdi_request_poll( 250 __in efx_nic_t *enp) 251{ 252 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 253 efx_mcdi_req_t *emrp; 254 efx_dword_t dword; 255 unsigned int pdur; 256 unsigned int seq; 257 unsigned int length; 258 int state; 259 int rc; 260 261 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 262 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 263 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); 264 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 265 266 /* Serialise against post-watchdog efx_mcdi_ev* */ 267 EFSYS_LOCK(enp->en_eslp, state); 268 269 EFSYS_ASSERT(emip->emi_pending_req != NULL); 270 EFSYS_ASSERT(!emip->emi_ev_cpl); 271 emrp = emip->emi_pending_req; 272 273 /* Check for reboot atomically w.r.t efx_mcdi_request_start */ 274 if (emip->emi_poll_cnt++ == 0) { 275 if ((rc = efx_mcdi_poll_reboot(enp)) != 0) { 276 emip->emi_pending_req = NULL; 277 EFSYS_UNLOCK(enp->en_eslp, state); 278 279 goto fail1; 280 } 281 } 282 283 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2); 284 pdur = (emip->emi_port == 1) ? MCDI_P1_PDU_OFST : MCDI_P2_PDU_OFST; 285 286 /* Read the command header */ 287 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_FALSE); 288 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_RESPONSE) == 0) { 289 EFSYS_UNLOCK(enp->en_eslp, state); 290 return (B_FALSE); 291 } 292 293 /* Request complete */ 294 emip->emi_pending_req = NULL; 295 seq = (emip->emi_seq - 1) & 0xf; 296 297 /* Check for synchronous reboot */ 298 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR) != 0 && 299 EFX_DWORD_FIELD(dword, MCDI_HEADER_DATALEN) == 0) { 300 /* Consume status word */ 301 EFSYS_SPIN(MCDI_STATUS_SLEEP_US); 302 efx_mcdi_poll_reboot(enp); 303 EFSYS_UNLOCK(enp->en_eslp, state); 304 rc = EIO; 305 goto fail2; 306 } 307 308 EFSYS_UNLOCK(enp->en_eslp, state); 309 310 /* Check that the returned data is consistent */ 311 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_CODE) != emrp->emr_cmd || 312 EFX_DWORD_FIELD(dword, MCDI_HEADER_SEQ) != seq) { 313 /* Response is for a different request */ 314 rc = EIO; 315 goto fail3; 316 } 317 318 length = EFX_DWORD_FIELD(dword, MCDI_HEADER_DATALEN); 319 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR)) { 320 efx_dword_t errdword; 321 int errcode; 322 323 EFSYS_ASSERT3U(length, ==, 4); 324 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, 325 pdur + 1 + (MC_CMD_ERR_CODE_OFST >> 2), 326 &errdword, B_FALSE); 327 errcode = EFX_DWORD_FIELD(errdword, EFX_DWORD_0); 328 rc = efx_mcdi_request_errcode(errcode); 329 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd, int, errcode); 330 goto fail4; 331 332 } else { 333 emrp->emr_out_length_used = length; 334 emrp->emr_rc = 0; 335 efx_mcdi_request_copyout(enp, emrp); 336 } 337 338 goto out; 339 340fail4: 341 EFSYS_PROBE(fail4); 342fail3: 343 EFSYS_PROBE(fail3); 344fail2: 345 EFSYS_PROBE(fail2); 346fail1: 347 EFSYS_PROBE1(fail1, int, rc); 348 349 /* Fill out error state */ 350 emrp->emr_rc = rc; 351 emrp->emr_out_length_used = 0; 352 353 /* Reboot/Assertion */ 354 if (rc == EIO || rc == EINTR) 355 efx_mcdi_raise_exception(enp, emrp, rc); 356 357out: 358 return (B_TRUE); 359} 360 361 void 362efx_mcdi_execute( 363 __in efx_nic_t *enp, 364 __in efx_mcdi_req_t *emrp) 365{ 366 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 367 const efx_mcdi_transport_t *emtp = emip->emi_mtp; 368 369 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 370 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); 371 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 372 373 emtp->emt_execute(emtp->emt_context, emrp); 374} 375 376 void 377efx_mcdi_ev_cpl( 378 __in efx_nic_t *enp, 379 __in unsigned int seq, 380 __in unsigned int outlen, 381 __in int errcode) 382{ 383 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 384 const efx_mcdi_transport_t *emtp = emip->emi_mtp; 385 efx_mcdi_req_t *emrp; 386 int state; 387 388 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 389 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); 390 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 391 392 /* 393 * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start() 394 * when we're completing an aborted request. 395 */ 396 EFSYS_LOCK(enp->en_eslp, state); 397 if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl || 398 (seq != ((emip->emi_seq - 1) & 0xf))) { 399 EFSYS_ASSERT(emip->emi_aborted > 0); 400 if (emip->emi_aborted > 0) 401 --emip->emi_aborted; 402 EFSYS_UNLOCK(enp->en_eslp, state); 403 return; 404 } 405 406 emrp = emip->emi_pending_req; 407 emip->emi_pending_req = NULL; 408 EFSYS_UNLOCK(enp->en_eslp, state); 409 410 /* 411 * Fill out the remaining hdr fields, and copyout the payload 412 * if the user supplied an output buffer. 413 */ 414 if (errcode != 0) { 415 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd, 416 int, errcode); 417 emrp->emr_out_length_used = 0; 418 emrp->emr_rc = efx_mcdi_request_errcode(errcode); 419 } else { 420 emrp->emr_out_length_used = outlen; 421 emrp->emr_rc = 0; 422 efx_mcdi_request_copyout(enp, emrp); 423 } 424 425 emtp->emt_ev_cpl(emtp->emt_context); 426} 427 428 void 429efx_mcdi_ev_death( 430 __in efx_nic_t *enp, 431 __in int rc) 432{ 433 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 434 const efx_mcdi_transport_t *emtp = emip->emi_mtp; 435 efx_mcdi_req_t *emrp = NULL; 436 boolean_t ev_cpl; 437 int state; 438 439 /* 440 * The MCDI request (if there is one) has been terminated, either 441 * by a BADASSERT or REBOOT event. 442 * 443 * If there is an outstanding event-completed MCDI operation, then we 444 * will never receive the completion event (because both MCDI 445 * completions and BADASSERT events are sent to the same evq). So 446 * complete this MCDI op. 447 * 448 * This function might run in parallel with efx_mcdi_request_poll() 449 * for poll completed mcdi requests, and also with 450 * efx_mcdi_request_start() for post-watchdog completions. 451 */ 452 EFSYS_LOCK(enp->en_eslp, state); 453 emrp = emip->emi_pending_req; 454 ev_cpl = emip->emi_ev_cpl; 455 if (emrp != NULL && emip->emi_ev_cpl) { 456 emip->emi_pending_req = NULL; 457 458 emrp->emr_out_length_used = 0; 459 emrp->emr_rc = rc; 460 ++emip->emi_aborted; 461 } 462
|
465 * status word before dropping the lock. 466 */ 467 if (rc == EIO || rc == EINTR) { 468 EFSYS_SPIN(MCDI_STATUS_SLEEP_US); 469 (void) efx_mcdi_poll_reboot(enp); 470 } 471 472 EFSYS_UNLOCK(enp->en_eslp, state); 473 474 efx_mcdi_raise_exception(enp, emrp, rc); 475 476 if (emrp != NULL && ev_cpl) 477 emtp->emt_ev_cpl(emtp->emt_context); 478} 479 480 __checkReturn int 481efx_mcdi_version( 482 __in efx_nic_t *enp, 483 __out_ecount_opt(4) uint16_t versionp[4], 484 __out_opt uint32_t *buildp, 485 __out_opt efx_mcdi_boot_t *statusp) 486{ 487 uint8_t outbuf[MAX(MC_CMD_GET_VERSION_OUT_LEN, 488 MC_CMD_GET_BOOT_STATUS_OUT_LEN)]; 489 efx_mcdi_req_t req; 490 efx_word_t *ver_words; 491 uint16_t version[4]; 492 uint32_t build; 493 efx_mcdi_boot_t status; 494 int rc; 495 496 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); 497 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 498 499 EFX_STATIC_ASSERT(MC_CMD_GET_VERSION_IN_LEN == 0); 500 req.emr_cmd = MC_CMD_GET_VERSION; 501 req.emr_in_buf = NULL; 502 req.emr_in_length = 0; 503 req.emr_out_buf = outbuf; 504 req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN; 505 506 efx_mcdi_execute(enp, &req); 507 508 if (req.emr_rc != 0) { 509 rc = req.emr_rc; 510 goto fail1; 511 } 512 513 /* bootrom support */ 514 if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) { 515 version[0] = version[1] = version[2] = version[3] = 0; 516 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 517 518 goto version; 519 } 520 521 if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) { 522 rc = EMSGSIZE; 523 goto fail2; 524 } 525 526 ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION); 527 version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0); 528 version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0); 529 version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0); 530 version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0); 531 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 532 533version: 534 /* The bootrom doesn't understand BOOT_STATUS */ 535 if (build == MC_CMD_GET_VERSION_OUT_FIRMWARE_BOOTROM) { 536 status = EFX_MCDI_BOOT_ROM; 537 goto out; 538 } 539 540 req.emr_cmd = MC_CMD_GET_BOOT_STATUS; 541 EFX_STATIC_ASSERT(MC_CMD_GET_BOOT_STATUS_IN_LEN == 0); 542 req.emr_in_buf = NULL; 543 req.emr_in_length = 0; 544 req.emr_out_buf = outbuf; 545 req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN; 546 547 efx_mcdi_execute(enp, &req); 548 549 if (req.emr_rc != 0) { 550 rc = req.emr_rc; 551 goto fail3; 552 } 553 554 if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) { 555 rc = EMSGSIZE; 556 goto fail4; 557 } 558 559 if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS, 560 GET_BOOT_STATUS_OUT_FLAGS_PRIMARY)) 561 status = EFX_MCDI_BOOT_PRIMARY; 562 else 563 status = EFX_MCDI_BOOT_SECONDARY; 564 565out: 566 if (versionp != NULL) 567 memcpy(versionp, version, sizeof (version)); 568 if (buildp != NULL) 569 *buildp = build; 570 if (statusp != NULL) 571 *statusp = status; 572 573 return (0); 574 575fail4: 576 EFSYS_PROBE(fail4); 577fail3: 578 EFSYS_PROBE(fail3); 579fail2: 580 EFSYS_PROBE(fail2); 581fail1: 582 EFSYS_PROBE1(fail1, int, rc); 583 584 return (rc); 585} 586 587 __checkReturn int 588efx_mcdi_init( 589 __in efx_nic_t *enp, 590 __in const efx_mcdi_transport_t *mtp) 591{ 592 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 593 efx_oword_t oword; 594 unsigned int portnum; 595 int rc; 596 597 EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); 598 enp->en_mod_flags |= EFX_MOD_MCDI; 599 600 if (enp->en_family == EFX_FAMILY_FALCON) 601 return (0); 602 603 emip->emi_mtp = mtp; 604 605 /* Determine the port number to use for MCDI */ 606 EFX_BAR_READO(enp, FR_AZ_CS_DEBUG_REG, &oword); 607 portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM); 608 609 if (portnum == 0) { 610 /* Presumably booted from ROM; only MCDI port 1 will work */ 611 emip->emi_port = 1; 612 } else if (portnum <= 2) { 613 emip->emi_port = portnum; 614 } else { 615 rc = EINVAL; 616 goto fail1; 617 } 618 619 /* 620 * Wipe the atomic reboot status so subsequent MCDI requests succeed. 621 * BOOT_STATUS is preserved so eno_nic_probe() can boot out of the 622 * assertion handler. 623 */ 624 (void) efx_mcdi_poll_reboot(enp); 625 626 return (0); 627 628fail1: 629 EFSYS_PROBE1(fail1, int, rc); 630 631 enp->en_mod_flags &= ~EFX_MOD_MCDI; 632 633 return (rc); 634} 635 636 637 __checkReturn int 638efx_mcdi_reboot( 639 __in efx_nic_t *enp) 640{ 641 uint8_t payload[MC_CMD_REBOOT_IN_LEN]; 642 efx_mcdi_req_t req; 643 int rc; 644 645 /* 646 * We could require the caller to have caused en_mod_flags=0 to 647 * call this function. This doesn't help the other port though, 648 * who's about to get the MC ripped out from underneath them. 649 * Since they have to cope with the subsequent fallout of MCDI 650 * failures, we should as well. 651 */ 652 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 653 654 req.emr_cmd = MC_CMD_REBOOT; 655 req.emr_in_buf = payload; 656 req.emr_in_length = MC_CMD_REBOOT_IN_LEN; 657 req.emr_out_buf = NULL; 658 req.emr_out_length = 0; 659 660 MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS, 0); 661 662 efx_mcdi_execute(enp, &req); 663 664 /* Invert EIO */ 665 if (req.emr_rc != EIO) { 666 rc = EIO; 667 goto fail1; 668 } 669 670 return (0); 671 672fail1: 673 EFSYS_PROBE1(fail1, int, rc); 674 675 return (rc); 676} 677 678 __checkReturn boolean_t 679efx_mcdi_request_abort( 680 __in efx_nic_t *enp) 681{ 682 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 683 efx_mcdi_req_t *emrp; 684 boolean_t aborted; 685 int state; 686 687 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); 688 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 689 690 /* 691 * efx_mcdi_ev_* may have already completed this event, and be 692 * spinning/blocked on the upper layer lock. So it *is* legitimate 693 * to for emi_pending_req to be NULL. If there is a pending event 694 * completed request, then provide a "credit" to allow 695 * efx_mcdi_ev_cpl() to accept a single spurious completion. 696 */ 697 EFSYS_LOCK(enp->en_eslp, state); 698 emrp = emip->emi_pending_req; 699 aborted = (emrp != NULL); 700 if (aborted) { 701 emip->emi_pending_req = NULL; 702 703 /* Error the request */ 704 emrp->emr_out_length_used = 0; 705 emrp->emr_rc = ETIMEDOUT; 706 707 /* Provide a credit for seqno/emr_pending_req mismatches */ 708 if (emip->emi_ev_cpl) 709 ++emip->emi_aborted; 710 711 /* 712 * The upper layer has called us, so we don't 713 * need to complete the request. 714 */ 715 } 716 EFSYS_UNLOCK(enp->en_eslp, state); 717 718 return (aborted); 719} 720 721 void 722efx_mcdi_fini( 723 __in efx_nic_t *enp) 724{ 725 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 726 727 EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI); 728 enp->en_mod_flags &= ~EFX_MOD_MCDI; 729 730 if (~(enp->en_features) & EFX_FEATURE_MCDI) 731 return; 732 733 emip->emi_mtp = NULL; 734 emip->emi_port = 0; 735 emip->emi_aborted = 0; 736} 737 738#endif /* EFSYS_OPT_MCDI */
|