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