1108684Sphk/*-
2108684Sphk * This file is provided under a dual BSD/GPLv2 license.  When using or
3108684Sphk * redistributing this file, you may do so under either license.
4108684Sphk *
5108684Sphk * GPL LICENSE SUMMARY
6108684Sphk *
7108684Sphk * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8108684Sphk *
9108684Sphk * This program is free software; you can redistribute it and/or modify
10108684Sphk * it under the terms of version 2 of the GNU General Public License as
11108684Sphk * published by the Free Software Foundation.
12108684Sphk *
13108684Sphk * This program is distributed in the hope that it will be useful, but
14108684Sphk * WITHOUT ANY WARRANTY; without even the implied warranty of
15108684Sphk * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16108684Sphk * General Public License for more details.
17108684Sphk *
18108684Sphk * You should have received a copy of the GNU General Public License
19108684Sphk * along with this program; if not, write to the Free Software
20108684Sphk * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21108684Sphk * The full GNU General Public License is included in this distribution
22108684Sphk * in the file called LICENSE.GPL.
23108684Sphk *
24108684Sphk * BSD LICENSE
25108684Sphk *
26108684Sphk * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27108684Sphk * All rights reserved.
28108684Sphk *
29108684Sphk * Redistribution and use in source and binary forms, with or without
30108684Sphk * modification, are permitted provided that the following conditions
31108684Sphk * are met:
32108684Sphk *
33108684Sphk *   * Redistributions of source code must retain the above copyright
34108684Sphk *     notice, this list of conditions and the following disclaimer.
35108684Sphk *   * Redistributions in binary form must reproduce the above copyright
36108684Sphk *     notice, this list of conditions and the following disclaimer in
37108684Sphk *     the documentation and/or other materials provided with the
38126775Sdwmalone *     distribution.
39108684Sphk *
40175239Sdelphij * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41247036Smelifaro * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42108684Sphk * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43108684Sphk * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44108684Sphk * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45108684Sphk * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46108684Sphk * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47226396Sed * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48108684Sphk * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49108684Sphk * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50158161Sbde * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51108684Sphk */
52108684Sphk
53108684Sphk#include <sys/cdefs.h>
54108684Sphk__FBSDID("$FreeBSD$");
55126775Sdwmalone
56126775Sdwmalone/**
57126775Sdwmalone * @file
58126775Sdwmalone *
59126775Sdwmalone * @brief This file contains the method implementations for the
60126775Sdwmalone *        SCIF_SAS_SMP_IO_REQUEST object.  The contents will implement SMP
61108684Sphk *        specific functionality.
62158161Sbde */
63108684Sphk
64108684Sphk#include <dev/isci/scil/scif_sas_smp_io_request.h>
65108684Sphk#include <dev/isci/scil/scif_sas_logger.h>
66108684Sphk#include <dev/isci/scil/scif_sas_controller.h>
67108684Sphk#include <dev/isci/scil/sci_controller.h>
68108684Sphk
69108684Sphk#include <dev/isci/scil/sci_status.h>
70108684Sphk#include <dev/isci/scil/scic_io_request.h>
71279473Srstone#include <dev/isci/scil/scic_user_callback.h>
72279473Srstone
73279473Srstone#include <dev/isci/scil/intel_sas.h>
74279473Srstone
75279473Srstone/**
76279473Srstone * @brief This routine is to fill in the space given by core the SMP command
77279473Srstone *        frame. Then it calls core's construction.
78279473Srstone *
79108684Sphk * @param[in] fw_io The smp io request to be constructed.
80108684Sphk * @param[in] smp_command The SMP request filled according to SAS spec.
81108684Sphk *
82247036Smelifaro * @return none
83108684Sphk */
84108684Sphkvoid scif_sas_smp_request_construct(
85247036Smelifaro   SCIF_SAS_REQUEST_T * fw_request,
86247036Smelifaro   SMP_REQUEST_T * smp_command
87247036Smelifaro)
88247036Smelifaro{
89108684Sphk   void * command_iu_address =
90247036Smelifaro      scic_io_request_get_command_iu_address(fw_request->core_object);
91247036Smelifaro
92164677Syar   //copy the smp_command to the address;
93108684Sphk   memcpy( (char*) command_iu_address,
94108684Sphk           smp_command,
95108684Sphk           sizeof(SMP_REQUEST_T)
96108684Sphk          );
97108684Sphk
98231011Sed   scic_io_request_construct_smp(fw_request->core_object);
99108684Sphk
100108684Sphk   fw_request->protocol_complete_handler
101108684Sphk      = NULL;
102108684Sphk}
103158160Sbde
104108684Sphk/**
105108684Sphk * @brief This method will perform all of the construction common to all
106108684Sphk *        SMP requests (e.g. filling in the frame type, zero-out memory,
107158160Sbde *        etc.).
108158160Sbde *
109158160Sbde * @param[out] smp_request This parameter specifies the SMP request
110247036Smelifaro *             structure containing the SMP request to be sent to the
111247036Smelifaro *             SMP target.
112247036Smelifaro * @param[in]  smp_function This parameter specifies the SMP function to
113247036Smelifaro *             sent.
114247036Smelifaro * @param[in]  smp_response_length This parameter specifies the length of
115247036Smelifaro *             the response (in DWORDs) that will be returned for this
116247036Smelifaro *             SMP request.
117247036Smelifaro * @param[in]  smp_request_length This parameter specifies the length of
118247036Smelifaro *             the request (in DWORDs) that will be sent.
119247036Smelifaro */
120108684Sphkstatic
121108684Sphkvoid scif_sas_smp_protocol_request_construct(
122108684Sphk   SMP_REQUEST_T * smp_request,
123108684Sphk   U8              smp_function,
124108684Sphk   U8              smp_response_length,
125108684Sphk   U8              smp_request_length
126247036Smelifaro)
127247036Smelifaro{
128247036Smelifaro   memset((char*)smp_request, 0, sizeof(SMP_REQUEST_T));
129247036Smelifaro
130247036Smelifaro   smp_request->header.smp_frame_type            = SMP_FRAME_TYPE_REQUEST;
131247036Smelifaro   smp_request->header.function                  = smp_function;
132247036Smelifaro   smp_request->header.allocated_response_length = smp_response_length;
133247036Smelifaro   smp_request->header.request_length            = smp_request_length;
134247036Smelifaro}
135247036Smelifaro
136247036Smelifaro
137247036Smelifaro/**
138108684Sphk * @brief This method will allocate the internal IO request object and
139108684Sphk *        construct its contents based upon the supplied SMP request.
140108684Sphk *
141226396Sed * @param[in] fw_controller This parameter specifies the controller object
142247036Smelifaro *            from which to allocate the internal IO request.
143247036Smelifaro * @param[in] fw_device This parameter specifies the remote device for
144247036Smelifaro *            which the internal IO request is destined.
145247036Smelifaro * @param[in] smp_request This parameter specifies the SMP request contents
146247036Smelifaro *            to be sent to the SMP target.
147247036Smelifaro *
148247036Smelifaro * @return void * The address of built scif sas smp request.
149247036Smelifaro */
150247036Smelifarostatic
151247036Smelifarovoid * scif_sas_smp_request_build(
152108684Sphk   SCIF_SAS_CONTROLLER_T    * fw_controller,
153108684Sphk   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
154108684Sphk   SMP_REQUEST_T            * smp_request,
155108684Sphk   void                     * external_request_object,
156108684Sphk   void                     * external_memory
157108684Sphk)
158108684Sphk{
159108684Sphk   if (external_memory != NULL && external_request_object != NULL)
160108684Sphk   {
161108684Sphk      scif_sas_io_request_construct_smp(
162108684Sphk         fw_controller,
163108684Sphk         fw_device,
164108684Sphk         external_memory,
165108684Sphk         (char *)external_memory + sizeof(SCIF_SAS_IO_REQUEST_T),
166108684Sphk         SCI_CONTROLLER_INVALID_IO_TAG,
167108684Sphk         smp_request,
168108684Sphk         external_request_object
169108684Sphk      );
170108684Sphk
171108684Sphk      return external_memory;
172108684Sphk   }
173158160Sbde   else
174108684Sphk   {
175108684Sphk      void * internal_io_memory;
176108684Sphk      internal_io_memory = scif_sas_controller_allocate_internal_request(fw_controller);
177108684Sphk      ASSERT(internal_io_memory != NULL);
178108684Sphk
179108684Sphk      if (internal_io_memory != NULL)
180108684Sphk      {
181108684Sphk         //construct, only when we got valid io memory.
182108684Sphk         scif_sas_internal_io_request_construct_smp(
183108684Sphk            fw_controller,
184108684Sphk            fw_device,
185108684Sphk            internal_io_memory,
186108684Sphk            SCI_CONTROLLER_INVALID_IO_TAG,
187108684Sphk            smp_request
188108684Sphk         );
189108684Sphk      }
190108684Sphk      else
191108684Sphk      {
192108684Sphk         SCIF_LOG_ERROR((
193108684Sphk            sci_base_object_get_logger(fw_controller),
194108684Sphk            SCIF_LOG_OBJECT_IO_REQUEST,
195108684Sphk            "scif_sas_smp_request_build, no memory available!\n"
196108684Sphk         ));
197108684Sphk      }
198108684Sphk
199108684Sphk      return internal_io_memory;
200108684Sphk   }
201108684Sphk}
202108684Sphk
203108684Sphk/**
204108684Sphk * @brief construct a smp Report Genernal command to the fw_device.
205108684Sphk *
206108684Sphk * @param[in] fw_controller The framework controller object.
207108684Sphk * @param[in] fw_device the framework device that the REPORT GENERAL command
208108684Sphk *       targets to.
209108684Sphk *
210108684Sphk * @return void * address to the built scif sas smp request.
211247036Smelifaro */
212108684Sphkvoid * scif_sas_smp_request_construct_report_general(
213247036Smelifaro   SCIF_SAS_CONTROLLER_T    * fw_controller,
214247036Smelifaro   SCIF_SAS_REMOTE_DEVICE_T * fw_device
215108684Sphk)
216108684Sphk{
217108684Sphk   SMP_REQUEST_T smp_report_general;
218108684Sphk
219108684Sphk   // Build the REPORT GENERAL request.
220108684Sphk   scif_sas_smp_protocol_request_construct(
221108684Sphk      &smp_report_general,
222108684Sphk      SMP_FUNCTION_REPORT_GENERAL,
223108684Sphk      sizeof(SMP_RESPONSE_REPORT_GENERAL_T) / sizeof(U32),
224108684Sphk      0
225158161Sbde   );
226108684Sphk
227108684Sphk   smp_report_general.request.report_general.crc = 0;
228108684Sphk
229108684Sphk   SCIF_LOG_INFO((
230108684Sphk      sci_base_object_get_logger(fw_device),
231108684Sphk      SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
232108684Sphk      "SMP REPORT GENERAL -  Device:0x%x\n",
233247037Smelifaro      fw_device
234108684Sphk   ));
235108684Sphk
236108684Sphk   return scif_sas_smp_request_build(
237108684Sphk             fw_controller, fw_device, &smp_report_general, NULL, NULL);
238175239Sdelphij}
239108684Sphk
240108684Sphk/**
241108684Sphk * @brief construct a SMP Report Manufacturer Info request to the fw_device.
242108684Sphk *
243108684Sphk * @param[in] fw_controller The framework controller object.
244108684Sphk * @param[in] fw_device the framework device that the REPORT MANUFACTURER
245247036Smelifaro *            INFO targets to.
246108684Sphk *
247158161Sbde * @return void * address to the built scif sas smp request.
248108684Sphk */
249108684Sphkvoid * scif_sas_smp_request_construct_report_manufacturer_info(
250108684Sphk   SCIF_SAS_CONTROLLER_T    * fw_controller,
251108684Sphk   SCIF_SAS_REMOTE_DEVICE_T * fw_device
252108684Sphk)
253108684Sphk{
254108684Sphk   SMP_REQUEST_T smp_report_manufacturer_info;
255108684Sphk
256108684Sphk   scif_sas_smp_protocol_request_construct(
257247037Smelifaro      &smp_report_manufacturer_info,
258108684Sphk      SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION,
259108684Sphk      sizeof(SMP_RESPONSE_REPORT_MANUFACTURER_INFORMATION_T) / sizeof(U32),
260108684Sphk      0
261108684Sphk   );
262108684Sphk
263108684Sphk   smp_report_manufacturer_info.request.report_general.crc = 0;
264108684Sphk
265108684Sphk   SCIF_LOG_INFO((
266279473Srstone      sci_base_object_get_logger(fw_device),
267279473Srstone      SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
268108684Sphk      "SMP REPORT MANUFACTURER_INFO -  Device:0x%x\n",
269108684Sphk      fw_device
270158161Sbde   ));
271108684Sphk
272108684Sphk   return scif_sas_smp_request_build(
273108684Sphk             fw_controller, fw_device, &smp_report_manufacturer_info, NULL, NULL
274158161Sbde          );
275108684Sphk}
276247036Smelifaro
277247036Smelifaro/**
278108684Sphk * @brief construct a smp Discover command to the fw_device.
279108684Sphk * @param[in] fw_controller The framework controller object.
280239991Sed * @param[in] fw_device the framework smp device that DISCOVER command targets
281108684Sphk *       to.
282108684Sphk * @param[in] phy_identifier The phy index the DISCOVER command targets to.
283226396Sed *
284226396Sed * @return void * address to the built scif sas smp request.
285247036Smelifaro */
286247036Smelifarovoid * scif_sas_smp_request_construct_discover(
287108684Sphk   SCIF_SAS_CONTROLLER_T    * fw_controller,
288108684Sphk   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
289108684Sphk   U8                         phy_identifier,
290108684Sphk   void                     * external_request_object,
291247036Smelifaro   void                     * external_memory
292158161Sbde)
293108684Sphk{
294108684Sphk   SMP_REQUEST_T smp_discover;
295108684Sphk
296108684Sphk   scif_sas_smp_protocol_request_construct(
297108684Sphk      &smp_discover,
298108684Sphk      SMP_FUNCTION_DISCOVER,
299226396Sed      sizeof(SMP_RESPONSE_DISCOVER_T) / sizeof(U32),
300226396Sed      sizeof(SMP_REQUEST_PHY_IDENTIFIER_T) / sizeof(U32)
301226396Sed   );
302108684Sphk
303108684Sphk   smp_discover.request.discover.phy_identifier = phy_identifier;
304108684Sphk
305108684Sphk   SCIF_LOG_INFO((
306247036Smelifaro      sci_base_object_get_logger(fw_device),
307247036Smelifaro      SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
308247036Smelifaro      "SMP DISCOVER - Device:0x%x PhyId:0x%x\n",
309108684Sphk      fw_device, phy_identifier
310108684Sphk   ));
311108684Sphk
312108684Sphk   return scif_sas_smp_request_build(
313108684Sphk             fw_controller, fw_device, &smp_discover,
314226396Sed             external_request_object, external_memory
315226396Sed          );
316247036Smelifaro}
317247036Smelifaro
318108684Sphk
319108684Sphk/**
320108684Sphk * @brief construct a smp REPORT PHY SATA command to the fw_device.
321108684Sphk * @param[in] fw_controller The framework controller object.
322108684Sphk * @param[in] fw_device the framework smp device that DISCOVER command targets
323108684Sphk *       to.
324108684Sphk * @param[in] phy_identifier The phy index the DISCOVER command targets to.
325247036Smelifaro *
326247036Smelifaro * @return void * address to the built scif sas smp request.
327247036Smelifaro */
328247036Smelifarovoid * scif_sas_smp_request_construct_report_phy_sata(
329247036Smelifaro   SCIF_SAS_CONTROLLER_T    * fw_controller,
330247036Smelifaro   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
331108684Sphk   U8                         phy_identifier
332108684Sphk)
333108684Sphk{
334108684Sphk   SMP_REQUEST_T report_phy_sata;
335108684Sphk
336247036Smelifaro   scif_sas_smp_protocol_request_construct(
337108684Sphk      &report_phy_sata,
338108684Sphk      SMP_FUNCTION_REPORT_PHY_SATA,
339108684Sphk      sizeof(SMP_RESPONSE_REPORT_PHY_SATA_T) / sizeof(U32),
340108684Sphk      sizeof(SMP_REQUEST_PHY_IDENTIFIER_T) / sizeof(U32)
341108684Sphk   );
342158161Sbde
343108684Sphk   report_phy_sata.request.report_phy_sata.phy_identifier = phy_identifier;
344108684Sphk
345108684Sphk   SCIF_LOG_INFO((
346108684Sphk      sci_base_object_get_logger(fw_device),
347164677Syar      SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
348108684Sphk      "SMP REPORT PHY SATA - Device:0x%x PhyId:0x%x\n",
349108684Sphk      fw_device, phy_identifier
350108684Sphk   ));
351108684Sphk
352108684Sphk   return scif_sas_smp_request_build(
353108684Sphk             fw_controller, fw_device, &report_phy_sata, NULL, NULL);
354108684Sphk}
355108684Sphk
356108684Sphk
357108684Sphk/**
358108684Sphk * @brief construct a smp REPORT PHY SATA command to the fw_device.
359164677Syar * @param[in] fw_controller The framework controller object.
360108684Sphk * @param[in] fw_device the framework smp device that PHY CONTROL command
361108684Sphk *       targets to.
362108684Sphk * @param[in] phy_identifier The phy index the DISCOVER command targets to.
363108684Sphk *
364108684Sphk * @return void * address to the built scif sas smp request.
365108684Sphk */
366108684Sphkvoid * scif_sas_smp_request_construct_phy_control(
367108684Sphk   SCIF_SAS_CONTROLLER_T    * fw_controller,
368108684Sphk   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
369247036Smelifaro   U8                         phy_operation,
370247036Smelifaro   U8                         phy_identifier,
371247036Smelifaro   void                     * external_request_object,
372247036Smelifaro   void                     * external_memory
373247036Smelifaro)
374247036Smelifaro{
375247037Smelifaro   SMP_REQUEST_T phy_control;
376247037Smelifaro
377247037Smelifaro   scif_sas_smp_protocol_request_construct(
378247036Smelifaro      &phy_control,
379247036Smelifaro      SMP_FUNCTION_PHY_CONTROL,
380247036Smelifaro      0,
381247036Smelifaro      sizeof(SMP_REQUEST_PHY_CONTROL_T) / sizeof(U32)
382247036Smelifaro   );
383247036Smelifaro
384247036Smelifaro   phy_control.request.phy_control.phy_operation = phy_operation;
385247036Smelifaro   phy_control.request.phy_control.phy_identifier = phy_identifier;
386247036Smelifaro
387247036Smelifaro   return scif_sas_smp_request_build(
388247036Smelifaro             fw_controller, fw_device, &phy_control,
389247036Smelifaro             external_request_object, external_memory
390247037Smelifaro          );
391247036Smelifaro}
392247036Smelifaro
393247036Smelifaro
394247036Smelifaro/**
395247036Smelifaro * @brief construct a smp CONFIG ROUTE INFO command to the fw_device.
396247036Smelifaro *
397247036Smelifaro * @param[in] fw_controller The framework controller object.
398247036Smelifaro * @param[in] fw_device the framework smp device that PHY CONTROL command
399247036Smelifaro *       targets to.
400247037Smelifaro * @param[in] phy_id The phy, whose route entry at route_index is to be configured.
401247036Smelifaro * @param[in] route_index The index of a phy's route entry that is to be configured.
402247036Smelifaro * @param[in] destination_sas_address A sas address for an route table entry
403108684Sphk *
404108684Sphk * @return void * address to the built scif sas smp request.
405108684Sphk */
406108684Sphkvoid * scif_sas_smp_request_construct_config_route_info(
407108684Sphk   struct SCIF_SAS_CONTROLLER    * fw_controller,
408108684Sphk   struct SCIF_SAS_REMOTE_DEVICE * fw_device,
409108684Sphk   U8                              phy_id,
410108684Sphk   U16                             route_index,
411108684Sphk   SCI_SAS_ADDRESS_T               destination_sas_address,
412108684Sphk   BOOL                            disable_expander_route_entry
413108684Sphk)
414108684Sphk{
415108684Sphk   SMP_REQUEST_T config_route_info;
416158161Sbde
417108684Sphk   scif_sas_smp_protocol_request_construct(
418108684Sphk      &config_route_info,
419108684Sphk      SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION,
420247036Smelifaro      0,
421247036Smelifaro      sizeof(SMP_REQUEST_CONFIGURE_ROUTE_INFORMATION_T) / sizeof(U32)
422247036Smelifaro   );
423247036Smelifaro
424247036Smelifaro   config_route_info.request.configure_route_information.phy_identifier = phy_id;
425108684Sphk   config_route_info.request.configure_route_information.expander_route_index_high =
426108684Sphk      ((route_index & 0xff00) >> 8);
427108684Sphk   config_route_info.request.configure_route_information.expander_route_index =
428108684Sphk      route_index & 0xff;
429247036Smelifaro   config_route_info.request.configure_route_information.routed_sas_address[0] =
430247036Smelifaro      destination_sas_address.high;
431247036Smelifaro   config_route_info.request.configure_route_information.routed_sas_address[1] =
432108684Sphk      destination_sas_address.low;
433108684Sphk
434108684Sphk   if (disable_expander_route_entry == TRUE)
435108684Sphk      config_route_info.request.configure_route_information.disable_route_entry = 1;
436108684Sphk
437108684Sphk   return scif_sas_smp_request_build(
438108684Sphk             fw_controller, fw_device, &config_route_info,
439108684Sphk             NULL, NULL
440108684Sphk          );
441108684Sphk}
442108684Sphk
443108684Sphk/**
444108684Sphk * @brief This method retry the internal smp request.
445108684Sphk *
446108684Sphk * @param[in] fw_device This parameter specifies the remote device for
447126775Sdwmalone *            which the internal IO request is destined.
448126775Sdwmalone * @param[in] retry_count This parameter specifies how many times the
449108684Sphk *            old smp request has been retried.
450247037Smelifaro *
451108684Sphk * @return none.
452108684Sphk */
453158161SbdeSCI_STATUS scif_sas_smp_internal_request_retry(
454108684Sphk   SCIF_SAS_REMOTE_DEVICE_T * fw_device
455108684Sphk)
456108684Sphk{
457108684Sphk   SCIF_SAS_CONTROLLER_T * fw_controller;
458108684Sphk   SCIF_SAS_IO_REQUEST_T * new_io;
459108684Sphk   void                  * new_request_memory = NULL;
460108684Sphk   U8 retry_count = fw_device->protocol_device.smp_device.io_retry_count;
461108684Sphk
462108684Sphk   SCIF_LOG_TRACE((
463108684Sphk      sci_base_object_get_logger(fw_device),
464108684Sphk      SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
465108684Sphk      "scif_sas_smp_internal_request_retry(0x%x, 0x%x) time %d!\n",
466175239Sdelphij      fw_device, retry_count
467175239Sdelphij   ));
468108684Sphk
469108684Sphk   fw_controller = fw_device->domain->controller;
470108684Sphk
471108684Sphk   switch (fw_device->protocol_device.smp_device.current_smp_request)
472108684Sphk   {
473108684Sphk      case SMP_FUNCTION_REPORT_GENERAL:
474108684Sphk         new_request_memory = scif_sas_smp_request_construct_report_general(
475108684Sphk            fw_controller, fw_device
476108684Sphk         );
477108684Sphk         break;
478108684Sphk
479108684Sphk      case SMP_FUNCTION_DISCOVER:
480108684Sphk         //We are retrying an internal io. So we are going to allocate
481247036Smelifaro         //a new memory from internal io memory pool.
482247036Smelifaro         new_request_memory = scif_sas_smp_request_construct_discover(
483247036Smelifaro            fw_controller, fw_device,
484247036Smelifaro            fw_device->protocol_device.smp_device.current_activity_phy_index,
485247036Smelifaro            NULL, NULL
486108684Sphk         );
487108684Sphk
488247037Smelifaro         break;
489108684Sphk
490      case SMP_FUNCTION_REPORT_PHY_SATA:
491         new_request_memory = scif_sas_smp_request_construct_report_phy_sata(
492            fw_controller, fw_device,
493            fw_device->protocol_device.smp_device.current_activity_phy_index
494         );
495         break;
496
497      default:
498         //unsupported case, TBD
499         break;
500   } //end of switch
501
502   if (new_request_memory != NULL)
503   {
504      //set the retry count to new built smp request.
505      new_io = (SCIF_SAS_IO_REQUEST_T *) new_request_memory;
506      new_io->retry_count = ++retry_count;
507
508      //need to schedule the DPC here.
509      scif_cb_start_internal_io_task_schedule(
510            fw_controller,
511            scif_sas_controller_start_high_priority_io,
512            fw_controller
513         );
514
515      return SCI_SUCCESS;
516   }
517   else
518      return SCI_FAILURE_INSUFFICIENT_RESOURCES;
519
520}
521
522/**
523 * @brief This method retry the external smp request.
524 *
525 * @param[in] fw_device This parameter specifies the remote device for
526 *            which the internal IO request is destined.
527 * @param[in] old_internal_io This parameter specifies the old smp request to be
528 *            retried.
529 *
530 * @return none.
531 */
532SCI_STATUS scif_sas_smp_external_request_retry(
533   SCIF_SAS_IO_REQUEST_T    * old_io
534)
535{
536   SCIF_SAS_REMOTE_DEVICE_T * fw_device = old_io->parent.device;
537   SCIF_SAS_CONTROLLER_T * fw_controller;
538   SCIF_SAS_IO_REQUEST_T * new_io;
539   void                  * new_request_memory = NULL;
540   U8                      retry_count = old_io->retry_count;
541
542   SCIF_LOG_TRACE((
543      sci_base_object_get_logger(fw_device),
544      SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
545      "scif_sas_smp_external_request_retry(0x%x) time %d!\n",
546      old_io
547   ));
548
549   fw_controller = fw_device->domain->controller;
550
551   // Before we construct new io using the same memory, we need to
552   // remove the IO from the list of outstanding requests on the domain
553   // so that we don't damage the domain's fast list of request.
554   sci_fast_list_remove_element(&old_io->parent.list_element);
555
556   switch (fw_device->protocol_device.smp_device.current_smp_request)
557   {
558      case SMP_FUNCTION_DISCOVER:
559         //we are retrying an external io, we are going to reuse the
560         //old io's memory. new_request_memory is same as old_io.
561         new_request_memory = scif_sas_smp_request_construct_discover(
562            fw_controller, fw_device,
563            fw_device->protocol_device.smp_device.current_activity_phy_index,
564            (void *)sci_object_get_association(old_io),
565            (void *)old_io
566         );
567
568         break;
569
570      case SMP_FUNCTION_PHY_CONTROL:
571         //Phy Control command always uses external io memory.
572         new_request_memory = scif_sas_smp_request_construct_phy_control(
573            fw_controller, fw_device, PHY_OPERATION_HARD_RESET,
574            fw_device->protocol_device.smp_device.current_activity_phy_index,
575            (void *)sci_object_get_association(old_io),
576            (void *)old_io
577         );
578
579         break;
580
581      default:
582         //unsupported case, TBD
583         return SCI_FAILURE;
584   } //end of switch
585
586   //set the retry count to new built smp request.
587   new_io = (SCIF_SAS_IO_REQUEST_T *) new_request_memory;
588   new_io->retry_count = ++retry_count;
589
590   //put into the high priority queue.
591   sci_pool_put(fw_controller->hprq.pool, (POINTER_UINT) new_request_memory);
592
593   //schedule the DPC to start new io.
594   scif_cb_start_internal_io_task_schedule(
595      fw_controller, scif_sas_controller_start_high_priority_io, fw_controller
596   );
597
598   return SCI_SUCCESS;
599}
600
601