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