xref: /illumos-gate/usr/src/uts/common/io/scsi/adapters/smartpqi/smartpqi_intr.c (revision 8226594fdd4479be135127f43632f1f995074654)
1*8226594fSRick McNeal /*
2*8226594fSRick McNeal  * This file and its contents are supplied under the terms of the
3*8226594fSRick McNeal  * Common Development and Distribution License ("CDDL"), version 1.0.
4*8226594fSRick McNeal  * You may only use this file in accordance with the terms of version
5*8226594fSRick McNeal  * 1.0 of the CDDL.
6*8226594fSRick McNeal  *
7*8226594fSRick McNeal  * A full copy of the text of the CDDL should have accompanied this
8*8226594fSRick McNeal  * source.  A copy of the CDDL is also available via the Internet at
9*8226594fSRick McNeal  * http://www.illumos.org/license/CDDL.
10*8226594fSRick McNeal  */
11*8226594fSRick McNeal 
12*8226594fSRick McNeal /*
13*8226594fSRick McNeal  * Copyright 2023 Tintri by DDN, Inc. All rights reserved.
14*8226594fSRick McNeal  */
15*8226594fSRick McNeal 
16*8226594fSRick McNeal /*
17*8226594fSRick McNeal  * This file sets up the interrupts with the system and also processes
18*8226594fSRick McNeal  * interrupts from the hardware.
19*8226594fSRick McNeal  */
20*8226594fSRick McNeal 
21*8226594fSRick McNeal /* ---- Driver specific header ---- */
22*8226594fSRick McNeal #include <smartpqi.h>
23*8226594fSRick McNeal 
24*8226594fSRick McNeal /* ---- Forward declarations of private methods ---- */
25*8226594fSRick McNeal static int add_intrs(pqi_state_t *s, int type);
26*8226594fSRick McNeal static uint_t intr_handler(caddr_t arg1, caddr_t arg2);
27*8226594fSRick McNeal static void sync_error(pqi_state_t *s, pqi_io_request_t *io,
28*8226594fSRick McNeal     pqi_io_response_t *rsp);
29*8226594fSRick McNeal static void process_raid_io_error(pqi_io_request_t *io);
30*8226594fSRick McNeal static void process_aio_io_error(pqi_io_request_t *io);
31*8226594fSRick McNeal static void disable_aio_path(pqi_io_request_t *io);
32*8226594fSRick McNeal 
33*8226594fSRick McNeal /*
34*8226594fSRick McNeal  * smartpqi_register_intrs -- Figure out which type of interrupts and register
35*8226594fSRick McNeal  *			      them with the framework.
36*8226594fSRick McNeal  */
37*8226594fSRick McNeal int
smartpqi_register_intrs(pqi_state_t * s)38*8226594fSRick McNeal smartpqi_register_intrs(pqi_state_t *s)
39*8226594fSRick McNeal {
40*8226594fSRick McNeal 	int	intr_types;
41*8226594fSRick McNeal 
42*8226594fSRick McNeal 	/* ---- Get supported interrupt types ---- */
43*8226594fSRick McNeal 	if (ddi_intr_get_supported_types(s->s_dip, &intr_types) !=
44*8226594fSRick McNeal 	    DDI_SUCCESS) {
45*8226594fSRick McNeal 		dev_err(s->s_dip, CE_NOTE,
46*8226594fSRick McNeal 		    "failed to get supported intr types");
47*8226594fSRick McNeal 		return (FALSE);
48*8226594fSRick McNeal 	}
49*8226594fSRick McNeal 
50*8226594fSRick McNeal 	if (intr_types & DDI_INTR_TYPE_MSIX) {
51*8226594fSRick McNeal 		if (add_intrs(s, DDI_INTR_TYPE_MSIX) == TRUE) {
52*8226594fSRick McNeal 			s->s_intr_type = DDI_INTR_TYPE_MSIX;
53*8226594fSRick McNeal 			return (TRUE);
54*8226594fSRick McNeal 		}
55*8226594fSRick McNeal 	} else if (intr_types & DDI_INTR_TYPE_MSI) {
56*8226594fSRick McNeal 		if (add_intrs(s, DDI_INTR_TYPE_MSI) == TRUE) {
57*8226594fSRick McNeal 			s->s_intr_type = DDI_INTR_TYPE_MSI;
58*8226594fSRick McNeal 			return (TRUE);
59*8226594fSRick McNeal 		}
60*8226594fSRick McNeal 	} else if (intr_types & DDI_INTR_TYPE_FIXED) {
61*8226594fSRick McNeal 		if (add_intrs(s, DDI_INTR_TYPE_FIXED) == TRUE) {
62*8226594fSRick McNeal 			s->s_intr_type = DDI_INTR_TYPE_FIXED;
63*8226594fSRick McNeal 			return (TRUE);
64*8226594fSRick McNeal 		}
65*8226594fSRick McNeal 	} else {
66*8226594fSRick McNeal 		/* ---- Warning since it's a DDI framework error ---- */
67*8226594fSRick McNeal 		dev_err(s->s_dip, CE_WARN,
68*8226594fSRick McNeal 		    "ddi_intr_get_supported_types returned bogus type of 0x%x",
69*8226594fSRick McNeal 		    intr_types);
70*8226594fSRick McNeal 	}
71*8226594fSRick McNeal 
72*8226594fSRick McNeal 	return (FALSE);
73*8226594fSRick McNeal }
74*8226594fSRick McNeal 
75*8226594fSRick McNeal /*
76*8226594fSRick McNeal  * smartqpi_unregister_intrs -- Disable and remove interrupt handlers
77*8226594fSRick McNeal  */
78*8226594fSRick McNeal void
smartpqi_unregister_intrs(pqi_state_t * s)79*8226594fSRick McNeal smartpqi_unregister_intrs(pqi_state_t *s)
80*8226594fSRick McNeal {
81*8226594fSRick McNeal 	int	i;
82*8226594fSRick McNeal 
83*8226594fSRick McNeal 	/* --- First disable the interrupts ---- */
84*8226594fSRick McNeal 	if (s->s_intr_cap & DDI_INTR_FLAG_BLOCK) {
85*8226594fSRick McNeal 		(void) ddi_intr_block_disable(s->s_itable, s->s_intr_cnt);
86*8226594fSRick McNeal 	} else {
87*8226594fSRick McNeal 		for (i = 0; i < s->s_intr_cnt; i++) {
88*8226594fSRick McNeal 			(void) ddi_intr_disable(s->s_itable[i]);
89*8226594fSRick McNeal 		}
90*8226594fSRick McNeal 	}
91*8226594fSRick McNeal 
92*8226594fSRick McNeal 	/* ---- Next remove the interrupt handlers ---- */
93*8226594fSRick McNeal 	for (i = 0; i < s->s_intr_cnt; i++) {
94*8226594fSRick McNeal 		(void) ddi_intr_remove_handler(s->s_itable[i]);
95*8226594fSRick McNeal 		(void) ddi_intr_free(s->s_itable[i]);
96*8226594fSRick McNeal 	}
97*8226594fSRick McNeal 
98*8226594fSRick McNeal 	kmem_free(s->s_itable, s->s_intr_size);
99*8226594fSRick McNeal 	/* ---- Just in case ---- */
100*8226594fSRick McNeal 	s->s_itable = NULL;
101*8226594fSRick McNeal 	s->s_intr_size = 0;
102*8226594fSRick McNeal }
103*8226594fSRick McNeal 
104*8226594fSRick McNeal void
pqi_process_io_intr(pqi_state_t * s,pqi_queue_group_t * qg)105*8226594fSRick McNeal pqi_process_io_intr(pqi_state_t *s, pqi_queue_group_t *qg)
106*8226594fSRick McNeal {
107*8226594fSRick McNeal 	pqi_index_t		oq_pi;
108*8226594fSRick McNeal 	pqi_index_t		oq_ci;
109*8226594fSRick McNeal 	pqi_io_request_t	*io;
110*8226594fSRick McNeal 	pqi_io_response_t	*rsp;
111*8226594fSRick McNeal 	uint16_t		rqst_ix;
112*8226594fSRick McNeal 	uint8_t			rqst_gen;
113*8226594fSRick McNeal 	int			response_cnt = 0;
114*8226594fSRick McNeal 	int			qnotify;
115*8226594fSRick McNeal 
116*8226594fSRick McNeal 	oq_ci = qg->oq_ci_copy;
117*8226594fSRick McNeal 	atomic_inc_32(&s->s_intr_count);
118*8226594fSRick McNeal 
119*8226594fSRick McNeal 	mutex_enter(&s->s_intr_mutex);
120*8226594fSRick McNeal 	for (;;) {
121*8226594fSRick McNeal 		(void) ddi_dma_sync(s->s_queue_dma->handle,
122*8226594fSRick McNeal 		    (uintptr_t)qg->oq_pi -
123*8226594fSRick McNeal 		    (uintptr_t)s->s_queue_dma->alloc_memory,
124*8226594fSRick McNeal 		    sizeof (oq_pi), DDI_DMA_SYNC_FORCPU);
125*8226594fSRick McNeal 
126*8226594fSRick McNeal 		oq_pi = *qg->oq_pi;
127*8226594fSRick McNeal 		if (oq_pi == oq_ci)
128*8226594fSRick McNeal 			break;
129*8226594fSRick McNeal 
130*8226594fSRick McNeal 		rsp = (pqi_io_response_t *)(qg->oq_element_array +
131*8226594fSRick McNeal 		    (oq_ci * PQI_OPERATIONAL_OQ_ELEMENT_LENGTH));
132*8226594fSRick McNeal 		(void) ddi_dma_sync(s->s_queue_dma->handle,
133*8226594fSRick McNeal 		    (uintptr_t)rsp - (uintptr_t)s->s_queue_dma->alloc_memory,
134*8226594fSRick McNeal 		    sizeof (*rsp), DDI_DMA_SYNC_FORCPU);
135*8226594fSRick McNeal 		rqst_ix = PQI_REQID_INDEX(rsp->request_id);
136*8226594fSRick McNeal 		ASSERT(rqst_ix < s->s_max_io_slots);
137*8226594fSRick McNeal 		rqst_gen = PQI_REQID_GEN(rsp->request_id);
138*8226594fSRick McNeal 		io = &s->s_io_rqst_pool[rqst_ix];
139*8226594fSRick McNeal 
140*8226594fSRick McNeal 		if (!pqi_service_io(io, rqst_gen)) {
141*8226594fSRick McNeal 			/*
142*8226594fSRick McNeal 			 * Generation does not match, this response must be
143*8226594fSRick McNeal 			 * a stale response for a previous (timed out) i/o req.
144*8226594fSRick McNeal 			 */
145*8226594fSRick McNeal 			goto skipto;
146*8226594fSRick McNeal 		}
147*8226594fSRick McNeal 		ASSERT(io->io_refcount == 1);
148*8226594fSRick McNeal 
149*8226594fSRick McNeal 		if (io->io_cmd != NULL) {
150*8226594fSRick McNeal 			pqi_cmd_t	*cmd = io->io_cmd;
151*8226594fSRick McNeal 
152*8226594fSRick McNeal 			if ((cmd->pc_flags & PQI_FLAG_TIMED_OUT) != 0)
153*8226594fSRick McNeal 				goto skipto;
154*8226594fSRick McNeal 		}
155*8226594fSRick McNeal 
156*8226594fSRick McNeal 		io->io_iu_type = rsp->header.iu_type;
157*8226594fSRick McNeal 		switch (rsp->header.iu_type) {
158*8226594fSRick McNeal 		case PQI_RESPONSE_IU_RAID_PATH_IO_SUCCESS:
159*8226594fSRick McNeal 		case PQI_RESPONSE_IU_AIO_PATH_IO_SUCCESS:
160*8226594fSRick McNeal 		case PQI_RESPONSE_IU_GENERAL_MANAGEMENT:
161*8226594fSRick McNeal 		case PQI_RESPONSE_IU_TASK_MANAGEMENT:
162*8226594fSRick McNeal 			io->io_status = PQI_DATA_IN_OUT_GOOD;
163*8226594fSRick McNeal 			break;
164*8226594fSRick McNeal 		case PQI_RESPONSE_IU_RAID_PATH_IO_ERROR:
165*8226594fSRick McNeal 			io->io_status = PQI_DATA_IN_OUT_ERROR;
166*8226594fSRick McNeal 			sync_error(s, io, rsp);
167*8226594fSRick McNeal 			process_raid_io_error(io);
168*8226594fSRick McNeal 			break;
169*8226594fSRick McNeal 		case PQI_RESPONSE_IU_AIO_PATH_IO_ERROR:
170*8226594fSRick McNeal 			io->io_status = PQI_DATA_IN_OUT_ERROR;
171*8226594fSRick McNeal 			sync_error(s, io, rsp);
172*8226594fSRick McNeal 			process_aio_io_error(io);
173*8226594fSRick McNeal 			break;
174*8226594fSRick McNeal 		case PQI_RESPONSE_IU_AIO_PATH_DISABLED:
175*8226594fSRick McNeal 			io->io_status = PQI_DATA_IN_OUT_PROTOCOL_ERROR;
176*8226594fSRick McNeal 			disable_aio_path(io);
177*8226594fSRick McNeal 			break;
178*8226594fSRick McNeal 
179*8226594fSRick McNeal 		default:
180*8226594fSRick McNeal 			ASSERT(0);
181*8226594fSRick McNeal 			break;
182*8226594fSRick McNeal 		}
183*8226594fSRick McNeal 		io->io_cb(io, io->io_context);
184*8226594fSRick McNeal skipto:
185*8226594fSRick McNeal 		response_cnt++;
186*8226594fSRick McNeal 		oq_ci = (oq_ci + 1) % s->s_num_elements_per_oq;
187*8226594fSRick McNeal 	}
188*8226594fSRick McNeal 
189*8226594fSRick McNeal 	if (response_cnt) {
190*8226594fSRick McNeal 		qg->cmplt_count += response_cnt;
191*8226594fSRick McNeal 		qg->oq_ci_copy = oq_ci;
192*8226594fSRick McNeal 		ddi_put32(s->s_datap, qg->oq_ci, oq_ci);
193*8226594fSRick McNeal 	}
194*8226594fSRick McNeal 	mutex_exit(&s->s_intr_mutex);
195*8226594fSRick McNeal 
196*8226594fSRick McNeal 	mutex_enter(&s->s_mutex);
197*8226594fSRick McNeal 	qnotify = HBA_QUIESCED_PENDING(s);
198*8226594fSRick McNeal 	mutex_exit(&s->s_mutex);
199*8226594fSRick McNeal 
200*8226594fSRick McNeal 	if (qnotify)
201*8226594fSRick McNeal 		pqi_quiesced_notify(s);
202*8226594fSRick McNeal 
203*8226594fSRick McNeal }
204*8226594fSRick McNeal 
205*8226594fSRick McNeal static int
add_intrs(pqi_state_t * s,int type)206*8226594fSRick McNeal add_intrs(pqi_state_t *s, int type)
207*8226594fSRick McNeal {
208*8226594fSRick McNeal 	dev_info_t	*dip	= s->s_dip;
209*8226594fSRick McNeal 	int		avail;
210*8226594fSRick McNeal 	int		actual;
211*8226594fSRick McNeal 	int		count	= 0;
212*8226594fSRick McNeal 	int		i;
213*8226594fSRick McNeal 	int		ret;
214*8226594fSRick McNeal 
215*8226594fSRick McNeal 	/* ---- Get number of interrupts ---- */
216*8226594fSRick McNeal 	ret = ddi_intr_get_nintrs(dip, type, &count);
217*8226594fSRick McNeal 	if (ret != DDI_SUCCESS || count <= 0) {
218*8226594fSRick McNeal 		dev_err(s->s_dip, CE_NOTE, "ddi_intr_get_nintrs failed, "
219*8226594fSRick McNeal 		    "ret=%d, count=%d", ret, count);
220*8226594fSRick McNeal 		return (FALSE);
221*8226594fSRick McNeal 	}
222*8226594fSRick McNeal 
223*8226594fSRick McNeal 	/* ---- Get number of available interrupts ---- */
224*8226594fSRick McNeal 	ret = ddi_intr_get_navail(dip, type, &avail);
225*8226594fSRick McNeal 	if (ret != DDI_SUCCESS || avail == 0) {
226*8226594fSRick McNeal 		dev_err(s->s_dip, CE_NOTE, "ddi_intr_get_navail failed, "
227*8226594fSRick McNeal 		    "ret=%d, avail=%d", ret, avail);
228*8226594fSRick McNeal 		return (FALSE);
229*8226594fSRick McNeal 	}
230*8226594fSRick McNeal 
231*8226594fSRick McNeal 	if (type != DDI_INTR_TYPE_FIXED)
232*8226594fSRick McNeal 		count = 1;
233*8226594fSRick McNeal 
234*8226594fSRick McNeal 	s->s_intr_size = count * sizeof (ddi_intr_handle_t);
235*8226594fSRick McNeal 	s->s_itable = kmem_zalloc(s->s_intr_size, KM_SLEEP);
236*8226594fSRick McNeal 	ret = ddi_intr_alloc(dip, s->s_itable, type, 0, count, &actual,
237*8226594fSRick McNeal 	    DDI_INTR_ALLOC_NORMAL);
238*8226594fSRick McNeal 	if (ret != DDI_SUCCESS || actual == 0) {
239*8226594fSRick McNeal 		dev_err(s->s_dip, CE_NOTE, "ddi_intr_alloc failed, ret=%d",
240*8226594fSRick McNeal 		    ret);
241*8226594fSRick McNeal 		return (FALSE);
242*8226594fSRick McNeal 	}
243*8226594fSRick McNeal 
244*8226594fSRick McNeal 	/* ---- Use count return or abort? Make note of at least---- */
245*8226594fSRick McNeal 	if (actual < count) {
246*8226594fSRick McNeal 		dev_err(s->s_dip, CE_NOTE,
247*8226594fSRick McNeal 		    "interrupts: requested=%d, received=%d",
248*8226594fSRick McNeal 		    count, actual);
249*8226594fSRick McNeal 	}
250*8226594fSRick McNeal 	s->s_intr_cnt = actual;
251*8226594fSRick McNeal 
252*8226594fSRick McNeal 	/* ---- Get priority for first intr, assume rest are the same ---- */
253*8226594fSRick McNeal 	if ((ret = ddi_intr_get_pri(s->s_itable[0], &s->s_intr_pri)) !=
254*8226594fSRick McNeal 	    DDI_SUCCESS) {
255*8226594fSRick McNeal 		dev_err(s->s_dip, CE_NOTE, "ddi_intr_get_pri failed, ret=%d",
256*8226594fSRick McNeal 		    ret);
257*8226594fSRick McNeal 		goto failure;
258*8226594fSRick McNeal 	}
259*8226594fSRick McNeal 
260*8226594fSRick McNeal 	/* ---- Test for high level mutex ---- */
261*8226594fSRick McNeal 	if (s->s_intr_pri >= ddi_intr_get_hilevel_pri()) {
262*8226594fSRick McNeal 		dev_err(s->s_dip, CE_NOTE, "Hi level interrupts not supported");
263*8226594fSRick McNeal 		goto failure;
264*8226594fSRick McNeal 	}
265*8226594fSRick McNeal 
266*8226594fSRick McNeal 	/* ---- Install interrupt handler ---- */
267*8226594fSRick McNeal 	for (i = 0; i < actual; i++) {
268*8226594fSRick McNeal 		if ((ret = ddi_intr_add_handler(s->s_itable[i], intr_handler,
269*8226594fSRick McNeal 		    (caddr_t)s, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
270*8226594fSRick McNeal 			dev_err(s->s_dip, CE_NOTE,
271*8226594fSRick McNeal 			    "ddi_intr_add_handler failed, index=%d, ret=%d",
272*8226594fSRick McNeal 			    i, ret);
273*8226594fSRick McNeal 			goto failure;
274*8226594fSRick McNeal 		}
275*8226594fSRick McNeal 	}
276*8226594fSRick McNeal 
277*8226594fSRick McNeal 	if ((ret = ddi_intr_get_cap(s->s_itable[0], &s->s_intr_cap))
278*8226594fSRick McNeal 	    != DDI_SUCCESS) {
279*8226594fSRick McNeal 		dev_err(s->s_dip, CE_NOTE, "ddi_intr_get_cap failed, ret=%d",
280*8226594fSRick McNeal 		    ret);
281*8226594fSRick McNeal 		goto failure;
282*8226594fSRick McNeal 	}
283*8226594fSRick McNeal 
284*8226594fSRick McNeal 	/* ---- Enable interrupts ---- */
285*8226594fSRick McNeal 	if (s->s_intr_cap & DDI_INTR_FLAG_BLOCK) {
286*8226594fSRick McNeal 		(void) ddi_intr_block_enable(s->s_itable, s->s_intr_cnt);
287*8226594fSRick McNeal 	} else {
288*8226594fSRick McNeal 		/* --- Enable interrupts for either MSI or FIXED ---- */
289*8226594fSRick McNeal 		for (i = 0; i < actual; i++)
290*8226594fSRick McNeal 			(void) ddi_intr_enable(s->s_itable[i]);
291*8226594fSRick McNeal 	}
292*8226594fSRick McNeal 
293*8226594fSRick McNeal 	return (TRUE);
294*8226594fSRick McNeal 
295*8226594fSRick McNeal failure:
296*8226594fSRick McNeal 	/* ---- Free allocated interrupts pointers ---- */
297*8226594fSRick McNeal 	for (i = 0; i < actual; i++)
298*8226594fSRick McNeal 		(void) ddi_intr_free(s->s_itable[i]);
299*8226594fSRick McNeal 	kmem_free(s->s_itable, s->s_intr_size);
300*8226594fSRick McNeal 	s->s_itable = NULL;
301*8226594fSRick McNeal 	s->s_intr_size = 0;
302*8226594fSRick McNeal 	return (FALSE);
303*8226594fSRick McNeal }
304*8226594fSRick McNeal 
305*8226594fSRick McNeal static void
disable_aio_path(pqi_io_request_t * io)306*8226594fSRick McNeal disable_aio_path(pqi_io_request_t *io)
307*8226594fSRick McNeal {
308*8226594fSRick McNeal 	pqi_device_t	*devp;
309*8226594fSRick McNeal 
310*8226594fSRick McNeal 	devp = io->io_cmd->pc_device;
311*8226594fSRick McNeal 	devp->pd_aio_enabled = 0;
312*8226594fSRick McNeal }
313*8226594fSRick McNeal 
314*8226594fSRick McNeal static void
process_raid_io_error(pqi_io_request_t * io)315*8226594fSRick McNeal process_raid_io_error(pqi_io_request_t *io)
316*8226594fSRick McNeal {
317*8226594fSRick McNeal 	pqi_raid_error_info_t	ei;
318*8226594fSRick McNeal 	pqi_cmd_t		*cmd;
319*8226594fSRick McNeal 	int			sense_len;
320*8226594fSRick McNeal 	int			statusbuf_len;
321*8226594fSRick McNeal 	int			sense_len_to_copy;
322*8226594fSRick McNeal 	struct scsi_arq_status	*arq;
323*8226594fSRick McNeal 	struct scsi_pkt		*pkt;
324*8226594fSRick McNeal 
325*8226594fSRick McNeal 	if ((ei = io->io_error_info) != NULL) {
326*8226594fSRick McNeal 		io->io_status = ei->data_out_result;
327*8226594fSRick McNeal 		if ((cmd = io->io_cmd) == NULL || cmd->pc_pkt == NULL)
328*8226594fSRick McNeal 			return;
329*8226594fSRick McNeal 
330*8226594fSRick McNeal 		pkt = cmd->pc_pkt;
331*8226594fSRick McNeal 		pkt->pkt_resid -= ei->data_out_transferred;
332*8226594fSRick McNeal 		/* LINTED E_BAD_PTR_CAST_ALIGN */
333*8226594fSRick McNeal 		arq = (struct scsi_arq_status *)pkt->pkt_scbp;
334*8226594fSRick McNeal 		*((uchar_t *)&arq->sts_status) = ei->status;
335*8226594fSRick McNeal 		*((uchar_t *)&arq->sts_rqpkt_status) = STATUS_GOOD;
336*8226594fSRick McNeal 		arq->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
337*8226594fSRick McNeal 		    STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS |
338*8226594fSRick McNeal 		    STATE_ARQ_DONE;
339*8226594fSRick McNeal 
340*8226594fSRick McNeal 		sense_len = ei->sense_data_length;
341*8226594fSRick McNeal 		if (sense_len == 0)
342*8226594fSRick McNeal 			sense_len = ei->response_data_length;
343*8226594fSRick McNeal 
344*8226594fSRick McNeal 		if (sense_len == 0) {
345*8226594fSRick McNeal 			/* ---- auto request sense failed ---- */
346*8226594fSRick McNeal 			arq->sts_rqpkt_status.sts_chk = 1;
347*8226594fSRick McNeal 			arq->sts_rqpkt_resid = cmd->pc_statuslen;
348*8226594fSRick McNeal 			return;
349*8226594fSRick McNeal 		} else if (sense_len < cmd->pc_statuslen) {
350*8226594fSRick McNeal 			/* ---- auto request sense short ---- */
351*8226594fSRick McNeal 			arq->sts_rqpkt_resid = cmd->pc_statuslen -
352*8226594fSRick McNeal 			    sense_len;
353*8226594fSRick McNeal 		} else {
354*8226594fSRick McNeal 			/* ---- auto request sense complete ---- */
355*8226594fSRick McNeal 			arq->sts_rqpkt_resid = 0;
356*8226594fSRick McNeal 		}
357*8226594fSRick McNeal 		arq->sts_rqpkt_statistics = 0;
358*8226594fSRick McNeal 		pkt->pkt_state |= STATE_ARQ_DONE;
359*8226594fSRick McNeal 		if (cmd->pc_statuslen > PQI_ARQ_STATUS_NOSENSE_LEN) {
360*8226594fSRick McNeal 			statusbuf_len = cmd->pc_statuslen -
361*8226594fSRick McNeal 			    PQI_ARQ_STATUS_NOSENSE_LEN;
362*8226594fSRick McNeal 		} else {
363*8226594fSRick McNeal 			statusbuf_len = 0;
364*8226594fSRick McNeal 		}
365*8226594fSRick McNeal 
366*8226594fSRick McNeal 		if (sense_len > sizeof (ei->data))
367*8226594fSRick McNeal 			sense_len = sizeof (ei->data);
368*8226594fSRick McNeal 		sense_len_to_copy = min(sense_len, statusbuf_len);
369*8226594fSRick McNeal 
370*8226594fSRick McNeal 		if (sense_len_to_copy) {
371*8226594fSRick McNeal 			(void) memcpy(&arq->sts_sensedata, ei->data,
372*8226594fSRick McNeal 			    sense_len_to_copy);
373*8226594fSRick McNeal 		}
374*8226594fSRick McNeal 	} else {
375*8226594fSRick McNeal 		/*
376*8226594fSRick McNeal 		 * sync_error is called before this and sets io_error_info
377*8226594fSRick McNeal 		 * which means the value must be non-zero
378*8226594fSRick McNeal 		 */
379*8226594fSRick McNeal 		ASSERT(0);
380*8226594fSRick McNeal 	}
381*8226594fSRick McNeal }
382*8226594fSRick McNeal 
383*8226594fSRick McNeal static void
process_aio_io_error(pqi_io_request_t * io __unused)384*8226594fSRick McNeal process_aio_io_error(pqi_io_request_t *io __unused)
385*8226594fSRick McNeal {
386*8226594fSRick McNeal }
387*8226594fSRick McNeal 
388*8226594fSRick McNeal static void
sync_error(pqi_state_t * s,pqi_io_request_t * io,pqi_io_response_t * rsp)389*8226594fSRick McNeal sync_error(pqi_state_t *s, pqi_io_request_t *io, pqi_io_response_t *rsp)
390*8226594fSRick McNeal {
391*8226594fSRick McNeal 	(void) ddi_dma_sync(s->s_error_dma->handle,
392*8226594fSRick McNeal 	    rsp->error_index * PQI_ERROR_BUFFER_ELEMENT_LENGTH,
393*8226594fSRick McNeal 	    PQI_ERROR_BUFFER_ELEMENT_LENGTH, DDI_DMA_SYNC_FORCPU);
394*8226594fSRick McNeal 
395*8226594fSRick McNeal 	io->io_error_info = s->s_error_dma->alloc_memory +
396*8226594fSRick McNeal 	    (rsp->error_index * PQI_ERROR_BUFFER_ELEMENT_LENGTH);
397*8226594fSRick McNeal }
398*8226594fSRick McNeal 
399*8226594fSRick McNeal static void
process_event_intr(pqi_state_t * s)400*8226594fSRick McNeal process_event_intr(pqi_state_t *s)
401*8226594fSRick McNeal {
402*8226594fSRick McNeal 	pqi_event_queue_t	*q = &s->s_event_queue;
403*8226594fSRick McNeal 	pqi_event_response_t	*rsp;
404*8226594fSRick McNeal 	int			idx;
405*8226594fSRick McNeal 	int			num_events	= 0;
406*8226594fSRick McNeal 	pqi_event_t		*e;
407*8226594fSRick McNeal 	pqi_index_t		oq_ci;
408*8226594fSRick McNeal 	pqi_index_t		oq_pi;
409*8226594fSRick McNeal 
410*8226594fSRick McNeal 	oq_ci = q->oq_ci_copy;
411*8226594fSRick McNeal 
412*8226594fSRick McNeal 	mutex_enter(&s->s_intr_mutex);
413*8226594fSRick McNeal 	for (;;) {
414*8226594fSRick McNeal 		(void) ddi_dma_sync(s->s_queue_dma->handle,
415*8226594fSRick McNeal 		    (uintptr_t)q->oq_pi -
416*8226594fSRick McNeal 		    (uintptr_t)s->s_queue_dma->alloc_memory,
417*8226594fSRick McNeal 		    sizeof (oq_pi), DDI_DMA_SYNC_FORCPU);
418*8226594fSRick McNeal 		oq_pi = *q->oq_pi;
419*8226594fSRick McNeal 
420*8226594fSRick McNeal 		if (oq_pi == oq_ci)
421*8226594fSRick McNeal 			break;
422*8226594fSRick McNeal 
423*8226594fSRick McNeal 		num_events++;
424*8226594fSRick McNeal 		(void) ddi_dma_sync(s->s_queue_dma->handle,
425*8226594fSRick McNeal 		    (uintptr_t)q->oq_element_array +
426*8226594fSRick McNeal 		    (oq_ci * PQI_EVENT_OQ_ELEMENT_LENGTH) -
427*8226594fSRick McNeal 		    (uintptr_t)s->s_queue_dma->alloc_memory,
428*8226594fSRick McNeal 		    sizeof (*rsp),
429*8226594fSRick McNeal 		    DDI_DMA_SYNC_FORCPU);
430*8226594fSRick McNeal 		rsp = (pqi_event_response_t *)((uintptr_t)q->oq_element_array +
431*8226594fSRick McNeal 		    (oq_ci * PQI_EVENT_OQ_ELEMENT_LENGTH));
432*8226594fSRick McNeal 		idx = pqi_map_event(rsp->event_type);
433*8226594fSRick McNeal 
434*8226594fSRick McNeal 		if (idx != -1 && rsp->request_acknowlege) {
435*8226594fSRick McNeal 			e = &s->s_events[idx];
436*8226594fSRick McNeal 			e->ev_pending = B_TRUE;
437*8226594fSRick McNeal 			e->ev_type = rsp->event_type;
438*8226594fSRick McNeal 			e->ev_id = rsp->event_id;
439*8226594fSRick McNeal 			e->ev_additional = rsp->additional_event_id;
440*8226594fSRick McNeal 		}
441*8226594fSRick McNeal 		oq_ci = (oq_ci + 1) % PQI_NUM_EVENT_QUEUE_ELEMENTS;
442*8226594fSRick McNeal 	}
443*8226594fSRick McNeal 
444*8226594fSRick McNeal 	if (num_events != 0) {
445*8226594fSRick McNeal 		q->oq_ci_copy = oq_ci;
446*8226594fSRick McNeal 		ddi_put32(s->s_datap, q->oq_ci, oq_ci);
447*8226594fSRick McNeal 		(void) ddi_taskq_dispatch(s->s_events_taskq, pqi_event_worker,
448*8226594fSRick McNeal 		    s, 0);
449*8226594fSRick McNeal 	}
450*8226594fSRick McNeal 	mutex_exit(&s->s_intr_mutex);
451*8226594fSRick McNeal }
452*8226594fSRick McNeal 
453*8226594fSRick McNeal static uint_t
intr_handler(caddr_t arg1,caddr_t arg2)454*8226594fSRick McNeal intr_handler(caddr_t arg1, caddr_t arg2)
455*8226594fSRick McNeal {
456*8226594fSRick McNeal 	pqi_state_t		*s = (pqi_state_t *)arg1;
457*8226594fSRick McNeal 	int			queue_group_idx = (int)(intptr_t)arg2;
458*8226594fSRick McNeal 	pqi_queue_group_t	*qg;
459*8226594fSRick McNeal 
460*8226594fSRick McNeal 	if (!s->s_intr_ready)
461*8226594fSRick McNeal 		return (DDI_INTR_CLAIMED);
462*8226594fSRick McNeal 
463*8226594fSRick McNeal 	qg = &s->s_queue_groups[queue_group_idx];
464*8226594fSRick McNeal 	pqi_process_io_intr(s, qg);
465*8226594fSRick McNeal 	if (queue_group_idx == s->s_event_queue.int_msg_num)
466*8226594fSRick McNeal 		process_event_intr(s);
467*8226594fSRick McNeal 
468*8226594fSRick McNeal 	pqi_start_io(s, qg, RAID_PATH, NULL);
469*8226594fSRick McNeal 	pqi_start_io(s, qg, AIO_PATH, NULL);
470*8226594fSRick McNeal 
471*8226594fSRick McNeal 	return (DDI_INTR_CLAIMED);
472*8226594fSRick McNeal }
473