1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This file contains functions that are called via interrupts. 28 */ 29 30 #include <sys/scsi/adapters/pmcs/pmcs.h> 31 32 #ifdef DEBUG 33 #define VALID_IOMB_CHECK(p, w, m, b, c) \ 34 if (!(w & PMCS_IOMB_VALID)) { \ 35 char l[64]; \ 36 (void) snprintf(l, sizeof (l), \ 37 "%s: INVALID IOMB (oq_ci=%u oq_pi=%u)", __func__, b, c); \ 38 pmcs_print_entry(pwp, PMCS_PRT_DEBUG, l, m); \ 39 STEP_OQ_ENTRY(pwp, PMCS_OQ_EVENTS, b, 1); \ 40 continue; \ 41 } 42 #define WRONG_OBID_CHECK(pwp, w, q) \ 43 if (((w & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT) != q) { \ 44 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, \ 45 "%s: COMPLETION WITH WRONG OBID (0x%x)", __func__, \ 46 (w & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT); \ 47 } 48 #else 49 #define VALID_IOMB_CHECK(a, b, c, d, e) 50 #define WRONG_OBID_CHECK(a, b, c) 51 #endif 52 53 #define OQLIM_CHECK(p, l) \ 54 if (++l == (p)->ioq_depth) { \ 55 pmcs_prt(p, PMCS_PRT_DEBUG, NULL, NULL, \ 56 "%s: possible ob queue overflow", \ 57 __func__); \ 58 break; \ 59 } 60 61 #define COPY_OUTBOUND(p, w, l, n, a, x, q, c) \ 62 n = ((w & PMCS_IOMB_BC_MASK) >> PMCS_IOMB_BC_SHIFT); \ 63 a = PMCS_QENTRY_SIZE; \ 64 (void) memcpy(l, x, PMCS_QENTRY_SIZE); \ 65 if (n > 1) { \ 66 a <<= 1; \ 67 (void) memcpy(&l[PMCS_QENTRY_SIZE], \ 68 GET_OQ_ENTRY(p, q, c, 1), PMCS_QENTRY_SIZE); \ 69 } \ 70 pmcs_prt(p, PMCS_PRT_DEBUG3, NULL, NULL, \ 71 "%s: ptr %p ci %d w0 %x nbuf %d", \ 72 __func__, (void *)x, ci, w0, n) 73 74 #define EVT_PRT(hwp, msg, phy) \ 75 pmcs_prt(hwp, PMCS_PRT_INFO, NULL, NULL, "Phy 0x%x: %s", phy, # msg) 76 77 78 /* 79 * Map the link rate reported in the event to the SAS link rate value 80 */ 81 static uint8_t 82 pmcs_link_rate(uint32_t event_link_rate) 83 { 84 uint8_t sas_link_rate = 0; 85 86 switch (event_link_rate) { 87 case 1: 88 sas_link_rate = SAS_LINK_RATE_1_5GBIT; 89 break; 90 case 2: 91 sas_link_rate = SAS_LINK_RATE_3GBIT; 92 break; 93 case 4: 94 sas_link_rate = SAS_LINK_RATE_6GBIT; 95 break; 96 } 97 98 return (sas_link_rate); 99 } 100 101 /* 102 * Called with pwrk lock 103 */ 104 static void 105 pmcs_complete_work(pmcs_hw_t *pwp, pmcwork_t *pwrk, uint32_t *iomb, size_t amt) 106 { 107 #ifdef DEBUG 108 pwp->ltime[pwp->lti] = gethrtime(); 109 pwp->ltags[pwp->lti++] = pwrk->htag; 110 #endif 111 pwrk->htag |= PMCS_TAG_DONE; 112 113 /* 114 * If the command has timed out, leave it in that state. 115 */ 116 if (pwrk->state != PMCS_WORK_STATE_TIMED_OUT) { 117 pwrk->state = PMCS_WORK_STATE_INTR; 118 } 119 120 pmcs_complete_work_impl(pwp, pwrk, iomb, amt); 121 } 122 123 static void 124 pmcs_work_not_found(pmcs_hw_t *pwp, uint32_t htag, uint32_t *iomb) 125 { 126 #ifdef DEBUG 127 int i; 128 hrtime_t now; 129 char buf[64]; 130 131 (void) snprintf(buf, sizeof (buf), 132 "unable to find work structure for tag 0x%x", htag); 133 134 pmcs_print_entry(pwp, PMCS_PRT_DEBUG, buf, iomb); 135 if (htag == 0) { 136 return; 137 } 138 now = gethrtime(); 139 for (i = 0; i < 256; i++) { 140 mutex_enter(&pwp->dbglock); 141 if (pwp->ltags[i] == htag) { 142 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 143 "same tag already completed (%llu us ago)", 144 (unsigned long long) (now - pwp->ltime[i])); 145 } 146 if (pwp->ftags[i] == htag) { 147 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 148 "same tag started (line %d) (%llu ns ago)", 149 pwp->ftag_lines[i], (unsigned long long) 150 (now - pwp->ftime[i])); 151 } 152 mutex_exit(&pwp->dbglock); 153 } 154 #else 155 char buf[64]; 156 (void) snprintf(buf, sizeof (buf), 157 "unable to find work structure for tag 0x%x", htag); 158 pmcs_print_entry(pwp, PMCS_PRT_DEBUG, buf, iomb); 159 #endif 160 } 161 162 163 static void 164 pmcs_process_io_completion(pmcs_hw_t *pwp, pmcs_iocomp_cb_t *ioccb, size_t amt) 165 { 166 pmcwork_t *pwrk; 167 uint32_t tag_type; 168 uint32_t htag = LE_32(((uint32_t *)((void *)ioccb->iomb))[1]); 169 170 pwrk = pmcs_tag2wp(pwp, htag); 171 if (pwrk == NULL) { 172 pmcs_work_not_found(pwp, htag, (void *)&ioccb->iomb); 173 kmem_cache_free(pwp->iocomp_cb_cache, ioccb); 174 return; 175 } 176 177 pwrk->htag |= PMCS_TAG_DONE; 178 179 /* 180 * If the command has timed out, leave it in that state. 181 */ 182 if (pwrk->state != PMCS_WORK_STATE_TIMED_OUT) { 183 pwrk->state = PMCS_WORK_STATE_INTR; 184 } 185 186 /* 187 * Some SATA and SAS commands are run in "WAIT" mode. 188 * We can tell this from the tag type. In this case, 189 * we just do a wakeup (not a callback). 190 */ 191 tag_type = PMCS_TAG_TYPE(pwrk->htag); 192 if (tag_type == PMCS_TAG_TYPE_WAIT) { 193 ASSERT(PMCS_TAG_TYPE(pwrk->htag) == PMCS_TAG_TYPE_WAIT); 194 if (pwrk->arg && amt) { 195 (void) memcpy(pwrk->arg, ioccb->iomb, amt); 196 } 197 cv_signal(&pwrk->sleep_cv); 198 mutex_exit(&pwrk->lock); 199 kmem_cache_free(pwp->iocomp_cb_cache, ioccb); 200 return; 201 } 202 ASSERT(tag_type == PMCS_TAG_TYPE_CBACK); 203 204 #ifdef DEBUG 205 pwp->ltime[pwp->lti] = gethrtime(); 206 pwp->ltags[pwp->lti++] = pwrk->htag; 207 #endif 208 209 ioccb->pwrk = pwrk; 210 211 /* 212 * Only update state to IOCOMPQ if we were in the INTR state. 213 * Any other state (e.g. TIMED_OUT, ABORTED) needs to remain. 214 */ 215 if (pwrk->state == PMCS_WORK_STATE_INTR) { 216 pwrk->state = PMCS_WORK_STATE_IOCOMPQ; 217 } 218 219 mutex_enter(&pwp->cq_lock); 220 if (pwp->iocomp_cb_tail) { 221 pwp->iocomp_cb_tail->next = ioccb; 222 pwp->iocomp_cb_tail = ioccb; 223 } else { 224 pwp->iocomp_cb_head = ioccb; 225 pwp->iocomp_cb_tail = ioccb; 226 } 227 ioccb->next = NULL; 228 mutex_exit(&pwp->cq_lock); 229 230 mutex_exit(&pwrk->lock); 231 /* Completion queue will be run at end of pmcs_iodone_intr */ 232 } 233 234 235 static void 236 pmcs_process_completion(pmcs_hw_t *pwp, void *iomb, size_t amt) 237 { 238 pmcwork_t *pwrk; 239 uint32_t htag = LE_32(((uint32_t *)iomb)[1]); 240 241 pwrk = pmcs_tag2wp(pwp, htag); 242 if (pwrk == NULL) { 243 pmcs_work_not_found(pwp, htag, iomb); 244 return; 245 } 246 247 pmcs_complete_work(pwp, pwrk, iomb, amt); 248 /* 249 * The pwrk lock is now released 250 */ 251 } 252 253 static void 254 pmcs_kill_port(pmcs_hw_t *pwp, int portid) 255 { 256 pmcs_phy_t *pptr = pwp->ports[portid]; 257 258 if (pptr == NULL) { 259 return; 260 } 261 262 /* 263 * Clear any subsidiary phys 264 */ 265 mutex_enter(&pwp->lock); 266 267 for (pptr = pwp->root_phys; pptr; pptr = pptr->sibling) { 268 pmcs_lock_phy(pptr); 269 if (pptr->link_rate && pptr->portid == portid && 270 pptr->subsidiary) { 271 pmcs_clear_phy(pwp, pptr); 272 } 273 pmcs_unlock_phy(pptr); 274 } 275 276 pptr = pwp->ports[portid]; 277 pwp->ports[portid] = NULL; 278 mutex_exit(&pwp->lock); 279 280 pmcs_lock_phy(pptr); 281 pmcs_kill_changed(pwp, pptr, 0); 282 pmcs_unlock_phy(pptr); 283 284 RESTART_DISCOVERY(pwp); 285 pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "PortID 0x%x Cleared", portid); 286 } 287 288 void 289 pmcs_process_sas_hw_event(pmcs_hw_t *pwp, void *iomb, size_t amt) 290 { 291 uint32_t w1 = LE_32(((uint32_t *)iomb)[1]); 292 uint32_t w3 = LE_32(((uint32_t *)iomb)[3]); 293 char buf[32]; 294 uint8_t phynum = IOP_EVENT_PHYNUM(w1); 295 uint8_t portid = IOP_EVENT_PORTID(w1); 296 pmcs_iport_t *iport; 297 pmcs_phy_t *pptr, *subphy, *tphyp; 298 int need_ack = 0; 299 int primary; 300 301 switch (IOP_EVENT_EVENT(w1)) { 302 case IOP_EVENT_PHY_STOP_STATUS: 303 if (IOP_EVENT_STATUS(w1)) { 304 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 305 "PORT %d failed to stop (0x%x)", 306 phynum, IOP_EVENT_STATUS(w1)); 307 } else { 308 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, 309 "PHY 0x%x Stopped", phynum); 310 mutex_enter(&pwp->lock); 311 pptr = pwp->root_phys + phynum; 312 pmcs_lock_phy(pptr); 313 mutex_exit(&pwp->lock); 314 if (pptr->configured) { 315 pmcs_kill_changed(pwp, pptr, 0); 316 } else { 317 pmcs_set_changed(pwp, pptr, B_TRUE, 0); 318 } 319 pmcs_unlock_phy(pptr); 320 RESTART_DISCOVERY(pwp); 321 } 322 /* Reposition htag to the 'expected' position. */ 323 ((uint32_t *)iomb)[1] = ((uint32_t *)iomb)[2]; 324 pmcs_process_completion(pwp, iomb, amt); 325 break; 326 case IOP_EVENT_SAS_PHY_UP: 327 { 328 static const uint8_t sas_identify_af_endian_xfvec[] = { 329 0x5c, 0x5a, 0x56, 0x00 330 }; 331 pmcs_phy_t *rp; 332 sas_identify_af_t af; 333 334 /* 335 * If we're not at running state, don't do anything 336 */ 337 mutex_enter(&pwp->lock); 338 if (pwp->state != STATE_RUNNING) { 339 mutex_exit(&pwp->lock); 340 break; 341 } 342 pptr = pwp->root_phys + phynum; 343 pmcs_lock_phy(pptr); 344 345 rp = pwp->ports[portid]; 346 347 /* rp and pptr may be the same */ 348 if (rp && (rp != pptr)) { 349 pmcs_lock_phy(rp); 350 } 351 mutex_exit(&pwp->lock); 352 353 pmcs_endian_transform(pwp, &af, &((uint32_t *)iomb)[4], 354 sas_identify_af_endian_xfvec); 355 356 /* Copy the remote address into our phy handle */ 357 (void) memcpy(pptr->sas_address, af.sas_address, 8); 358 359 /* 360 * Check to see if there is a PortID already active. 361 */ 362 if (rp) { 363 if (rp->portid != portid) { 364 if (rp != pptr) { 365 pmcs_unlock_phy(rp); 366 } 367 pmcs_unlock_phy(pptr); 368 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 369 "PortID 0x%x: PHY 0x%x SAS LINK UP IS FOR " 370 "A DIFFERENT PORTID 0x%x", rp->portid, 371 phynum, portid); 372 break; 373 } 374 375 /* 376 * If the dtype isn't NOTHING, then this is actually 377 * the primary PHY for this port. It probably went 378 * down and came back up, so be sure not to mark it 379 * as a subsidiary. 380 */ 381 if (pptr->dtype == NOTHING) { 382 pptr->subsidiary = 1; 383 } 384 pptr->link_rate = 385 pmcs_link_rate(IOP_EVENT_LINK_RATE(w1)); 386 pptr->portid = portid; 387 pptr->dead = 0; 388 389 if (pptr != rp) { 390 pmcs_unlock_phy(pptr); 391 } 392 393 rp->width = IOP_EVENT_NPIP(w3); 394 395 /* Add this PHY to the phymap */ 396 if (sas_phymap_phy_add(pwp->hss_phymap, phynum, 397 pwp->sas_wwns[0], 398 pmcs_barray2wwn(pptr->sas_address)) != 399 DDI_SUCCESS) { 400 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 401 "Unable to add phy %u for 0x%" PRIx64 ".0x%" 402 PRIx64, phynum, pwp->sas_wwns[rp->phynum], 403 pmcs_barray2wwn(pptr->sas_address)); 404 } 405 406 /* Get our iport, if attached, and set it up */ 407 if (pptr != rp) { 408 pmcs_lock_phy(pptr); 409 } 410 iport = pmcs_get_iport_by_phy(pwp, pptr); 411 if (iport) { 412 pptr->iport = iport; 413 primary = !pptr->subsidiary; 414 415 mutex_enter(&iport->lock); 416 if (primary) { 417 iport->pptr = pptr; 418 } 419 if (iport->ua_state == UA_ACTIVE) { 420 pmcs_add_phy_to_iport(iport, pptr); 421 } 422 mutex_exit(&iport->lock); 423 pmcs_rele_iport(iport); 424 } 425 426 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, 427 "PortID 0x%x: PHY 0x%x SAS LINK UP WIDENS PORT " 428 "TO %d PHYS", portid, phynum, rp->width); 429 430 if (pptr != rp) { 431 pmcs_unlock_phy(pptr); 432 } 433 pmcs_unlock_phy(rp); 434 break; 435 } 436 437 /* 438 * Check to see if anything is here already 439 */ 440 if (pptr->dtype != NOTHING && pptr->configured) { 441 pmcs_unlock_phy(pptr); 442 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 443 "PortID 0x%x: SAS PHY 0x%x UP HITS EXISTING " 444 "CONFIGURED TREE", portid, phynum); 445 break; 446 } 447 448 if (af.address_frame_type != SAS_AF_IDENTIFY) { 449 pmcs_unlock_phy(pptr); 450 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 451 "SAS link up on phy 0x%x, " 452 "but unexpected frame type 0x%x found", phynum, 453 af.address_frame_type); 454 break; 455 } 456 pptr->width = IOP_EVENT_NPIP(w3); 457 pptr->portid = portid; 458 pptr->dead = 0; 459 pptr->link_rate = pmcs_link_rate(IOP_EVENT_LINK_RATE(w1)); 460 461 /* 462 * Check to see whether this is an expander or an endpoint 463 */ 464 switch (af.device_type) { 465 case SAS_IF_DTYPE_ENDPOINT: 466 pptr->pend_dtype = SAS; 467 pptr->dtype = SAS; 468 break; 469 case SAS_IF_DTYPE_EDGE: 470 case SAS_IF_DTYPE_FANOUT: 471 pptr->pend_dtype = EXPANDER; 472 pptr->dtype = EXPANDER; 473 break; 474 default: 475 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 476 "unknown device type 0x%x", af.device_type); 477 pptr->pend_dtype = NOTHING; 478 pptr->dtype = NOTHING; 479 break; 480 } 481 482 /* 483 * If this is a direct-attached SAS drive, do the spinup 484 * release now. 485 */ 486 if (pptr->dtype == SAS) { 487 pptr->spinup_hold = 1; 488 pmcs_spinup_release(pwp, pptr); 489 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL, 490 "Release spinup hold on PHY 0x%x", phynum); 491 } 492 493 pmcs_set_changed(pwp, pptr, B_TRUE, 0); 494 if (pptr->width > 1) { 495 pmcs_prt(pwp, PMCS_PRT_INFO, pptr, NULL, 496 "PortID 0x%x: PHY 0x%x SAS" 497 " LINK UP @ %s Gb with %d phys/s", portid, phynum, 498 pmcs_get_rate(pptr->link_rate), pptr->width); 499 } else { 500 pmcs_prt(pwp, PMCS_PRT_INFO, pptr, NULL, 501 "PortID 0x%x: PHY 0x%x SAS" 502 " LINK UP @ %s Gb/s", portid, phynum, 503 pmcs_get_rate(pptr->link_rate)); 504 } 505 pmcs_unlock_phy(pptr); 506 507 /* Add this PHY to the phymap */ 508 if (sas_phymap_phy_add(pwp->hss_phymap, phynum, 509 pwp->sas_wwns[0], 510 pmcs_barray2wwn(pptr->sas_address)) != DDI_SUCCESS) { 511 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 512 "Unable to add phy %u for 0x%" PRIx64 ".0x%" 513 PRIx64, phynum, pwp->sas_wwns[pptr->phynum], 514 pmcs_barray2wwn(pptr->sas_address)); 515 } 516 517 /* Get a pointer to our iport and set it up if attached */ 518 pmcs_lock_phy(pptr); 519 iport = pmcs_get_iport_by_phy(pwp, pptr); 520 if (iport) { 521 pptr->iport = iport; 522 primary = !pptr->subsidiary; 523 524 mutex_enter(&iport->lock); 525 if (primary) { 526 iport->pptr = pptr; 527 } 528 if (iport->ua_state == UA_ACTIVE) { 529 pmcs_add_phy_to_iport(iport, pptr); 530 } 531 mutex_exit(&iport->lock); 532 pmcs_rele_iport(iport); 533 } 534 535 pmcs_smhba_log_sysevent(pwp, ESC_SAS_PHY_EVENT, 536 SAS_PHY_ONLINE, pptr); 537 pmcs_unlock_phy(pptr); 538 539 mutex_enter(&pwp->lock); 540 pwp->ports[portid] = pptr; 541 mutex_exit(&pwp->lock); 542 RESTART_DISCOVERY(pwp); 543 544 break; 545 } 546 case IOP_EVENT_SATA_PHY_UP: 547 /* 548 * If we're not at running state, don't do anything 549 */ 550 mutex_enter(&pwp->lock); 551 if (pwp->state != STATE_RUNNING) { 552 mutex_exit(&pwp->lock); 553 break; 554 } 555 556 /* 557 * Check to see if anything is here already 558 */ 559 pmcs_lock_phy(pwp->root_phys + phynum); 560 pptr = pwp->root_phys + phynum; 561 mutex_exit(&pwp->lock); 562 563 if (pptr->dtype != NOTHING && pptr->configured) { 564 pmcs_unlock_phy(pptr); 565 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 566 "PortID 0x%x: SATA PHY 0x%x" 567 " UP HITS EXISTING CONFIGURED TREE", 568 portid, phynum); 569 break; 570 } 571 572 pptr->width = 1; 573 pptr->dead = 0; 574 575 /* 576 * Install the PHY number in the least significant byte 577 * with a NAA=3 (locally assigned address) in the most 578 * significant nubble. 579 * 580 * Later, we'll either use that or dig a 581 * WWN out of words 108..111. 582 */ 583 pptr->sas_address[0] = 0x30; 584 pptr->sas_address[1] = 0; 585 pptr->sas_address[2] = 0; 586 pptr->sas_address[3] = 0; 587 pptr->sas_address[4] = 0; 588 pptr->sas_address[5] = 0; 589 pptr->sas_address[6] = 0; 590 pptr->sas_address[7] = phynum; 591 pptr->portid = portid; 592 pptr->link_rate = pmcs_link_rate(IOP_EVENT_LINK_RATE(w1)); 593 pptr->dtype = SATA; 594 pmcs_set_changed(pwp, pptr, B_TRUE, 0); 595 pmcs_prt(pwp, PMCS_PRT_INFO, pptr, NULL, 596 "PortID 0x%x: PHY 0x%x SATA LINK UP @ %s Gb/s", 597 pptr->portid, phynum, pmcs_get_rate(pptr->link_rate)); 598 pmcs_unlock_phy(pptr); 599 600 /* Add this PHY to the phymap */ 601 if (sas_phymap_phy_add(pwp->hss_phymap, phynum, 602 pwp->sas_wwns[0], 603 pmcs_barray2wwn(pptr->sas_address)) != DDI_SUCCESS) { 604 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 605 "Unable to add phy %u for 0x%" PRIx64 ".0x%" 606 PRIx64, phynum, pwp->sas_wwns[pptr->phynum], 607 pmcs_barray2wwn(pptr->sas_address)); 608 } 609 610 /* Get our iport, if attached, and set it up */ 611 pmcs_lock_phy(pptr); 612 iport = pmcs_get_iport_by_phy(pwp, pptr); 613 if (iport) { 614 pptr->iport = iport; 615 616 mutex_enter(&iport->lock); 617 iport->pptr = pptr; 618 if (iport->ua_state == UA_ACTIVE) { 619 pmcs_add_phy_to_iport(iport, pptr); 620 ASSERT(iport->nphy == 1); 621 iport->nphy = 1; 622 } 623 mutex_exit(&iport->lock); 624 pmcs_rele_iport(iport); 625 } 626 627 pmcs_smhba_log_sysevent(pwp, ESC_SAS_PHY_EVENT, 628 SAS_PHY_ONLINE, pptr); 629 pmcs_unlock_phy(pptr); 630 631 mutex_enter(&pwp->lock); 632 pwp->ports[pptr->portid] = pptr; 633 mutex_exit(&pwp->lock); 634 RESTART_DISCOVERY(pwp); 635 break; 636 637 case IOP_EVENT_SATA_SPINUP_HOLD: 638 tphyp = (pmcs_phy_t *)(pwp->root_phys + phynum); 639 /* 640 * No need to lock the entire tree for this 641 */ 642 mutex_enter(&tphyp->phy_lock); 643 tphyp->spinup_hold = 1; 644 pmcs_spinup_release(pwp, tphyp); 645 mutex_exit(&tphyp->phy_lock); 646 break; 647 case IOP_EVENT_PHY_DOWN: 648 /* 649 * If we're not at running state, don't do anything 650 */ 651 mutex_enter(&pwp->lock); 652 if (pwp->state != STATE_RUNNING) { 653 mutex_exit(&pwp->lock); 654 break; 655 } 656 pptr = pwp->ports[portid]; 657 658 subphy = pwp->root_phys + phynum; 659 /* 660 * subphy is a pointer to the PHY corresponding to the incoming 661 * event. pptr points to the primary PHY for the corresponding 662 * port. So, subphy and pptr may or may not be the same PHY, 663 * but that doesn't change what we need to do with each. 664 */ 665 ASSERT(subphy); 666 mutex_exit(&pwp->lock); 667 668 if (pptr == NULL) { 669 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 670 "PortID 0x%x: PHY 0x%x LINK DOWN- no portid ptr", 671 portid, phynum); 672 break; 673 } 674 if (IOP_EVENT_PORT_STATE(w3) == IOP_EVENT_PS_NIL) { 675 pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, 676 "PortID 0x%x: PHY 0x%x NOT VALID YET", 677 portid, phynum); 678 need_ack = 1; 679 break; 680 } 681 if (IOP_EVENT_PORT_STATE(w3) == IOP_EVENT_PS_IN_RESET) { 682 pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, 683 "PortID 0x%x: PHY 0x%x IN RESET", 684 portid, phynum); 685 break; 686 } 687 if (IOP_EVENT_PORT_STATE(w3) == IOP_EVENT_PS_LOSTCOMM) { 688 pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, 689 "PortID 0x%x: PHY 0x%x TEMPORARILY DOWN", 690 portid, phynum); 691 need_ack = 1; 692 break; 693 } 694 695 if (IOP_EVENT_PORT_STATE(w3) == IOP_EVENT_PS_VALID) { 696 /* 697 * Drop port width on the primary phy handle 698 * No need to lock the entire tree for this 699 */ 700 mutex_enter(&pptr->phy_lock); 701 pptr->width = IOP_EVENT_NPIP(w3); 702 mutex_exit(&pptr->phy_lock); 703 704 /* Clear the iport reference on the subphy */ 705 mutex_enter(&subphy->phy_lock); 706 iport = subphy->iport; 707 subphy->iport = NULL; 708 mutex_exit(&subphy->phy_lock); 709 710 /* 711 * If the iport was set on this phy, decrement its 712 * nphy count and remove this phy from the phys list. 713 */ 714 if (iport) { 715 mutex_enter(&iport->lock); 716 pmcs_remove_phy_from_iport(iport, subphy); 717 mutex_exit(&iport->lock); 718 } 719 720 pmcs_lock_phy(subphy); 721 if (subphy->subsidiary) 722 pmcs_clear_phy(pwp, subphy); 723 pmcs_unlock_phy(subphy); 724 725 /* Remove this PHY from the phymap */ 726 if (sas_phymap_phy_rem(pwp->hss_phymap, phynum) != 727 DDI_SUCCESS) { 728 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 729 "Unable to remove phy %u for 0x%" PRIx64 730 ".0x%" PRIx64, phynum, 731 pwp->sas_wwns[pptr->phynum], 732 pmcs_barray2wwn((pwp->root_phys + 733 pptr->phynum)-> sas_address)); 734 } 735 736 pmcs_prt(pwp, PMCS_PRT_INFO, pptr, NULL, 737 "PortID 0x%x: PHY 0x%x LINK DOWN NARROWS PORT " 738 "TO %d PHYS", portid, phynum, pptr->width); 739 break; 740 } 741 if (IOP_EVENT_PORT_STATE(w3) != IOP_EVENT_PS_INVALID) { 742 pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, 743 "PortID 0x%x: PHY 0x%x LINK DOWN NOT HANDLED " 744 "(state 0x%x)", portid, phynum, 745 IOP_EVENT_PORT_STATE(w3)); 746 need_ack = 1; 747 break; 748 } 749 /* Remove this PHY from the phymap */ 750 if (sas_phymap_phy_rem(pwp->hss_phymap, phynum) != 751 DDI_SUCCESS) { 752 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 753 "Unable to remove phy %u for 0x%" PRIx64 754 ".0x%" PRIx64, phynum, 755 pwp->sas_wwns[pptr->phynum], 756 pmcs_barray2wwn( 757 (pwp->root_phys + pptr->phynum)->sas_address)); 758 } 759 760 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 761 "PortID 0x%x: PHY 0x%x LINK DOWN (port invalid)", 762 portid, phynum); 763 764 /* 765 * Last PHY on the port. 766 * Assumption: pptr and subphy are both "valid" 767 * 768 * Drop port width on the primary phy handle 769 * Report the event while we've got the lock 770 */ 771 mutex_enter(&pptr->phy_lock); 772 pptr->width = 0; 773 pmcs_smhba_log_sysevent(pwp, ESC_SAS_PHY_EVENT, 774 SAS_PHY_OFFLINE, pptr); 775 mutex_exit(&pptr->phy_lock); 776 777 /* Clear the iport reference on the subphy */ 778 mutex_enter(&subphy->phy_lock); 779 iport = subphy->iport; 780 subphy->iport = NULL; 781 mutex_exit(&subphy->phy_lock); 782 783 /* 784 * If the iport was set on this phy, decrement its 785 * nphy count and remove this phy from the phys list. 786 * Also, clear the iport's pptr as this port is now 787 * down. 788 */ 789 if (iport) { 790 mutex_enter(&iport->lock); 791 pmcs_remove_phy_from_iport(iport, subphy); 792 iport->pptr = NULL; 793 iport->ua_state = UA_PEND_DEACTIVATE; 794 mutex_exit(&iport->lock); 795 } 796 797 pmcs_lock_phy(subphy); 798 if (subphy->subsidiary) 799 pmcs_clear_phy(pwp, subphy); 800 pmcs_unlock_phy(subphy); 801 802 /* 803 * Since we're now really dead, it's time to clean up. 804 */ 805 pmcs_kill_port(pwp, portid); 806 need_ack = 1; 807 808 break; 809 case IOP_EVENT_BROADCAST_CHANGE: 810 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, 811 "PortID 0x%x: PHY 0x%x Broadcast Change", portid, phynum); 812 need_ack = 1; 813 mutex_enter(&pwp->lock); 814 pptr = pwp->ports[portid]; 815 if (pptr) { 816 pmcs_lock_phy(pptr); 817 if (pptr->phynum == phynum) { 818 pmcs_set_changed(pwp, pptr, B_TRUE, 0); 819 } 820 pmcs_smhba_log_sysevent(pwp, ESC_SAS_HBA_PORT_BROADCAST, 821 SAS_PORT_BROADCAST_CHANGE, pptr); 822 pmcs_unlock_phy(pptr); 823 } 824 mutex_exit(&pwp->lock); 825 RESTART_DISCOVERY(pwp); 826 break; 827 case IOP_EVENT_BROADCAST_SES: 828 EVT_PRT(pwp, IOP_EVENT_BROADCAST_SES, phynum); 829 mutex_enter(&pwp->lock); 830 pptr = pwp->ports[portid]; 831 mutex_exit(&pwp->lock); 832 if (pptr) { 833 pmcs_lock_phy(pptr); 834 pmcs_smhba_log_sysevent(pwp, ESC_SAS_HBA_PORT_BROADCAST, 835 SAS_PORT_BROADCAST_SES, pptr); 836 pmcs_unlock_phy(pptr); 837 } 838 break; 839 case IOP_EVENT_PHY_ERR_INBOUND_CRC: 840 { 841 char buf[32]; 842 (void) snprintf(buf, sizeof (buf), "Inbound PHY CRC error"); 843 need_ack = 1; 844 break; 845 } 846 case IOP_EVENT_HARD_RESET_RECEIVED: 847 EVT_PRT(pwp, IOP_EVENT_HARD_RESET_RECEIVED, phynum); 848 break; 849 case IOP_EVENT_EVENT_ID_FRAME_TIMO: 850 EVT_PRT(pwp, IOP_EVENT_EVENT_ID_FRAME_TIMO, phynum); 851 break; 852 case IOP_EVENT_BROADCAST_EXP: 853 pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, 854 "PortID 0x%x: PHY 0x%x Broadcast Exp Change", 855 portid, phynum); 856 /* 857 * Comparing Section 6.8.1.4 of SMHBA (rev 7) spec and Section 858 * 7.2.3 of SAS2 (Rev 15) spec, 859 * _BROADCAST_EXPANDER event corresponds to _D01_4 primitive 860 */ 861 mutex_enter(&pwp->lock); 862 pptr = pwp->ports[portid]; 863 mutex_exit(&pwp->lock); 864 if (pptr) { 865 pmcs_lock_phy(pptr); 866 pmcs_smhba_log_sysevent(pwp, ESC_SAS_HBA_PORT_BROADCAST, 867 SAS_PORT_BROADCAST_D01_4, pptr); 868 pmcs_unlock_phy(pptr); 869 } 870 break; 871 case IOP_EVENT_PHY_START_STATUS: 872 switch (IOP_EVENT_STATUS(w1)) { 873 case IOP_PHY_START_OK: 874 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, 875 "PHY 0x%x Started", phynum); 876 break; 877 case IOP_PHY_START_ALREADY: 878 pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, 879 "PHY 0x%x Started (Already)", phynum); 880 break; 881 case IOP_PHY_START_INVALID: 882 pmcs_prt(pwp, PMCS_PRT_WARN, NULL, NULL, 883 "PHY 0x%x failed to start (invalid phy)", phynum); 884 break; 885 case IOP_PHY_START_ERROR: 886 pmcs_prt(pwp, PMCS_PRT_WARN, NULL, NULL, 887 "PHY 0x%x Start Error", phynum); 888 break; 889 default: 890 pmcs_prt(pwp, PMCS_PRT_WARN, NULL, NULL, 891 "PHY 0x%x failed to start (0x%x)", phynum, 892 IOP_EVENT_STATUS(w1)); 893 break; 894 } 895 /* Reposition htag to the 'expected' position. */ 896 ((uint32_t *)iomb)[1] = ((uint32_t *)iomb)[2]; 897 pmcs_process_completion(pwp, iomb, amt); 898 break; 899 case IOP_EVENT_PHY_ERR_INVALID_DWORD: 900 need_ack = 1; 901 EVT_PRT(pwp, IOP_EVENT_PHY_ERR_INVALID_DWORD, phynum); 902 break; 903 case IOP_EVENT_PHY_ERR_DISPARITY_ERROR: 904 need_ack = 1; 905 EVT_PRT(pwp, IOP_EVENT_PHY_ERR_DISPARITY_ERROR, phynum); 906 break; 907 case IOP_EVENT_PHY_ERR_CODE_VIOLATION: 908 need_ack = 1; 909 EVT_PRT(pwp, IOP_EVENT_PHY_ERR_CODE_VIOLATION, phynum); 910 break; 911 case IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN: 912 need_ack = 1; 913 EVT_PRT(pwp, IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN, phynum); 914 break; 915 case IOP_EVENT_PHY_ERR_PHY_RESET_FAILD: 916 need_ack = 1; 917 EVT_PRT(pwp, IOP_EVENT_PHY_ERR_PHY_RESET_FAILD, phynum); 918 break; 919 case IOP_EVENT_PORT_RECOVERY_TIMER_TMO: 920 EVT_PRT(pwp, IOP_EVENT_PORT_RECOVERY_TIMER_TMO, phynum); 921 break; 922 case IOP_EVENT_PORT_RECOVER: 923 EVT_PRT(pwp, IOP_EVENT_PORT_RECOVER, phynum); 924 break; 925 case IOP_EVENT_PORT_INVALID: 926 mutex_enter(&pwp->lock); 927 if (pwp->state != STATE_RUNNING) { 928 mutex_exit(&pwp->lock); 929 break; 930 } 931 mutex_exit(&pwp->lock); 932 pmcs_kill_port(pwp, portid); 933 pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, 934 "PortID 0x%x: PORT Now Invalid", portid); 935 break; 936 case IOP_EVENT_PORT_RESET_TIMER_TMO: 937 EVT_PRT(pwp, IOP_EVENT_PORT_RESET_TIMER_TMO, phynum); 938 break; 939 case IOP_EVENT_PORT_RESET_COMPLETE: 940 EVT_PRT(pwp, IOP_EVENT_PORT_RESET_COMPLETE, phynum); 941 break; 942 case IOP_EVENT_BROADCAST_ASYNC_EVENT: 943 EVT_PRT(pwp, IOP_EVENT_BROADCAST_ASYNC_EVENT, phynum); 944 /* 945 * Comparing Section 6.8.1.4 of SMHBA (rev 7) spec and Section 946 * 7.2.3 of SAS2 (Rev 15) spec, 947 * _BROADCAST_ASYNC event corresponds to _D04_7 primitive 948 */ 949 mutex_enter(&pwp->lock); 950 pptr = pwp->ports[portid]; 951 mutex_exit(&pwp->lock); 952 if (pptr) { 953 pmcs_lock_phy(pptr); 954 pmcs_smhba_log_sysevent(pwp, ESC_SAS_HBA_PORT_BROADCAST, 955 SAS_PORT_BROADCAST_D04_7, pptr); 956 pmcs_unlock_phy(pptr); 957 } 958 break; 959 default: 960 (void) snprintf(buf, sizeof (buf), 961 "unknown SAS H/W Event PHY 0x%x", phynum); 962 pmcs_print_entry(pwp, PMCS_PRT_DEBUG, buf, iomb); 963 break; 964 } 965 if (need_ack) { 966 mutex_enter(&pwp->lock); 967 /* 968 * Don't lock the entire tree for this. Just grab the mutex 969 * on the root PHY. 970 */ 971 tphyp = pwp->root_phys + phynum; 972 mutex_enter(&tphyp->phy_lock); 973 tphyp->hw_event_ack = w1; 974 mutex_exit(&tphyp->phy_lock); 975 mutex_exit(&pwp->lock); 976 pmcs_ack_events(pwp); 977 } 978 } 979 980 static void 981 pmcs_process_echo_completion(pmcs_hw_t *pwp, void *iomb, size_t amt) 982 { 983 echo_test_t fred; 984 pmcwork_t *pwrk; 985 uint32_t *msg = iomb, htag = LE_32(msg[1]); 986 pwrk = pmcs_tag2wp(pwp, htag); 987 if (pwrk) { 988 (void) memcpy(&fred, &((uint32_t *)iomb)[2], sizeof (fred)); 989 fred.ptr[0]++; 990 msg[2] = LE_32(PMCOUT_STATUS_OK); 991 pmcs_complete_work(pwp, pwrk, msg, amt); 992 } else { 993 pmcs_print_entry(pwp, PMCS_PRT_DEBUG, 994 "ECHO completion with no work structure", iomb); 995 } 996 } 997 998 static void 999 pmcs_process_ssp_event(pmcs_hw_t *pwp, void *iomb, size_t amt) 1000 { 1001 _NOTE(ARGUNUSED(amt)); 1002 uint32_t status, htag, *w; 1003 pmcwork_t *pwrk; 1004 pmcs_phy_t *phyp = NULL; 1005 char *path; 1006 1007 w = iomb; 1008 htag = LE_32(w[1]); 1009 status = LE_32(w[2]); 1010 1011 1012 pwrk = pmcs_tag2wp(pwp, htag); 1013 if (pwrk == NULL) { 1014 path = "????"; 1015 } else { 1016 phyp = pwrk->phy; 1017 path = pwrk->phy->path; 1018 } 1019 1020 if (status != PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED) { 1021 char buf[20]; 1022 const char *emsg = pmcs_status_str(status); 1023 1024 if (emsg == NULL) { 1025 (void) snprintf(buf, sizeof (buf), "Status 0x%x", 1026 status); 1027 emsg = buf; 1028 } 1029 pmcs_prt(pwp, PMCS_PRT_DEBUG, phyp, NULL, "%s: Bad SAS Status " 1030 "(tag 0x%x) %s on %s", __func__, htag, emsg, path); 1031 if (pwrk != NULL) { 1032 /* 1033 * There may be pending command on a target device. 1034 * Or, it may be a double fault. 1035 */ 1036 pmcs_start_ssp_event_recovery(pwp, pwrk, iomb, amt); 1037 } 1038 } else { 1039 pmcs_prt(pwp, PMCS_PRT_DEBUG2, phyp, NULL, 1040 "%s: tag %x put onto the wire for %s", 1041 __func__, htag, path); 1042 if (pwrk) { 1043 pwrk->onwire = 1; 1044 mutex_exit(&pwrk->lock); 1045 } 1046 } 1047 } 1048 1049 static void 1050 pmcs_process_sata_event(pmcs_hw_t *pwp, void *iomb, size_t amt) 1051 { 1052 _NOTE(ARGUNUSED(amt)); 1053 pmcwork_t *pwrk = NULL; 1054 pmcs_phy_t *pptr; 1055 uint32_t status, htag, *w; 1056 char *path; 1057 1058 w = iomb; 1059 htag = LE_32(w[1]); 1060 status = LE_32(w[2]); 1061 1062 /* 1063 * If the status is PMCOUT_STATUS_XFER_ERROR_ABORTED_NCQ_MODE, 1064 * we have to issue a READ LOG EXT ATA (page 0x10) command 1065 * to the device. In this case, htag is not valid. 1066 * 1067 * If the status is PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED, we're 1068 * just noting that an I/O got put onto the wire. 1069 * 1070 * Othewise, other errors are indicative that things need to 1071 * be aborted. 1072 */ 1073 path = NULL; 1074 if (htag) { 1075 pwrk = pmcs_tag2wp(pwp, htag); 1076 if (pwrk) { 1077 pmcs_lock_phy(pwrk->phy); 1078 pptr = pwrk->phy; 1079 path = pptr->path; 1080 } 1081 } 1082 if (path == NULL) { 1083 mutex_enter(&pwp->lock); 1084 pptr = pmcs_find_phy_by_devid(pwp, LE_32(w[4])); 1085 /* This PHY is now locked */ 1086 mutex_exit(&pwp->lock); 1087 if (pptr) { 1088 path = pptr->path; 1089 } else { 1090 path = "????"; 1091 } 1092 } 1093 1094 if (status != PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED) { 1095 char buf[20]; 1096 const char *emsg = pmcs_status_str(status); 1097 1098 ASSERT(pptr != NULL); 1099 if (emsg == NULL) { 1100 (void) snprintf(buf, sizeof (buf), "Status 0x%x", 1101 status); 1102 emsg = buf; 1103 } 1104 if (status == PMCOUT_STATUS_XFER_ERROR_ABORTED_NCQ_MODE) { 1105 ASSERT(pptr != NULL); 1106 pptr->need_rl_ext = 1; 1107 htag = 0; 1108 } else { 1109 pptr->abort_pending = 1; 1110 } 1111 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 1112 "%s: Bad SATA Status (tag 0x%x) %s on %s", 1113 __func__, htag, emsg, path); 1114 SCHEDULE_WORK(pwp, PMCS_WORK_ABORT_HANDLE); 1115 /* 1116 * Unlike SSP devices, we let the abort we 1117 * schedule above force the completion of 1118 * problem commands. 1119 */ 1120 if (pwrk) { 1121 mutex_exit(&pwrk->lock); 1122 } 1123 } else if (status == PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED) { 1124 pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, NULL, 1125 "%s: tag %x put onto the wire for %s", 1126 __func__, htag, path); 1127 if (pwrk) { 1128 pwrk->onwire = 1; 1129 mutex_exit(&pwrk->lock); 1130 } 1131 } 1132 1133 if (pptr) { 1134 pmcs_unlock_phy(pptr); 1135 } 1136 } 1137 1138 static void 1139 pmcs_process_abort_completion(pmcs_hw_t *pwp, void *iomb, size_t amt) 1140 { 1141 pmcs_phy_t *pptr; 1142 struct pmcwork *pwrk; 1143 uint32_t htag = LE_32(((uint32_t *)iomb)[1]); 1144 uint32_t status = LE_32(((uint32_t *)iomb)[2]); 1145 uint32_t scp = LE_32(((uint32_t *)iomb)[3]) & 0x1; 1146 char *path; 1147 1148 pwrk = pmcs_tag2wp(pwp, htag); 1149 if (pwrk == NULL) { 1150 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 1151 "%s: cannot find work structure for ABORT", __func__); 1152 return; 1153 } 1154 1155 pptr = pwrk->phy; 1156 if (pptr) { 1157 pmcs_lock_phy(pptr); 1158 pptr->abort_pending = 0; 1159 pptr->abort_sent = 0; 1160 1161 /* 1162 * Don't do this if the status was ABORT_IN_PROGRESS and 1163 * the scope bit was set 1164 */ 1165 if ((status != PMCOUT_STATUS_IO_ABORT_IN_PROGRESS) || !scp) { 1166 pptr->abort_all_start = 0; 1167 cv_signal(&pptr->abort_all_cv); 1168 } 1169 path = pptr->path; 1170 pmcs_unlock_phy(pptr); 1171 } else { 1172 path = "(no phy)"; 1173 } 1174 1175 switch (status) { 1176 case PMCOUT_STATUS_OK: 1177 if (scp) { 1178 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 1179 "%s: abort all succeeded for %s. (htag=0x%x)", 1180 __func__, path, htag); 1181 } else { 1182 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 1183 "%s: abort tag 0x%x succeeded for %s. (htag=0x%x)", 1184 __func__, pwrk->abt_htag, path, htag); 1185 } 1186 break; 1187 1188 case PMCOUT_STATUS_IO_NOT_VALID: 1189 if (scp) { 1190 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 1191 "%s: ABORT %s failed (DEV NOT VALID) for %s. " 1192 "(htag=0x%x)", __func__, scp ? "all" : "tag", 1193 path, htag); 1194 } else { 1195 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 1196 "%s: ABORT %s failed (I/O NOT VALID) for %s. " 1197 "(htag=0x%x)", __func__, scp ? "all" : "tag", 1198 path, htag); 1199 } 1200 break; 1201 1202 case PMCOUT_STATUS_IO_ABORT_IN_PROGRESS: 1203 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, "%s: ABORT %s failed " 1204 "for %s, htag 0x%x (ABORT IN PROGRESS)", __func__, 1205 scp ? "all" : "tag", path, htag); 1206 break; 1207 1208 default: 1209 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, "%s: Unknown status " 1210 "%d for ABORT %s, htag 0x%x, PHY %s", __func__, status, 1211 scp ? "all" : "tag", htag, path); 1212 break; 1213 } 1214 1215 pmcs_complete_work(pwp, pwrk, iomb, amt); 1216 } 1217 1218 static void 1219 pmcs_process_general_event(pmcs_hw_t *pwp, uint32_t *iomb) 1220 { 1221 uint32_t htag; 1222 char local[60]; 1223 struct pmcwork *pwrk; 1224 int i; 1225 1226 if (LE_32(iomb[1]) == INBOUND_IOMB_V_BIT_NOT_SET) { 1227 (void) snprintf(local, sizeof (local), 1228 "VALID bit not set on INBOUND IOMB"); 1229 } else if (LE_32(iomb[1]) == 1230 INBOUND_IOMB_OPC_NOT_SUPPORTED) { 1231 (void) snprintf(local, sizeof (local), 1232 "opcode not set on inbound IOMB"); 1233 } else { 1234 (void) snprintf(local, sizeof (local), 1235 "unknown GENERAL EVENT status (0x%x)", 1236 LE_32(iomb[1])); 1237 } 1238 /* Pull up bad IOMB into usual position */ 1239 for (i = 0; i < PMCS_MSG_SIZE - 2; i++) { 1240 iomb[i] = iomb[i+2]; 1241 } 1242 /* overwrite status with an error */ 1243 iomb[2] = LE_32(PMCOUT_STATUS_PROG_ERROR); 1244 iomb[PMCS_MSG_SIZE - 2] = 0; 1245 iomb[PMCS_MSG_SIZE - 1] = 0; 1246 htag = LE_32(iomb[1]); 1247 pmcs_print_entry(pwp, PMCS_PRT_DEBUG, local, iomb); 1248 pwrk = pmcs_tag2wp(pwp, htag); 1249 if (pwrk) { 1250 pmcs_complete_work(pwp, pwrk, iomb, PMCS_QENTRY_SIZE); 1251 } 1252 } 1253 1254 void 1255 pmcs_general_intr(pmcs_hw_t *pwp) 1256 { 1257 char local[PMCS_QENTRY_SIZE << 1]; 1258 uint32_t w0, pi, ci; 1259 uint32_t *ptr, nbuf, lim = 0; 1260 size_t amt; 1261 1262 ci = pmcs_rd_oqci(pwp, PMCS_OQ_GENERAL); 1263 pi = pmcs_rd_oqpi(pwp, PMCS_OQ_GENERAL); 1264 1265 while (ci != pi) { 1266 OQLIM_CHECK(pwp, lim); 1267 ptr = GET_OQ_ENTRY(pwp, PMCS_OQ_GENERAL, ci, 0); 1268 w0 = LE_32(ptr[0]); 1269 VALID_IOMB_CHECK(pwp, w0, ptr, ci, pi); 1270 WRONG_OBID_CHECK(pwp, w0, PMCS_OQ_GENERAL); 1271 COPY_OUTBOUND(pwp, w0, local, nbuf, amt, ptr, 1272 PMCS_OQ_GENERAL, ci); 1273 1274 switch (w0 & PMCS_IOMB_OPCODE_MASK) { 1275 case PMCOUT_SSP_COMPLETION: 1276 /* 1277 * We only get SSP completion here for Task Management 1278 * completions. 1279 */ 1280 case PMCOUT_SMP_COMPLETION: 1281 case PMCOUT_LOCAL_PHY_CONTROL: 1282 case PMCOUT_DEVICE_REGISTRATION: 1283 case PMCOUT_DEREGISTER_DEVICE_HANDLE: 1284 case PMCOUT_GET_NVMD_DATA: 1285 case PMCOUT_SET_NVMD_DATA: 1286 case PMCOUT_GET_DEVICE_STATE: 1287 case PMCOUT_SET_DEVICE_STATE: 1288 pmcs_process_completion(pwp, local, amt); 1289 break; 1290 case PMCOUT_SSP_ABORT: 1291 case PMCOUT_SATA_ABORT: 1292 case PMCOUT_SMP_ABORT: 1293 pmcs_process_abort_completion(pwp, local, amt); 1294 break; 1295 case PMCOUT_SSP_EVENT: 1296 pmcs_process_ssp_event(pwp, local, amt); 1297 break; 1298 case PMCOUT_ECHO: 1299 pmcs_process_echo_completion(pwp, local, amt); 1300 break; 1301 case PMCOUT_SAS_HW_EVENT_ACK_ACK: 1302 if (LE_32(ptr[2]) != SAS_HW_EVENT_ACK_OK) { 1303 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 1304 "SAS H/W EVENT ACK/ACK Status=0x%b", 1305 LE_32(ptr[2]), "\020\4InvParm\3" 1306 "InvPort\2InvPhy\1InvSEA"); 1307 } 1308 pmcs_process_completion(pwp, local, amt); 1309 break; 1310 case PMCOUT_SKIP_ENTRIES: 1311 pmcs_prt(pwp, PMCS_PRT_DEBUG3, NULL, NULL, 1312 "%s: skip %d entries", __func__, nbuf); 1313 break; 1314 default: 1315 (void) snprintf(local, sizeof (local), 1316 "%s: unhandled message", __func__); 1317 pmcs_print_entry(pwp, PMCS_PRT_DEBUG, local, ptr); 1318 break; 1319 } 1320 STEP_OQ_ENTRY(pwp, PMCS_OQ_GENERAL, ci, nbuf); 1321 } 1322 if (lim) { 1323 SYNC_OQ_ENTRY(pwp, PMCS_OQ_GENERAL, ci, pi); 1324 } 1325 } 1326 1327 /* 1328 * pmcs_check_intr_coal 1329 * 1330 * This function makes a determination on the dynamic value of the 1331 * interrupt coalescing timer register. We only use this for I/O 1332 * completions. 1333 * 1334 * The basic algorithm is as follows: 1335 * 1336 * PMCS_MAX_IO_COMPS_PER_INTR: The maximum number of I/O completions per 1337 * I/O completion interrupt. We won't increase the interrupt coalescing 1338 * timer if we're already processing this many completions per interrupt 1339 * beyond the threshold. 1340 * 1341 * Values in io_intr_coal structure: 1342 * 1343 * intr_latency: The average number of nsecs between interrupts during 1344 * the echo test. Used to help determine whether to increase the coalescing 1345 * timer. 1346 * 1347 * intr_threshold: Calculated number of interrupts beyond which we may 1348 * increase the timer. This value is calculated based on the calculated 1349 * interrupt latency during the ECHO test and the current value of the 1350 * coalescing timer. 1351 * 1352 * nsecs_between_intrs: Total number of nsecs between all the interrupts 1353 * in the current timeslice. 1354 * 1355 * last_io_comp: Time of the last I/O interrupt. 1356 * 1357 * num_io_completions: Number of I/O completions during the slice 1358 * 1359 * num_intrs: Number of I/O completion interrupts during the slice 1360 * 1361 * max_io_completions: Number of times we hit >= PMCS_MAX_IO_COMPS_PER_INTR 1362 * during interrupt processing. 1363 * 1364 * PMCS_MAX_IO_COMPS_LOWAT_SHIFT/HIWAT_SHIFT 1365 * Low and high marks used to determine whether we processed enough interrupts 1366 * that contained the maximum number of I/O completions to warrant increasing 1367 * the timer 1368 * 1369 * intr_coal_timer: The current value of the register (in usecs) 1370 * 1371 * timer_on: B_TRUE means we are using the timer 1372 * 1373 * The timer is increased if we processed more than intr_threshold interrupts 1374 * during the quantum and the number of interrupts containing the maximum 1375 * number of I/O completions is between PMCS_MAX_IO_COMPS_LOWAT_SHIFT and 1376 * _HIWAT_SHIFT 1377 * 1378 * If the average time between completions is greater than twice 1379 * the current timer value, the timer value is decreased. 1380 * 1381 * If we did not take any interrupts during a quantum, we turn the timer off. 1382 */ 1383 void 1384 pmcs_check_intr_coal(void *arg) 1385 { 1386 pmcs_hw_t *pwp = (pmcs_hw_t *)arg; 1387 uint32_t avg_nsecs; 1388 pmcs_io_intr_coal_t *ici; 1389 1390 ici = &pwp->io_intr_coal; 1391 mutex_enter(&pwp->ict_lock); 1392 1393 while (ici->stop_thread == B_FALSE) { 1394 /* 1395 * Wait for next time quantum... collect stats 1396 */ 1397 (void) cv_timedwait(&pwp->ict_cv, &pwp->ict_lock, 1398 ddi_get_lbolt() + ici->quantum); 1399 1400 if (ici->stop_thread == B_TRUE) { 1401 continue; 1402 } 1403 1404 DTRACE_PROBE1(pmcs__check__intr__coal, pmcs_io_intr_coal_t *, 1405 &pwp->io_intr_coal); 1406 1407 /* 1408 * Determine whether to adjust timer 1409 */ 1410 if (ici->num_intrs == 0) { 1411 /* 1412 * If timer is off, nothing more to do. 1413 */ 1414 if (!pwp->io_intr_coal.timer_on) { 1415 continue; 1416 } 1417 1418 /* 1419 * No interrupts. Turn off the timer. 1420 */ 1421 pmcs_wr_topunit(pwp, PMCS_INT_COALESCING_CONTROL, 0); 1422 1423 if (pwp->odb_auto_clear & (1 << PMCS_MSIX_IODONE)) { 1424 pmcs_wr_topunit(pwp, PMCS_OBDB_AUTO_CLR, 1425 pwp->odb_auto_clear); 1426 } 1427 1428 ici->timer_on = B_FALSE; 1429 ici->max_io_completions = 0; 1430 ici->num_intrs = 0; 1431 ici->int_cleared = B_FALSE; 1432 ici->num_io_completions = 0; 1433 DTRACE_PROBE1(pmcs__intr__coalesce__timer__off, 1434 pmcs_io_intr_coal_t *, ici); 1435 continue; 1436 } 1437 1438 avg_nsecs = ici->nsecs_between_intrs / ici->num_intrs; 1439 1440 if ((ici->num_intrs > ici->intr_threshold) && 1441 (ici->max_io_completions > (ici->num_intrs >> 1442 PMCS_MAX_IO_COMPS_LOWAT_SHIFT)) && 1443 (ici->max_io_completions < (ici->num_intrs >> 1444 PMCS_MAX_IO_COMPS_HIWAT_SHIFT))) { 1445 pmcs_set_intr_coal_timer(pwp, INCREASE_TIMER); 1446 } else if (avg_nsecs > 1447 (ici->intr_coal_timer * 1000 * 2)) { 1448 pmcs_set_intr_coal_timer(pwp, DECREASE_TIMER); 1449 } 1450 1451 /* 1452 * Reset values for new sampling period. 1453 */ 1454 ici->max_io_completions = 0; 1455 ici->nsecs_between_intrs = 0; 1456 ici->num_intrs = 0; 1457 ici->num_io_completions = 0; 1458 } 1459 1460 mutex_exit(&pwp->ict_lock); 1461 thread_exit(); 1462 } 1463 1464 void 1465 pmcs_iodone_intr(pmcs_hw_t *pwp) 1466 { 1467 char local[PMCS_QENTRY_SIZE << 1]; 1468 pmcs_iocomp_cb_t *ioccb; 1469 uint32_t w0, ci, pi, nbuf, lim = 0, niodone = 0, iomb_opcode; 1470 size_t amt; 1471 uint32_t *ptr; 1472 hrtime_t curtime = gethrtime(); 1473 1474 ci = pmcs_rd_oqci(pwp, PMCS_OQ_IODONE); 1475 pi = pmcs_rd_oqpi(pwp, PMCS_OQ_IODONE); 1476 1477 while (ci != pi) { 1478 OQLIM_CHECK(pwp, lim); 1479 ptr = GET_OQ_ENTRY(pwp, PMCS_OQ_IODONE, ci, 0); 1480 w0 = LE_32(ptr[0]); 1481 VALID_IOMB_CHECK(pwp, w0, ptr, ci, pi); 1482 WRONG_OBID_CHECK(pwp, w0, PMCS_OQ_IODONE); 1483 iomb_opcode = (w0 & PMCS_IOMB_OPCODE_MASK); 1484 1485 if ((iomb_opcode == PMCOUT_SSP_COMPLETION) || 1486 (iomb_opcode == PMCOUT_SATA_COMPLETION)) { 1487 ioccb = 1488 kmem_cache_alloc(pwp->iocomp_cb_cache, KM_NOSLEEP); 1489 if (ioccb == NULL) { 1490 pmcs_prt(pwp, PMCS_PRT_WARN, NULL, NULL, 1491 "%s: kmem_cache_alloc failed", __func__); 1492 break; 1493 } 1494 1495 COPY_OUTBOUND(pwp, w0, ioccb->iomb, nbuf, amt, ptr, 1496 PMCS_OQ_IODONE, ci); 1497 1498 niodone++; 1499 pmcs_process_io_completion(pwp, ioccb, amt); 1500 } else { 1501 COPY_OUTBOUND(pwp, w0, local, nbuf, amt, ptr, 1502 PMCS_OQ_IODONE, ci); 1503 1504 switch (iomb_opcode) { 1505 case PMCOUT_ECHO: 1506 pmcs_process_echo_completion(pwp, local, amt); 1507 break; 1508 case PMCOUT_SATA_EVENT: 1509 pmcs_process_sata_event(pwp, local, amt); 1510 break; 1511 case PMCOUT_SSP_EVENT: 1512 pmcs_process_ssp_event(pwp, local, amt); 1513 break; 1514 case PMCOUT_SKIP_ENTRIES: 1515 pmcs_prt(pwp, PMCS_PRT_DEBUG3, NULL, NULL, 1516 "%s: skip %d entries", __func__, nbuf); 1517 break; 1518 default: 1519 (void) snprintf(local, sizeof (local), 1520 "%s: unhandled message", __func__); 1521 pmcs_print_entry(pwp, PMCS_PRT_DEBUG, local, 1522 ptr); 1523 break; 1524 } 1525 } 1526 1527 STEP_OQ_ENTRY(pwp, PMCS_OQ_IODONE, ci, nbuf); 1528 } 1529 1530 if (lim != 0) { 1531 SYNC_OQ_ENTRY(pwp, PMCS_OQ_IODONE, ci, pi); 1532 } 1533 1534 /* 1535 * Update the interrupt coalescing timer check stats and run 1536 * completions for queued up commands. 1537 */ 1538 1539 if (niodone > 0) { 1540 /* 1541 * If we can't get the lock, then completions are either 1542 * already running or will be scheduled to do so shortly. 1543 */ 1544 if (mutex_tryenter(&pwp->cq_lock) != 0) { 1545 PMCS_CQ_RUN_LOCKED(pwp); 1546 mutex_exit(&pwp->cq_lock); 1547 } 1548 1549 mutex_enter(&pwp->ict_lock); 1550 pwp->io_intr_coal.nsecs_between_intrs += 1551 curtime - pwp->io_intr_coal.last_io_comp; 1552 pwp->io_intr_coal.num_intrs++; 1553 pwp->io_intr_coal.num_io_completions += niodone; 1554 if (niodone >= PMCS_MAX_IO_COMPS_PER_INTR) { 1555 pwp->io_intr_coal.max_io_completions++; 1556 } 1557 pwp->io_intr_coal.last_io_comp = gethrtime(); 1558 mutex_exit(&pwp->ict_lock); 1559 } 1560 } 1561 1562 void 1563 pmcs_event_intr(pmcs_hw_t *pwp) 1564 { 1565 char local[PMCS_QENTRY_SIZE << 1]; 1566 uint32_t w0, ci, pi, nbuf, lim = 0; 1567 size_t amt; 1568 uint32_t *ptr; 1569 1570 ci = pmcs_rd_oqci(pwp, PMCS_OQ_EVENTS); 1571 pi = pmcs_rd_oqpi(pwp, PMCS_OQ_EVENTS); 1572 1573 while (ci != pi) { 1574 OQLIM_CHECK(pwp, lim); 1575 ptr = GET_OQ_ENTRY(pwp, PMCS_OQ_EVENTS, ci, 0); 1576 w0 = LE_32(ptr[0]); 1577 VALID_IOMB_CHECK(pwp, w0, ptr, ci, pi); 1578 WRONG_OBID_CHECK(pwp, w0, PMCS_OQ_EVENTS); 1579 COPY_OUTBOUND(pwp, w0, local, nbuf, amt, ptr, 1580 PMCS_OQ_EVENTS, ci); 1581 1582 switch (w0 & PMCS_IOMB_OPCODE_MASK) { 1583 case PMCOUT_ECHO: 1584 pmcs_process_echo_completion(pwp, local, amt); 1585 break; 1586 case PMCOUT_SATA_EVENT: 1587 pmcs_process_sata_event(pwp, local, amt); 1588 break; 1589 case PMCOUT_SSP_EVENT: 1590 pmcs_process_ssp_event(pwp, local, amt); 1591 break; 1592 case PMCOUT_GENERAL_EVENT: 1593 pmcs_process_general_event(pwp, ptr); 1594 break; 1595 case PMCOUT_DEVICE_HANDLE_REMOVED: 1596 { 1597 uint32_t port = IOP_EVENT_PORTID(LE_32(ptr[1])); 1598 uint32_t did = LE_32(ptr[2]); 1599 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 1600 "PortID 0x%x device_id 0x%x removed", port, did); 1601 break; 1602 } 1603 case PMCOUT_SAS_HW_EVENT: 1604 if (nbuf > 1) { 1605 pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, 1606 "multiple SAS HW_EVENT (%d) responses " 1607 "in EVENT OQ", nbuf); 1608 } 1609 pmcs_process_sas_hw_event(pwp, local, PMCS_QENTRY_SIZE); 1610 break; 1611 case PMCOUT_FW_FLASH_UPDATE: 1612 case PMCOUT_GET_TIME_STAMP: 1613 case PMCOUT_GET_DEVICE_STATE: 1614 case PMCOUT_SET_DEVICE_STATE: 1615 case PMCOUT_SAS_DIAG_EXECUTE: 1616 pmcs_process_completion(pwp, local, amt); 1617 break; 1618 case PMCOUT_SKIP_ENTRIES: 1619 pmcs_prt(pwp, PMCS_PRT_DEBUG3, NULL, NULL, 1620 "%s: skip %d entries", __func__, nbuf); 1621 break; 1622 default: 1623 (void) snprintf(local, sizeof (local), 1624 "%s: unhandled message", __func__); 1625 pmcs_print_entry(pwp, PMCS_PRT_DEBUG, local, ptr); 1626 break; 1627 } 1628 STEP_OQ_ENTRY(pwp, PMCS_OQ_EVENTS, ci, nbuf); 1629 } 1630 if (lim) { 1631 SYNC_OQ_ENTRY(pwp, PMCS_OQ_EVENTS, ci, pi); 1632 } 1633 } 1634 1635 void 1636 pmcs_timed_out(pmcs_hw_t *pwp, uint32_t htag, const char *func) 1637 { 1638 #ifdef DEBUG 1639 hrtime_t now = gethrtime(); 1640 int i; 1641 1642 for (i = 0; i < 256; i++) { 1643 if (pwp->ftags[i] == htag) { 1644 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 1645 "Inbound msg (tag 0x%8x) timed out - " 1646 "was started %llu ns ago in %s:%d", 1647 htag, (unsigned long long) (now - pwp->ftime[i]), 1648 func, pwp->ftag_lines[i]); 1649 return; 1650 } 1651 } 1652 #endif 1653 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 1654 "Inbound Message (tag 0x%08x) timed out- was started in %s", 1655 htag, func); 1656 } 1657