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