scic_sds_smp_request.c revision 230843
160786Sps/*-
2128345Stjr * This file is provided under a dual BSD/GPLv2 license.  When using or
360786Sps * redistributing this file, you may do so under either license.
460786Sps *
560786Sps * GPL LICENSE SUMMARY
660786Sps *
760786Sps * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
860786Sps *
960786Sps * This program is free software; you can redistribute it and/or modify
1060786Sps * it under the terms of version 2 of the GNU General Public License as
1160786Sps * published by the Free Software Foundation.
1260786Sps *
1360786Sps * This program is distributed in the hope that it will be useful, but
1460786Sps * WITHOUT ANY WARRANTY; without even the implied warranty of
1560786Sps * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1660786Sps * General Public License for more details.
1760786Sps *
1860786Sps * You should have received a copy of the GNU General Public License
1960786Sps * along with this program; if not, write to the Free Software
2060786Sps * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
2160786Sps * The full GNU General Public License is included in this distribution
2260786Sps * in the file called LICENSE.GPL.
2360786Sps *
2460786Sps * BSD LICENSE
2560786Sps *
2660786Sps * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
2760786Sps * All rights reserved.
2860786Sps *
2960786Sps * Redistribution and use in source and binary forms, with or without
3060786Sps * modification, are permitted provided that the following conditions
3160786Sps * are met:
3260786Sps *
3360786Sps *   * Redistributions of source code must retain the above copyright
3460786Sps *     notice, this list of conditions and the following disclaimer.
3560786Sps *   * Redistributions in binary form must reproduce the above copyright
3660786Sps *     notice, this list of conditions and the following disclaimer in
3760786Sps *     the documentation and/or other materials provided with the
3860786Sps *     distribution.
3960786Sps *
4060786Sps * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4160786Sps * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4260786Sps * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4360786Sps * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4460786Sps * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4560786Sps * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4660786Sps * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4760786Sps * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4860786Sps * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4960786Sps * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
5060786Sps * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5160786Sps */
5260786Sps
5360786Sps#include <sys/cdefs.h>
5460786Sps__FBSDID("$FreeBSD$");
5560786Sps
5660786Sps#include <dev/isci/scil/scic_sds_smp_request.h>
5760786Sps#include <dev/isci/scil/scic_sds_logger.h>
5860786Sps#include <dev/isci/scil/scic_sds_controller.h>
5960786Sps#include <dev/isci/scil/scic_sds_remote_device.h>
6060786Sps#include <dev/isci/scil/scic_remote_device.h>
6160786Sps#include <dev/isci/scil/sci_util.h>
6260786Sps#include <dev/isci/sci_environment.h>
6360786Sps#include <dev/isci/scil/intel_sas.h>
6460786Sps#include <dev/isci/scil/scic_sds_request.h>
6560786Sps#include <dev/isci/scil/scic_controller.h>
6660786Sps#include <dev/isci/scil/scu_completion_codes.h>
67128345Stjr#include <dev/isci/scil/scu_task_context.h>
6860786Sps#include <dev/isci/scil/sci_base_state_machine.h>
6960786Sps
7060786Sps/**
71128345Stjr * This method return the memory space required for STP PIO requests.
7260786Sps *
7360786Sps * @return U32
7460786Sps */
7560786SpsU32 scic_sds_smp_request_get_object_size(void)
76128345Stjr{
7760786Sps   return   sizeof(SCIC_SDS_REQUEST_T)
7860786Sps          + sizeof(SMP_REQUEST_T)
7960786Sps          + sizeof(U32)
8060786Sps          + sizeof(SMP_RESPONSE_T)
8160786Sps          + sizeof(U32)
82128345Stjr          + sizeof(SCU_TASK_CONTEXT_T)
83128345Stjr          + CACHE_LINE_SIZE;
8460786Sps}
85128345Stjr
8660786Sps/**
8760786Sps * This macro returns the address of the smp command buffer in the smp request
8860786Sps * memory. No need to cast to SMP request type.
8960786Sps */
9060786Sps#define scic_sds_smp_request_get_command_buffer_unaligned(memory) \
9160786Sps   ( ((char *)(memory)) + sizeof(SCIC_SDS_REQUEST_T) )
9260786Sps
9360786Sps/**
9460786Sps * This macro aligns the smp command buffer in DWORD alignment
9560786Sps*/
9660786Sps#define scic_sds_smp_request_align_command_buffer(address) \
9760786Sps   ((char *)( \
9860786Sps      (((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \
9960786Sps         & ~(sizeof(U32)- 1) \
10060786Sps   ))
10160786Sps
10260786Sps/**
10360786Sps * This macro returns the DWORD-aligned smp command buffer
10460786Sps*/
10560786Sps#define scic_sds_smp_request_get_command_buffer(memory) \
10660786Sps   ((char *)  \
10760786Sps      ((char *)scic_sds_smp_request_align_command_buffer( \
10860786Sps         (char *) scic_sds_smp_request_get_command_buffer_unaligned(memory) \
10960786Sps   )))
11060786Sps
11160786Sps/**
11260786Sps * This macro returns the address of the smp response buffer in the smp request
11360786Sps * memory.
11460786Sps */
11560786Sps#define scic_sds_smp_request_get_response_buffer_unaligned(memory) \
11660786Sps   ( ((char *)(scic_sds_smp_request_get_command_buffer(memory))) \
11760786Sps      + sizeof(SMP_REQUEST_T) )
11860786Sps
11960786Sps/**
12060786Sps * This macro aligns the smp command buffer in DWORD alignment
12160786Sps*/
12260786Sps#define scic_sds_smp_request_align_response_buffer(address) \
12360786Sps   ((char *)( \
12460786Sps      (((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \
12560786Sps         & ~(sizeof(U32)- 1) \
12660786Sps   ))
12760786Sps
12860786Sps/**
12960786Sps * This macro returns the DWORD-aligned smp resposne buffer
13060786Sps*/
13160786Sps#define scic_sds_smp_request_get_response_buffer(memory) \
13260786Sps   ((char *)  \
13360786Sps      ((char *)scic_sds_smp_request_align_response_buffer( \
13460786Sps         (char *) scic_sds_smp_request_get_response_buffer_unaligned(memory) \
13560786Sps   )))
13660786Sps
13760786Sps/**
13860786Sps * This macro returs the task context buffer for the SMP request.
13960786Sps */
14060786Sps#define scic_sds_smp_request_get_task_context_buffer_unaligned(memory) \
14160786Sps   ((SCU_TASK_CONTEXT_T *)( \
14260786Sps        ((char *)(scic_sds_smp_request_get_response_buffer(memory))) \
14360786Sps      + sizeof(SMP_RESPONSE_T) \
14460786Sps   ))
14560786Sps
14660786Sps/**
14760786Sps * This macro returns the dword-aligned smp task context buffer
14860786Sps */
14960786Sps#define scic_sds_smp_request_get_task_context_buffer(memory) \
15060786Sps   ((SCU_TASK_CONTEXT_T *)( \
15160786Sps      ((char *)scic_sds_request_align_task_context_buffer( \
15260786Sps         (char *)scic_sds_smp_request_get_task_context_buffer_unaligned(memory)) \
15360786Sps   )))
15460786Sps
15560786Sps/**
15660786Sps * @brief This method build the remainder of the IO request object.
15760786Sps *
15889019Sps * @pre The scic_sds_general_request_construct() must be called before this
15960786Sps *      call is valid.
16060786Sps *
16160786Sps * @param[in] this_request This parameter specifies the request object being
16260786Sps *            constructed.
16360786Sps *
16460786Sps * @return none
16560786Sps */
16660786Sps
16760786Spsvoid scic_sds_smp_request_assign_buffers(
16860786Sps   SCIC_SDS_REQUEST_T *this_request
16960786Sps)
17060786Sps{
17160786Sps   // Assign all of the buffer pointers
17260786Sps   this_request->command_buffer =
17360786Sps      scic_sds_smp_request_get_command_buffer(this_request);
17460786Sps   this_request->response_buffer =
17560786Sps      scic_sds_smp_request_get_response_buffer(this_request);
17660786Sps   this_request->sgl_element_pair_buffer = NULL;
17760786Sps
17860786Sps   if (this_request->was_tag_assigned_by_user == FALSE)
17960786Sps   {
18060786Sps      this_request->task_context_buffer =
18160786Sps         scic_sds_smp_request_get_task_context_buffer(this_request);
18260786Sps   }
18360786Sps
18460786Sps}
18560786Sps/**
18660786Sps * @brief This method is called by the SCI user to build an SMP
18760786Sps *        IO request.
18860786Sps *
18960786Sps * @pre
19060786Sps *        - The user must have previously called scic_io_request_construct()
19160786Sps *          on the supplied IO request.
19260786Sps *
19360786Sps * @param[in]  scic_io_request This parameter specifies the handle to the
19460786Sps *             io request object to be built.
19560786Sps *
19660786Sps * @return Indicate if the controller successfully built the IO request.
19760786Sps * @retval SCI_SUCCESS This value is returned if the IO request was
19860786Sps *         successfully built.
19960786Sps * @retval SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned if the
20060786Sps *         remote_device does not support the SMP protocol.
20160786Sps * @retval SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the
20260786Sps *         user did not properly set the association between the SCIC IO
20360786Sps *         request and the user's IO request.  Please refer to the
20460786Sps *         sci_object_set_association() routine for more
20560786Sps *         information.
20660786Sps */
20760786SpsSCI_STATUS scic_io_request_construct_smp(
20860786Sps   SCI_IO_REQUEST_HANDLE_T  scic_smp_request
20960786Sps)
21060786Sps{
21160786Sps   SMP_REQUEST_T smp_request;
21260786Sps
21360786Sps   SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *) scic_smp_request;
21460786Sps   SCIC_LOG_TRACE((
21560786Sps      sci_base_object_get_logger(this_request),
21660786Sps      SCIC_LOG_OBJECT_SMP_IO_REQUEST,
21760786Sps      "scic_io_request_construct_smp(0x%x) enter\n",
21860786Sps      this_request
21960786Sps   ));
22060786Sps
22160786Sps   this_request->protocol                     = SCIC_SMP_PROTOCOL;
22260786Sps   this_request->has_started_substate_machine = TRUE;
22360786Sps
22460786Sps   // Construct the started sub-state machine.
22560786Sps   sci_base_state_machine_construct(
22660786Sps      &this_request->started_substate_machine,
22760786Sps      &this_request->parent.parent,
22860786Sps      scic_sds_smp_request_started_substate_table,
22960786Sps      SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
23060786Sps   );
23160786Sps
23260786Sps   // Construct the SMP SCU Task Context
23360786Sps   memcpy((char *)&smp_request,
23460786Sps        this_request->command_buffer,
23560786Sps        sizeof(SMP_REQUEST_T));
23660786Sps
23760786Sps   // Look at the SMP requests' header fields; for certain SAS 1.x SMP
23860786Sps   // functions under SAS 2.0, a zero request length really indicates
23960786Sps   // a non-zero default length.
24060786Sps   if( smp_request.header.request_length == 0 )
24160786Sps   {
24260786Sps       switch( smp_request.header.function )
24360786Sps       {
24460786Sps       case SMP_FUNCTION_DISCOVER:
24560786Sps       case SMP_FUNCTION_REPORT_PHY_ERROR_LOG:
24660786Sps       case SMP_FUNCTION_REPORT_PHY_SATA:
24760786Sps       case SMP_FUNCTION_REPORT_ROUTE_INFORMATION:
24860786Sps           smp_request.header.request_length = 2;
24960786Sps           break;
25060786Sps       case SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION:
25160786Sps       case SMP_FUNCTION_PHY_CONTROL:
25260786Sps       case SMP_FUNCTION_PHY_TEST:
25360786Sps           smp_request.header.request_length = 9;
25460786Sps           break;
25560786Sps       // Default - zero is a valid default for 2.0.
25660786Sps       }
25760786Sps   }
25889019Sps
25960786Sps   scu_smp_request_construct_task_context(
26089019Sps      this_request,
26160786Sps      &smp_request
26260786Sps   );
26360786Sps
26460786Sps   sci_base_state_machine_change_state(
26560786Sps      &this_request->parent.state_machine,
26660786Sps      SCI_BASE_REQUEST_STATE_CONSTRUCTED
26760786Sps   );
26860786Sps
26960786Sps   return SCI_SUCCESS;
27060786Sps}
27160786Sps
27260786Sps/**
27360786Sps * @brief This method is called by the SCI user to build an SMP pass-through
27460786Sps *        IO request.
27560786Sps *
27660786Sps * @pre
27760786Sps *        - The user must have previously called scic_io_request_construct()
27860786Sps *          on the supplied IO request.
27960786Sps *
28060786Sps * @param[in]  scic_smp_request This parameter specifies the handle to the
28160786Sps *             io request object to be built.
28289019Sps *
28360786Sps * @param[in]  passthru_cb This parameter specifies the pointer to the callback
28460786Sps *             structure that contains the function pointers
28560786Sps *
28660786Sps * @return Indicate if the controller successfully built the IO request.
28760786Sps */
28860786SpsSCI_STATUS scic_io_request_construct_smp_pass_through(
28960786Sps   SCI_IO_REQUEST_HANDLE_T  scic_smp_request,
29060786Sps   SCIC_SMP_PASSTHRU_REQUEST_CALLBACKS_T *passthru_cb
29160786Sps)
29260786Sps{
29360786Sps   SMP_REQUEST_T smp_request;
29460786Sps   U8 * request_buffer;
29560786Sps   U32 request_buffer_length_in_bytes;
29660786Sps
29760786Sps   SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *) scic_smp_request;
29860786Sps   SCIC_LOG_TRACE((
29960786Sps      sci_base_object_get_logger(this_request),
30060786Sps      SCIC_LOG_OBJECT_SMP_IO_REQUEST,
30160786Sps      "scic_io_request_construct_smp_pass_through(0x%x) enter\n",
30260786Sps      this_request
30360786Sps   ));
30460786Sps
30560786Sps   this_request->protocol                     = SCIC_SMP_PROTOCOL;
30660786Sps   this_request->has_started_substate_machine = TRUE;
30760786Sps
30860786Sps   // Call the callback function to retrieve the SMP passthrough request
30960786Sps   request_buffer_length_in_bytes = passthru_cb->scic_cb_smp_passthru_get_request (
31060786Sps                                       (void *)this_request,
31160786Sps                                       &request_buffer
31260786Sps                                    );
31360786Sps
31460786Sps   //copy the request to smp request
31560786Sps   memcpy((char *)&smp_request.request.vendor_specific_request,
31660786Sps        request_buffer,
31760786Sps        request_buffer_length_in_bytes);
31860786Sps
31960786Sps   //the header length in smp_request is in dwords - the sas spec has similar way,
32060786Sps   //but the csmi header contains the number of bytes, so we need to convert the
32160786Sps   //number of bytes to number of dwords
32260786Sps   smp_request.header.request_length = (U8) (request_buffer_length_in_bytes / sizeof (U32));
32360786Sps
32460786Sps   //Grab the other needed fields from the smp request using callbacks
32560786Sps   smp_request.header.smp_frame_type = passthru_cb->scic_cb_smp_passthru_get_frame_type ((void *)this_request);
32660786Sps   smp_request.header.function = passthru_cb->scic_cb_smp_passthru_get_function ((void *)this_request);
32760786Sps   smp_request.header.allocated_response_length = passthru_cb->scic_cb_smp_passthru_get_allocated_response_length((void *)this_request);
32860786Sps
32960786Sps   // Construct the started sub-state machine.
33060786Sps   sci_base_state_machine_construct(
33160786Sps      &this_request->started_substate_machine,
33260786Sps      &this_request->parent.parent,
33360786Sps      scic_sds_smp_request_started_substate_table,
33460786Sps      SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
33560786Sps   );
33660786Sps
33760786Sps   // Construct the SMP SCU Task Context
33860786Sps   scu_smp_request_construct_task_context (this_request, &smp_request);
33960786Sps
34060786Sps   sci_base_state_machine_change_state(
34160786Sps      &this_request->parent.state_machine,
34260786Sps      SCI_BASE_REQUEST_STATE_CONSTRUCTED
34360786Sps   );
34460786Sps
34560786Sps   return SCI_SUCCESS;
34660786Sps}
34760786Sps
34860786Sps/**
34960786Sps * @brief This method will fill in the SCU Task Context for a SMP request. The
35060786Sps *        following important settings are utilized:
35160786Sps *
35260786Sps *          -# task_type == SCU_TASK_TYPE_SMP.  This simply indicates
35360786Sps *             that a normal request type (i.e. non-raw frame) is being
35460786Sps *             utilized to perform task management.
35560786Sps *          -# control_frame == 1.  This ensures that the proper endianess
35660786Sps *             is set so that the bytes are transmitted in the right order
35760786Sps *             for a smp request frame.
35860786Sps *
35960786Sps * @param[in] this_request This parameter specifies the smp request object
36060786Sps *            being constructed.
36160786Sps *
36260786Sps * @return none
36360786Sps */
36460786Spsvoid scu_smp_request_construct_task_context(
36560786Sps   SCIC_SDS_REQUEST_T *this_request,
36660786Sps   SMP_REQUEST_T      *smp_request
36760786Sps)
36860786Sps{
36960786Sps   SCI_PHYSICAL_ADDRESS      physical_address;
37060786Sps   SCIC_SDS_CONTROLLER_T    *owning_controller;
37160786Sps   SCIC_SDS_REMOTE_DEVICE_T *target_device;
37260786Sps   SCIC_SDS_PORT_T          *target_port;
37360786Sps   SCU_TASK_CONTEXT_T *task_context;
37460786Sps
37560786Sps   //byte swap the smp request.
37660786Sps   scic_word_copy_with_swap(
37760786Sps      this_request->command_buffer,
37860786Sps      (U32*) smp_request,
37960786Sps      sizeof(SMP_REQUEST_T)/sizeof(U32)
38060786Sps   );
38160786Sps
38260786Sps   task_context = scic_sds_request_get_task_context(this_request);
38360786Sps
38460786Sps   owning_controller = scic_sds_request_get_controller(this_request);
38560786Sps   target_device = scic_sds_request_get_device(this_request);
38660786Sps   target_port = scic_sds_request_get_port(this_request);
38760786Sps
38860786Sps   SCIC_LOG_TRACE((
38960786Sps      sci_base_object_get_logger(this_request),
39060786Sps      SCIC_LOG_OBJECT_SMP_IO_REQUEST,
39160786Sps      "scu_smp_request_construct_task_context(0x%x) contents\n"
39260786Sps      "   reqlen=%x; function=%x;\n",
39360786Sps      this_request,
39460786Sps      smp_request->header.request_length,
39560786Sps      smp_request->header.function
39660786Sps   ));
39760786Sps
39860786Sps   // Fill in the TC with the its required data
39960786Sps   // 00h
40060786Sps   task_context->priority = 0;
40160786Sps   task_context->initiator_request = 1;
40260786Sps   task_context->connection_rate =
40360786Sps      scic_remote_device_get_connection_rate(target_device);
40460786Sps   task_context->protocol_engine_index =
40560786Sps      scic_sds_controller_get_protocol_engine_group(owning_controller);
40660786Sps   task_context->logical_port_index =
40760786Sps      scic_sds_port_get_index(target_port);
40860786Sps   task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SMP;
40960786Sps   task_context->abort = 0;
41060786Sps   task_context->valid = SCU_TASK_CONTEXT_VALID;
41160786Sps   task_context->context_type = SCU_TASK_CONTEXT_TYPE;
41260786Sps
41360786Sps   //04h
41460786Sps   task_context->remote_node_index = this_request->target_device->rnc->remote_node_index;
41560786Sps   task_context->command_code = 0;
41660786Sps   task_context->task_type = SCU_TASK_TYPE_SMP_REQUEST;
41760786Sps
41860786Sps   //08h
41960786Sps   task_context->link_layer_control = 0;
42060786Sps   task_context->do_not_dma_ssp_good_response = 1;
42160786Sps   task_context->strict_ordering = 0;
42260786Sps   task_context->control_frame = 1;
42360786Sps   task_context->timeout_enable = 0;
42460786Sps   task_context->block_guard_enable = 0;
42560786Sps
42660786Sps   //0ch
42760786Sps   task_context->address_modifier = 0;
42860786Sps
42960786Sps   //10h
43060786Sps   task_context->ssp_command_iu_length = smp_request->header.request_length;
43160786Sps
43260786Sps   //14h
43360786Sps   task_context->transfer_length_bytes = 0;
43460786Sps
43560786Sps   //18h ~ 30h, protocol specific
43660786Sps   // since commandIU has been build by framework at this point, we just
43760786Sps   // copy the frist DWord from command IU to this location.
43860786Sps   memcpy((void *)(&task_context->type.smp), this_request->command_buffer, sizeof(U32) );
43960786Sps
44060786Sps   //40h
44160786Sps   // "For SMP you could program it to zero. We would prefer that way so that
44260786Sps   // done code will be consistent." - Venki
44360786Sps   task_context->task_phase = 0;
44460786Sps
44560786Sps   if (this_request->was_tag_assigned_by_user)
44660786Sps   {
44760786Sps      // Build the task context now since we have already read the data
44860786Sps      this_request->post_context = (
44960786Sps           SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC
45060786Sps         | (
45160786Sps                scic_sds_controller_get_protocol_engine_group(owning_controller)
45260786Sps             << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT
45360786Sps           )
45460786Sps         | (
45560786Sps                 scic_sds_port_get_index(target_port)
45660786Sps              << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT
45760786Sps           )
45860786Sps         | scic_sds_io_tag_get_index(this_request->io_tag)
45960786Sps      );
46060786Sps   }
46160786Sps   else
46260786Sps   {
46360786Sps      // Build the task context now since we have already read the data
46460786Sps      this_request->post_context = (
46560786Sps           SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC
46660786Sps         | (
46760786Sps               scic_sds_controller_get_protocol_engine_group(owning_controller)
46860786Sps            << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT
46960786Sps           )
47060786Sps         | (
47160786Sps                scic_sds_port_get_index(target_port)
47260786Sps             << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT
47360786Sps           )
47460786Sps         // This is not assigned because we have to wait until we get a TCi
47560786Sps      );
47660786Sps   }
47760786Sps
47860786Sps   // Copy the physical address for the command buffer to the SCU Task Context
47960786Sps   // command buffer should not contain command header.
48060786Sps   scic_cb_io_request_get_physical_address(
48160786Sps         scic_sds_request_get_controller(this_request),
48260786Sps         this_request,
48360786Sps         ((char *)(this_request->command_buffer) + sizeof(U32)),
48460786Sps         &physical_address
48560786Sps      );
48660786Sps
48760786Sps   task_context->command_iu_upper =
48860786Sps      sci_cb_physical_address_upper(physical_address);
48960786Sps   task_context->command_iu_lower =
49060786Sps      sci_cb_physical_address_lower(physical_address);
49160786Sps
49260786Sps
49360786Sps   //SMP response comes as UF, so no need to set response IU address.
49460786Sps   task_context->response_iu_upper = 0;
49560786Sps   task_context->response_iu_lower = 0;
49660786Sps}
49760786Sps
49860786Sps//******************************************************************************
49960786Sps//* SMP REQUEST STATE MACHINE
50060786Sps//******************************************************************************
50160786Sps
50260786Sps/**
50360786Sps * @brief This method processes an unsolicited frame while the SMP request is
50460786Sps *        waiting for a response frame.  It will copy the response data, release
50560786Sps *        the unsolicited frame, and transition the request to the
50660786Sps *        SCI_BASE_REQUEST_STATE_COMPLETED state.
50760786Sps *
50860786Sps * @param[in] this_request This parameter specifies the request for which
50960786Sps *            the unsolicited frame was received.
51060786Sps * @param[in] frame_index This parameter indicates the unsolicited frame
51160786Sps *            index that should contain the response.
51260786Sps *
51360786Sps * @return This method returns an indication of whether the response
51460786Sps *         frame was handled successfully or not.
51560786Sps * @retval SCI_SUCCESS Currently this value is always returned and indicates
51660786Sps *         successful processing of the TC response.
51760786Sps */
51860786Spsstatic
51960786SpsSCI_STATUS scic_sds_smp_request_await_response_frame_handler(
52060786Sps   SCIC_SDS_REQUEST_T * this_request,
52160786Sps   U32                  frame_index
52260786Sps)
52360786Sps{
52460786Sps   SCI_STATUS              status;
52560786Sps   void                  * frame_header;
52660786Sps   SMP_RESPONSE_HEADER_T * this_frame_header;
52760786Sps   U8                    * user_smp_buffer = this_request->response_buffer;
52860786Sps
52960786Sps   // Save off the controller, so that we do not touch the request after it
53060786Sps   //  is completed.
53160786Sps   SCIC_SDS_CONTROLLER_T * controller = scic_sds_request_get_controller(this_request);
53260786Sps
53360786Sps   SCIC_LOG_TRACE((
53460786Sps      sci_base_object_get_logger(this_request),
53560786Sps      SCIC_LOG_OBJECT_SMP_IO_REQUEST,
53660786Sps      "scic_sds_smp_request_await_response_frame_handler(0x%x, 0x%x) enter\n",
53760786Sps      this_request, frame_index
53860786Sps   ));
53960786Sps
54060786Sps   status = scic_sds_unsolicited_frame_control_get_header(
54160786Sps      &(controller->uf_control),
54260786Sps      frame_index,
54360786Sps      &frame_header
54460786Sps   );
54560786Sps
54660786Sps   //byte swap the header.
54760786Sps   scic_word_copy_with_swap(
54860786Sps      (U32*) user_smp_buffer,
54960786Sps      frame_header,
55060786Sps      sizeof(SMP_RESPONSE_HEADER_T)/sizeof(U32)
55160786Sps   );
55260786Sps   this_frame_header = (SMP_RESPONSE_HEADER_T*) user_smp_buffer;
55360786Sps
55460786Sps   if (this_frame_header->smp_frame_type == SMP_FRAME_TYPE_RESPONSE)
55560786Sps   {
55660786Sps      void * smp_response_buffer;
55760786Sps
55860786Sps      status = scic_sds_unsolicited_frame_control_get_buffer(
55960786Sps         &(controller->uf_control),
56060786Sps         frame_index,
56160786Sps         &smp_response_buffer
56260786Sps      );
56360786Sps
56460786Sps      scic_word_copy_with_swap(
56560786Sps         (U32*) (user_smp_buffer + sizeof(SMP_RESPONSE_HEADER_T)),
56660786Sps         smp_response_buffer,
56760786Sps         sizeof(SMP_RESPONSE_BODY_T)/sizeof(U32)
56860786Sps      );
56960786Sps      if (this_frame_header->function == SMP_FUNCTION_DISCOVER)
57060786Sps      {
57160786Sps          SMP_RESPONSE_T * this_smp_response;
57260786Sps
57360786Sps          this_smp_response = (SMP_RESPONSE_T *)user_smp_buffer;
57460786Sps
57560786Sps          // Some expanders only report an attached SATA device, and
57660786Sps          // not an STP target.  Since the core depends on the STP
57760786Sps          // target attribute to correctly build I/O, set the bit now
57860786Sps          // if necessary.
57960786Sps          if (this_smp_response->response.discover.protocols.u.bits.attached_sata_device
58060786Sps           && !this_smp_response->response.discover.protocols.u.bits.attached_stp_target)
58160786Sps          {
58260786Sps              this_smp_response->response.discover.protocols.u.bits.attached_stp_target = 1;
58360786Sps
58460786Sps              SCIC_LOG_TRACE((
58560786Sps                  sci_base_object_get_logger(this_request),
58660786Sps                 SCIC_LOG_OBJECT_SMP_IO_REQUEST,
58760786Sps                 "scic_sds_smp_request_await_response_frame_handler(0x%x) Found SATA dev, setting STP bit.\n",
58860786Sps                 this_request
58960786Sps              ));
59060786Sps          }
59160786Sps      }
59260786Sps
59360786Sps     //Don't need to copy to user space. User instead will refer to
59460786Sps     //core request's response buffer.
59560786Sps
59660786Sps     //copy the smp response to framework smp request's response buffer.
59760786Sps     //scic_sds_smp_request_copy_response(this_request);
59860786Sps
59960786Sps      scic_sds_request_set_status(
60060786Sps         this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
60160786Sps      );
60260786Sps
60360786Sps      sci_base_state_machine_change_state(
60460786Sps         &this_request->started_substate_machine,
60560786Sps         SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
60660786Sps      );
60760786Sps   }
60860786Sps   else
60960786Sps   {
61060786Sps      // This was not a response frame why did it get forwarded?
61160786Sps      SCIC_LOG_ERROR((
61260786Sps         sci_base_object_get_logger(this_request),
61360786Sps         SCIC_LOG_OBJECT_SMP_IO_REQUEST,
61460786Sps         "SCIC SMP Request 0x%08x received unexpected frame %d type 0x%02x\n",
61560786Sps         this_request, frame_index, this_frame_header->smp_frame_type
61660786Sps      ));
61760786Sps
61860786Sps     scic_sds_request_set_status(
61960786Sps        this_request,
62060786Sps        SCU_TASK_DONE_SMP_FRM_TYPE_ERR,
62160786Sps        SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
62260786Sps     );
62360786Sps
62460786Sps     sci_base_state_machine_change_state(
62560786Sps         &this_request->parent.state_machine,
62660786Sps         SCI_BASE_REQUEST_STATE_COMPLETED
62760786Sps      );
62860786Sps   }
62960786Sps
63060786Sps   scic_sds_controller_release_frame(
63160786Sps      controller, frame_index
63260786Sps   );
63360786Sps
63460786Sps   return SCI_SUCCESS;
63560786Sps}
63660786Sps
63760786Sps
63860786Sps/**
63960786Sps * @brief This method processes an abnormal TC completion while the SMP
64060786Sps *        request is waiting for a response frame.  It decides what
64160786Sps *        happened to the IO based on TC completion status.
64260786Sps *
64360786Sps * @param[in] this_request This parameter specifies the request for which
64460786Sps *            the TC completion was received.
64560786Sps * @param[in] completion_code This parameter indicates the completion status
64660786Sps *            information for the TC.
64760786Sps *
64860786Sps * @return Indicate if the tc completion handler was successful.
64960786Sps * @retval SCI_SUCCESS currently this method always returns success.
65060786Sps */
65160786Spsstatic
65260786SpsSCI_STATUS scic_sds_smp_request_await_response_tc_completion_handler(
65360786Sps   SCIC_SDS_REQUEST_T * this_request,
65460786Sps   U32                  completion_code
65560786Sps)
65660786Sps{
65760786Sps   SCIC_LOG_TRACE((
65860786Sps      sci_base_object_get_logger(this_request),
65960786Sps      SCIC_LOG_OBJECT_SMP_IO_REQUEST,
66060786Sps      "scic_sds_smp_request_await_response_tc_completion_handler(0x%x, 0x%x) enter\n",
66160786Sps      this_request, completion_code
66260786Sps   ));
66360786Sps
66460786Sps   switch (SCU_GET_COMPLETION_TL_STATUS(completion_code))
66560786Sps   {
66660786Sps   case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
66760786Sps      //In the AWAIT RESPONSE state, any TC completion is unexpected.
66860786Sps      //but if the TC has success status, we complete the IO anyway.
66960786Sps      scic_sds_request_set_status(
67060786Sps         this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
67160786Sps      );
67260786Sps
67360786Sps      sci_base_state_machine_change_state(
67460786Sps         &this_request->parent.state_machine,
67560786Sps         SCI_BASE_REQUEST_STATE_COMPLETED
67660786Sps      );
67760786Sps   break;
67860786Sps
67960786Sps   case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR):
68060786Sps   case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR):
68160786Sps   case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR):
68260786Sps   case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR):
68360786Sps      //These status has been seen in a specific LSI expander, which sometimes
68460786Sps      //is not able to send smp response within 2 ms. This causes our hardware
68560786Sps      //break the connection and set TC completion with one of these SMP_XXX_XX_ERR
68660786Sps      //status. For these type of error, we ask scic user to retry the request.
68760786Sps      scic_sds_request_set_status(
68860786Sps         this_request, SCU_TASK_DONE_SMP_RESP_TO_ERR, SCI_FAILURE_RETRY_REQUIRED
68960786Sps      );
69060786Sps
69160786Sps      sci_base_state_machine_change_state(
69260786Sps         &this_request->parent.state_machine,
69360786Sps         SCI_BASE_REQUEST_STATE_COMPLETED
69460786Sps      );
69560786Sps   break;
69660786Sps
69760786Sps   default:
69860786Sps      // All other completion status cause the IO to be complete.  If a NAK
69960786Sps      // was received, then it is up to the user to retry the request.
70060786Sps      scic_sds_request_set_status(
70160786Sps         this_request,
70260786Sps         SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
70360786Sps         SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
70460786Sps      );
70560786Sps
70660786Sps      sci_base_state_machine_change_state(
70760786Sps         &this_request->parent.state_machine,
70860786Sps         SCI_BASE_REQUEST_STATE_COMPLETED
70960786Sps      );
71060786Sps   break;
71160786Sps   }
71260786Sps
71360786Sps   return SCI_SUCCESS;
71460786Sps}
71560786Sps
71660786Sps
71760786Sps/**
71860786Sps * @brief This method processes the completions transport layer (TL) status
71960786Sps *        to determine if the SMP request was sent successfully. If the SMP
72060786Sps *        request was sent successfully, then the state for the SMP request
72160786Sps *        transits to waiting for a response frame.
72260786Sps *
72360786Sps * @param[in] this_request This parameter specifies the request for which
72460786Sps *            the TC completion was received.
72560786Sps * @param[in] completion_code This parameter indicates the completion status
72660786Sps *            information for the TC.
72760786Sps *
72860786Sps * @return Indicate if the tc completion handler was successful.
72960786Sps * @retval SCI_SUCCESS currently this method always returns success.
73060786Sps */
73160786Spsstatic
73260786SpsSCI_STATUS scic_sds_smp_request_await_tc_completion_tc_completion_handler(
733128345Stjr   SCIC_SDS_REQUEST_T * this_request,
734128345Stjr   U32                  completion_code
735128345Stjr)
736128345Stjr{
73760786Sps   SCIC_LOG_TRACE((
73860786Sps      sci_base_object_get_logger(this_request),
73960786Sps      SCIC_LOG_OBJECT_SMP_IO_REQUEST,
74060786Sps      "scic_sds_smp_request_await_tc_completion_tc_completion_handler(0x%x, 0x%x) enter\n",
74160786Sps      this_request, completion_code
74260786Sps   ));
74360786Sps
74460786Sps   switch (SCU_GET_COMPLETION_TL_STATUS(completion_code))
74560786Sps   {
74660786Sps   case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
74760786Sps      scic_sds_request_set_status(
74860786Sps         this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
74960786Sps      );
75060786Sps
75160786Sps      sci_base_state_machine_change_state(
75260786Sps         &this_request->parent.state_machine,
75360786Sps         SCI_BASE_REQUEST_STATE_COMPLETED
75460786Sps      );
75560786Sps   break;
75660786Sps
757128345Stjr   default:
75860786Sps      // All other completion status cause the IO to be complete.  If a NAK
75960786Sps      // was received, then it is up to the user to retry the request.
76060786Sps      scic_sds_request_set_status(
76160786Sps         this_request,
76260786Sps         SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
76360786Sps         SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
76460786Sps      );
765128345Stjr
76660786Sps      sci_base_state_machine_change_state(
76760786Sps         &this_request->parent.state_machine,
768128345Stjr         SCI_BASE_REQUEST_STATE_COMPLETED
76960786Sps      );
77060786Sps   break;
77160786Sps   }
77260786Sps
77360786Sps   return SCI_SUCCESS;
77460786Sps}
77560786Sps
77660786Sps
77760786SpsSCIC_SDS_IO_REQUEST_STATE_HANDLER_T
778128345Stjrscic_sds_smp_request_started_substate_handler_table
779128345Stjr[SCIC_SDS_SMP_REQUEST_STARTED_MAX_SUBSTATES] =
780128345Stjr{
781128345Stjr   // SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
782128345Stjr   {
78360786Sps      {
78460786Sps         scic_sds_request_default_start_handler,
785128345Stjr         scic_sds_request_started_state_abort_handler,
78660786Sps         scic_sds_request_default_complete_handler,
787128345Stjr         scic_sds_request_default_destruct_handler
788128345Stjr      },
789128345Stjr      scic_sds_smp_request_await_response_tc_completion_handler,
79060786Sps      scic_sds_request_default_event_handler,
791128345Stjr      scic_sds_smp_request_await_response_frame_handler
792128345Stjr   },
793128345Stjr   // SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
794128345Stjr   {
795128345Stjr      {
796128345Stjr         scic_sds_request_default_start_handler,
797128345Stjr         scic_sds_request_started_state_abort_handler,
798128345Stjr         scic_sds_request_default_complete_handler,
799128345Stjr         scic_sds_request_default_destruct_handler
800128345Stjr      },
801128345Stjr      scic_sds_smp_request_await_tc_completion_tc_completion_handler,
802128345Stjr      scic_sds_request_default_event_handler,
80360786Sps      scic_sds_request_default_frame_handler
80460786Sps   }
80560786Sps};
80660786Sps
80760786Sps/**
80860786Sps * @brief This method performs the actions required when entering the
80960786Sps *        SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_RESPONSE sub-state.
81060786Sps *        This includes setting the IO request state handlers for this
81160786Sps *        sub-state.
81260786Sps *
81360786Sps * @param[in]  object This parameter specifies the request object for which
81460786Sps *             the sub-state change is occuring.
81560786Sps *
81660786Sps * @return none.
81760786Sps */
81860786Spsstatic
81960786Spsvoid scic_sds_smp_request_started_await_response_substate_enter(
82060786Sps   SCI_BASE_OBJECT_T *object
82160786Sps)
82260786Sps{
82360786Sps   SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
82460786Sps
82560786Sps   SET_STATE_HANDLER(
82660786Sps      this_request,
82760786Sps      scic_sds_smp_request_started_substate_handler_table,
82860786Sps      SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
82960786Sps   );
83060786Sps}
83160786Sps
83260786Sps/**
83360786Sps * @brief This method performs the actions required when entering the
83460786Sps *        SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
83560786Sps *        sub-state.  This includes setting the SMP request state handlers for
83660786Sps *        this sub-state.
83760786Sps *
83860786Sps * @param[in]  object This parameter specifies the request object for which
83960786Sps *             the sub-state change is occuring.
84060786Sps *
84160786Sps * @return none.
84260786Sps */
84360786Spsstatic
84460786Spsvoid scic_sds_smp_request_started_await_tc_completion_substate_enter(
84560786Sps   SCI_BASE_OBJECT_T *object
84660786Sps)
84760786Sps{
84860786Sps   SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
84960786Sps
85060786Sps   SET_STATE_HANDLER(
85160786Sps      this_request,
85260786Sps      scic_sds_smp_request_started_substate_handler_table,
853128345Stjr      SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
854128345Stjr   );
855128345Stjr}
856128345Stjr
857128345StjrSCI_BASE_STATE_T scic_sds_smp_request_started_substate_table
858128345Stjr[SCIC_SDS_SMP_REQUEST_STARTED_MAX_SUBSTATES] =
859128345Stjr{
860128345Stjr   {
861128345Stjr      SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE,
862128345Stjr      scic_sds_smp_request_started_await_response_substate_enter,
863128345Stjr      NULL
864128345Stjr   },
865128345Stjr   {
866128345Stjr      SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION,
86760786Sps      scic_sds_smp_request_started_await_tc_completion_substate_enter,
86860786Sps      NULL
86960786Sps   }
87060786Sps};
87160786Sps
87260786Sps
87360786Sps