1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3  *
4  * This file is provided under a dual BSD/GPLv2 license.  When using or
5  * redistributing this file, you may do so under either license.
6  *
7  * GPL LICENSE SUMMARY
8  *
9  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of version 2 of the GNU General Public License as
13  * published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23  * The full GNU General Public License is included in this distribution
24  * in the file called LICENSE.GPL.
25  *
26  * BSD LICENSE
27  *
28  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  *
35  *   * Redistributions of source code must retain the above copyright
36  *     notice, this list of conditions and the following disclaimer.
37  *   * Redistributions in binary form must reproduce the above copyright
38  *     notice, this list of conditions and the following disclaimer in
39  *     the documentation and/or other materials provided with the
40  *     distribution.
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53  */
54 
55 #include <sys/cdefs.h>
56 __FBSDID("$FreeBSD$");
57 
58 /**
59  * @file
60  *
61  * @brief This file contains the task management substate handlers for the
62  *        SCIC_SDS_IO_REQUEST object.
63  *        This file contains the enter/exit methods associated with each of
64  *        the task management raw request states.  For more information on the
65  *        task management request state machine please refer to
66  *        scic_sds_io_request.h
67  */
68 
69 #include <dev/isci/scil/intel_sas.h>
70 #include <dev/isci/scil/scic_sds_request.h>
71 #include <dev/isci/scil/scic_controller.h>
72 #include <dev/isci/scil/scic_sds_logger.h>
73 #include <dev/isci/scil/scic_sds_controller.h>
74 #include <dev/isci/scil/scu_completion_codes.h>
75 #include <dev/isci/scil/scu_task_context.h>
76 #include <dev/isci/scil/sci_base_state_machine.h>
77 
78 /**
79  * @brief This method processes the completions transport layer (TL) status
80  *        to determine if the RAW task management frame was sent successfully.
81  *        If the raw frame was sent successfully, then the state for the
82  *        task request transitions to waiting for a response frame.
83  *
84  * @param[in] this_request This parameter specifies the request for which
85  *            the TC completion was received.
86  * @param[in] completion_code This parameter indicates the completion status
87  *            information for the TC.
88  *
89  * @return Indicate if the tc completion handler was successful.
90  * @retval SCI_SUCCESS currently this method always returns success.
91  */
92 static
93 SCI_STATUS scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler(
94    SCIC_SDS_REQUEST_T * this_request,
95    U32                  completion_code
96 )
97 {
98    SCIC_LOG_TRACE((
99       sci_base_object_get_logger(this_request),
100       SCIC_LOG_OBJECT_TASK_MANAGEMENT,
101       "scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler(0x%x, 0x%x) enter\n",
102       this_request, completion_code
103    ));
104 
105    switch (SCU_GET_COMPLETION_TL_STATUS(completion_code))
106    {
107    case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
108       scic_sds_request_set_status(
109          this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
110       );
111 
112       sci_base_state_machine_change_state(
113          &this_request->started_substate_machine,
114          SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE
115       );
116    break;
117 
118    case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO):
119       // Currently, the decision is to simply allow the task request to
120       // timeout if the task IU wasn't received successfully.
121       // There is a potential for receiving multiple task responses if we
122       // decide to send the task IU again.
123       SCIC_LOG_WARNING((
124          sci_base_object_get_logger(this_request),
125          SCIC_LOG_OBJECT_TASK_MANAGEMENT,
126          "TaskRequest:0x%x CompletionCode:%x - ACK/NAK timeout\n",
127          this_request, completion_code
128       ));
129 
130       sci_base_state_machine_change_state(
131          &this_request->started_substate_machine,
132          SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE
133       );
134    break;
135 
136    default:
137       // All other completion status cause the IO to be complete.  If a NAK
138       // was received, then it is up to the user to retry the request.
139       scic_sds_request_set_status(
140          this_request,
141          SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
142          SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
143       );
144 
145       sci_base_state_machine_change_state(
146          &this_request->parent.state_machine,
147          SCI_BASE_REQUEST_STATE_COMPLETED
148       );
149    break;
150    }
151 
152    return SCI_SUCCESS;
153 }
154 
155 /**
156  * @brief This method is responsible for processing a terminate/abort
157  *        request for this TC while the request is waiting for the task
158  *        management response unsolicited frame.
159  *
160  * @param[in] this_request This parameter specifies the request for which
161  *            the termination was requested.
162  *
163  * @return This method returns an indication as to whether the abort
164  *         request was successfully handled.
165  *
166  * @todo need to update to ensure the received UF doesn't cause damage
167  *       to subsequent requests (i.e. put the extended tag in a holding
168  *       pattern for this particular device).
169  */
170 static
171 SCI_STATUS scic_sds_ssp_task_request_await_tc_response_abort_handler(
172    SCI_BASE_REQUEST_T * request
173 )
174 {
175    SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)request;
176 
177    SCIC_LOG_TRACE((
178       sci_base_object_get_logger(this_request),
179       SCIC_LOG_OBJECT_TASK_MANAGEMENT,
180       "scic_sds_ssp_task_request_await_tc_response_abort_handler(0x%x) enter\n",
181       this_request
182    ));
183 
184    sci_base_state_machine_change_state(
185       &this_request->parent.state_machine,
186       SCI_BASE_REQUEST_STATE_ABORTING
187    );
188 
189    sci_base_state_machine_change_state(
190       &this_request->parent.state_machine,
191       SCI_BASE_REQUEST_STATE_COMPLETED
192    );
193 
194    return SCI_SUCCESS;
195 }
196 
197 /**
198  * @brief This method processes an unsolicited frame while the task mgmt
199  *        request is waiting for a response frame.  It will copy the
200  *        response data, release the unsolicited frame, and transition
201  *        the request to the SCI_BASE_REQUEST_STATE_COMPLETED state.
202  *
203  * @param[in] this_request This parameter specifies the request for which
204  *            the unsolicited frame was received.
205  * @param[in] frame_index This parameter indicates the unsolicited frame
206  *            index that should contain the response.
207  *
208  * @return This method returns an indication of whether the TC response
209  *         frame was handled successfully or not.
210  * @retval SCI_SUCCESS Currently this value is always returned and indicates
211  *         successful processing of the TC response.
212  *
213  * @todo Should probably update to check frame type and make sure it is
214  *       a response frame.
215  */
216 static
217 SCI_STATUS scic_sds_ssp_task_request_await_tc_response_frame_handler(
218    SCIC_SDS_REQUEST_T * this_request,
219    U32                  frame_index
220 )
221 {
222    // Save off the controller, so that we do not touch the request after it
223    //  is completed.
224    SCIC_SDS_CONTROLLER_T * owning_controller = this_request->owning_controller;
225 
226    SCIC_LOG_TRACE((
227       sci_base_object_get_logger(this_request),
228       SCIC_LOG_OBJECT_TASK_MANAGEMENT,
229       "scic_sds_ssp_task_request_await_tc_response_frame_handler(0x%x, 0x%x) enter\n",
230       this_request, frame_index
231    ));
232 
233    scic_sds_io_request_copy_response(this_request);
234 
235    sci_base_state_machine_change_state(
236       &this_request->parent.state_machine,
237       SCI_BASE_REQUEST_STATE_COMPLETED
238    );
239 
240    scic_sds_controller_release_frame(
241       owning_controller, frame_index
242    );
243 
244    return SCI_SUCCESS;
245 }
246 
247 SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
248 scic_sds_ssp_task_request_started_substate_handler_table
249 [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_MAX_SUBSTATES] =
250 {
251    // SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION
252    {
253       {
254          scic_sds_request_default_start_handler,
255          scic_sds_request_started_state_abort_handler,
256          scic_sds_request_default_complete_handler,
257          scic_sds_request_default_destruct_handler
258       },
259       scic_sds_ssp_task_request_await_tc_completion_tc_completion_handler,
260       scic_sds_request_default_event_handler,
261       scic_sds_request_default_frame_handler
262    },
263    // SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE
264    {
265       {
266          scic_sds_request_default_start_handler,
267          scic_sds_ssp_task_request_await_tc_response_abort_handler,
268          scic_sds_request_default_complete_handler,
269          scic_sds_request_default_destruct_handler
270       },
271       scic_sds_request_default_tc_completion_handler,
272       scic_sds_request_default_event_handler,
273       scic_sds_ssp_task_request_await_tc_response_frame_handler
274    }
275 };
276 
277 /**
278  * @brief This method performs the actions required when entering the
279  *        SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION
280  *        sub-state.  This includes setting the IO request state handlers
281  *        for this sub-state.
282  *
283  * @param[in]  object This parameter specifies the request object for which
284  *             the sub-state change is occurring.
285  *
286  * @return none.
287  */
288 static
289 void scic_sds_io_request_started_task_mgmt_await_tc_completion_substate_enter(
290    SCI_BASE_OBJECT_T *object
291 )
292 {
293    SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
294 
295    SET_STATE_HANDLER(
296       this_request,
297       scic_sds_ssp_task_request_started_substate_handler_table,
298       SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION
299    );
300 }
301 
302 /**
303  * @brief This method performs the actions required when entering the
304  *        SCIC_SDS_IO_REQUEST_STARTED_SUBSTATE_AWAIT_TC_RESPONSE sub-state.
305  *        This includes setting the IO request state handlers for this
306  *        sub-state.
307  *
308  * @param[in]  object This parameter specifies the request object for which
309  *             the sub-state change is occurring.
310  *
311  * @return none.
312  */
313 static
314 void scic_sds_io_request_started_task_mgmt_await_task_response_substate_enter(
315    SCI_BASE_OBJECT_T *object
316 )
317 {
318    SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
319 
320    SET_STATE_HANDLER(
321       this_request,
322       scic_sds_ssp_task_request_started_substate_handler_table,
323       SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE
324    );
325 }
326 
327 SCI_BASE_STATE_T scic_sds_io_request_started_task_mgmt_substate_table
328 [SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_MAX_SUBSTATES] =
329 {
330    {
331       SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION,
332       scic_sds_io_request_started_task_mgmt_await_tc_completion_substate_enter,
333       NULL
334    },
335    {
336       SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_RESPONSE,
337       scic_sds_io_request_started_task_mgmt_await_task_response_substate_enter,
338       NULL
339    }
340 };
341 
342 
343