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/**
59 * @file
60 *
61 * @brief This file contains the implementation of the SCIF_SAS_REMOTE_DEVICE
62 *        object.
63 */
64
65
66#include <dev/isci/scil/scic_remote_device.h>
67#include <dev/isci/scil/scic_port.h>
68#include <dev/isci/scil/scic_user_callback.h>
69
70#include <dev/isci/scil/scif_sas_logger.h>
71#include <dev/isci/scil/scif_sas_remote_device.h>
72#include <dev/isci/scil/scif_sas_stp_remote_device.h>
73#include <dev/isci/scil/scif_sas_domain.h>
74#include <dev/isci/scil/scif_sas_controller.h>
75#include <dev/isci/scil/sci_controller.h>
76#include <dev/isci/scil/sci_util.h>
77
78
79//******************************************************************************
80//* P U B L I C   M E T H O D S
81//******************************************************************************
82
83U32 scif_remote_device_get_object_size(
84   void
85)
86{
87   return ( sizeof(SCIF_SAS_REMOTE_DEVICE_T)
88          + scic_remote_device_get_object_size() );
89}
90
91// ---------------------------------------------------------------------------
92
93void scif_remote_device_construct(
94   SCI_DOMAIN_HANDLE_T          domain,
95   void                       * remote_device_memory,
96   SCI_REMOTE_DEVICE_HANDLE_T * new_scif_remote_device_handle
97)
98{
99   SCIF_SAS_DOMAIN_T        * fw_domain = (SCIF_SAS_DOMAIN_T *) domain;
100   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
101                                          remote_device_memory;
102
103   SCIF_LOG_TRACE((
104      sci_base_object_get_logger(fw_domain),
105      SCIF_LOG_OBJECT_REMOTE_DEVICE,
106      "scif_remote_device_construct(0x%x, 0x%x, 0x%x) enter\n",
107      domain, remote_device_memory, new_scif_remote_device_handle
108   ));
109
110   memset(remote_device_memory, 0, sizeof(SCIF_SAS_REMOTE_DEVICE_T));
111
112   // The user's handle to the remote device evaluates to the memory
113   // address where the remote device object is stored.
114   *new_scif_remote_device_handle = remote_device_memory;
115
116   fw_device->domain                = fw_domain;
117   fw_device->destruct_when_stopped = FALSE;
118   //fw_device->parent.is_failed      = FALSE;
119   fw_device->operation_status      = SCI_SUCCESS;
120   fw_device->request_count         = 0;
121   fw_device->task_request_count    = 0;
122   fw_device->is_currently_discovered = TRUE;
123   fw_device->containing_device       = NULL;
124   fw_device->device_port_width       = 1;
125   fw_device->expander_phy_identifier = 0;
126   fw_device->destination_state       =
127      SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UNSPECIFIED;
128   fw_device->ea_target_reset_request_scheduled = NULL;
129
130   // Construct the base object first in order to ensure logging can
131   // function.
132   sci_base_remote_device_construct(
133      &fw_device->parent,
134      sci_base_object_get_logger(fw_domain),
135      scif_sas_remote_device_state_table
136   );
137
138   sci_base_state_machine_construct(
139      &fw_device->starting_substate_machine,
140      &fw_device->parent.parent,
141      scif_sas_remote_device_starting_substate_table,
142      SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_AWAIT_COMPLETE
143   );
144
145   sci_base_state_machine_construct(
146      &fw_device->ready_substate_machine,
147      &fw_device->parent.parent,
148      scif_sas_remote_device_ready_substate_table,
149      SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL
150   );
151
152   scif_sas_remote_device_initialize_state_logging(fw_device);
153
154   scic_remote_device_construct(
155      fw_domain->core_object,
156      ((U8*) remote_device_memory) + sizeof(SCIF_SAS_REMOTE_DEVICE_T),
157      &fw_device->core_object
158   );
159
160   // Set the association in the core object, so that we are able to
161   // determine our framework remote device object from the core remote
162   // device.
163   sci_object_set_association(fw_device->core_object, fw_device);
164}
165
166// ---------------------------------------------------------------------------
167
168SCI_STATUS scif_remote_device_da_construct(
169   SCI_REMOTE_DEVICE_HANDLE_T                   remote_device,
170   SCI_SAS_ADDRESS_T                          * sas_address,
171   SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
172)
173{
174   SCI_STATUS                 status    = SCI_SUCCESS;
175   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
176                                          remote_device;
177
178   SCIF_LOG_TRACE((
179      sci_base_object_get_logger(fw_device),
180      SCIF_LOG_OBJECT_REMOTE_DEVICE,
181      "scif_remote_device_da_construct(0x%x, 0x%x, 0x%x) enter\n",
182      remote_device, sas_address, protocols
183   ));
184
185   // Make sure the device hasn't already been constructed and added
186   // to the domain.
187   if (scif_domain_get_device_by_sas_address(fw_device->domain, sas_address)
188       == SCI_INVALID_HANDLE)
189   {
190      SCIC_PORT_PROPERTIES_T  properties;
191
192      scic_port_get_properties(fw_device->domain->core_object, &properties);
193
194      // Check to see if this is the direct attached device.
195      if (  (sas_address->low == properties.remote.sas_address.low)
196         && (sas_address->high == properties.remote.sas_address.high) )
197      {
198         //Get accurate port width from port's phy mask for a DA device.
199         SCI_GET_BITS_SET_COUNT(properties.phy_mask, fw_device->device_port_width);
200
201         status = scic_remote_device_da_construct(fw_device->core_object);
202      }
203      else
204         // Don't allow the user to construct a direct attached device
205         // if it's not a direct attached device.
206         status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
207   }
208   else
209      status = SCI_FAILURE_DEVICE_EXISTS;
210
211   if (status == SCI_SUCCESS)
212   {
213      // Add the device to the domain list.
214      sci_abstract_list_pushback(
215         &fw_device->domain->remote_device_list, fw_device
216      );
217
218      // If a SATA/STP device is connected, then construct it.
219      if (protocols->u.bits.stp_target)
220         scif_sas_stp_remote_device_construct(fw_device);
221      else if (protocols->u.bits.smp_target)
222         scif_sas_smp_remote_device_construct(fw_device);
223
224      SCIF_LOG_INFO((
225         sci_base_object_get_logger(fw_device),
226         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
227         "Domain:0x%x SasAddress:0x%x,0x%x remote device constructed\n",
228         fw_device->domain, sas_address->low, sas_address->high
229      ));
230
231      status = fw_device->state_handlers->parent.start_handler(
232                  &fw_device->parent
233               );
234   }
235   else
236   {
237      SCIF_LOG_WARNING((
238         sci_base_object_get_logger(fw_device),
239         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
240         "Domain:0x%x SasAddress:0x%x,0x%x Status:0x%x remote device construct failure\n",
241         fw_device->domain, sas_address->low, sas_address->high, status
242      ));
243   }
244
245   return status;
246}
247
248// ---------------------------------------------------------------------------
249
250SCI_STATUS scif_remote_device_ea_construct(
251   SCI_REMOTE_DEVICE_HANDLE_T   remote_device,
252   SCI_REMOTE_DEVICE_HANDLE_T   containing_device,
253   SMP_RESPONSE_DISCOVER_T    * smp_response
254)
255{
256   SCI_SAS_ADDRESS_T        * sas_address;
257   SCI_STATUS                 status        = SCI_SUCCESS;
258   SCIF_SAS_REMOTE_DEVICE_T * fw_device     = (SCIF_SAS_REMOTE_DEVICE_T *)
259                                              remote_device;
260   SCIF_SAS_REMOTE_DEVICE_T * fw_smp_device = (SCIF_SAS_REMOTE_DEVICE_T *)
261                                              containing_device;
262
263   fw_device->containing_device = fw_smp_device;
264   fw_device->expander_phy_identifier =
265      fw_smp_device->protocol_device.smp_device.current_activity_phy_index;
266
267   sas_address = &smp_response->attached_sas_address;
268
269   SCIF_LOG_TRACE((
270      sci_base_object_get_logger(fw_device),
271      SCIF_LOG_OBJECT_REMOTE_DEVICE,
272      "scif_remote_device_ea_construct(0x%x, 0x%x) enter\n",
273      remote_device, smp_response
274   ));
275
276   // Make sure the device hasn't already been constructed and added
277   // to the domain.
278   if (scif_domain_get_device_by_sas_address(fw_device->domain, sas_address)
279       == SCI_INVALID_HANDLE)
280   {
281      //for sata device, we need another routine. likely
282      //scif_remote_device_ea_sata_construct.
283      status = scic_remote_device_ea_construct(fw_device->core_object, smp_response);
284   }
285   else
286      status = SCI_FAILURE_DEVICE_EXISTS;
287
288   if (status == SCI_SUCCESS)
289   {
290      // Add the device to the domain list.
291      sci_abstract_list_pushback(
292         &fw_device->domain->remote_device_list, fw_device
293      );
294
295      if (smp_response->protocols.u.bits.attached_smp_target)
296         scif_sas_smp_remote_device_construct(fw_device);
297      else if (smp_response->protocols.u.bits.attached_stp_target)
298         scif_sas_stp_remote_device_construct(fw_device);
299
300      SCIF_LOG_INFO((
301         sci_base_object_get_logger(fw_device),
302         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
303         "Domain:0x%x SasAddress:0x%x,0x%x remote device constructed\n",
304         fw_device->domain, sas_address->low, sas_address->high
305      ));
306
307      //only start the device if the device is not a SATA disk on SPINUP_HOLD state.
308      if ( scic_remote_device_get_connection_rate(fw_device->core_object) !=
309              SCI_SATA_SPINUP_HOLD )
310      {
311          status = fw_device->state_handlers->parent.start_handler(
312                      &fw_device->parent
313                   );
314      }
315   }
316   else
317   {
318      SCIF_LOG_WARNING((
319         sci_base_object_get_logger(fw_device),
320         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
321         "Domain:0x%x SasAddress:0x%x,0x%x Status:0x%x remote device construct failure\n",
322         fw_device->domain, sas_address->low, sas_address->high, status
323      ));
324   }
325
326   return status;
327}
328
329// ---------------------------------------------------------------------------
330
331SCI_STATUS scif_remote_device_destruct(
332   SCI_REMOTE_DEVICE_HANDLE_T  remote_device
333)
334{
335   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
336                                          remote_device;
337
338   SCIF_LOG_TRACE((
339      sci_base_object_get_logger(fw_device),
340      SCIF_LOG_OBJECT_REMOTE_DEVICE,
341      "scif_remote_device_destruct(0x%x) enter\n",
342      remote_device
343   ));
344
345   //remove the device from domain's remote_device_list
346   fw_device->domain->state_handlers->device_destruct_handler(
347      &fw_device->domain->parent, &fw_device->parent
348   );
349
350   // The destruct process may not complete immediately, since the core
351   // remote device likely needs to be stopped first.  However, the user
352   // is not given a callback notification for destruction.
353   return fw_device->state_handlers->parent.destruct_handler(
354             &fw_device->parent
355          );
356}
357
358// ---------------------------------------------------------------------------
359
360SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device_get_scic_handle(
361   SCI_REMOTE_DEVICE_HANDLE_T  scif_remote_device
362)
363{
364   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
365                                          scif_remote_device;
366
367   if ( (fw_device == NULL) || (fw_device->core_object == SCI_INVALID_HANDLE) )
368      return SCI_INVALID_HANDLE;
369
370   SCIF_LOG_WARNING((
371      sci_base_object_get_logger(fw_device),
372      SCIF_LOG_OBJECT_REMOTE_DEVICE,
373      "RemoteDevice:0x%x no associated core device found\n",
374      fw_device
375   ));
376
377   return fw_device->core_object;
378}
379
380// ---------------------------------------------------------------------------
381
382void scic_cb_remote_device_start_complete(
383   SCI_CONTROLLER_HANDLE_T    controller,
384   SCI_REMOTE_DEVICE_HANDLE_T remote_device,
385   SCI_STATUS                 completion_status
386)
387{
388   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
389                                      sci_object_get_association(remote_device);
390
391   SCIF_LOG_TRACE((
392      sci_base_object_get_logger(fw_device),
393      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
394      "scic_cb_remote_device_start_complete(0x%x, 0x%x, 0x%x) enter\n",
395      controller, remote_device, completion_status
396   ));
397
398   fw_device->state_handlers->start_complete_handler(
399      fw_device, completion_status
400   );
401}
402
403// ---------------------------------------------------------------------------
404
405void scic_cb_remote_device_stop_complete(
406   SCI_CONTROLLER_HANDLE_T    controller,
407   SCI_REMOTE_DEVICE_HANDLE_T remote_device,
408   SCI_STATUS                 completion_status
409)
410{
411   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
412                                      sci_object_get_association(remote_device);
413
414   SCIF_LOG_TRACE((
415      sci_base_object_get_logger(fw_device),
416      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
417      "scic_cb_remote_device_stop_complete(0x%x, 0x%x, 0x%x) enter\n",
418      controller, remote_device, completion_status
419   ));
420
421   fw_device->state_handlers->stop_complete_handler(
422      fw_device, completion_status
423   );
424}
425
426// ---------------------------------------------------------------------------
427
428void scic_cb_remote_device_ready(
429   SCI_CONTROLLER_HANDLE_T     controller,
430   SCI_REMOTE_DEVICE_HANDLE_T  remote_device
431)
432{
433   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
434                                      sci_object_get_association(remote_device);
435
436   fw_device->state_handlers->ready_handler(fw_device);
437}
438
439// ---------------------------------------------------------------------------
440
441void scic_cb_remote_device_not_ready(
442   SCI_CONTROLLER_HANDLE_T     controller,
443   SCI_REMOTE_DEVICE_HANDLE_T  remote_device,
444   U32                         reason_code
445)
446{
447   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
448                                      sci_object_get_association(remote_device);
449
450   fw_device->state_handlers->not_ready_handler(fw_device,reason_code);
451}
452
453// ---------------------------------------------------------------------------
454
455U16 scif_remote_device_get_max_queue_depth(
456   SCI_REMOTE_DEVICE_HANDLE_T  remote_device
457)
458{
459   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
460                                          remote_device;
461   SMP_DISCOVER_RESPONSE_PROTOCOLS_T  protocols;
462
463   scic_remote_device_get_protocols(fw_device->core_object, &protocols);
464
465   // If the target is a SATA/STP target, then determine the queue depth
466   // for either NCQ or for UDMA.
467   if (protocols.u.bits.attached_stp_target)
468   {
469      if (fw_device->protocol_device.stp_device.sati_device.capabilities
470          & SATI_DEVICE_CAP_NCQ_SUPPORTED_ENABLE)
471      {
472         return fw_device->protocol_device.stp_device.sati_device.ncq_depth;
473      }
474      else
475      {
476         // At the moment, we only allow a single UDMA request to be queued.
477         return 1;
478      }
479   }
480
481   // For SSP devices return a no maximum queue depth supported.
482   return SCIF_REMOTE_DEVICE_NO_MAX_QUEUE_DEPTH;
483}
484
485// ---------------------------------------------------------------------------
486
487SCI_STATUS scif_remote_device_get_containing_device(
488   SCI_REMOTE_DEVICE_HANDLE_T          remote_device,
489   SCI_REMOTE_DEVICE_HANDLE_T        * containing_device
490)
491{
492   SCI_STATUS                 status      = SCI_FAILURE;
493   SCIF_SAS_REMOTE_DEVICE_T * this_device = (SCIF_SAS_REMOTE_DEVICE_T *)
494                                            remote_device;
495
496   if ( (this_device != NULL) && (containing_device != NULL) )
497   {
498      *containing_device = (SCI_REMOTE_DEVICE_HANDLE_T)(this_device->containing_device);
499      if (*containing_device != NULL)
500      {
501         status = SCI_SUCCESS;
502      }
503   }
504
505   return status;
506}
507
508// ---------------------------------------------------------------------------
509
510U32 scif_remote_device_get_started_io_count(
511   SCI_REMOTE_DEVICE_HANDLE_T  remote_device
512)
513{
514   SCIF_SAS_REMOTE_DEVICE_T * this_device = (SCIF_SAS_REMOTE_DEVICE_T *)
515                                            remote_device;
516
517   return this_device->request_count - this_device->task_request_count;
518}
519//******************************************************************************
520//* P R O T E C T E D   M E T H O D S
521//******************************************************************************
522
523/*
524void scif_sas_remote_device_failure(
525   SCIF_SAS_REMOTE_DEVICE_T * fw_device
526)
527{
528   fw_device->parent.is_failed = TRUE;
529   sci_base_state_machine_change_state(
530      &fw_device->parent.state_machine, SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
531   );
532}
533*/
534
535
536/**
537 * @brief This method retrieves info from Report Phy Sata response and
538 *        save the additional data for a SATA remote device, if necessary.
539 *
540 * @param[in] report_phy_sata_response SMP Report Phy Sata response
541 *
542 * @return none
543 */
544void scif_sas_remote_device_save_report_phy_sata_information(
545   SMP_RESPONSE_REPORT_PHY_SATA_T * report_phy_sata_response
546)
547{
548   //do nothing currently. Later, if needed, we will search the existed
549   //remote device by stp_sas_address, then save more information for
550   //that device off the report_phy_sata_response. This assumes the
551   //stp_sas_address from report_phy_sata response is the same sas address
552   //from discover response.
553
554   return;
555}
556
557/**
558 * @brief This method does target reset for DA or EA remote device.
559 *
560 * @param[in] fw_controller, the controller object the target device belongs
561 *            to.
562 * @param[in] fw_device, the target device to be hard reset.
563 * @param[in] fw_request, the scif task request object that asked for this
564 *            target reset.
565 */
566void scif_sas_remote_device_target_reset(
567   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
568   SCIF_SAS_REQUEST_T       * fw_request
569)
570{
571   SCIF_LOG_INFO((
572      sci_base_object_get_logger(fw_device),
573      SCIF_LOG_OBJECT_REMOTE_DEVICE,
574      "scif_sas_remote_device_target_reset! fw_device:0x%x fw_request:0x%x\n",
575      fw_device, fw_request
576   ));
577
578   if (fw_device->containing_device == NULL)
579   {
580      SCI_PORT_HANDLE_T port;
581
582      port = scif_domain_get_scic_port_handle(fw_device->domain);
583
584      //Direct attached device target reset.
585      //calling core to do port reset. The fw_request will not be used here.
586      scic_port_hard_reset(
587         port,
588         scic_remote_device_get_suggested_reset_timeout(fw_device->core_object)
589      );
590   }
591   else
592   {  //Expander attached device target reset.
593
594      if ( fw_device->containing_device->protocol_device.smp_device.current_activity
595              == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET )
596      {
597         //The containing expander is in the middle of target resetting other of its
598         //remote disks. Flag this remote device to be target reset later.
599         SCIF_LOG_INFO((
600            sci_base_object_get_logger(fw_device),
601            SCIF_LOG_OBJECT_REMOTE_DEVICE,
602            "scif_sas_remote_device_target_reset DELAYED! fw_device:0x%x fw_request:0x%x\n",
603            fw_device, fw_request
604         ));
605
606         fw_device->ea_target_reset_request_scheduled = fw_request;
607         return;
608      }
609
610      //set current_activity and current_smp_request to expander device.
611      scif_sas_smp_remote_device_start_target_reset(
612         fw_device->containing_device, fw_device, fw_request);
613   }
614
615   scic_remote_device_reset(fw_device->core_object);
616}
617
618
619/**
620 * @brief This method completes target reset for DA or EA remote device.
621 *
622 * @param[in] fw_device, the target device to be hard reset.
623 * @param[in] fw_request, the scif task request object that asked for this
624 *            target reset.
625 * @param[in] completion_status
626 */
627void scif_sas_remote_device_target_reset_complete(
628   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
629   SCIF_SAS_REQUEST_T       * fw_request,
630   SCI_STATUS                 completion_status
631)
632{
633   SCIF_LOG_INFO((
634      sci_base_object_get_logger(fw_device),
635      SCIF_LOG_OBJECT_REMOTE_DEVICE,
636      "scif_sas_remote_device_target_reset_complete! "
637      "fw_device:0x%x fw_request:0x%x completion_status 0x%x\n",
638      fw_device, fw_request, completion_status
639   ));
640
641   scif_cb_task_request_complete(
642      fw_device->domain->controller,
643      fw_device,
644      fw_request,
645      (SCI_TASK_STATUS) completion_status
646   );
647
648   scic_remote_device_reset_complete(fw_device->core_object);
649
650   //For expander attached device done target reset.
651   if (fw_device->containing_device != NULL)
652   {
653      //search for all the devices in the domain to find other remote devices
654      //needs to be target reset.
655      SCIF_SAS_REMOTE_DEVICE_T * next_device;
656
657      scif_sas_smp_remote_device_clear(fw_device->containing_device);
658
659      if( (next_device = scif_sas_domain_find_next_ea_target_reset(fw_device->domain))
660              != NULL )
661      {
662         scif_sas_smp_remote_device_start_target_reset(
663            next_device->containing_device,
664            next_device,
665            next_device->ea_target_reset_request_scheduled
666         );
667
668         next_device->ea_target_reset_request_scheduled = NULL;
669      }
670      else
671      {
672         //if the domain is in the DISCOVER state, we should resume the DISCOVER.
673         if (fw_device->domain->parent.state_machine.current_state_id ==
674                SCI_BASE_DOMAIN_STATE_DISCOVERING)
675         {
676            SCIF_SAS_REMOTE_DEVICE_T * top_expander = fw_device->containing_device;
677
678            while(top_expander->containing_device != NULL)
679               top_expander = top_expander->containing_device;
680
681            scif_sas_domain_start_smp_discover(fw_device->domain, top_expander);
682         }
683         else
684         {
685            //Tell driver to kick off Discover process. If the domain is already
686            //in Discovery state, this discovery requst will not be carried on.
687            scif_cb_domain_change_notification(
688            fw_device->domain->controller, fw_device->domain );
689         }
690      }
691   }
692   else
693   {
694      //Tell driver to kick off Discover process. If the domain is already
695      //in Discovery state, this discovery requst will not be carried on.
696      scif_cb_domain_change_notification(
697         fw_device->domain->controller, fw_device->domain );
698   }
699}
700
701#if !defined(DISABLE_WIDE_PORTED_TARGETS)
702SCI_STATUS scif_sas_remote_device_update_port_width(
703   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
704   U8                         new_port_width
705)
706{
707   SCIF_LOG_INFO((
708      sci_base_object_get_logger(fw_device),
709      SCIF_LOG_OBJECT_REMOTE_DEVICE,
710      "scif_sas_remote_device_update_port_width (0x%x, 0x%x) enter\n",
711      fw_device, new_port_width
712   ));
713
714   fw_device->device_port_width = new_port_width;
715
716   //Don't Start a new update of port width if a device is already in
717   //UPDATING PORT WIDTH state.
718   if (fw_device->parent.state_machine.current_state_id == SCI_BASE_REMOTE_DEVICE_STATE_READY)
719   {
720      if (fw_device->device_port_width != 0)
721      {
722         //Change state to UPDATING_PORT_WIDTH
723         sci_base_state_machine_change_state(
724            &fw_device->parent.state_machine,
725            SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH
726         );
727      }
728
729      return SCI_SUCCESS;
730   }
731   else if (fw_device->parent.state_machine.current_state_id ==
732               SCI_BASE_REMOTE_DEVICE_STATE_STARTING)
733   {
734      fw_device->destination_state =
735         SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UPDATING_PORT_WIDTH;
736   }
737
738   return SCI_FAILURE_INVALID_STATE;
739}
740#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
741
742
743#ifdef SCI_LOGGING
744void scif_sas_remote_device_initialize_state_logging(
745   SCIF_SAS_REMOTE_DEVICE_T * remote_device
746)
747{
748   sci_base_state_machine_logger_initialize(
749      &remote_device->parent.state_machine_logger,
750      &remote_device->parent.state_machine,
751      &remote_device->parent.parent,
752      scif_cb_logger_log_states,
753      "SCIF_SAS_REMOTE_DEVICE_T", "base_state_machine",
754      SCIF_LOG_OBJECT_REMOTE_DEVICE
755   );
756
757   sci_base_state_machine_logger_initialize(
758      &remote_device->starting_substate_machine_logger,
759      &remote_device->starting_substate_machine,
760      &remote_device->parent.parent,
761      scif_cb_logger_log_states,
762      "SCIF_SAS_REMOTE_DEVICE_T", "starting substate machine",
763      SCIF_LOG_OBJECT_REMOTE_DEVICE
764   );
765
766   sci_base_state_machine_logger_initialize(
767      &remote_device->ready_substate_machine_logger,
768      &remote_device->ready_substate_machine,
769      &remote_device->parent.parent,
770      scif_cb_logger_log_states,
771      "SCIF_SAS_REMOTE_DEVICE_T", "ready substate machine",
772      SCIF_LOG_OBJECT_REMOTE_DEVICE
773   );
774}
775
776void scif_sas_remote_device_deinitialize_state_logging(
777   SCIF_SAS_REMOTE_DEVICE_T * remote_device
778)
779{
780   sci_base_state_machine_logger_deinitialize(
781      &remote_device->parent.state_machine_logger,
782      &remote_device->parent.state_machine
783   );
784
785   sci_base_state_machine_logger_deinitialize(
786      &remote_device->starting_substate_machine_logger,
787      &remote_device->starting_substate_machine
788   );
789
790   sci_base_state_machine_logger_deinitialize(
791      &remote_device->ready_substate_machine_logger,
792      &remote_device->ready_substate_machine
793   );
794}
795#endif // SCI_LOGGING
796
797