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 		/*
346 		 * No need to lock the primary root PHY.  It can never go
347 		 * away, and we're only concerned with the port width and
348 		 * the portid, both of which only ever change in this function.
349 		 */
350 		rp = pwp->ports[portid];
351 
352 		mutex_exit(&pwp->lock);
353 
354 		pmcs_endian_transform(pwp, &af, &((uint32_t *)iomb)[4],
355 		    sas_identify_af_endian_xfvec);
356 
357 		/* Copy the remote address into our phy handle */
358 		(void) memcpy(pptr->sas_address, af.sas_address, 8);
359 
360 		/*
361 		 * Check to see if there is a PortID already active.
362 		 */
363 		if (rp) {
364 			if (rp->portid != portid) {
365 				pmcs_unlock_phy(pptr);
366 				pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
367 				    "PortID 0x%x: PHY 0x%x SAS LINK UP IS FOR "
368 				    "A DIFFERENT PORTID 0x%x", rp->portid,
369 				    phynum, portid);
370 				break;
371 			}
372 
373 			/*
374 			 * If the dtype isn't NOTHING, then this is actually
375 			 * the primary PHY for this port.  It probably went
376 			 * down and came back up, so be sure not to mark it
377 			 * as a subsidiary.
378 			 */
379 			if (pptr->dtype == NOTHING) {
380 				pptr->subsidiary = 1;
381 			}
382 			pptr->link_rate =
383 			    pmcs_link_rate(IOP_EVENT_LINK_RATE(w1));
384 			pptr->portid = portid;
385 			pptr->dead = 0;
386 			pmcs_unlock_phy(pptr);
387 
388 			rp->width = IOP_EVENT_NPIP(w3);
389 
390 			/* Add this PHY to the phymap */
391 			if (sas_phymap_phy_add(pwp->hss_phymap, phynum,
392 			    pwp->sas_wwns[0],
393 			    pmcs_barray2wwn(pptr->sas_address)) !=
394 			    DDI_SUCCESS) {
395 				pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
396 				    "Unable to add phy %u for 0x%" PRIx64 ".0x%"
397 				    PRIx64, phynum, pwp->sas_wwns[rp->phynum],
398 				    pmcs_barray2wwn(pptr->sas_address));
399 			}
400 
401 			/* Get our iport, if attached, and set it up */
402 			pmcs_lock_phy(pptr);
403 			iport = pmcs_get_iport_by_phy(pwp, pptr);
404 			pmcs_unlock_phy(pptr);
405 			if (iport) {
406 				primary = !pptr->subsidiary;
407 
408 				mutex_enter(&iport->lock);
409 				if (primary) {
410 					iport->pptr = pptr;
411 				}
412 				if (iport->ua_state == UA_ACTIVE) {
413 					pmcs_add_phy_to_iport(iport, pptr);
414 					pptr->iport = iport;
415 				}
416 				mutex_exit(&iport->lock);
417 				pmcs_rele_iport(iport);
418 			}
419 
420 			pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL,
421 			    "PortID 0x%x: PHY 0x%x SAS LINK UP WIDENS PORT "
422 			    "TO %d PHYS", portid, phynum, rp->width);
423 
424 			break;
425 		}
426 
427 		/*
428 		 * Check to see if anything is here already
429 		 */
430 		if (pptr->dtype != NOTHING && pptr->configured) {
431 			pmcs_unlock_phy(pptr);
432 			pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
433 			    "PortID 0x%x: SAS PHY 0x%x UP HITS EXISTING "
434 			    "CONFIGURED TREE", portid, phynum);
435 			break;
436 		}
437 
438 		if (af.address_frame_type != SAS_AF_IDENTIFY) {
439 			pmcs_unlock_phy(pptr);
440 			pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
441 			    "SAS link up on phy 0x%x, "
442 			    "but unexpected frame type 0x%x found", phynum,
443 			    af.address_frame_type);
444 			break;
445 		}
446 		pptr->width = IOP_EVENT_NPIP(w3);
447 		pptr->portid = portid;
448 		pptr->dead = 0;
449 		pptr->link_rate = pmcs_link_rate(IOP_EVENT_LINK_RATE(w1));
450 
451 		/*
452 		 * Check to see whether this is an expander or an endpoint
453 		 */
454 		switch (af.device_type) {
455 		case SAS_IF_DTYPE_ENDPOINT:
456 			pptr->pend_dtype = SAS;
457 			pptr->dtype = SAS;
458 			break;
459 		case SAS_IF_DTYPE_EDGE:
460 		case SAS_IF_DTYPE_FANOUT:
461 			pptr->pend_dtype = EXPANDER;
462 			pptr->dtype = EXPANDER;
463 			break;
464 		default:
465 			pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
466 			    "unknown device type 0x%x", af.device_type);
467 			pptr->pend_dtype = NOTHING;
468 			pptr->dtype = NOTHING;
469 			break;
470 		}
471 
472 		/*
473 		 * If this is a direct-attached SAS drive, do the spinup
474 		 * release now.
475 		 */
476 		if (pptr->dtype == SAS) {
477 			pptr->spinup_hold = 1;
478 			pmcs_spinup_release(pwp, pptr);
479 			pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL,
480 			    "Release spinup hold on PHY 0x%x", phynum);
481 		}
482 
483 		pmcs_set_changed(pwp, pptr, B_TRUE, 0);
484 		if (pptr->width > 1) {
485 			pmcs_prt(pwp, PMCS_PRT_INFO, pptr, NULL,
486 			    "PortID 0x%x: PHY 0x%x SAS"
487 			    " LINK UP @ %s Gb with %d phys/s", portid, phynum,
488 			    pmcs_get_rate(pptr->link_rate), pptr->width);
489 		} else {
490 			pmcs_prt(pwp, PMCS_PRT_INFO, pptr, NULL,
491 			    "PortID 0x%x: PHY 0x%x SAS"
492 			    " LINK UP @ %s Gb/s", portid, phynum,
493 			    pmcs_get_rate(pptr->link_rate));
494 		}
495 		pmcs_unlock_phy(pptr);
496 
497 		/* Add this PHY to the phymap */
498 		if (sas_phymap_phy_add(pwp->hss_phymap, phynum,
499 		    pwp->sas_wwns[0],
500 		    pmcs_barray2wwn(pptr->sas_address)) != DDI_SUCCESS) {
501 			pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
502 			    "Unable to add phy %u for 0x%" PRIx64 ".0x%"
503 			    PRIx64, phynum, pwp->sas_wwns[pptr->phynum],
504 			    pmcs_barray2wwn(pptr->sas_address));
505 		}
506 
507 		/* Get a pointer to our iport and set it up if attached */
508 		pmcs_lock_phy(pptr);
509 		iport = pmcs_get_iport_by_phy(pwp, pptr);
510 		pmcs_unlock_phy(pptr);
511 		if (iport) {
512 			primary = !pptr->subsidiary;
513 
514 			mutex_enter(&iport->lock);
515 			if (primary) {
516 				iport->pptr = pptr;
517 			}
518 			if (iport->ua_state == UA_ACTIVE) {
519 				pmcs_add_phy_to_iport(iport, pptr);
520 				pptr->iport = iport;
521 			}
522 			mutex_exit(&iport->lock);
523 			pmcs_rele_iport(iport);
524 		}
525 
526 		pmcs_lock_phy(pptr);
527 		pmcs_smhba_log_sysevent(pwp, ESC_SAS_PHY_EVENT,
528 		    SAS_PHY_ONLINE, pptr);
529 		pmcs_unlock_phy(pptr);
530 
531 		mutex_enter(&pwp->lock);
532 		pwp->ports[portid] = pptr;
533 		mutex_exit(&pwp->lock);
534 		RESTART_DISCOVERY(pwp);
535 
536 		break;
537 	}
538 	case IOP_EVENT_SATA_PHY_UP:
539 		/*
540 		 * If we're not at running state, don't do anything
541 		 */
542 		mutex_enter(&pwp->lock);
543 		if (pwp->state != STATE_RUNNING) {
544 			mutex_exit(&pwp->lock);
545 			break;
546 		}
547 
548 		/*
549 		 * Check to see if anything is here already
550 		 */
551 		pmcs_lock_phy(pwp->root_phys + phynum);
552 		pptr = pwp->root_phys + phynum;
553 		mutex_exit(&pwp->lock);
554 
555 		if (pptr->dtype != NOTHING && pptr->configured) {
556 			pmcs_unlock_phy(pptr);
557 			pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
558 			    "PortID 0x%x: SATA PHY 0x%x"
559 			    " UP HITS EXISTING CONFIGURED TREE",
560 			    portid, phynum);
561 			break;
562 		}
563 
564 		pptr->width = 1;
565 		pptr->dead = 0;
566 
567 		/*
568 		 * Install the PHY number in the least significant byte
569 		 * with a NAA=3 (locally assigned address) in the most
570 		 * significant nubble.
571 		 *
572 		 * Later, we'll either use that or dig a
573 		 * WWN out of words 108..111.
574 		 */
575 		pptr->sas_address[0] = 0x30;
576 		pptr->sas_address[1] = 0;
577 		pptr->sas_address[2] = 0;
578 		pptr->sas_address[3] = 0;
579 		pptr->sas_address[4] = 0;
580 		pptr->sas_address[5] = 0;
581 		pptr->sas_address[6] = 0;
582 		pptr->sas_address[7] = phynum;
583 		pptr->portid = portid;
584 		pptr->link_rate = pmcs_link_rate(IOP_EVENT_LINK_RATE(w1));
585 		pptr->dtype = SATA;
586 		pmcs_set_changed(pwp, pptr, B_TRUE, 0);
587 		pmcs_prt(pwp, PMCS_PRT_INFO, pptr, NULL,
588 		    "PortID 0x%x: PHY 0x%x SATA LINK UP @ %s Gb/s",
589 		    pptr->portid, phynum, pmcs_get_rate(pptr->link_rate));
590 		pmcs_unlock_phy(pptr);
591 
592 		/* Add this PHY to the phymap */
593 		if (sas_phymap_phy_add(pwp->hss_phymap, phynum,
594 		    pwp->sas_wwns[0],
595 		    pmcs_barray2wwn(pptr->sas_address)) != DDI_SUCCESS) {
596 			pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
597 			    "Unable to add phy %u for 0x%" PRIx64 ".0x%"
598 			    PRIx64, phynum, pwp->sas_wwns[pptr->phynum],
599 			    pmcs_barray2wwn(pptr->sas_address));
600 		}
601 
602 		/* Get our iport, if attached, and set it up */
603 		pmcs_lock_phy(pptr);
604 		iport = pmcs_get_iport_by_phy(pwp, pptr);
605 		pmcs_unlock_phy(pptr);
606 		if (iport) {
607 			mutex_enter(&iport->lock);
608 			iport->pptr = pptr;
609 			if (iport->ua_state == UA_ACTIVE) {
610 				pmcs_add_phy_to_iport(iport, pptr);
611 				pptr->iport = iport;
612 				ASSERT(iport->nphy == 1);
613 				iport->nphy = 1;
614 			}
615 			mutex_exit(&iport->lock);
616 			pmcs_rele_iport(iport);
617 		}
618 
619 		pmcs_lock_phy(pptr);
620 		pmcs_smhba_log_sysevent(pwp, ESC_SAS_PHY_EVENT,
621 		    SAS_PHY_ONLINE, pptr);
622 		pmcs_unlock_phy(pptr);
623 
624 		mutex_enter(&pwp->lock);
625 		pwp->ports[pptr->portid] = pptr;
626 		mutex_exit(&pwp->lock);
627 		RESTART_DISCOVERY(pwp);
628 		break;
629 
630 	case IOP_EVENT_SATA_SPINUP_HOLD:
631 		tphyp = (pmcs_phy_t *)(pwp->root_phys + phynum);
632 		/*
633 		 * No need to lock the entire tree for this
634 		 */
635 		mutex_enter(&tphyp->phy_lock);
636 		tphyp->spinup_hold = 1;
637 		pmcs_spinup_release(pwp, tphyp);
638 		mutex_exit(&tphyp->phy_lock);
639 		break;
640 	case IOP_EVENT_PHY_DOWN:
641 		/*
642 		 * If we're not at running state, don't do anything
643 		 */
644 		mutex_enter(&pwp->lock);
645 		if (pwp->state != STATE_RUNNING) {
646 			mutex_exit(&pwp->lock);
647 			break;
648 		}
649 		pptr = pwp->ports[portid];
650 
651 		subphy = pwp->root_phys + phynum;
652 		/*
653 		 * subphy is a pointer to the PHY corresponding to the incoming
654 		 * event. pptr points to the primary PHY for the corresponding
655 		 * port.  So, subphy and pptr may or may not be the same PHY,
656 		 * but that doesn't change what we need to do with each.
657 		 */
658 		ASSERT(subphy);
659 		mutex_exit(&pwp->lock);
660 
661 		if (pptr == NULL) {
662 			pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
663 			    "PortID 0x%x: PHY 0x%x LINK DOWN- no portid ptr",
664 			    portid, phynum);
665 			break;
666 		}
667 		if (IOP_EVENT_PORT_STATE(w3) == IOP_EVENT_PS_NIL) {
668 			pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL,
669 			    "PortID 0x%x: PHY 0x%x NOT VALID YET",
670 			    portid, phynum);
671 			need_ack = 1;
672 			break;
673 		}
674 		if (IOP_EVENT_PORT_STATE(w3) == IOP_EVENT_PS_IN_RESET) {
675 			pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL,
676 			    "PortID 0x%x: PHY 0x%x IN RESET",
677 			    portid, phynum);
678 			/* Entire port is down due to a host-initiated reset */
679 			mutex_enter(&pptr->phy_lock);
680 			iport = pptr->iport;
681 			mutex_exit(&pptr->phy_lock);
682 			if (iport) {
683 				mutex_enter(&iport->lock);
684 				pmcs_iport_teardown_phys(iport);
685 				mutex_exit(&iport->lock);
686 			}
687 
688 			break;
689 		}
690 		if (IOP_EVENT_PORT_STATE(w3) == IOP_EVENT_PS_LOSTCOMM) {
691 			pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL,
692 			    "PortID 0x%x: PHY 0x%x TEMPORARILY DOWN",
693 			    portid, phynum);
694 			need_ack = 1;
695 			break;
696 		}
697 
698 		if (IOP_EVENT_PORT_STATE(w3) == IOP_EVENT_PS_VALID) {
699 			/*
700 			 * This is not the last phy in the port, so if this
701 			 * is the primary PHY, promote another PHY to primary.
702 			 */
703 			if (pptr == subphy) {
704 				primary = !subphy->subsidiary;
705 				ASSERT(primary);
706 
707 				tphyp = pptr;
708 				pptr = pmcs_promote_next_phy(tphyp);
709 
710 				if (pptr) {
711 					/* Update primary pptr in ports */
712 					pwp->ports[portid] = pptr;
713 					pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr,
714 					    NULL, "PortID 0x%x: PHY 0x%x "
715 					    "promoted to primary", portid,
716 					    pptr->phynum);
717 				} else {
718 					pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr,
719 					    NULL, "PortID 0x%x: PHY 0x%x: "
720 					    "unable to promote phy", portid,
721 					    phynum);
722 				}
723 			}
724 
725 			/*
726 			 * Drop port width on the primary phy handle
727 			 * No need to lock the entire tree for this
728 			 */
729 			mutex_enter(&pptr->phy_lock);
730 			pptr->width = IOP_EVENT_NPIP(w3);
731 			mutex_exit(&pptr->phy_lock);
732 
733 			/* Clear the iport reference on the subphy */
734 			mutex_enter(&subphy->phy_lock);
735 			iport = subphy->iport;
736 			subphy->iport = NULL;
737 			mutex_exit(&subphy->phy_lock);
738 
739 			/*
740 			 * If the iport was set on this phy, decrement its
741 			 * nphy count and remove this phy from the phys list.
742 			 */
743 			if (iport) {
744 				mutex_enter(&iport->lock);
745 				if (iport->ua_state == UA_ACTIVE) {
746 					pmcs_remove_phy_from_iport(iport,
747 					    subphy);
748 				}
749 				mutex_exit(&iport->lock);
750 			}
751 
752 			pmcs_lock_phy(subphy);
753 			if (subphy->subsidiary)
754 				pmcs_clear_phy(pwp, subphy);
755 			pmcs_unlock_phy(subphy);
756 
757 			/* Remove this PHY from the phymap */
758 			if (sas_phymap_phy_rem(pwp->hss_phymap, phynum) !=
759 			    DDI_SUCCESS) {
760 				pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
761 				    "Unable to remove phy %u for 0x%" PRIx64
762 				    ".0x%" PRIx64, phynum,
763 				    pwp->sas_wwns[pptr->phynum],
764 				    pmcs_barray2wwn((pwp->root_phys +
765 				    pptr->phynum)-> sas_address));
766 			}
767 
768 			pmcs_prt(pwp, PMCS_PRT_INFO, pptr, NULL,
769 			    "PortID 0x%x: PHY 0x%x LINK DOWN NARROWS PORT "
770 			    "TO %d PHYS", portid, phynum, pptr->width);
771 			break;
772 		}
773 		if (IOP_EVENT_PORT_STATE(w3) != IOP_EVENT_PS_INVALID) {
774 			pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL,
775 			    "PortID 0x%x: PHY 0x%x LINK DOWN NOT HANDLED "
776 			    "(state 0x%x)", portid, phynum,
777 			    IOP_EVENT_PORT_STATE(w3));
778 			need_ack = 1;
779 			break;
780 		}
781 		/* Remove this PHY from the phymap */
782 		if (sas_phymap_phy_rem(pwp->hss_phymap, phynum) !=
783 		    DDI_SUCCESS) {
784 			pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
785 			    "Unable to remove phy %u for 0x%" PRIx64
786 			    ".0x%" PRIx64, phynum,
787 			    pwp->sas_wwns[pptr->phynum],
788 			    pmcs_barray2wwn(
789 			    (pwp->root_phys + pptr->phynum)->sas_address));
790 		}
791 
792 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
793 		    "PortID 0x%x: PHY 0x%x LINK DOWN (port invalid)",
794 		    portid, phynum);
795 
796 		/*
797 		 * Last PHY on the port.
798 		 * Assumption: pptr and subphy are both "valid"
799 		 *
800 		 * Drop port width on the primary phy handle
801 		 * Report the event while we've got the lock
802 		 */
803 		mutex_enter(&pptr->phy_lock);
804 		pptr->width = 0;
805 		pmcs_smhba_log_sysevent(pwp, ESC_SAS_PHY_EVENT,
806 		    SAS_PHY_OFFLINE, pptr);
807 		mutex_exit(&pptr->phy_lock);
808 
809 		/* Clear the iport reference on the subphy */
810 		mutex_enter(&subphy->phy_lock);
811 		iport = subphy->iport;
812 		subphy->iport = NULL;
813 		mutex_exit(&subphy->phy_lock);
814 
815 		/*
816 		 * If the iport was set on this phy, decrement its
817 		 * nphy count and remove this phy from the phys list.
818 		 * Also, clear the iport's pptr as this port is now
819 		 * down.
820 		 */
821 		if (iport) {
822 			mutex_enter(&iport->lock);
823 			if (iport->ua_state == UA_ACTIVE) {
824 				pmcs_remove_phy_from_iport(iport, subphy);
825 				iport->pptr = NULL;
826 				iport->ua_state = UA_PEND_DEACTIVATE;
827 			}
828 			mutex_exit(&iport->lock);
829 		}
830 
831 		pmcs_lock_phy(subphy);
832 		if (subphy->subsidiary)
833 			pmcs_clear_phy(pwp, subphy);
834 		pmcs_unlock_phy(subphy);
835 
836 		/*
837 		 * Since we're now really dead, it's time to clean up.
838 		 */
839 		pmcs_kill_port(pwp, portid);
840 		need_ack = 1;
841 
842 		break;
843 	case IOP_EVENT_BROADCAST_CHANGE:
844 		pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL,
845 		    "PortID 0x%x: PHY 0x%x Broadcast Change", portid, phynum);
846 		need_ack = 1;
847 		mutex_enter(&pwp->lock);
848 		pptr = pwp->ports[portid];
849 		if (pptr) {
850 			pmcs_lock_phy(pptr);
851 			if (pptr->phynum == phynum) {
852 				pmcs_set_changed(pwp, pptr, B_TRUE, 0);
853 			}
854 			pmcs_smhba_log_sysevent(pwp, ESC_SAS_HBA_PORT_BROADCAST,
855 			    SAS_PORT_BROADCAST_CHANGE, pptr);
856 			pmcs_unlock_phy(pptr);
857 		}
858 		mutex_exit(&pwp->lock);
859 		RESTART_DISCOVERY(pwp);
860 		break;
861 	case IOP_EVENT_BROADCAST_SES:
862 		EVT_PRT(pwp, IOP_EVENT_BROADCAST_SES, phynum);
863 		mutex_enter(&pwp->lock);
864 		pptr = pwp->ports[portid];
865 		mutex_exit(&pwp->lock);
866 		if (pptr) {
867 			pmcs_lock_phy(pptr);
868 			pmcs_smhba_log_sysevent(pwp, ESC_SAS_HBA_PORT_BROADCAST,
869 			    SAS_PORT_BROADCAST_SES, pptr);
870 			pmcs_unlock_phy(pptr);
871 		}
872 		break;
873 	case IOP_EVENT_PHY_ERR_INBOUND_CRC:
874 	{
875 		char buf[32];
876 		(void) snprintf(buf, sizeof (buf), "Inbound PHY CRC error");
877 		need_ack = 1;
878 		break;
879 	}
880 	case IOP_EVENT_HARD_RESET_RECEIVED:
881 		EVT_PRT(pwp, IOP_EVENT_HARD_RESET_RECEIVED, phynum);
882 		break;
883 	case IOP_EVENT_EVENT_ID_FRAME_TIMO:
884 		EVT_PRT(pwp, IOP_EVENT_EVENT_ID_FRAME_TIMO, phynum);
885 		break;
886 	case IOP_EVENT_BROADCAST_EXP:
887 		pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL,
888 		    "PortID 0x%x: PHY 0x%x Broadcast Exp Change",
889 		    portid, phynum);
890 		/*
891 		 * Comparing Section 6.8.1.4 of SMHBA (rev 7) spec and Section
892 		 * 7.2.3 of SAS2 (Rev 15) spec,
893 		 * _BROADCAST_EXPANDER event corresponds to _D01_4 primitive
894 		 */
895 		mutex_enter(&pwp->lock);
896 		pptr = pwp->ports[portid];
897 		mutex_exit(&pwp->lock);
898 		if (pptr) {
899 			pmcs_lock_phy(pptr);
900 			pmcs_smhba_log_sysevent(pwp, ESC_SAS_HBA_PORT_BROADCAST,
901 			    SAS_PORT_BROADCAST_D01_4, pptr);
902 			pmcs_unlock_phy(pptr);
903 		}
904 		break;
905 	case IOP_EVENT_PHY_START_STATUS:
906 		switch (IOP_EVENT_STATUS(w1)) {
907 		case IOP_PHY_START_OK:
908 			pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL,
909 			    "PHY 0x%x Started", phynum);
910 			break;
911 		case IOP_PHY_START_ALREADY:
912 			pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL,
913 			    "PHY 0x%x Started (Already)", phynum);
914 			break;
915 		case IOP_PHY_START_INVALID:
916 			pmcs_prt(pwp, PMCS_PRT_WARN, NULL, NULL,
917 			    "PHY 0x%x failed to start (invalid phy)", phynum);
918 			break;
919 		case IOP_PHY_START_ERROR:
920 			pmcs_prt(pwp, PMCS_PRT_WARN, NULL, NULL,
921 			    "PHY 0x%x Start Error", phynum);
922 			break;
923 		default:
924 			pmcs_prt(pwp, PMCS_PRT_WARN, NULL, NULL,
925 			    "PHY 0x%x failed to start (0x%x)", phynum,
926 			    IOP_EVENT_STATUS(w1));
927 			break;
928 		}
929 		/* Reposition htag to the 'expected' position. */
930 		((uint32_t *)iomb)[1] = ((uint32_t *)iomb)[2];
931 		pmcs_process_completion(pwp, iomb, amt);
932 		break;
933 	case IOP_EVENT_PHY_ERR_INVALID_DWORD:
934 		need_ack = 1;
935 		EVT_PRT(pwp, IOP_EVENT_PHY_ERR_INVALID_DWORD, phynum);
936 		break;
937 	case IOP_EVENT_PHY_ERR_DISPARITY_ERROR:
938 		need_ack = 1;
939 		EVT_PRT(pwp, IOP_EVENT_PHY_ERR_DISPARITY_ERROR, phynum);
940 		break;
941 	case IOP_EVENT_PHY_ERR_CODE_VIOLATION:
942 		need_ack = 1;
943 		EVT_PRT(pwp, IOP_EVENT_PHY_ERR_CODE_VIOLATION, phynum);
944 		break;
945 	case IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN:
946 		need_ack = 1;
947 		EVT_PRT(pwp, IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN, phynum);
948 		break;
949 	case IOP_EVENT_PHY_ERR_PHY_RESET_FAILD:
950 		need_ack = 1;
951 		EVT_PRT(pwp, IOP_EVENT_PHY_ERR_PHY_RESET_FAILD, phynum);
952 		break;
953 	case IOP_EVENT_PORT_RECOVERY_TIMER_TMO:
954 		EVT_PRT(pwp, IOP_EVENT_PORT_RECOVERY_TIMER_TMO, phynum);
955 		break;
956 	case IOP_EVENT_PORT_RECOVER:
957 		EVT_PRT(pwp, IOP_EVENT_PORT_RECOVER, phynum);
958 		break;
959 	case IOP_EVENT_PORT_INVALID:
960 		mutex_enter(&pwp->lock);
961 		if (pwp->state != STATE_RUNNING) {
962 			mutex_exit(&pwp->lock);
963 			break;
964 		}
965 		mutex_exit(&pwp->lock);
966 		pmcs_kill_port(pwp, portid);
967 		pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL,
968 		    "PortID 0x%x: PORT Now Invalid", portid);
969 		break;
970 	case IOP_EVENT_PORT_RESET_TIMER_TMO:
971 		EVT_PRT(pwp, IOP_EVENT_PORT_RESET_TIMER_TMO, phynum);
972 		break;
973 	case IOP_EVENT_PORT_RESET_COMPLETE:
974 		EVT_PRT(pwp, IOP_EVENT_PORT_RESET_COMPLETE, phynum);
975 		break;
976 	case IOP_EVENT_BROADCAST_ASYNC_EVENT:
977 		EVT_PRT(pwp, IOP_EVENT_BROADCAST_ASYNC_EVENT, phynum);
978 		/*
979 		 * Comparing Section 6.8.1.4 of SMHBA (rev 7) spec and Section
980 		 * 7.2.3 of SAS2 (Rev 15) spec,
981 		 * _BROADCAST_ASYNC event corresponds to _D04_7 primitive
982 		 */
983 		mutex_enter(&pwp->lock);
984 		pptr = pwp->ports[portid];
985 		mutex_exit(&pwp->lock);
986 		if (pptr) {
987 			pmcs_lock_phy(pptr);
988 			pmcs_smhba_log_sysevent(pwp, ESC_SAS_HBA_PORT_BROADCAST,
989 			    SAS_PORT_BROADCAST_D04_7, pptr);
990 			pmcs_unlock_phy(pptr);
991 		}
992 		break;
993 	default:
994 		(void) snprintf(buf, sizeof (buf),
995 		    "unknown SAS H/W Event PHY 0x%x", phynum);
996 		pmcs_print_entry(pwp, PMCS_PRT_DEBUG, buf, iomb);
997 		break;
998 	}
999 	if (need_ack) {
1000 		mutex_enter(&pwp->lock);
1001 		/*
1002 		 * Don't lock the entire tree for this.  Just grab the mutex
1003 		 * on the root PHY.
1004 		 */
1005 		tphyp = pwp->root_phys + phynum;
1006 		mutex_enter(&tphyp->phy_lock);
1007 		tphyp->hw_event_ack = w1;
1008 		mutex_exit(&tphyp->phy_lock);
1009 		mutex_exit(&pwp->lock);
1010 		pmcs_ack_events(pwp);
1011 	}
1012 }
1013 
1014 static void
1015 pmcs_process_echo_completion(pmcs_hw_t *pwp, void *iomb, size_t amt)
1016 {
1017 	echo_test_t fred;
1018 	pmcwork_t *pwrk;
1019 	uint32_t *msg = iomb, htag = LE_32(msg[1]);
1020 	pwrk = pmcs_tag2wp(pwp, htag);
1021 	if (pwrk) {
1022 		(void) memcpy(&fred, &((uint32_t *)iomb)[2], sizeof (fred));
1023 		fred.ptr[0]++;
1024 		msg[2] = LE_32(PMCOUT_STATUS_OK);
1025 		pmcs_complete_work(pwp, pwrk, msg, amt);
1026 	} else {
1027 		pmcs_print_entry(pwp, PMCS_PRT_DEBUG,
1028 		    "ECHO completion with no work structure", iomb);
1029 	}
1030 }
1031 
1032 static void
1033 pmcs_process_ssp_event(pmcs_hw_t *pwp, void *iomb, size_t amt)
1034 {
1035 	_NOTE(ARGUNUSED(amt));
1036 	uint32_t status, htag, *w;
1037 	pmcwork_t *pwrk;
1038 	pmcs_phy_t *phyp = NULL;
1039 	char *path;
1040 
1041 	w = iomb;
1042 	htag = LE_32(w[1]);
1043 	status = LE_32(w[2]);
1044 
1045 
1046 	pwrk = pmcs_tag2wp(pwp, htag);
1047 	if (pwrk == NULL) {
1048 		path = "????";
1049 	} else {
1050 		phyp = pwrk->phy;
1051 		path = pwrk->phy->path;
1052 	}
1053 
1054 	if (status != PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED) {
1055 		char buf[20];
1056 		const char *emsg = pmcs_status_str(status);
1057 
1058 		if (emsg == NULL) {
1059 			(void) snprintf(buf, sizeof (buf), "Status 0x%x",
1060 			    status);
1061 			emsg = buf;
1062 		}
1063 		pmcs_prt(pwp, PMCS_PRT_DEBUG, phyp, NULL, "%s: Bad SAS Status "
1064 		    "(tag 0x%x) %s on %s", __func__, htag, emsg, path);
1065 		if (pwrk != NULL) {
1066 			/*
1067 			 * There may be pending command on a target device.
1068 			 * Or, it may be a double fault.
1069 			 */
1070 			pmcs_start_ssp_event_recovery(pwp, pwrk, iomb, amt);
1071 		}
1072 	} else {
1073 		pmcs_prt(pwp, PMCS_PRT_DEBUG2, phyp, NULL,
1074 		    "%s: tag %x put onto the wire for %s",
1075 		    __func__, htag, path);
1076 		if (pwrk) {
1077 			pwrk->onwire = 1;
1078 			mutex_exit(&pwrk->lock);
1079 		}
1080 	}
1081 }
1082 
1083 static void
1084 pmcs_process_sata_event(pmcs_hw_t *pwp, void *iomb, size_t amt)
1085 {
1086 	_NOTE(ARGUNUSED(amt));
1087 	pmcwork_t *pwrk = NULL;
1088 	pmcs_phy_t *pptr;
1089 	uint32_t status, htag, *w;
1090 	char *path;
1091 
1092 	w = iomb;
1093 	htag = LE_32(w[1]);
1094 	status = LE_32(w[2]);
1095 
1096 	/*
1097 	 * If the status is PMCOUT_STATUS_XFER_ERROR_ABORTED_NCQ_MODE,
1098 	 * we have to issue a READ LOG EXT ATA (page 0x10) command
1099 	 * to the device. In this case, htag is not valid.
1100 	 *
1101 	 * If the status is PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED, we're
1102 	 * just noting that an I/O got put onto the wire.
1103 	 *
1104 	 * Othewise, other errors are indicative that things need to
1105 	 * be aborted.
1106 	 */
1107 	path = NULL;
1108 	if (htag) {
1109 		pwrk = pmcs_tag2wp(pwp, htag);
1110 		if (pwrk) {
1111 			pmcs_lock_phy(pwrk->phy);
1112 			pptr = pwrk->phy;
1113 			path = pptr->path;
1114 		}
1115 	}
1116 	if (path == NULL) {
1117 		mutex_enter(&pwp->lock);
1118 		pptr = pmcs_find_phy_by_devid(pwp, LE_32(w[4]));
1119 		/* This PHY is now locked */
1120 		mutex_exit(&pwp->lock);
1121 		if (pptr) {
1122 			path = pptr->path;
1123 		} else {
1124 			path = "????";
1125 		}
1126 	}
1127 
1128 	if (status != PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED) {
1129 		char buf[20];
1130 		const char *emsg = pmcs_status_str(status);
1131 
1132 		ASSERT(pptr != NULL);
1133 		if (emsg == NULL) {
1134 			(void) snprintf(buf, sizeof (buf), "Status 0x%x",
1135 			    status);
1136 			emsg = buf;
1137 		}
1138 		if (status == PMCOUT_STATUS_XFER_ERROR_ABORTED_NCQ_MODE) {
1139 			ASSERT(pptr != NULL);
1140 			pptr->need_rl_ext = 1;
1141 			htag = 0;
1142 		} else {
1143 			pptr->abort_pending = 1;
1144 		}
1145 		pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
1146 		    "%s: Bad SATA Status (tag 0x%x) %s on %s",
1147 		    __func__, htag, emsg, path);
1148 		SCHEDULE_WORK(pwp, PMCS_WORK_ABORT_HANDLE);
1149 		/*
1150 		 * Unlike SSP devices, we let the abort we
1151 		 * schedule above force the completion of
1152 		 * problem commands.
1153 		 */
1154 		if (pwrk) {
1155 			mutex_exit(&pwrk->lock);
1156 		}
1157 	} else if (status == PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED) {
1158 		pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, NULL,
1159 		    "%s: tag %x put onto the wire for %s",
1160 		    __func__, htag, path);
1161 		if (pwrk) {
1162 			pwrk->onwire = 1;
1163 			mutex_exit(&pwrk->lock);
1164 		}
1165 	}
1166 
1167 	if (pptr) {
1168 		pmcs_unlock_phy(pptr);
1169 	}
1170 }
1171 
1172 static void
1173 pmcs_process_abort_completion(pmcs_hw_t *pwp, void *iomb, size_t amt)
1174 {
1175 	pmcs_phy_t *pptr;
1176 	struct pmcwork *pwrk;
1177 	uint32_t htag = LE_32(((uint32_t *)iomb)[1]);
1178 	uint32_t status = LE_32(((uint32_t *)iomb)[2]);
1179 	uint32_t scp = LE_32(((uint32_t *)iomb)[3]) & 0x1;
1180 	char *path;
1181 
1182 	pwrk = pmcs_tag2wp(pwp, htag);
1183 	if (pwrk == NULL) {
1184 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
1185 		    "%s: cannot find work structure for ABORT", __func__);
1186 		return;
1187 	}
1188 
1189 	pptr = pwrk->phy;
1190 	if (pptr) {
1191 		pmcs_lock_phy(pptr);
1192 		pptr->abort_pending = 0;
1193 		pptr->abort_sent = 0;
1194 
1195 		/*
1196 		 * Don't do this if the status was ABORT_IN_PROGRESS and
1197 		 * the scope bit was set
1198 		 */
1199 		if ((status != PMCOUT_STATUS_IO_ABORT_IN_PROGRESS) || !scp) {
1200 			pptr->abort_all_start = 0;
1201 			cv_signal(&pptr->abort_all_cv);
1202 		}
1203 		path = pptr->path;
1204 		pmcs_unlock_phy(pptr);
1205 	} else {
1206 		path = "(no phy)";
1207 	}
1208 
1209 	switch (status) {
1210 	case PMCOUT_STATUS_OK:
1211 		if (scp) {
1212 			pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
1213 			    "%s: abort all succeeded for %s. (htag=0x%x)",
1214 			    __func__, path, htag);
1215 		} else {
1216 			pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
1217 			    "%s: abort tag 0x%x succeeded for %s. (htag=0x%x)",
1218 			    __func__, pwrk->abt_htag, path, htag);
1219 		}
1220 		break;
1221 
1222 	case PMCOUT_STATUS_IO_NOT_VALID:
1223 		if (scp) {
1224 			pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
1225 			    "%s: ABORT %s failed (DEV NOT VALID) for %s. "
1226 			    "(htag=0x%x)", __func__, scp ? "all" : "tag",
1227 			    path, htag);
1228 		} else {
1229 			pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL,
1230 			    "%s: ABORT %s failed (I/O NOT VALID) for %s. "
1231 			    "(htag=0x%x)", __func__, scp ? "all" : "tag",
1232 			    path, htag);
1233 		}
1234 		break;
1235 
1236 	case PMCOUT_STATUS_IO_ABORT_IN_PROGRESS:
1237 		pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, "%s: ABORT %s failed "
1238 		    "for %s, htag 0x%x (ABORT IN PROGRESS)", __func__,
1239 		    scp ? "all" : "tag", path, htag);
1240 		break;
1241 
1242 	default:
1243 		pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, "%s: Unknown status "
1244 		    "%d for ABORT %s, htag 0x%x, PHY %s", __func__, status,
1245 		    scp ? "all" : "tag", htag, path);
1246 		break;
1247 	}
1248 
1249 	pmcs_complete_work(pwp, pwrk, iomb, amt);
1250 }
1251 
1252 static void
1253 pmcs_process_general_event(pmcs_hw_t *pwp, uint32_t *iomb)
1254 {
1255 	uint32_t htag;
1256 	char local[60];
1257 	struct pmcwork *pwrk;
1258 	int i;
1259 
1260 	if (LE_32(iomb[1]) == INBOUND_IOMB_V_BIT_NOT_SET) {
1261 		(void) snprintf(local, sizeof (local),
1262 		    "VALID bit not set on INBOUND IOMB");
1263 	} else if (LE_32(iomb[1]) ==
1264 	    INBOUND_IOMB_OPC_NOT_SUPPORTED) {
1265 		(void) snprintf(local, sizeof (local),
1266 		    "opcode not set on inbound IOMB");
1267 	} else {
1268 		(void) snprintf(local, sizeof (local),
1269 		    "unknown GENERAL EVENT status (0x%x)",
1270 		    LE_32(iomb[1]));
1271 	}
1272 	/* Pull up bad IOMB into usual position */
1273 	for (i = 0; i < PMCS_MSG_SIZE - 2; i++) {
1274 		iomb[i] = iomb[i+2];
1275 	}
1276 	/* overwrite status with an error */
1277 	iomb[2] = LE_32(PMCOUT_STATUS_PROG_ERROR);
1278 	iomb[PMCS_MSG_SIZE - 2] = 0;
1279 	iomb[PMCS_MSG_SIZE - 1] = 0;
1280 	htag = LE_32(iomb[1]);
1281 	pmcs_print_entry(pwp, PMCS_PRT_DEBUG, local, iomb);
1282 	pwrk = pmcs_tag2wp(pwp, htag);
1283 	if (pwrk) {
1284 		pmcs_complete_work(pwp, pwrk, iomb, PMCS_QENTRY_SIZE);
1285 	}
1286 }
1287 
1288 void
1289 pmcs_general_intr(pmcs_hw_t *pwp)
1290 {
1291 	char local[PMCS_QENTRY_SIZE << 1];
1292 	uint32_t w0, pi, ci;
1293 	uint32_t *ptr, nbuf, lim = 0;
1294 	size_t amt;
1295 
1296 	ci = pmcs_rd_oqci(pwp, PMCS_OQ_GENERAL);
1297 	pi = pmcs_rd_oqpi(pwp, PMCS_OQ_GENERAL);
1298 
1299 	while (ci != pi) {
1300 		OQLIM_CHECK(pwp, lim);
1301 		ptr = GET_OQ_ENTRY(pwp, PMCS_OQ_GENERAL, ci, 0);
1302 		w0 = LE_32(ptr[0]);
1303 		VALID_IOMB_CHECK(pwp, w0, ptr, ci, pi);
1304 		WRONG_OBID_CHECK(pwp, w0, PMCS_OQ_GENERAL);
1305 		COPY_OUTBOUND(pwp, w0, local, nbuf, amt, ptr,
1306 		    PMCS_OQ_GENERAL, ci);
1307 
1308 		switch (w0 & PMCS_IOMB_OPCODE_MASK) {
1309 		case PMCOUT_SSP_COMPLETION:
1310 			/*
1311 			 * We only get SSP completion here for Task Management
1312 			 * completions.
1313 			 */
1314 		case PMCOUT_SMP_COMPLETION:
1315 		case PMCOUT_LOCAL_PHY_CONTROL:
1316 		case PMCOUT_DEVICE_REGISTRATION:
1317 		case PMCOUT_DEREGISTER_DEVICE_HANDLE:
1318 		case PMCOUT_GET_NVMD_DATA:
1319 		case PMCOUT_SET_NVMD_DATA:
1320 		case PMCOUT_GET_DEVICE_STATE:
1321 		case PMCOUT_SET_DEVICE_STATE:
1322 			pmcs_process_completion(pwp, local, amt);
1323 			break;
1324 		case PMCOUT_SSP_ABORT:
1325 		case PMCOUT_SATA_ABORT:
1326 		case PMCOUT_SMP_ABORT:
1327 			pmcs_process_abort_completion(pwp, local, amt);
1328 			break;
1329 		case PMCOUT_SSP_EVENT:
1330 			pmcs_process_ssp_event(pwp, local, amt);
1331 			break;
1332 		case PMCOUT_ECHO:
1333 			pmcs_process_echo_completion(pwp, local, amt);
1334 			break;
1335 		case PMCOUT_SAS_HW_EVENT_ACK_ACK:
1336 			if (LE_32(ptr[2]) != SAS_HW_EVENT_ACK_OK) {
1337 				pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
1338 				    "SAS H/W EVENT ACK/ACK Status=0x%b",
1339 				    LE_32(ptr[2]), "\020\4InvParm\3"
1340 				    "InvPort\2InvPhy\1InvSEA");
1341 			}
1342 			pmcs_process_completion(pwp, local, amt);
1343 			break;
1344 		case PMCOUT_SKIP_ENTRIES:
1345 			pmcs_prt(pwp, PMCS_PRT_DEBUG3, NULL, NULL,
1346 			    "%s: skip %d entries", __func__, nbuf);
1347 			break;
1348 		default:
1349 			(void) snprintf(local, sizeof (local),
1350 			    "%s: unhandled message", __func__);
1351 			pmcs_print_entry(pwp, PMCS_PRT_DEBUG, local, ptr);
1352 			break;
1353 		}
1354 		STEP_OQ_ENTRY(pwp, PMCS_OQ_GENERAL, ci, nbuf);
1355 	}
1356 	if (lim) {
1357 		SYNC_OQ_ENTRY(pwp, PMCS_OQ_GENERAL, ci, pi);
1358 	}
1359 }
1360 
1361 /*
1362  * pmcs_check_intr_coal
1363  *
1364  * This function makes a determination on the dynamic value of the
1365  * interrupt coalescing timer register.  We only use this for I/O
1366  * completions.
1367  *
1368  * The basic algorithm is as follows:
1369  *
1370  * PMCS_MAX_IO_COMPS_PER_INTR: The maximum number of I/O completions per
1371  * I/O completion interrupt.  We won't increase the interrupt coalescing
1372  * timer if we're already processing this many completions per interrupt
1373  * beyond the threshold.
1374  *
1375  * Values in io_intr_coal structure:
1376  *
1377  * intr_latency: The average number of nsecs between interrupts during
1378  * the echo test.  Used to help determine whether to increase the coalescing
1379  * timer.
1380  *
1381  * intr_threshold: Calculated number of interrupts beyond which we may
1382  * increase the timer.  This value is calculated based on the calculated
1383  * interrupt latency during the ECHO test and the current value of the
1384  * coalescing timer.
1385  *
1386  * nsecs_between_intrs: Total number of nsecs between all the interrupts
1387  * in the current timeslice.
1388  *
1389  * last_io_comp: Time of the last I/O interrupt.
1390  *
1391  * num_io_completions: Number of I/O completions during the slice
1392  *
1393  * num_intrs: Number of I/O completion interrupts during the slice
1394  *
1395  * max_io_completions: Number of times we hit >= PMCS_MAX_IO_COMPS_PER_INTR
1396  * during interrupt processing.
1397  *
1398  * PMCS_MAX_IO_COMPS_LOWAT_SHIFT/HIWAT_SHIFT
1399  * Low and high marks used to determine whether we processed enough interrupts
1400  * that contained the maximum number of I/O completions to warrant increasing
1401  * the timer
1402  *
1403  * intr_coal_timer: The current value of the register (in usecs)
1404  *
1405  * timer_on: B_TRUE means we are using the timer
1406  *
1407  * The timer is increased if we processed more than intr_threshold interrupts
1408  * during the quantum and the number of interrupts containing the maximum
1409  * number of I/O completions is between PMCS_MAX_IO_COMPS_LOWAT_SHIFT and
1410  * _HIWAT_SHIFT
1411  *
1412  * If the average time between completions is greater than twice
1413  * the current timer value, the timer value is decreased.
1414  *
1415  * If we did not take any interrupts during a quantum, we turn the timer off.
1416  */
1417 void
1418 pmcs_check_intr_coal(void *arg)
1419 {
1420 	pmcs_hw_t	*pwp = (pmcs_hw_t *)arg;
1421 	uint32_t	avg_nsecs;
1422 	pmcs_io_intr_coal_t *ici;
1423 
1424 	ici = &pwp->io_intr_coal;
1425 	mutex_enter(&pwp->ict_lock);
1426 
1427 	while (ici->stop_thread == B_FALSE) {
1428 		/*
1429 		 * Wait for next time quantum... collect stats
1430 		 */
1431 		(void) cv_timedwait(&pwp->ict_cv, &pwp->ict_lock,
1432 		    ddi_get_lbolt() + ici->quantum);
1433 
1434 		if (ici->stop_thread == B_TRUE) {
1435 			continue;
1436 		}
1437 
1438 		DTRACE_PROBE1(pmcs__check__intr__coal, pmcs_io_intr_coal_t *,
1439 		    &pwp->io_intr_coal);
1440 
1441 		/*
1442 		 * Determine whether to adjust timer
1443 		 */
1444 		if (ici->num_intrs == 0) {
1445 			/*
1446 			 * If timer is off, nothing more to do.
1447 			 */
1448 			if (!pwp->io_intr_coal.timer_on) {
1449 				continue;
1450 			}
1451 
1452 			/*
1453 			 * No interrupts.  Turn off the timer.
1454 			 */
1455 			pmcs_wr_topunit(pwp, PMCS_INT_COALESCING_CONTROL, 0);
1456 
1457 			if (pwp->odb_auto_clear & (1 << PMCS_MSIX_IODONE)) {
1458 				pmcs_wr_topunit(pwp, PMCS_OBDB_AUTO_CLR,
1459 				    pwp->odb_auto_clear);
1460 			}
1461 
1462 			ici->timer_on = B_FALSE;
1463 			ici->max_io_completions = 0;
1464 			ici->num_intrs = 0;
1465 			ici->int_cleared = B_FALSE;
1466 			ici->num_io_completions = 0;
1467 			DTRACE_PROBE1(pmcs__intr__coalesce__timer__off,
1468 			    pmcs_io_intr_coal_t *, ici);
1469 			continue;
1470 		}
1471 
1472 		avg_nsecs = ici->nsecs_between_intrs / ici->num_intrs;
1473 
1474 		if ((ici->num_intrs > ici->intr_threshold) &&
1475 		    (ici->max_io_completions > (ici->num_intrs >>
1476 		    PMCS_MAX_IO_COMPS_LOWAT_SHIFT)) &&
1477 		    (ici->max_io_completions < (ici->num_intrs >>
1478 		    PMCS_MAX_IO_COMPS_HIWAT_SHIFT))) {
1479 			pmcs_set_intr_coal_timer(pwp, INCREASE_TIMER);
1480 		} else if (avg_nsecs >
1481 		    (ici->intr_coal_timer * 1000 * 2)) {
1482 			pmcs_set_intr_coal_timer(pwp, DECREASE_TIMER);
1483 		}
1484 
1485 		/*
1486 		 * Reset values for new sampling period.
1487 		 */
1488 		ici->max_io_completions = 0;
1489 		ici->nsecs_between_intrs = 0;
1490 		ici->num_intrs = 0;
1491 		ici->num_io_completions = 0;
1492 	}
1493 
1494 	mutex_exit(&pwp->ict_lock);
1495 	thread_exit();
1496 }
1497 
1498 void
1499 pmcs_iodone_intr(pmcs_hw_t *pwp)
1500 {
1501 	char local[PMCS_QENTRY_SIZE << 1];
1502 	pmcs_iocomp_cb_t *ioccb;
1503 	uint32_t w0, ci, pi, nbuf, lim = 0, niodone = 0, iomb_opcode;
1504 	size_t amt;
1505 	uint32_t *ptr;
1506 	hrtime_t curtime = gethrtime();
1507 
1508 	ci = pmcs_rd_oqci(pwp, PMCS_OQ_IODONE);
1509 	pi = pmcs_rd_oqpi(pwp, PMCS_OQ_IODONE);
1510 
1511 	while (ci != pi) {
1512 		OQLIM_CHECK(pwp, lim);
1513 		ptr = GET_OQ_ENTRY(pwp, PMCS_OQ_IODONE, ci, 0);
1514 		w0 = LE_32(ptr[0]);
1515 		VALID_IOMB_CHECK(pwp, w0, ptr, ci, pi);
1516 		WRONG_OBID_CHECK(pwp, w0, PMCS_OQ_IODONE);
1517 		iomb_opcode = (w0 & PMCS_IOMB_OPCODE_MASK);
1518 
1519 		if ((iomb_opcode == PMCOUT_SSP_COMPLETION) ||
1520 		    (iomb_opcode == PMCOUT_SATA_COMPLETION)) {
1521 			ioccb =
1522 			    kmem_cache_alloc(pwp->iocomp_cb_cache, KM_NOSLEEP);
1523 			if (ioccb == NULL) {
1524 				pmcs_prt(pwp, PMCS_PRT_WARN, NULL, NULL,
1525 				    "%s: kmem_cache_alloc failed", __func__);
1526 				break;
1527 			}
1528 
1529 			COPY_OUTBOUND(pwp, w0, ioccb->iomb, nbuf, amt, ptr,
1530 			    PMCS_OQ_IODONE, ci);
1531 
1532 			niodone++;
1533 			pmcs_process_io_completion(pwp, ioccb, amt);
1534 		} else {
1535 			COPY_OUTBOUND(pwp, w0, local, nbuf, amt, ptr,
1536 			    PMCS_OQ_IODONE, ci);
1537 
1538 			switch (iomb_opcode) {
1539 			case PMCOUT_ECHO:
1540 				pmcs_process_echo_completion(pwp, local, amt);
1541 				break;
1542 			case PMCOUT_SATA_EVENT:
1543 				pmcs_process_sata_event(pwp, local, amt);
1544 				break;
1545 			case PMCOUT_SSP_EVENT:
1546 				pmcs_process_ssp_event(pwp, local, amt);
1547 				break;
1548 			case PMCOUT_SKIP_ENTRIES:
1549 				pmcs_prt(pwp, PMCS_PRT_DEBUG3, NULL, NULL,
1550 				    "%s: skip %d entries", __func__, nbuf);
1551 				break;
1552 			default:
1553 				(void) snprintf(local, sizeof (local),
1554 				    "%s: unhandled message", __func__);
1555 				pmcs_print_entry(pwp, PMCS_PRT_DEBUG, local,
1556 				    ptr);
1557 				break;
1558 			}
1559 		}
1560 
1561 		STEP_OQ_ENTRY(pwp, PMCS_OQ_IODONE, ci, nbuf);
1562 	}
1563 
1564 	if (lim != 0) {
1565 		SYNC_OQ_ENTRY(pwp, PMCS_OQ_IODONE, ci, pi);
1566 	}
1567 
1568 	/*
1569 	 * Update the interrupt coalescing timer check stats and run
1570 	 * completions for queued up commands.
1571 	 */
1572 
1573 	if (niodone > 0) {
1574 		/*
1575 		 * If we can't get the lock, then completions are either
1576 		 * already running or will be scheduled to do so shortly.
1577 		 */
1578 		if (mutex_tryenter(&pwp->cq_lock) != 0) {
1579 			PMCS_CQ_RUN_LOCKED(pwp);
1580 			mutex_exit(&pwp->cq_lock);
1581 		}
1582 
1583 		mutex_enter(&pwp->ict_lock);
1584 		pwp->io_intr_coal.nsecs_between_intrs +=
1585 		    curtime - pwp->io_intr_coal.last_io_comp;
1586 		pwp->io_intr_coal.num_intrs++;
1587 		pwp->io_intr_coal.num_io_completions += niodone;
1588 		if (niodone >= PMCS_MAX_IO_COMPS_PER_INTR) {
1589 			pwp->io_intr_coal.max_io_completions++;
1590 		}
1591 		pwp->io_intr_coal.last_io_comp = gethrtime();
1592 		mutex_exit(&pwp->ict_lock);
1593 	}
1594 }
1595 
1596 void
1597 pmcs_event_intr(pmcs_hw_t *pwp)
1598 {
1599 	char local[PMCS_QENTRY_SIZE << 1];
1600 	uint32_t w0, ci, pi, nbuf, lim =  0;
1601 	size_t amt;
1602 	uint32_t *ptr;
1603 
1604 	ci = pmcs_rd_oqci(pwp, PMCS_OQ_EVENTS);
1605 	pi = pmcs_rd_oqpi(pwp, PMCS_OQ_EVENTS);
1606 
1607 	while (ci != pi) {
1608 		OQLIM_CHECK(pwp, lim);
1609 		ptr = GET_OQ_ENTRY(pwp, PMCS_OQ_EVENTS, ci, 0);
1610 		w0 = LE_32(ptr[0]);
1611 		VALID_IOMB_CHECK(pwp, w0, ptr, ci, pi);
1612 		WRONG_OBID_CHECK(pwp, w0, PMCS_OQ_EVENTS);
1613 		COPY_OUTBOUND(pwp, w0, local, nbuf, amt, ptr,
1614 		    PMCS_OQ_EVENTS, ci);
1615 
1616 		switch (w0 & PMCS_IOMB_OPCODE_MASK) {
1617 		case PMCOUT_ECHO:
1618 			pmcs_process_echo_completion(pwp, local, amt);
1619 			break;
1620 		case PMCOUT_SATA_EVENT:
1621 			pmcs_process_sata_event(pwp, local, amt);
1622 			break;
1623 		case PMCOUT_SSP_EVENT:
1624 			pmcs_process_ssp_event(pwp, local, amt);
1625 			break;
1626 		case PMCOUT_GENERAL_EVENT:
1627 			pmcs_process_general_event(pwp, ptr);
1628 			break;
1629 		case PMCOUT_DEVICE_HANDLE_REMOVED:
1630 		{
1631 			uint32_t port = IOP_EVENT_PORTID(LE_32(ptr[1]));
1632 			uint32_t did = LE_32(ptr[2]);
1633 			pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
1634 			    "PortID 0x%x device_id 0x%x removed", port, did);
1635 			break;
1636 		}
1637 		case PMCOUT_SAS_HW_EVENT:
1638 			if (nbuf > 1) {
1639 				pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL,
1640 				    "multiple SAS HW_EVENT (%d) responses "
1641 				    "in EVENT OQ", nbuf);
1642 			}
1643 			pmcs_process_sas_hw_event(pwp, local, PMCS_QENTRY_SIZE);
1644 			break;
1645 		case PMCOUT_FW_FLASH_UPDATE:
1646 		case PMCOUT_GET_TIME_STAMP:
1647 		case PMCOUT_GET_DEVICE_STATE:
1648 		case PMCOUT_SET_DEVICE_STATE:
1649 		case PMCOUT_SAS_DIAG_EXECUTE:
1650 			pmcs_process_completion(pwp, local, amt);
1651 			break;
1652 		case PMCOUT_SKIP_ENTRIES:
1653 			pmcs_prt(pwp, PMCS_PRT_DEBUG3, NULL, NULL,
1654 			    "%s: skip %d entries", __func__, nbuf);
1655 			break;
1656 		default:
1657 			(void) snprintf(local, sizeof (local),
1658 			    "%s: unhandled message", __func__);
1659 			pmcs_print_entry(pwp, PMCS_PRT_DEBUG, local, ptr);
1660 			break;
1661 		}
1662 		STEP_OQ_ENTRY(pwp, PMCS_OQ_EVENTS, ci, nbuf);
1663 	}
1664 	if (lim) {
1665 		SYNC_OQ_ENTRY(pwp, PMCS_OQ_EVENTS, ci, pi);
1666 	}
1667 }
1668 
1669 void
1670 pmcs_timed_out(pmcs_hw_t *pwp, uint32_t htag, const char *func)
1671 {
1672 #ifdef	DEBUG
1673 	hrtime_t now = gethrtime();
1674 	int i;
1675 
1676 	for (i = 0; i < 256; i++) {
1677 		if (pwp->ftags[i] == htag) {
1678 			pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
1679 			    "Inbound msg (tag 0x%8x) timed out - "
1680 			    "was started %llu ns ago in %s:%d",
1681 			    htag, (unsigned long long) (now - pwp->ftime[i]),
1682 			    func, pwp->ftag_lines[i]);
1683 			return;
1684 		}
1685 	}
1686 #endif
1687 	pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
1688 	    "Inbound Message (tag 0x%08x) timed out- was started in %s",
1689 	    htag, func);
1690 }
1691