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