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