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