xref: /freebsd/sys/dev/isci/scil/scic_sds_smp_request.c (revision ebacd8013fe5f7fdf9f6a5b286f6680dd2891036)
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 #include <dev/isci/scil/scic_sds_smp_request.h>
59 #include <dev/isci/scil/scic_sds_logger.h>
60 #include <dev/isci/scil/scic_sds_controller.h>
61 #include <dev/isci/scil/scic_sds_remote_device.h>
62 #include <dev/isci/scil/scic_remote_device.h>
63 #include <dev/isci/scil/sci_util.h>
64 #include <dev/isci/sci_environment.h>
65 #include <dev/isci/scil/intel_sas.h>
66 #include <dev/isci/scil/scic_sds_request.h>
67 #include <dev/isci/scil/scic_controller.h>
68 #include <dev/isci/scil/scu_completion_codes.h>
69 #include <dev/isci/scil/scu_task_context.h>
70 #include <dev/isci/scil/sci_base_state_machine.h>
71 
72 /**
73  * This method return the memory space required for STP PIO requests.
74  *
75  * @return U32
76  */
77 U32 scic_sds_smp_request_get_object_size(void)
78 {
79    return   sizeof(SCIC_SDS_REQUEST_T)
80           + sizeof(SMP_REQUEST_T)
81           + sizeof(U32)
82           + sizeof(SMP_RESPONSE_T)
83           + sizeof(U32)
84           + sizeof(SCU_TASK_CONTEXT_T)
85           + CACHE_LINE_SIZE;
86 }
87 
88 /**
89  * This macro returns the address of the smp command buffer in the smp request
90  * memory. No need to cast to SMP request type.
91  */
92 #define scic_sds_smp_request_get_command_buffer_unaligned(memory) \
93    ( ((char *)(memory)) + sizeof(SCIC_SDS_REQUEST_T) )
94 
95 /**
96  * This macro aligns the smp command buffer in DWORD alignment
97 */
98 #define scic_sds_smp_request_align_command_buffer(address) \
99    ((char *)( \
100       (((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \
101          & ~(sizeof(U32)- 1) \
102    ))
103 
104 /**
105  * This macro returns the DWORD-aligned smp command buffer
106 */
107 #define scic_sds_smp_request_get_command_buffer(memory) \
108    ((char *)  \
109       ((char *)scic_sds_smp_request_align_command_buffer( \
110          (char *) scic_sds_smp_request_get_command_buffer_unaligned(memory) \
111    )))
112 
113 /**
114  * This macro returns the address of the smp response buffer in the smp request
115  * memory.
116  */
117 #define scic_sds_smp_request_get_response_buffer_unaligned(memory) \
118    ( ((char *)(scic_sds_smp_request_get_command_buffer(memory))) \
119       + sizeof(SMP_REQUEST_T) )
120 
121 /**
122  * This macro aligns the smp command buffer in DWORD alignment
123 */
124 #define scic_sds_smp_request_align_response_buffer(address) \
125    ((char *)( \
126       (((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \
127          & ~(sizeof(U32)- 1) \
128    ))
129 
130 /**
131  * This macro returns the DWORD-aligned smp resposne buffer
132 */
133 #define scic_sds_smp_request_get_response_buffer(memory) \
134    ((char *)  \
135       ((char *)scic_sds_smp_request_align_response_buffer( \
136          (char *) scic_sds_smp_request_get_response_buffer_unaligned(memory) \
137    )))
138 
139 /**
140  * This macro returs the task context buffer for the SMP request.
141  */
142 #define scic_sds_smp_request_get_task_context_buffer_unaligned(memory) \
143    ((SCU_TASK_CONTEXT_T *)( \
144         ((char *)(scic_sds_smp_request_get_response_buffer(memory))) \
145       + sizeof(SMP_RESPONSE_T) \
146    ))
147 
148 /**
149  * This macro returns the dword-aligned smp task context buffer
150  */
151 #define scic_sds_smp_request_get_task_context_buffer(memory) \
152    ((SCU_TASK_CONTEXT_T *)( \
153       ((char *)scic_sds_request_align_task_context_buffer( \
154          (char *)scic_sds_smp_request_get_task_context_buffer_unaligned(memory)) \
155    )))
156 
157 /**
158  * @brief This method build the remainder of the IO request object.
159  *
160  * @pre The scic_sds_general_request_construct() must be called before this
161  *      call is valid.
162  *
163  * @param[in] this_request This parameter specifies the request object being
164  *            constructed.
165  *
166  * @return none
167  */
168 
169 void scic_sds_smp_request_assign_buffers(
170    SCIC_SDS_REQUEST_T *this_request
171 )
172 {
173    // Assign all of the buffer pointers
174    this_request->command_buffer =
175       scic_sds_smp_request_get_command_buffer(this_request);
176    this_request->response_buffer =
177       scic_sds_smp_request_get_response_buffer(this_request);
178    this_request->sgl_element_pair_buffer = NULL;
179 
180    if (this_request->was_tag_assigned_by_user == FALSE)
181    {
182       this_request->task_context_buffer =
183          scic_sds_smp_request_get_task_context_buffer(this_request);
184    }
185 
186 }
187 /**
188  * @brief This method is called by the SCI user to build an SMP
189  *        IO request.
190  *
191  * @pre
192  *        - The user must have previously called scic_io_request_construct()
193  *          on the supplied IO request.
194  *
195  * @param[in]  scic_io_request This parameter specifies the handle to the
196  *             io request object to be built.
197  *
198  * @return Indicate if the controller successfully built the IO request.
199  * @retval SCI_SUCCESS This value is returned if the IO request was
200  *         successfully built.
201  * @retval SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned if the
202  *         remote_device does not support the SMP protocol.
203  * @retval SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the
204  *         user did not properly set the association between the SCIC IO
205  *         request and the user's IO request.  Please refer to the
206  *         sci_object_set_association() routine for more
207  *         information.
208  */
209 SCI_STATUS scic_io_request_construct_smp(
210    SCI_IO_REQUEST_HANDLE_T  scic_smp_request
211 )
212 {
213    SMP_REQUEST_T smp_request;
214 
215    SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *) scic_smp_request;
216    SCIC_LOG_TRACE((
217       sci_base_object_get_logger(this_request),
218       SCIC_LOG_OBJECT_SMP_IO_REQUEST,
219       "scic_io_request_construct_smp(0x%x) enter\n",
220       this_request
221    ));
222 
223    this_request->protocol                     = SCIC_SMP_PROTOCOL;
224    this_request->has_started_substate_machine = TRUE;
225 
226    // Construct the started sub-state machine.
227    sci_base_state_machine_construct(
228       &this_request->started_substate_machine,
229       &this_request->parent.parent,
230       scic_sds_smp_request_started_substate_table,
231       SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
232    );
233 
234    // Construct the SMP SCU Task Context
235    memcpy((char *)&smp_request,
236         this_request->command_buffer,
237         sizeof(SMP_REQUEST_T));
238 
239    // Look at the SMP requests' header fields; for certain SAS 1.x SMP
240    // functions under SAS 2.0, a zero request length really indicates
241    // a non-zero default length.
242    if( smp_request.header.request_length == 0 )
243    {
244        switch( smp_request.header.function )
245        {
246        case SMP_FUNCTION_DISCOVER:
247        case SMP_FUNCTION_REPORT_PHY_ERROR_LOG:
248        case SMP_FUNCTION_REPORT_PHY_SATA:
249        case SMP_FUNCTION_REPORT_ROUTE_INFORMATION:
250            smp_request.header.request_length = 2;
251            break;
252        case SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION:
253        case SMP_FUNCTION_PHY_CONTROL:
254        case SMP_FUNCTION_PHY_TEST:
255            smp_request.header.request_length = 9;
256            break;
257        // Default - zero is a valid default for 2.0.
258        }
259    }
260 
261    scu_smp_request_construct_task_context(
262       this_request,
263       &smp_request
264    );
265 
266    sci_base_state_machine_change_state(
267       &this_request->parent.state_machine,
268       SCI_BASE_REQUEST_STATE_CONSTRUCTED
269    );
270 
271    return SCI_SUCCESS;
272 }
273 
274 /**
275  * @brief This method is called by the SCI user to build an SMP pass-through
276  *        IO request.
277  *
278  * @pre
279  *        - The user must have previously called scic_io_request_construct()
280  *          on the supplied IO request.
281  *
282  * @param[in]  scic_smp_request This parameter specifies the handle to the
283  *             io request object to be built.
284  *
285  * @param[in]  passthru_cb This parameter specifies the pointer to the callback
286  *             structure that contains the function pointers
287  *
288  * @return Indicate if the controller successfully built the IO request.
289  */
290 SCI_STATUS scic_io_request_construct_smp_pass_through(
291    SCI_IO_REQUEST_HANDLE_T  scic_smp_request,
292    SCIC_SMP_PASSTHRU_REQUEST_CALLBACKS_T *passthru_cb
293 )
294 {
295    SMP_REQUEST_T smp_request;
296    U8 * request_buffer;
297    U32 request_buffer_length_in_bytes;
298 
299    SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *) scic_smp_request;
300    SCIC_LOG_TRACE((
301       sci_base_object_get_logger(this_request),
302       SCIC_LOG_OBJECT_SMP_IO_REQUEST,
303       "scic_io_request_construct_smp_pass_through(0x%x) enter\n",
304       this_request
305    ));
306 
307    this_request->protocol                     = SCIC_SMP_PROTOCOL;
308    this_request->has_started_substate_machine = TRUE;
309 
310    // Call the callback function to retrieve the SMP passthrough request
311    request_buffer_length_in_bytes = passthru_cb->scic_cb_smp_passthru_get_request (
312                                        (void *)this_request,
313                                        &request_buffer
314                                     );
315 
316    //copy the request to smp request
317    memcpy((char *)&smp_request.request.vendor_specific_request,
318         request_buffer,
319         request_buffer_length_in_bytes);
320 
321    //the header length in smp_request is in dwords - the sas spec has similar way,
322    //but the csmi header contains the number of bytes, so we need to convert the
323    //number of bytes to number of dwords
324    smp_request.header.request_length = (U8) (request_buffer_length_in_bytes / sizeof (U32));
325 
326    //Grab the other needed fields from the smp request using callbacks
327    smp_request.header.smp_frame_type = passthru_cb->scic_cb_smp_passthru_get_frame_type ((void *)this_request);
328    smp_request.header.function = passthru_cb->scic_cb_smp_passthru_get_function ((void *)this_request);
329    smp_request.header.allocated_response_length = passthru_cb->scic_cb_smp_passthru_get_allocated_response_length((void *)this_request);
330 
331    // Construct the started sub-state machine.
332    sci_base_state_machine_construct(
333       &this_request->started_substate_machine,
334       &this_request->parent.parent,
335       scic_sds_smp_request_started_substate_table,
336       SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
337    );
338 
339    // Construct the SMP SCU Task Context
340    scu_smp_request_construct_task_context (this_request, &smp_request);
341 
342    sci_base_state_machine_change_state(
343       &this_request->parent.state_machine,
344       SCI_BASE_REQUEST_STATE_CONSTRUCTED
345    );
346 
347    return SCI_SUCCESS;
348 }
349 
350 /**
351  * @brief This method will fill in the SCU Task Context for a SMP request. The
352  *        following important settings are utilized:
353  *
354  *          -# task_type == SCU_TASK_TYPE_SMP.  This simply indicates
355  *             that a normal request type (i.e. non-raw frame) is being
356  *             utilized to perform task management.
357  *          -# control_frame == 1.  This ensures that the proper endianness
358  *             is set so that the bytes are transmitted in the right order
359  *             for a smp request frame.
360  *
361  * @param[in] this_request This parameter specifies the smp request object
362  *            being constructed.
363  *
364  * @return none
365  */
366 void scu_smp_request_construct_task_context(
367    SCIC_SDS_REQUEST_T *this_request,
368    SMP_REQUEST_T      *smp_request
369 )
370 {
371    SCI_PHYSICAL_ADDRESS      physical_address;
372    SCIC_SDS_CONTROLLER_T    *owning_controller;
373    SCIC_SDS_REMOTE_DEVICE_T *target_device;
374    SCIC_SDS_PORT_T          *target_port;
375    SCU_TASK_CONTEXT_T *task_context;
376 
377    //byte swap the smp request.
378    scic_word_copy_with_swap(
379       this_request->command_buffer,
380       (U32*) smp_request,
381       sizeof(SMP_REQUEST_T)/sizeof(U32)
382    );
383 
384    task_context = scic_sds_request_get_task_context(this_request);
385 
386    owning_controller = scic_sds_request_get_controller(this_request);
387    target_device = scic_sds_request_get_device(this_request);
388    target_port = scic_sds_request_get_port(this_request);
389 
390    SCIC_LOG_TRACE((
391       sci_base_object_get_logger(this_request),
392       SCIC_LOG_OBJECT_SMP_IO_REQUEST,
393       "scu_smp_request_construct_task_context(0x%x) contents\n"
394       "   reqlen=%x; function=%x;\n",
395       this_request,
396       smp_request->header.request_length,
397       smp_request->header.function
398    ));
399 
400    // Fill in the TC with the its required data
401    // 00h
402    task_context->priority = 0;
403    task_context->initiator_request = 1;
404    task_context->connection_rate =
405       scic_remote_device_get_connection_rate(target_device);
406    task_context->protocol_engine_index =
407       scic_sds_controller_get_protocol_engine_group(owning_controller);
408    task_context->logical_port_index =
409       scic_sds_port_get_index(target_port);
410    task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SMP;
411    task_context->abort = 0;
412    task_context->valid = SCU_TASK_CONTEXT_VALID;
413    task_context->context_type = SCU_TASK_CONTEXT_TYPE;
414 
415    //04h
416    task_context->remote_node_index = this_request->target_device->rnc->remote_node_index;
417    task_context->command_code = 0;
418    task_context->task_type = SCU_TASK_TYPE_SMP_REQUEST;
419 
420    //08h
421    task_context->link_layer_control = 0;
422    task_context->do_not_dma_ssp_good_response = 1;
423    task_context->strict_ordering = 0;
424    task_context->control_frame = 1;
425    task_context->timeout_enable = 0;
426    task_context->block_guard_enable = 0;
427 
428    //0ch
429    task_context->address_modifier = 0;
430 
431    //10h
432    task_context->ssp_command_iu_length = smp_request->header.request_length;
433 
434    //14h
435    task_context->transfer_length_bytes = 0;
436 
437    //18h ~ 30h, protocol specific
438    // since commandIU has been build by framework at this point, we just
439    // copy the frist DWord from command IU to this location.
440    memcpy((void *)(&task_context->type.smp), this_request->command_buffer, sizeof(U32) );
441 
442    //40h
443    // "For SMP you could program it to zero. We would prefer that way so that
444    // done code will be consistent." - Venki
445    task_context->task_phase = 0;
446 
447    if (this_request->was_tag_assigned_by_user)
448    {
449       // Build the task context now since we have already read the data
450       this_request->post_context = (
451            SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC
452          | (
453                 scic_sds_controller_get_protocol_engine_group(owning_controller)
454              << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT
455            )
456          | (
457                  scic_sds_port_get_index(target_port)
458               << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT
459            )
460          | scic_sds_io_tag_get_index(this_request->io_tag)
461       );
462    }
463    else
464    {
465       // Build the task context now since we have already read the data
466       this_request->post_context = (
467            SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC
468          | (
469                scic_sds_controller_get_protocol_engine_group(owning_controller)
470             << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT
471            )
472          | (
473                 scic_sds_port_get_index(target_port)
474              << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT
475            )
476          // This is not assigned because we have to wait until we get a TCi
477       );
478    }
479 
480    // Copy the physical address for the command buffer to the SCU Task Context
481    // command buffer should not contain command header.
482    scic_cb_io_request_get_physical_address(
483          scic_sds_request_get_controller(this_request),
484          this_request,
485          ((char *)(this_request->command_buffer) + sizeof(U32)),
486          &physical_address
487       );
488 
489    task_context->command_iu_upper =
490       sci_cb_physical_address_upper(physical_address);
491    task_context->command_iu_lower =
492       sci_cb_physical_address_lower(physical_address);
493 
494 
495    //SMP response comes as UF, so no need to set response IU address.
496    task_context->response_iu_upper = 0;
497    task_context->response_iu_lower = 0;
498 }
499 
500 //******************************************************************************
501 //* SMP REQUEST STATE MACHINE
502 //******************************************************************************
503 
504 /**
505  * @brief This method processes an unsolicited frame while the SMP request is
506  *        waiting for a response frame.  It will copy the response data, release
507  *        the unsolicited frame, and transition the request to the
508  *        SCI_BASE_REQUEST_STATE_COMPLETED state.
509  *
510  * @param[in] this_request This parameter specifies the request for which
511  *            the unsolicited frame was received.
512  * @param[in] frame_index This parameter indicates the unsolicited frame
513  *            index that should contain the response.
514  *
515  * @return This method returns an indication of whether the response
516  *         frame was handled successfully or not.
517  * @retval SCI_SUCCESS Currently this value is always returned and indicates
518  *         successful processing of the TC response.
519  */
520 static
521 SCI_STATUS scic_sds_smp_request_await_response_frame_handler(
522    SCIC_SDS_REQUEST_T * this_request,
523    U32                  frame_index
524 )
525 {
526    SCI_STATUS              status;
527    void                  * frame_header;
528    SMP_RESPONSE_HEADER_T * this_frame_header;
529    U8                    * user_smp_buffer = this_request->response_buffer;
530 
531    // Save off the controller, so that we do not touch the request after it
532    //  is completed.
533    SCIC_SDS_CONTROLLER_T * controller = scic_sds_request_get_controller(this_request);
534 
535    SCIC_LOG_TRACE((
536       sci_base_object_get_logger(this_request),
537       SCIC_LOG_OBJECT_SMP_IO_REQUEST,
538       "scic_sds_smp_request_await_response_frame_handler(0x%x, 0x%x) enter\n",
539       this_request, frame_index
540    ));
541 
542    status = scic_sds_unsolicited_frame_control_get_header(
543       &(controller->uf_control),
544       frame_index,
545       &frame_header
546    );
547 
548    //byte swap the header.
549    scic_word_copy_with_swap(
550       (U32*) user_smp_buffer,
551       frame_header,
552       sizeof(SMP_RESPONSE_HEADER_T)/sizeof(U32)
553    );
554    this_frame_header = (SMP_RESPONSE_HEADER_T*) user_smp_buffer;
555 
556    if (this_frame_header->smp_frame_type == SMP_FRAME_TYPE_RESPONSE)
557    {
558       void * smp_response_buffer;
559 
560       status = scic_sds_unsolicited_frame_control_get_buffer(
561          &(controller->uf_control),
562          frame_index,
563          &smp_response_buffer
564       );
565 
566       scic_word_copy_with_swap(
567          (U32*) (user_smp_buffer + sizeof(SMP_RESPONSE_HEADER_T)),
568          smp_response_buffer,
569          sizeof(SMP_RESPONSE_BODY_T)/sizeof(U32)
570       );
571       if (this_frame_header->function == SMP_FUNCTION_DISCOVER)
572       {
573           SMP_RESPONSE_T * this_smp_response;
574 
575           this_smp_response = (SMP_RESPONSE_T *)user_smp_buffer;
576 
577           // Some expanders only report an attached SATA device, and
578           // not an STP target.  Since the core depends on the STP
579           // target attribute to correctly build I/O, set the bit now
580           // if necessary.
581           if (this_smp_response->response.discover.protocols.u.bits.attached_sata_device
582            && !this_smp_response->response.discover.protocols.u.bits.attached_stp_target)
583           {
584               this_smp_response->response.discover.protocols.u.bits.attached_stp_target = 1;
585 
586               SCIC_LOG_TRACE((
587                   sci_base_object_get_logger(this_request),
588                  SCIC_LOG_OBJECT_SMP_IO_REQUEST,
589                  "scic_sds_smp_request_await_response_frame_handler(0x%x) Found SATA dev, setting STP bit.\n",
590                  this_request
591               ));
592           }
593       }
594 
595      //Don't need to copy to user space. User instead will refer to
596      //core request's response buffer.
597 
598      //copy the smp response to framework smp request's response buffer.
599      //scic_sds_smp_request_copy_response(this_request);
600 
601       scic_sds_request_set_status(
602          this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
603       );
604 
605       sci_base_state_machine_change_state(
606          &this_request->started_substate_machine,
607          SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
608       );
609    }
610    else
611    {
612       // This was not a response frame why did it get forwarded?
613       SCIC_LOG_ERROR((
614          sci_base_object_get_logger(this_request),
615          SCIC_LOG_OBJECT_SMP_IO_REQUEST,
616          "SCIC SMP Request 0x%08x received unexpected frame %d type 0x%02x\n",
617          this_request, frame_index, this_frame_header->smp_frame_type
618       ));
619 
620      scic_sds_request_set_status(
621         this_request,
622         SCU_TASK_DONE_SMP_FRM_TYPE_ERR,
623         SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
624      );
625 
626      sci_base_state_machine_change_state(
627          &this_request->parent.state_machine,
628          SCI_BASE_REQUEST_STATE_COMPLETED
629       );
630    }
631 
632    scic_sds_controller_release_frame(
633       controller, frame_index
634    );
635 
636    return SCI_SUCCESS;
637 }
638 
639 
640 /**
641  * @brief This method processes an abnormal TC completion while the SMP
642  *        request is waiting for a response frame.  It decides what
643  *        happened to the IO based on TC completion status.
644  *
645  * @param[in] this_request This parameter specifies the request for which
646  *            the TC completion was received.
647  * @param[in] completion_code This parameter indicates the completion status
648  *            information for the TC.
649  *
650  * @return Indicate if the tc completion handler was successful.
651  * @retval SCI_SUCCESS currently this method always returns success.
652  */
653 static
654 SCI_STATUS scic_sds_smp_request_await_response_tc_completion_handler(
655    SCIC_SDS_REQUEST_T * this_request,
656    U32                  completion_code
657 )
658 {
659    SCIC_LOG_TRACE((
660       sci_base_object_get_logger(this_request),
661       SCIC_LOG_OBJECT_SMP_IO_REQUEST,
662       "scic_sds_smp_request_await_response_tc_completion_handler(0x%x, 0x%x) enter\n",
663       this_request, completion_code
664    ));
665 
666    switch (SCU_GET_COMPLETION_TL_STATUS(completion_code))
667    {
668    case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
669       //In the AWAIT RESPONSE state, any TC completion is unexpected.
670       //but if the TC has success status, we complete the IO anyway.
671       scic_sds_request_set_status(
672          this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
673       );
674 
675       sci_base_state_machine_change_state(
676          &this_request->parent.state_machine,
677          SCI_BASE_REQUEST_STATE_COMPLETED
678       );
679    break;
680 
681    case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR):
682    case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR):
683    case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR):
684    case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR):
685       //These status has been seen in a specific LSI expander, which sometimes
686       //is not able to send smp response within 2 ms. This causes our hardware
687       //break the connection and set TC completion with one of these SMP_XXX_XX_ERR
688       //status. For these type of error, we ask scic user to retry the request.
689       scic_sds_request_set_status(
690          this_request, SCU_TASK_DONE_SMP_RESP_TO_ERR, SCI_FAILURE_RETRY_REQUIRED
691       );
692 
693       sci_base_state_machine_change_state(
694          &this_request->parent.state_machine,
695          SCI_BASE_REQUEST_STATE_COMPLETED
696       );
697    break;
698 
699    default:
700       // All other completion status cause the IO to be complete.  If a NAK
701       // was received, then it is up to the user to retry the request.
702       scic_sds_request_set_status(
703          this_request,
704          SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
705          SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
706       );
707 
708       sci_base_state_machine_change_state(
709          &this_request->parent.state_machine,
710          SCI_BASE_REQUEST_STATE_COMPLETED
711       );
712    break;
713    }
714 
715    return SCI_SUCCESS;
716 }
717 
718 
719 /**
720  * @brief This method processes the completions transport layer (TL) status
721  *        to determine if the SMP request was sent successfully. If the SMP
722  *        request was sent successfully, then the state for the SMP request
723  *        transits to waiting for a response frame.
724  *
725  * @param[in] this_request This parameter specifies the request for which
726  *            the TC completion was received.
727  * @param[in] completion_code This parameter indicates the completion status
728  *            information for the TC.
729  *
730  * @return Indicate if the tc completion handler was successful.
731  * @retval SCI_SUCCESS currently this method always returns success.
732  */
733 static
734 SCI_STATUS scic_sds_smp_request_await_tc_completion_tc_completion_handler(
735    SCIC_SDS_REQUEST_T * this_request,
736    U32                  completion_code
737 )
738 {
739    SCIC_LOG_TRACE((
740       sci_base_object_get_logger(this_request),
741       SCIC_LOG_OBJECT_SMP_IO_REQUEST,
742       "scic_sds_smp_request_await_tc_completion_tc_completion_handler(0x%x, 0x%x) enter\n",
743       this_request, completion_code
744    ));
745 
746    switch (SCU_GET_COMPLETION_TL_STATUS(completion_code))
747    {
748    case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
749       scic_sds_request_set_status(
750          this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
751       );
752 
753       sci_base_state_machine_change_state(
754          &this_request->parent.state_machine,
755          SCI_BASE_REQUEST_STATE_COMPLETED
756       );
757    break;
758 
759    default:
760       // All other completion status cause the IO to be complete.  If a NAK
761       // was received, then it is up to the user to retry the request.
762       scic_sds_request_set_status(
763          this_request,
764          SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
765          SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
766       );
767 
768       sci_base_state_machine_change_state(
769          &this_request->parent.state_machine,
770          SCI_BASE_REQUEST_STATE_COMPLETED
771       );
772    break;
773    }
774 
775    return SCI_SUCCESS;
776 }
777 
778 
779 SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
780 scic_sds_smp_request_started_substate_handler_table
781 [SCIC_SDS_SMP_REQUEST_STARTED_MAX_SUBSTATES] =
782 {
783    // SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
784    {
785       {
786          scic_sds_request_default_start_handler,
787          scic_sds_request_started_state_abort_handler,
788          scic_sds_request_default_complete_handler,
789          scic_sds_request_default_destruct_handler
790       },
791       scic_sds_smp_request_await_response_tc_completion_handler,
792       scic_sds_request_default_event_handler,
793       scic_sds_smp_request_await_response_frame_handler
794    },
795    // SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
796    {
797       {
798          scic_sds_request_default_start_handler,
799          scic_sds_request_started_state_abort_handler,
800          scic_sds_request_default_complete_handler,
801          scic_sds_request_default_destruct_handler
802       },
803       scic_sds_smp_request_await_tc_completion_tc_completion_handler,
804       scic_sds_request_default_event_handler,
805       scic_sds_request_default_frame_handler
806    }
807 };
808 
809 /**
810  * @brief This method performs the actions required when entering the
811  *        SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_RESPONSE sub-state.
812  *        This includes setting the IO request state handlers for this
813  *        sub-state.
814  *
815  * @param[in]  object This parameter specifies the request object for which
816  *             the sub-state change is occurring.
817  *
818  * @return none.
819  */
820 static
821 void scic_sds_smp_request_started_await_response_substate_enter(
822    SCI_BASE_OBJECT_T *object
823 )
824 {
825    SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
826 
827    SET_STATE_HANDLER(
828       this_request,
829       scic_sds_smp_request_started_substate_handler_table,
830       SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
831    );
832 }
833 
834 /**
835  * @brief This method performs the actions required when entering the
836  *        SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
837  *        sub-state.  This includes setting the SMP request state handlers for
838  *        this sub-state.
839  *
840  * @param[in]  object This parameter specifies the request object for which
841  *             the sub-state change is occurring.
842  *
843  * @return none.
844  */
845 static
846 void scic_sds_smp_request_started_await_tc_completion_substate_enter(
847    SCI_BASE_OBJECT_T *object
848 )
849 {
850    SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
851 
852    SET_STATE_HANDLER(
853       this_request,
854       scic_sds_smp_request_started_substate_handler_table,
855       SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
856    );
857 }
858 
859 SCI_BASE_STATE_T scic_sds_smp_request_started_substate_table
860 [SCIC_SDS_SMP_REQUEST_STARTED_MAX_SUBSTATES] =
861 {
862    {
863       SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE,
864       scic_sds_smp_request_started_await_response_substate_enter,
865       NULL
866    },
867    {
868       SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION,
869       scic_sds_smp_request_started_await_tc_completion_substate_enter,
870       NULL
871    }
872 };
873 
874 
875