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