1 /*-
2  * Copyright (c) 2018 Microsemi Corporation.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /* $FreeBSD$ */
28 
29 #include "smartpqi_includes.h"
30 
31 /*
32  * Process internal RAID response in the case of success.
33  */
34 void pqisrc_process_internal_raid_response_success(pqisrc_softstate_t *softs,
35 					  rcb_t *rcb)
36 {
37 	DBG_FUNC("IN");
38 
39 	rcb->status = REQUEST_SUCCESS;
40 	rcb->req_pending = false;
41 
42 	DBG_FUNC("OUT");
43 }
44 
45 /*
46  * Process internal RAID response in the case of failure.
47  */
48 void  pqisrc_process_internal_raid_response_error(pqisrc_softstate_t *softs,
49 				       rcb_t *rcb, uint16_t err_idx)
50 {
51 	raid_path_error_info_elem_t error_info;
52 
53 	DBG_FUNC("IN");
54 
55 	rcb->error_info = (char *) (softs->err_buf_dma_mem.virt_addr) +
56 			  (err_idx * PQI_ERROR_BUFFER_ELEMENT_LENGTH);
57 	rcb->status = REQUEST_SUCCESS;
58 	memcpy(&error_info, rcb->error_info, sizeof(error_info));
59 
60 	DBG_INFO("error_status 0x%x data_in_result 0x%x data_out_result 0x%x\n",
61 		error_info.status, error_info.data_in_result, error_info.data_out_result);
62 
63 	if (error_info.status != 0)
64 		rcb->status = REQUEST_FAILED;
65 	if (error_info.data_in_result != PQI_RAID_DATA_IN_OUT_GOOD)
66 		rcb->status = REQUEST_FAILED;
67 	if (error_info.data_out_result != PQI_RAID_DATA_IN_OUT_GOOD)
68 		rcb->status = REQUEST_FAILED;
69 
70 	rcb->req_pending = false;
71 
72 	DBG_FUNC("OUT");
73 }
74 
75 /*
76  * Process the AIO/RAID IO in the case of success.
77  */
78 void pqisrc_process_io_response_success(pqisrc_softstate_t *softs,
79 		rcb_t *rcb)
80 {
81 	DBG_FUNC("IN");
82 
83 	os_io_response_success(rcb);
84 
85 	DBG_FUNC("OUT");
86 }
87 
88 /*
89  * Process the error info for AIO in the case of failure.
90  */
91 void pqisrc_process_aio_response_error(pqisrc_softstate_t *softs,
92 		rcb_t *rcb, uint16_t err_idx)
93 {
94 	aio_path_error_info_elem_t *err_info = NULL;
95 
96 	DBG_FUNC("IN");
97 
98 	err_info = (aio_path_error_info_elem_t*)
99 			softs->err_buf_dma_mem.virt_addr +
100 			err_idx;
101 
102 	if(err_info == NULL) {
103 		DBG_ERR("err_info structure is NULL  err_idx :%x", err_idx);
104 		return;
105 	}
106 
107 	os_aio_response_error(rcb, err_info);
108 
109 	DBG_FUNC("OUT");
110 }
111 
112 /*
113  * Process the error info for RAID IO in the case of failure.
114  */
115 void pqisrc_process_raid_response_error(pqisrc_softstate_t *softs,
116 		rcb_t *rcb, uint16_t err_idx)
117 {
118 	raid_path_error_info_elem_t *err_info = NULL;
119 
120 	DBG_FUNC("IN");
121 
122 	err_info = (raid_path_error_info_elem_t*)
123 			softs->err_buf_dma_mem.virt_addr +
124 			err_idx;
125 
126 	if(err_info == NULL) {
127 		DBG_ERR("err_info structure is NULL  err_idx :%x", err_idx);
128 		return;
129 	}
130 
131 	os_raid_response_error(rcb, err_info);
132 
133 	DBG_FUNC("OUT");
134 }
135 
136 /*
137  * Process the Task Management function response.
138  */
139 int pqisrc_process_task_management_response(pqisrc_softstate_t *softs,
140 			pqi_tmf_resp_t *tmf_resp)
141 {
142 	int ret = REQUEST_SUCCESS;
143 	uint32_t tag = (uint32_t)tmf_resp->req_id;
144 	rcb_t *rcb = &softs->rcb[tag];
145 
146 	ASSERT(rcb->tag == tag);
147 
148 	DBG_FUNC("IN\n");
149 
150 	switch (tmf_resp->resp_code) {
151 	case SOP_TASK_MANAGEMENT_FUNCTION_COMPLETE:
152 	case SOP_TASK_MANAGEMENT_FUNCTION_SUCCEEDED:
153 		ret = REQUEST_SUCCESS;
154 		break;
155 	default:
156 		DBG_ERR("TMF Failed, Response code : 0x%x\n", tmf_resp->resp_code);
157 		ret = REQUEST_FAILED;
158 		break;
159 	}
160 
161 	rcb->status = ret;
162 	rcb->req_pending = false;
163 
164 	DBG_FUNC("OUT");
165 	return ret;
166 }
167 
168 /*
169  * Function used to process the response from the adapter
170  * which is invoked by IRQ handler.
171  */
172 void
173 pqisrc_process_response_queue(pqisrc_softstate_t *softs, int oq_id)
174 {
175 	ob_queue_t *ob_q;
176 	struct pqi_io_response *response;
177 	uint32_t oq_pi, oq_ci;
178 
179 	DBG_FUNC("IN");
180 
181 	OS_ATOMIC64_INC(softs, num_intrs);
182 
183 	ob_q = &softs->op_ob_q[oq_id - 1]; /* zero for event Q */
184 	oq_ci = ob_q->ci_local;
185 	oq_pi = *(ob_q->pi_virt_addr);
186 
187 	DBG_INFO("ci : %d pi : %d qid : %d\n", oq_ci, oq_pi, ob_q->q_id);
188 
189 	while (1) {
190 		rcb_t *rcb = NULL;
191 		uint32_t tag = 0;
192 		uint32_t offset;
193 
194 		if (oq_pi == oq_ci)
195 			break;
196 		/* Get the response */
197 		offset = oq_ci * ob_q->elem_size;
198 		response = (struct pqi_io_response *)(ob_q->array_virt_addr +
199 							offset);
200 		tag = response->request_id;
201 		rcb = &softs->rcb[tag];
202 		/* Make sure we are processing a valid response. */
203 		ASSERT(rcb->tag == tag && rcb->req_pending);
204 		rcb->req_pending = false;
205 
206 		DBG_INFO("response.header.iu_type : %x \n", response->header.iu_type);
207 
208 		switch (response->header.iu_type) {
209 		case PQI_RESPONSE_IU_RAID_PATH_IO_SUCCESS:
210 		case PQI_RESPONSE_IU_AIO_PATH_IO_SUCCESS:
211 			rcb->success_cmp_callback(softs, rcb);
212 			break;
213 		case PQI_RESPONSE_IU_RAID_PATH_IO_ERROR:
214 		case PQI_RESPONSE_IU_AIO_PATH_IO_ERROR:
215 			rcb->error_cmp_callback(softs, rcb, LE_16(response->error_index));
216 			break;
217 		case PQI_RESPONSE_IU_GENERAL_MANAGEMENT:
218 			rcb->req_pending = false;
219 			break;
220 		case PQI_RESPONSE_IU_TASK_MANAGEMENT:
221 			rcb->status = pqisrc_process_task_management_response(softs, (void *)response);
222 			break;
223 
224 		default:
225 			DBG_ERR("Invalid Response IU 0x%x\n",response->header.iu_type);
226 			break;
227 		}
228 
229 		oq_ci = (oq_ci + 1) % ob_q->num_elem;
230 	}
231 
232 	ob_q->ci_local = oq_ci;
233 	PCI_MEM_PUT32(softs, ob_q->ci_register_abs,
234         ob_q->ci_register_offset, ob_q->ci_local );
235 	DBG_FUNC("OUT");
236 }
237