1230557Sjimharris/*-
2230557Sjimharris * This file is provided under a dual BSD/GPLv2 license.  When using or
3230557Sjimharris * redistributing this file, you may do so under either license.
4230557Sjimharris *
5230557Sjimharris * GPL LICENSE SUMMARY
6230557Sjimharris *
7230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8230557Sjimharris *
9230557Sjimharris * This program is free software; you can redistribute it and/or modify
10230557Sjimharris * it under the terms of version 2 of the GNU General Public License as
11230557Sjimharris * published by the Free Software Foundation.
12230557Sjimharris *
13230557Sjimharris * This program is distributed in the hope that it will be useful, but
14230557Sjimharris * WITHOUT ANY WARRANTY; without even the implied warranty of
15230557Sjimharris * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16230557Sjimharris * General Public License for more details.
17230557Sjimharris *
18230557Sjimharris * You should have received a copy of the GNU General Public License
19230557Sjimharris * along with this program; if not, write to the Free Software
20230557Sjimharris * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21230557Sjimharris * The full GNU General Public License is included in this distribution
22230557Sjimharris * in the file called LICENSE.GPL.
23230557Sjimharris *
24230557Sjimharris * BSD LICENSE
25230557Sjimharris *
26230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27230557Sjimharris * All rights reserved.
28230557Sjimharris *
29230557Sjimharris * Redistribution and use in source and binary forms, with or without
30230557Sjimharris * modification, are permitted provided that the following conditions
31230557Sjimharris * are met:
32230557Sjimharris *
33230557Sjimharris *   * Redistributions of source code must retain the above copyright
34230557Sjimharris *     notice, this list of conditions and the following disclaimer.
35230557Sjimharris *   * Redistributions in binary form must reproduce the above copyright
36230557Sjimharris *     notice, this list of conditions and the following disclaimer in
37230557Sjimharris *     the documentation and/or other materials provided with the
38230557Sjimharris *     distribution.
39230557Sjimharris *
40230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51230557Sjimharris */
52230557Sjimharris
53230557Sjimharris#include <sys/cdefs.h>
54230557Sjimharris__FBSDID("$FreeBSD$");
55230557Sjimharris
56230557Sjimharris/**
57230557Sjimharris * @file
58230557Sjimharris *
59230557Sjimharris * @brief This file contains the implementation of the SCIF_SAS_REMOTE_DEVICE
60230557Sjimharris *        object.
61230557Sjimharris */
62230557Sjimharris
63230557Sjimharris
64230557Sjimharris#include <dev/isci/scil/scic_remote_device.h>
65230557Sjimharris#include <dev/isci/scil/scic_port.h>
66230557Sjimharris#include <dev/isci/scil/scic_user_callback.h>
67230557Sjimharris
68230557Sjimharris#include <dev/isci/scil/scif_sas_logger.h>
69230557Sjimharris#include <dev/isci/scil/scif_sas_remote_device.h>
70230557Sjimharris#include <dev/isci/scil/scif_sas_stp_remote_device.h>
71230557Sjimharris#include <dev/isci/scil/scif_sas_domain.h>
72230557Sjimharris#include <dev/isci/scil/scif_sas_controller.h>
73230557Sjimharris#include <dev/isci/scil/sci_controller.h>
74230557Sjimharris#include <dev/isci/scil/sci_util.h>
75230557Sjimharris
76230557Sjimharris
77230557Sjimharris//******************************************************************************
78230557Sjimharris//* P U B L I C   M E T H O D S
79230557Sjimharris//******************************************************************************
80230557Sjimharris
81230557SjimharrisU32 scif_remote_device_get_object_size(
82230557Sjimharris   void
83230557Sjimharris)
84230557Sjimharris{
85230557Sjimharris   return ( sizeof(SCIF_SAS_REMOTE_DEVICE_T)
86230557Sjimharris          + scic_remote_device_get_object_size() );
87230557Sjimharris}
88230557Sjimharris
89230557Sjimharris// ---------------------------------------------------------------------------
90230557Sjimharris
91230557Sjimharrisvoid scif_remote_device_construct(
92230557Sjimharris   SCI_DOMAIN_HANDLE_T          domain,
93230557Sjimharris   void                       * remote_device_memory,
94230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T * new_scif_remote_device_handle
95230557Sjimharris)
96230557Sjimharris{
97230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain = (SCIF_SAS_DOMAIN_T *) domain;
98230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
99230557Sjimharris                                          remote_device_memory;
100230557Sjimharris
101230557Sjimharris   SCIF_LOG_TRACE((
102230557Sjimharris      sci_base_object_get_logger(fw_domain),
103230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE,
104230557Sjimharris      "scif_remote_device_construct(0x%x, 0x%x, 0x%x) enter\n",
105230557Sjimharris      domain, remote_device_memory, new_scif_remote_device_handle
106230557Sjimharris   ));
107230557Sjimharris
108230557Sjimharris   memset(remote_device_memory, 0, sizeof(SCIF_SAS_REMOTE_DEVICE_T));
109230557Sjimharris
110230557Sjimharris   // The user's handle to the remote device evaluates to the memory
111230557Sjimharris   // address where the remote device object is stored.
112230557Sjimharris   *new_scif_remote_device_handle = remote_device_memory;
113230557Sjimharris
114230557Sjimharris   fw_device->domain                = fw_domain;
115230557Sjimharris   fw_device->destruct_when_stopped = FALSE;
116230557Sjimharris   //fw_device->parent.is_failed      = FALSE;
117230557Sjimharris   fw_device->operation_status      = SCI_SUCCESS;
118230557Sjimharris   fw_device->request_count         = 0;
119230557Sjimharris   fw_device->task_request_count    = 0;
120230557Sjimharris   fw_device->is_currently_discovered = TRUE;
121230557Sjimharris   fw_device->containing_device       = NULL;
122230557Sjimharris   fw_device->device_port_width       = 1;
123230557Sjimharris   fw_device->expander_phy_identifier = 0;
124230557Sjimharris   fw_device->destination_state       =
125230557Sjimharris      SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UNSPECIFIED;
126230557Sjimharris   fw_device->ea_target_reset_request_scheduled = NULL;
127230557Sjimharris
128230557Sjimharris   // Construct the base object first in order to ensure logging can
129230557Sjimharris   // function.
130230557Sjimharris   sci_base_remote_device_construct(
131230557Sjimharris      &fw_device->parent,
132230557Sjimharris      sci_base_object_get_logger(fw_domain),
133230557Sjimharris      scif_sas_remote_device_state_table
134230557Sjimharris   );
135230557Sjimharris
136230557Sjimharris   sci_base_state_machine_construct(
137230557Sjimharris      &fw_device->starting_substate_machine,
138230557Sjimharris      &fw_device->parent.parent,
139230557Sjimharris      scif_sas_remote_device_starting_substate_table,
140230557Sjimharris      SCIF_SAS_REMOTE_DEVICE_STARTING_SUBSTATE_AWAIT_COMPLETE
141230557Sjimharris   );
142230557Sjimharris
143230557Sjimharris   sci_base_state_machine_construct(
144230557Sjimharris      &fw_device->ready_substate_machine,
145230557Sjimharris      &fw_device->parent.parent,
146230557Sjimharris      scif_sas_remote_device_ready_substate_table,
147230557Sjimharris      SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL
148230557Sjimharris   );
149230557Sjimharris
150230557Sjimharris   scif_sas_remote_device_initialize_state_logging(fw_device);
151230557Sjimharris
152230557Sjimharris   scic_remote_device_construct(
153230557Sjimharris      fw_domain->core_object,
154230557Sjimharris      ((U8*) remote_device_memory) + sizeof(SCIF_SAS_REMOTE_DEVICE_T),
155230557Sjimharris      &fw_device->core_object
156230557Sjimharris   );
157230557Sjimharris
158230557Sjimharris   // Set the association in the core object, so that we are able to
159230557Sjimharris   // determine our framework remote device object from the core remote
160230557Sjimharris   // device.
161230557Sjimharris   sci_object_set_association(fw_device->core_object, fw_device);
162230557Sjimharris}
163230557Sjimharris
164230557Sjimharris// ---------------------------------------------------------------------------
165230557Sjimharris
166230557SjimharrisSCI_STATUS scif_remote_device_da_construct(
167230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T                   remote_device,
168230557Sjimharris   SCI_SAS_ADDRESS_T                          * sas_address,
169230557Sjimharris   SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
170230557Sjimharris)
171230557Sjimharris{
172230557Sjimharris   SCI_STATUS                 status    = SCI_SUCCESS;
173230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
174230557Sjimharris                                          remote_device;
175230557Sjimharris
176230557Sjimharris   SCIF_LOG_TRACE((
177230557Sjimharris      sci_base_object_get_logger(fw_device),
178230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE,
179230557Sjimharris      "scif_remote_device_da_construct(0x%x, 0x%x, 0x%x) enter\n",
180230557Sjimharris      remote_device, sas_address, protocols
181230557Sjimharris   ));
182230557Sjimharris
183230557Sjimharris   // Make sure the device hasn't already been constructed and added
184230557Sjimharris   // to the domain.
185230557Sjimharris   if (scif_domain_get_device_by_sas_address(fw_device->domain, sas_address)
186230557Sjimharris       == SCI_INVALID_HANDLE)
187230557Sjimharris   {
188230557Sjimharris      SCIC_PORT_PROPERTIES_T  properties;
189230557Sjimharris
190230557Sjimharris      scic_port_get_properties(fw_device->domain->core_object, &properties);
191230557Sjimharris
192230557Sjimharris      // Check to see if this is the direct attached device.
193230557Sjimharris      if (  (sas_address->low == properties.remote.sas_address.low)
194230557Sjimharris         && (sas_address->high == properties.remote.sas_address.high) )
195230557Sjimharris      {
196230557Sjimharris         //Get accurate port width from port's phy mask for a DA device.
197230557Sjimharris         SCI_GET_BITS_SET_COUNT(properties.phy_mask, fw_device->device_port_width);
198230557Sjimharris
199230557Sjimharris         status = scic_remote_device_da_construct(fw_device->core_object);
200230557Sjimharris      }
201230557Sjimharris      else
202230557Sjimharris         // Don't allow the user to construct a direct attached device
203230557Sjimharris         // if it's not a direct attached device.
204230557Sjimharris         status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
205230557Sjimharris   }
206230557Sjimharris   else
207230557Sjimharris      status = SCI_FAILURE_DEVICE_EXISTS;
208230557Sjimharris
209230557Sjimharris   if (status == SCI_SUCCESS)
210230557Sjimharris   {
211230557Sjimharris      // Add the device to the domain list.
212230557Sjimharris      sci_abstract_list_pushback(
213230557Sjimharris         &fw_device->domain->remote_device_list, fw_device
214230557Sjimharris      );
215230557Sjimharris
216230557Sjimharris      // If a SATA/STP device is connected, then construct it.
217230557Sjimharris      if (protocols->u.bits.stp_target)
218230557Sjimharris         scif_sas_stp_remote_device_construct(fw_device);
219230557Sjimharris      else if (protocols->u.bits.smp_target)
220230557Sjimharris         scif_sas_smp_remote_device_construct(fw_device);
221230557Sjimharris
222230557Sjimharris      SCIF_LOG_INFO((
223230557Sjimharris         sci_base_object_get_logger(fw_device),
224230557Sjimharris         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
225230557Sjimharris         "Domain:0x%x SasAddress:0x%x,0x%x remote device constructed\n",
226230557Sjimharris         fw_device->domain, sas_address->low, sas_address->high
227230557Sjimharris      ));
228230557Sjimharris
229230557Sjimharris      status = fw_device->state_handlers->parent.start_handler(
230230557Sjimharris                  &fw_device->parent
231230557Sjimharris               );
232230557Sjimharris   }
233230557Sjimharris   else
234230557Sjimharris   {
235230557Sjimharris      SCIF_LOG_WARNING((
236230557Sjimharris         sci_base_object_get_logger(fw_device),
237230557Sjimharris         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
238230557Sjimharris         "Domain:0x%x SasAddress:0x%x,0x%x Status:0x%x remote device construct failure\n",
239230557Sjimharris         fw_device->domain, sas_address->low, sas_address->high, status
240230557Sjimharris      ));
241230557Sjimharris   }
242230557Sjimharris
243230557Sjimharris   return status;
244230557Sjimharris}
245230557Sjimharris
246230557Sjimharris// ---------------------------------------------------------------------------
247230557Sjimharris
248230557SjimharrisSCI_STATUS scif_remote_device_ea_construct(
249230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T   remote_device,
250230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T   containing_device,
251230557Sjimharris   SMP_RESPONSE_DISCOVER_T    * smp_response
252230557Sjimharris)
253230557Sjimharris{
254230557Sjimharris   SCI_SAS_ADDRESS_T        * sas_address;
255230557Sjimharris   SCI_STATUS                 status        = SCI_SUCCESS;
256230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device     = (SCIF_SAS_REMOTE_DEVICE_T *)
257230557Sjimharris                                              remote_device;
258230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_smp_device = (SCIF_SAS_REMOTE_DEVICE_T *)
259230557Sjimharris                                              containing_device;
260230557Sjimharris
261230557Sjimharris   fw_device->containing_device = fw_smp_device;
262230557Sjimharris   fw_device->expander_phy_identifier =
263230557Sjimharris      fw_smp_device->protocol_device.smp_device.current_activity_phy_index;
264230557Sjimharris
265230557Sjimharris   sas_address = &smp_response->attached_sas_address;
266230557Sjimharris
267230557Sjimharris   SCIF_LOG_TRACE((
268230557Sjimharris      sci_base_object_get_logger(fw_device),
269230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE,
270230557Sjimharris      "scif_remote_device_ea_construct(0x%x, 0x%x) enter\n",
271230557Sjimharris      remote_device, smp_response
272230557Sjimharris   ));
273230557Sjimharris
274230557Sjimharris   // Make sure the device hasn't already been constructed and added
275230557Sjimharris   // to the domain.
276230557Sjimharris   if (scif_domain_get_device_by_sas_address(fw_device->domain, sas_address)
277230557Sjimharris       == SCI_INVALID_HANDLE)
278230557Sjimharris   {
279230557Sjimharris      //for sata device, we need another routine. likely
280230557Sjimharris      //scif_remote_device_ea_sata_construct.
281230557Sjimharris      status = scic_remote_device_ea_construct(fw_device->core_object, smp_response);
282230557Sjimharris   }
283230557Sjimharris   else
284230557Sjimharris      status = SCI_FAILURE_DEVICE_EXISTS;
285230557Sjimharris
286230557Sjimharris   if (status == SCI_SUCCESS)
287230557Sjimharris   {
288230557Sjimharris      // Add the device to the domain list.
289230557Sjimharris      sci_abstract_list_pushback(
290230557Sjimharris         &fw_device->domain->remote_device_list, fw_device
291230557Sjimharris      );
292230557Sjimharris
293230557Sjimharris      if (smp_response->protocols.u.bits.attached_smp_target)
294230557Sjimharris         scif_sas_smp_remote_device_construct(fw_device);
295230557Sjimharris      else if (smp_response->protocols.u.bits.attached_stp_target)
296230557Sjimharris         scif_sas_stp_remote_device_construct(fw_device);
297230557Sjimharris
298230557Sjimharris      SCIF_LOG_INFO((
299230557Sjimharris         sci_base_object_get_logger(fw_device),
300230557Sjimharris         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
301230557Sjimharris         "Domain:0x%x SasAddress:0x%x,0x%x remote device constructed\n",
302230557Sjimharris         fw_device->domain, sas_address->low, sas_address->high
303230557Sjimharris      ));
304230557Sjimharris
305230557Sjimharris      //only start the device if the device is not a SATA disk on SPINUP_HOLD state.
306230557Sjimharris      if ( scic_remote_device_get_connection_rate(fw_device->core_object) !=
307230557Sjimharris              SCI_SATA_SPINUP_HOLD )
308230557Sjimharris      {
309230557Sjimharris          status = fw_device->state_handlers->parent.start_handler(
310230557Sjimharris                      &fw_device->parent
311230557Sjimharris                   );
312230557Sjimharris      }
313230557Sjimharris   }
314230557Sjimharris   else
315230557Sjimharris   {
316230557Sjimharris      SCIF_LOG_WARNING((
317230557Sjimharris         sci_base_object_get_logger(fw_device),
318230557Sjimharris         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
319230557Sjimharris         "Domain:0x%x SasAddress:0x%x,0x%x Status:0x%x remote device construct failure\n",
320230557Sjimharris         fw_device->domain, sas_address->low, sas_address->high, status
321230557Sjimharris      ));
322230557Sjimharris   }
323230557Sjimharris
324230557Sjimharris   return status;
325230557Sjimharris}
326230557Sjimharris
327230557Sjimharris// ---------------------------------------------------------------------------
328230557Sjimharris
329230557SjimharrisSCI_STATUS scif_remote_device_destruct(
330230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T  remote_device
331230557Sjimharris)
332230557Sjimharris{
333230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
334230557Sjimharris                                          remote_device;
335230557Sjimharris
336230557Sjimharris   SCIF_LOG_TRACE((
337230557Sjimharris      sci_base_object_get_logger(fw_device),
338230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE,
339230557Sjimharris      "scif_remote_device_destruct(0x%x) enter\n",
340230557Sjimharris      remote_device
341230557Sjimharris   ));
342230557Sjimharris
343230557Sjimharris   //remove the device from domain's remote_device_list
344230557Sjimharris   fw_device->domain->state_handlers->device_destruct_handler(
345230557Sjimharris      &fw_device->domain->parent, &fw_device->parent
346230557Sjimharris   );
347230557Sjimharris
348230557Sjimharris   // The destruct process may not complete immediately, since the core
349230557Sjimharris   // remote device likely needs to be stopped first.  However, the user
350230557Sjimharris   // is not given a callback notification for destruction.
351230557Sjimharris   return fw_device->state_handlers->parent.destruct_handler(
352230557Sjimharris             &fw_device->parent
353230557Sjimharris          );
354230557Sjimharris}
355230557Sjimharris
356230557Sjimharris// ---------------------------------------------------------------------------
357230557Sjimharris
358230557SjimharrisSCI_REMOTE_DEVICE_HANDLE_T scif_remote_device_get_scic_handle(
359230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T  scif_remote_device
360230557Sjimharris)
361230557Sjimharris{
362230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
363230557Sjimharris                                          scif_remote_device;
364230557Sjimharris
365231137Sjimharris   if ( (fw_device == NULL) || (fw_device->core_object == SCI_INVALID_HANDLE) )
366231137Sjimharris      return SCI_INVALID_HANDLE;
367230557Sjimharris
368230557Sjimharris   SCIF_LOG_WARNING((
369230557Sjimharris      sci_base_object_get_logger(fw_device),
370230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE,
371230557Sjimharris      "RemoteDevice:0x%x no associated core device found\n",
372230557Sjimharris      fw_device
373230557Sjimharris   ));
374230557Sjimharris
375231137Sjimharris   return fw_device->core_object;
376230557Sjimharris}
377230557Sjimharris
378230557Sjimharris// ---------------------------------------------------------------------------
379230557Sjimharris
380230557Sjimharrisvoid scic_cb_remote_device_start_complete(
381230557Sjimharris   SCI_CONTROLLER_HANDLE_T    controller,
382230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T remote_device,
383230557Sjimharris   SCI_STATUS                 completion_status
384230557Sjimharris)
385230557Sjimharris{
386230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
387230557Sjimharris                                      sci_object_get_association(remote_device);
388230557Sjimharris
389230557Sjimharris   SCIF_LOG_TRACE((
390230557Sjimharris      sci_base_object_get_logger(fw_device),
391230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
392230557Sjimharris      "scic_cb_remote_device_start_complete(0x%x, 0x%x, 0x%x) enter\n",
393230557Sjimharris      controller, remote_device, completion_status
394230557Sjimharris   ));
395230557Sjimharris
396230557Sjimharris   fw_device->state_handlers->start_complete_handler(
397230557Sjimharris      fw_device, completion_status
398230557Sjimharris   );
399230557Sjimharris}
400230557Sjimharris
401230557Sjimharris// ---------------------------------------------------------------------------
402230557Sjimharris
403230557Sjimharrisvoid scic_cb_remote_device_stop_complete(
404230557Sjimharris   SCI_CONTROLLER_HANDLE_T    controller,
405230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T remote_device,
406230557Sjimharris   SCI_STATUS                 completion_status
407230557Sjimharris)
408230557Sjimharris{
409230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
410230557Sjimharris                                      sci_object_get_association(remote_device);
411230557Sjimharris
412230557Sjimharris   SCIF_LOG_TRACE((
413230557Sjimharris      sci_base_object_get_logger(fw_device),
414230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
415230557Sjimharris      "scic_cb_remote_device_stop_complete(0x%x, 0x%x, 0x%x) enter\n",
416230557Sjimharris      controller, remote_device, completion_status
417230557Sjimharris   ));
418230557Sjimharris
419230557Sjimharris   fw_device->state_handlers->stop_complete_handler(
420230557Sjimharris      fw_device, completion_status
421230557Sjimharris   );
422230557Sjimharris}
423230557Sjimharris
424230557Sjimharris// ---------------------------------------------------------------------------
425230557Sjimharris
426230557Sjimharrisvoid scic_cb_remote_device_ready(
427230557Sjimharris   SCI_CONTROLLER_HANDLE_T     controller,
428230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T  remote_device
429230557Sjimharris)
430230557Sjimharris{
431230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
432230557Sjimharris                                      sci_object_get_association(remote_device);
433230557Sjimharris
434230557Sjimharris   fw_device->state_handlers->ready_handler(fw_device);
435230557Sjimharris}
436230557Sjimharris
437230557Sjimharris// ---------------------------------------------------------------------------
438230557Sjimharris
439230557Sjimharrisvoid scic_cb_remote_device_not_ready(
440230557Sjimharris   SCI_CONTROLLER_HANDLE_T     controller,
441230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T  remote_device,
442230557Sjimharris   U32                         reason_code
443230557Sjimharris)
444230557Sjimharris{
445230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
446230557Sjimharris                                      sci_object_get_association(remote_device);
447230557Sjimharris
448230557Sjimharris   fw_device->state_handlers->not_ready_handler(fw_device,reason_code);
449230557Sjimharris}
450230557Sjimharris
451230557Sjimharris// ---------------------------------------------------------------------------
452230557Sjimharris
453230557SjimharrisU16 scif_remote_device_get_max_queue_depth(
454230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T  remote_device
455230557Sjimharris)
456230557Sjimharris{
457230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
458230557Sjimharris                                          remote_device;
459230557Sjimharris   SMP_DISCOVER_RESPONSE_PROTOCOLS_T  protocols;
460230557Sjimharris
461230557Sjimharris   scic_remote_device_get_protocols(fw_device->core_object, &protocols);
462230557Sjimharris
463230557Sjimharris   // If the target is a SATA/STP target, then determine the queue depth
464230557Sjimharris   // for either NCQ or for UDMA.
465230557Sjimharris   if (protocols.u.bits.attached_stp_target)
466230557Sjimharris   {
467230557Sjimharris      if (fw_device->protocol_device.stp_device.sati_device.capabilities
468230557Sjimharris          & SATI_DEVICE_CAP_NCQ_SUPPORTED_ENABLE)
469230557Sjimharris      {
470230557Sjimharris         return fw_device->protocol_device.stp_device.sati_device.ncq_depth;
471230557Sjimharris      }
472230557Sjimharris      else
473230557Sjimharris      {
474230557Sjimharris         // At the moment, we only allow a single UDMA request to be queued.
475230557Sjimharris         return 1;
476230557Sjimharris      }
477230557Sjimharris   }
478230557Sjimharris
479230557Sjimharris   // For SSP devices return a no maximum queue depth supported.
480230557Sjimharris   return SCIF_REMOTE_DEVICE_NO_MAX_QUEUE_DEPTH;
481230557Sjimharris}
482230557Sjimharris
483230557Sjimharris// ---------------------------------------------------------------------------
484230557Sjimharris
485230557SjimharrisSCI_STATUS scif_remote_device_get_containing_device(
486230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T          remote_device,
487230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T        * containing_device
488230557Sjimharris)
489230557Sjimharris{
490230557Sjimharris   SCI_STATUS                 status      = SCI_FAILURE;
491230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * this_device = (SCIF_SAS_REMOTE_DEVICE_T *)
492230557Sjimharris                                            remote_device;
493230557Sjimharris
494230557Sjimharris   if ( (this_device != NULL) && (containing_device != NULL) )
495230557Sjimharris   {
496230557Sjimharris      *containing_device = (SCI_REMOTE_DEVICE_HANDLE_T)(this_device->containing_device);
497230557Sjimharris      if (*containing_device != NULL)
498230557Sjimharris      {
499230557Sjimharris         status = SCI_SUCCESS;
500230557Sjimharris      }
501230557Sjimharris   }
502230557Sjimharris
503230557Sjimharris   return status;
504230557Sjimharris}
505230557Sjimharris
506230557Sjimharris// ---------------------------------------------------------------------------
507230557Sjimharris
508230557SjimharrisU32 scif_remote_device_get_started_io_count(
509230557Sjimharris   SCI_REMOTE_DEVICE_HANDLE_T  remote_device
510230557Sjimharris)
511230557Sjimharris{
512230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * this_device = (SCIF_SAS_REMOTE_DEVICE_T *)
513230557Sjimharris                                            remote_device;
514230557Sjimharris
515230557Sjimharris   return this_device->request_count - this_device->task_request_count;
516230557Sjimharris}
517230557Sjimharris//******************************************************************************
518230557Sjimharris//* P R O T E C T E D   M E T H O D S
519230557Sjimharris//******************************************************************************
520230557Sjimharris
521230557Sjimharris/*
522230557Sjimharrisvoid scif_sas_remote_device_failure(
523230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
524230557Sjimharris)
525230557Sjimharris{
526230557Sjimharris   fw_device->parent.is_failed = TRUE;
527230557Sjimharris   sci_base_state_machine_change_state(
528230557Sjimharris      &fw_device->parent.state_machine, SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
529230557Sjimharris   );
530230557Sjimharris}
531230557Sjimharris*/
532230557Sjimharris
533230557Sjimharris
534230557Sjimharris/**
535230557Sjimharris * @brief This method retrieves info from Report Phy Sata response and
536230557Sjimharris *        save the additional data for a SATA remote device, if necessary.
537230557Sjimharris *
538230557Sjimharris * @param[in] report_phy_sata_response SMP Report Phy Sata response
539230557Sjimharris *
540230557Sjimharris * @return none
541230557Sjimharris */
542230557Sjimharrisvoid scif_sas_remote_device_save_report_phy_sata_information(
543230557Sjimharris   SMP_RESPONSE_REPORT_PHY_SATA_T * report_phy_sata_response
544230557Sjimharris)
545230557Sjimharris{
546230557Sjimharris   //do nothing currently. Later, if needed, we will search the existed
547230557Sjimharris   //remote device by stp_sas_address, then save more information for
548230557Sjimharris   //that device off the report_phy_sata_response. This assumes the
549230557Sjimharris   //stp_sas_address from report_phy_sata response is the same sas address
550230557Sjimharris   //from discover response.
551230557Sjimharris
552230557Sjimharris   return;
553230557Sjimharris}
554230557Sjimharris
555230557Sjimharris/**
556230557Sjimharris * @brief This method does target reset for DA or EA remote device.
557230557Sjimharris *
558230557Sjimharris * @param[in] fw_controller, the controller object the target device belongs
559230557Sjimharris *            to.
560230557Sjimharris * @param[in] fw_device, the target device to be hard reset.
561230557Sjimharris * @param[in] fw_request, the scif task request object that asked for this
562230557Sjimharris *            target reset.
563230557Sjimharris */
564230557Sjimharrisvoid scif_sas_remote_device_target_reset(
565230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
566230557Sjimharris   SCIF_SAS_REQUEST_T       * fw_request
567230557Sjimharris)
568230557Sjimharris{
569230557Sjimharris   SCIF_LOG_INFO((
570230557Sjimharris      sci_base_object_get_logger(fw_device),
571230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE,
572230557Sjimharris      "scif_sas_remote_device_target_reset! fw_device:0x%x fw_request:0x%x\n",
573230557Sjimharris      fw_device, fw_request
574230557Sjimharris   ));
575230557Sjimharris
576230557Sjimharris   if (fw_device->containing_device == NULL)
577230557Sjimharris   {
578230557Sjimharris      SCI_PORT_HANDLE_T port;
579230557Sjimharris
580230557Sjimharris      port = scif_domain_get_scic_port_handle(fw_device->domain);
581230557Sjimharris
582230557Sjimharris      //Direct attached device target reset.
583230557Sjimharris      //calling core to do port reset. The fw_request will not be used here.
584230557Sjimharris      scic_port_hard_reset(
585230557Sjimharris         port,
586230557Sjimharris         scic_remote_device_get_suggested_reset_timeout(fw_device->core_object)
587230557Sjimharris      );
588230557Sjimharris   }
589230557Sjimharris   else
590230557Sjimharris   {  //Expander attached device target reset.
591230557Sjimharris
592230557Sjimharris      if ( fw_device->containing_device->protocol_device.smp_device.current_activity
593230557Sjimharris              == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET )
594230557Sjimharris      {
595230557Sjimharris         //The containing expander is in the middle of target resetting other of its
596230557Sjimharris         //remote disks. Flag this remote device to be target reset later.
597230557Sjimharris         SCIF_LOG_INFO((
598230557Sjimharris            sci_base_object_get_logger(fw_device),
599230557Sjimharris            SCIF_LOG_OBJECT_REMOTE_DEVICE,
600230557Sjimharris            "scif_sas_remote_device_target_reset DELAYED! fw_device:0x%x fw_request:0x%x\n",
601230557Sjimharris            fw_device, fw_request
602230557Sjimharris         ));
603230557Sjimharris
604230557Sjimharris         fw_device->ea_target_reset_request_scheduled = fw_request;
605230557Sjimharris         return;
606230557Sjimharris      }
607230557Sjimharris
608230557Sjimharris      //set current_activity and current_smp_request to expander device.
609230557Sjimharris      scif_sas_smp_remote_device_start_target_reset(
610230557Sjimharris         fw_device->containing_device, fw_device, fw_request);
611230557Sjimharris   }
612230557Sjimharris
613230557Sjimharris   scic_remote_device_reset(fw_device->core_object);
614230557Sjimharris}
615230557Sjimharris
616230557Sjimharris
617230557Sjimharris/**
618230557Sjimharris * @brief This method completes target reset for DA or EA remote device.
619230557Sjimharris *
620230557Sjimharris * @param[in] fw_device, the target device to be hard reset.
621230557Sjimharris * @param[in] fw_request, the scif task request object that asked for this
622230557Sjimharris *            target reset.
623230557Sjimharris * @param[in] completion_status
624230557Sjimharris */
625230557Sjimharrisvoid scif_sas_remote_device_target_reset_complete(
626230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
627230557Sjimharris   SCIF_SAS_REQUEST_T       * fw_request,
628230557Sjimharris   SCI_STATUS                 completion_status
629230557Sjimharris)
630230557Sjimharris{
631230557Sjimharris   SCIF_LOG_INFO((
632230557Sjimharris      sci_base_object_get_logger(fw_device),
633230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE,
634230557Sjimharris      "scif_sas_remote_device_target_reset_complete! "
635230557Sjimharris      "fw_device:0x%x fw_request:0x%x completion_status 0x%x\n",
636230557Sjimharris      fw_device, fw_request, completion_status
637230557Sjimharris   ));
638230557Sjimharris
639230557Sjimharris   scif_cb_task_request_complete(
640230557Sjimharris      fw_device->domain->controller,
641230557Sjimharris      fw_device,
642230557Sjimharris      fw_request,
643230557Sjimharris      (SCI_TASK_STATUS) completion_status
644230557Sjimharris   );
645230557Sjimharris
646230557Sjimharris   scic_remote_device_reset_complete(fw_device->core_object);
647230557Sjimharris
648230557Sjimharris   //For expander attached device done target reset.
649230557Sjimharris   if (fw_device->containing_device != NULL)
650230557Sjimharris   {
651230557Sjimharris      //search for all the devices in the domain to find other remote devices
652230557Sjimharris      //needs to be target reset.
653230557Sjimharris      SCIF_SAS_REMOTE_DEVICE_T * next_device;
654230557Sjimharris
655230557Sjimharris      scif_sas_smp_remote_device_clear(fw_device->containing_device);
656230557Sjimharris
657230557Sjimharris      if( (next_device = scif_sas_domain_find_next_ea_target_reset(fw_device->domain))
658230557Sjimharris              != NULL )
659230557Sjimharris      {
660230557Sjimharris         scif_sas_smp_remote_device_start_target_reset(
661230557Sjimharris            next_device->containing_device,
662230557Sjimharris            next_device,
663230557Sjimharris            next_device->ea_target_reset_request_scheduled
664230557Sjimharris         );
665230557Sjimharris
666230557Sjimharris         next_device->ea_target_reset_request_scheduled = NULL;
667230557Sjimharris      }
668230557Sjimharris      else
669230557Sjimharris      {
670230557Sjimharris         //if the domain is in the DISCOVER state, we should resume the DISCOVER.
671230557Sjimharris         if (fw_device->domain->parent.state_machine.current_state_id ==
672230557Sjimharris                SCI_BASE_DOMAIN_STATE_DISCOVERING)
673230557Sjimharris         {
674230557Sjimharris            SCIF_SAS_REMOTE_DEVICE_T * top_expander = fw_device->containing_device;
675230557Sjimharris
676230557Sjimharris            while(top_expander->containing_device != NULL)
677230557Sjimharris               top_expander = top_expander->containing_device;
678230557Sjimharris
679230557Sjimharris            scif_sas_domain_start_smp_discover(fw_device->domain, top_expander);
680230557Sjimharris         }
681230557Sjimharris         else
682230557Sjimharris         {
683230557Sjimharris            //Tell driver to kick off Discover process. If the domain is already
684230557Sjimharris            //in Discovery state, this discovery requst will not be carried on.
685230557Sjimharris            scif_cb_domain_change_notification(
686230557Sjimharris            fw_device->domain->controller, fw_device->domain );
687230557Sjimharris         }
688230557Sjimharris      }
689230557Sjimharris   }
690230557Sjimharris   else
691230557Sjimharris   {
692230557Sjimharris      //Tell driver to kick off Discover process. If the domain is already
693230557Sjimharris      //in Discovery state, this discovery requst will not be carried on.
694230557Sjimharris      scif_cb_domain_change_notification(
695230557Sjimharris         fw_device->domain->controller, fw_device->domain );
696230557Sjimharris   }
697230557Sjimharris}
698230557Sjimharris
699230557Sjimharris#if !defined(DISABLE_WIDE_PORTED_TARGETS)
700230557SjimharrisSCI_STATUS scif_sas_remote_device_update_port_width(
701230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
702230557Sjimharris   U8                         new_port_width
703230557Sjimharris)
704230557Sjimharris{
705230557Sjimharris   SCIF_LOG_INFO((
706230557Sjimharris      sci_base_object_get_logger(fw_device),
707230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE,
708230557Sjimharris      "scif_sas_remote_device_update_port_width (0x%x, 0x%x) enter\n",
709230557Sjimharris      fw_device, new_port_width
710230557Sjimharris   ));
711230557Sjimharris
712230557Sjimharris   fw_device->device_port_width = new_port_width;
713230557Sjimharris
714230557Sjimharris   //Don't Start a new update of port width if a device is already in
715230557Sjimharris   //UPDATING PORT WIDTH state.
716230557Sjimharris   if (fw_device->parent.state_machine.current_state_id == SCI_BASE_REMOTE_DEVICE_STATE_READY)
717230557Sjimharris   {
718230557Sjimharris      if (fw_device->device_port_width != 0)
719230557Sjimharris      {
720230557Sjimharris         //Change state to UPDATING_PORT_WIDTH
721230557Sjimharris         sci_base_state_machine_change_state(
722230557Sjimharris            &fw_device->parent.state_machine,
723230557Sjimharris            SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH
724230557Sjimharris         );
725230557Sjimharris      }
726230557Sjimharris
727230557Sjimharris      return SCI_SUCCESS;
728230557Sjimharris   }
729230557Sjimharris   else if (fw_device->parent.state_machine.current_state_id ==
730230557Sjimharris               SCI_BASE_REMOTE_DEVICE_STATE_STARTING)
731230557Sjimharris   {
732230557Sjimharris      fw_device->destination_state =
733230557Sjimharris         SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UPDATING_PORT_WIDTH;
734230557Sjimharris   }
735230557Sjimharris
736230557Sjimharris   return SCI_FAILURE_INVALID_STATE;
737230557Sjimharris}
738230557Sjimharris#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
739230557Sjimharris
740230557Sjimharris
741230557Sjimharris#ifdef SCI_LOGGING
742230557Sjimharrisvoid scif_sas_remote_device_initialize_state_logging(
743230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * remote_device
744230557Sjimharris)
745230557Sjimharris{
746230557Sjimharris   sci_base_state_machine_logger_initialize(
747230557Sjimharris      &remote_device->parent.state_machine_logger,
748230557Sjimharris      &remote_device->parent.state_machine,
749230557Sjimharris      &remote_device->parent.parent,
750230557Sjimharris      scif_cb_logger_log_states,
751230557Sjimharris      "SCIF_SAS_REMOTE_DEVICE_T", "base_state_machine",
752230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE
753230557Sjimharris   );
754230557Sjimharris
755230557Sjimharris   sci_base_state_machine_logger_initialize(
756230557Sjimharris      &remote_device->starting_substate_machine_logger,
757230557Sjimharris      &remote_device->starting_substate_machine,
758230557Sjimharris      &remote_device->parent.parent,
759230557Sjimharris      scif_cb_logger_log_states,
760230557Sjimharris      "SCIF_SAS_REMOTE_DEVICE_T", "starting substate machine",
761230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE
762230557Sjimharris   );
763230557Sjimharris
764230557Sjimharris   sci_base_state_machine_logger_initialize(
765230557Sjimharris      &remote_device->ready_substate_machine_logger,
766230557Sjimharris      &remote_device->ready_substate_machine,
767230557Sjimharris      &remote_device->parent.parent,
768230557Sjimharris      scif_cb_logger_log_states,
769230557Sjimharris      "SCIF_SAS_REMOTE_DEVICE_T", "ready substate machine",
770230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE
771230557Sjimharris   );
772230557Sjimharris}
773230557Sjimharris
774230557Sjimharrisvoid scif_sas_remote_device_deinitialize_state_logging(
775230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * remote_device
776230557Sjimharris)
777230557Sjimharris{
778230557Sjimharris   sci_base_state_machine_logger_deinitialize(
779230557Sjimharris      &remote_device->parent.state_machine_logger,
780230557Sjimharris      &remote_device->parent.state_machine
781230557Sjimharris   );
782230557Sjimharris
783230557Sjimharris   sci_base_state_machine_logger_deinitialize(
784230557Sjimharris      &remote_device->starting_substate_machine_logger,
785230557Sjimharris      &remote_device->starting_substate_machine
786230557Sjimharris   );
787230557Sjimharris
788230557Sjimharris   sci_base_state_machine_logger_deinitialize(
789230557Sjimharris      &remote_device->ready_substate_machine_logger,
790230557Sjimharris      &remote_device->ready_substate_machine
791230557Sjimharris   );
792230557Sjimharris}
793230557Sjimharris#endif // SCI_LOGGING
794230557Sjimharris
795