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 */
77U32 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
169void 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 */
209SCI_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 */
290SCI_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 */
366void 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 */
520static
521SCI_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 */
653static
654SCI_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 */
733static
734SCI_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
779SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
780scic_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 */
820static
821void 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 */
845static
846void 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
859SCI_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