]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/isci/scil/scif_sas_remote_device_states.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / isci / scil / scif_sas_remote_device_states.c
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
60  */
61
62 #include <dev/isci/scil/scic_remote_device.h>
63
64 #include <dev/isci/scil/scif_sas_remote_device.h>
65 #include <dev/isci/scil/scif_sas_domain.h>
66 #include <dev/isci/scil/scif_sas_logger.h>
67
68
69 /**
70  * This constant indicates the number of milliseconds to wait for the core
71  * to start/stop it's remote device object.
72  */
73 //#define SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT 1000
74
75 //******************************************************************************
76 //* P R O T E C T E D   M E T H O D S
77 //******************************************************************************
78
79 /**
80  * @brief This method implements the actions taken when entering the
81  *        INITIAL state.  This basically, causes an immediate transition
82  *        into the STOPPED state.
83  *
84  * @param[in]  object This parameter specifies the base object for which
85  *             the state transition is occurring.  This is cast into a
86  *             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
87  *
88  * @return none
89  */
90 static
91 void scif_sas_remote_device_initial_state_enter(
92    SCI_BASE_OBJECT_T *object
93 )
94 {
95    SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
96
97    SET_STATE_HANDLER(
98       fw_device,
99       scif_sas_remote_device_state_handler_table,
100       SCI_BASE_REMOTE_DEVICE_STATE_INITIAL
101    );
102
103    // Initial state is a transitional state to the stopped state
104    sci_base_state_machine_change_state(
105       &fw_device->parent.state_machine,
106       SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
107    );
108 }
109
110 /**
111  * @brief This method implements the actions taken when entering the
112  *        STOPPED state.  This method updates the domains count of started
113  *        devices and will invoke the destruct method if this entrance into
114  *        the STOPPED state was due to a scif_remote_device_destruct()
115  *        call by the user.
116  *
117  * @param[in]  object This parameter specifies the base object for which
118  *             the state transition is occurring.  This is cast into a
119  *             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
120  *
121  * @return none
122  */
123 static
124 void scif_sas_remote_device_stopped_state_enter(
125    SCI_BASE_OBJECT_T *object
126 )
127 {
128    SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
129
130    SET_STATE_HANDLER(
131       fw_device,
132       scif_sas_remote_device_state_handler_table,
133       SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
134    );
135
136    // There should be no outstanding requests for this device in the
137    // stopped state.
138    ASSERT(fw_device->request_count == 0);
139
140    // If we are entering the stopped state as a result of a destruct
141    // request, then let's perform the actual destruct operation now.
142    if (fw_device->destruct_when_stopped == TRUE)
143       fw_device->operation_status
144          = fw_device->state_handlers->parent.destruct_handler(
145               &fw_device->parent
146            );
147
148    /// @todo What should we do if this call fails?
149    fw_device->domain->state_handlers->device_stop_complete_handler(
150       &fw_device->domain->parent, &fw_device->parent
151    );
152 }
153
154 /**
155  * @brief This method implements the actions taken when entering the
156  *        STARTING state.  This method will attempt to start the core
157  *        remote device and will kick-start the starting sub-state machine
158  *        if no errors are encountered.
159  *
160  * @param[in]  object This parameter specifies the base object for which
161  *             the state transition is occurring.  This is cast into a
162  *             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
163  *
164  * @return none
165  */
166 static
167 void scif_sas_remote_device_starting_state_enter(
168    SCI_BASE_OBJECT_T *object
169 )
170 {
171    SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
172
173    SET_STATE_HANDLER(
174       fw_device,
175       scif_sas_remote_device_state_handler_table,
176       SCI_BASE_REMOTE_DEVICE_STATE_STARTING
177    );
178
179    SCIF_LOG_INFO((
180       sci_base_object_get_logger(fw_device),
181       SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
182       "RemoteDevice:0x%x starting/configuring\n",
183       fw_device
184    ));
185
186    fw_device->destination_state =
187       SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_READY;
188
189    sci_base_state_machine_start(&fw_device->starting_substate_machine);
190
191    fw_device->operation_status = scic_remote_device_start(
192                                     fw_device->core_object,
193                                     SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT
194                                  );
195
196    if (fw_device->operation_status != SCI_SUCCESS)
197    {
198       fw_device->state_handlers->parent.fail_handler(&fw_device->parent);
199
200       // Something is seriously wrong.  Starting the core remote device
201       // shouldn't fail in anyway in this state.
202       scif_cb_controller_error(fw_device->domain->controller,
203               SCI_CONTROLLER_REMOTE_DEVICE_ERROR);
204    }
205 }
206
207 /**
208  * @brief This method implements the actions taken when exiting the
209  *        STARTING state.  Currently this method simply stops the
210  *        sub-state machine.
211  *
212  * @param[in]  object This parameter specifies the base object for which
213  *             the state transition is occurring.  This is cast into a
214  *             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
215  *
216  * @return none
217  */
218 static
219 void scif_sas_remote_device_starting_state_exit(
220    SCI_BASE_OBJECT_T *object
221 )
222 {
223    SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
224
225    fw_device->destination_state =
226       SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UNSPECIFIED;
227
228    // Transition immediately into the operational sub-state.
229    sci_base_state_machine_stop(&fw_device->starting_substate_machine);
230 }
231
232 /**
233  * @brief This method implements the actions taken when entering the
234  *        READY state.  Currently this method simply starts the
235  *        sub-state machine.
236  *
237  * @param[in]  object This parameter specifies the base object for which
238  *             the state transition is occurring.  This is cast into a
239  *             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
240  *
241  * @return none
242  */
243 static
244 void scif_sas_remote_device_ready_state_enter(
245    SCI_BASE_OBJECT_T *object
246 )
247 {
248    SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
249
250    // Transition immediately into the operational sub-state.
251    sci_base_state_machine_start(&fw_device->ready_substate_machine);
252
253 #if defined(DISABLE_WIDE_PORTED_TARGETS)
254    scif_sas_domain_remote_device_start_complete(fw_device->domain,fw_device);
255 #endif
256 }
257
258 /**
259  * @brief This method implements the actions taken when exiting the
260  *        READY state.  Currently this method simply stops the
261  *        sub-state machine.
262  *
263  * @param[in]  object This parameter specifies the base object for which
264  *             the state transition is occurring.  This is cast into a
265  *             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
266  *
267  * @return none
268  */
269 static
270 void scif_sas_remote_device_ready_state_exit(
271    SCI_BASE_OBJECT_T *object
272 )
273 {
274    SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
275
276    // Transition immediately into the operational sub-state.
277    sci_base_state_machine_stop(&fw_device->ready_substate_machine);
278 }
279
280 /**
281  * @brief This method implements the actions taken when entering the
282  *        STOPPING state.  This includes: stopping the core remote device
283  *        and handling any errors that may occur.
284  *
285  * @param[in]  object This parameter specifies the base object for which
286  *             the state transition is occurring.  This is cast into a
287  *             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
288  *
289  * @return none
290  */
291 static
292 void scif_sas_remote_device_stopping_state_enter(
293    SCI_BASE_OBJECT_T *object
294 )
295 {
296    SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
297
298    SET_STATE_HANDLER(
299       fw_device,
300       scif_sas_remote_device_state_handler_table,
301       SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
302    );
303
304    fw_device->operation_status = scic_remote_device_stop(
305                                     fw_device->core_object,
306                                     SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT
307                                  );
308
309    // If there was a failure, then transition directly to the stopped state.
310    if (fw_device->operation_status != SCI_SUCCESS)
311    {
312       /**
313        * @todo We may want to consider adding handling to reset the
314        *       structure data for the framework and core devices here
315        *       in order to help aid recovery.
316        */
317
318       fw_device->state_handlers->stop_complete_handler(
319          fw_device, fw_device->operation_status
320       );
321    }
322 }
323
324 /**
325  * @brief This method implements the actions taken when exiting the
326  *        STOPPING state.
327  *
328  * @param[in]  object This parameter specifies the base object for which
329  *             the state transition is occurring.  This is cast into a
330  *             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
331  *
332  * @return none
333  */
334 static
335 void scif_sas_remote_device_stopping_state_exit(
336    SCI_BASE_OBJECT_T *object
337 )
338 {
339    SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
340
341    // Let the domain know that the device has stopped
342    fw_device->domain->device_start_count--;
343 }
344
345 /**
346  * @brief This method implements the actions taken when entering the
347  *        FAILED state.  This includes setting the state handler methods
348  *        and issuing a scif_cb_remote_device_failed() notification to
349  *        the user.
350  *
351  * @param[in]  object This parameter specifies the base object for which
352  *             the state transition is occurring.  This is cast into a
353  *             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
354  *
355  * @return none
356  */
357 static
358 void scif_sas_remote_device_failed_state_enter(
359    SCI_BASE_OBJECT_T *object
360 )
361 {
362    SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
363
364    SET_STATE_HANDLER(
365       fw_device,
366       scif_sas_remote_device_state_handler_table,
367       SCI_BASE_REMOTE_DEVICE_STATE_FAILED
368    );
369
370    SCIF_LOG_INFO((
371       sci_base_object_get_logger(fw_device),
372       SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
373       "Domain:0x%x Device:0x%x Status:0x%x device failed\n",
374       fw_device->domain, fw_device, fw_device->operation_status
375    ));
376
377    // Notify the user that the device has failed.
378    scif_cb_remote_device_failed(
379       fw_device->domain->controller,
380       fw_device->domain,
381       fw_device,
382       fw_device->operation_status
383    );
384
385    // Only call start_complete for the remote device if the device failed
386    // from the STARTING state.
387    if (fw_device->parent.state_machine.previous_state_id
388        == SCI_BASE_REMOTE_DEVICE_STATE_STARTING)
389       scif_sas_domain_remote_device_start_complete(fw_device->domain,fw_device);
390 }
391
392 /**
393  * @brief This method implements the actions taken when entering the RESETTING
394  *        state.
395  *
396  * @param[in]  object This parameter specifies the base object for which
397  *             the state transition is occurring.  This is cast into a
398  *             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
399  *
400  * @return none
401  */
402 static
403 void scif_sas_remote_device_resetting_state_enter(
404    SCI_BASE_OBJECT_T *object
405 )
406 {
407 }
408
409 #if !defined(DISABLE_WIDE_PORTED_TARGETS)
410 /**
411  * @brief This method implements the actions taken when entering the UPDATING
412  *        PORT WIDTH state.
413  *
414  * @param[in]  object This parameter specifies the base object for which
415  *             the state transition is occurring.  This is cast into a
416  *             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
417  *
418  * @return none
419  */
420 static
421 void scif_sas_remote_device_updating_port_width_state_enter(
422    SCI_BASE_OBJECT_T *object
423 )
424 {
425    SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
426
427    SET_STATE_HANDLER(
428       fw_device,
429       scif_sas_remote_device_state_handler_table,
430       SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH
431    );
432
433    fw_device->destination_state = SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_READY;
434
435    //If the request count is zero, go ahead to update the RNC.
436    //If not, don't do anything for now. The IO complete handler of this state
437    //will update the RNC whenever the request count goes down to zero.
438    if (fw_device->request_count == 0)
439    {
440       //stop the device, upon the stop complete callback, start the device again
441       //with the updated port width.
442       scic_remote_device_stop(
443          fw_device->core_object, SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT);
444    }
445 }
446
447
448 /**
449  * @brief This method implements the actions taken when exiting the
450  *        STOPPING state.
451  *
452  * @param[in]  object This parameter specifies the base object for which
453  *             the state transition is occurring.  This is cast into a
454  *             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
455  *
456  * @return none
457  */
458 static
459 void scif_sas_remote_device_updating_port_width_state_exit(
460    SCI_BASE_OBJECT_T *object
461 )
462 {
463    SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
464
465    fw_device->destination_state =
466       SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UNSPECIFIED;
467 }
468
469
470 #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
471
472 /**
473  * @brief This method implements the actions taken when entering the
474  *        FINAL state.  This includes setting the FINAL state handler
475  *        methods.
476  *
477  * @param[in]  object This parameter specifies the base object for which
478  *             the state transition is occurring.  This is cast into a
479  *             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
480  *
481  * @return none
482  */
483 static
484 void scif_sas_remote_device_final_state_enter(
485    SCI_BASE_OBJECT_T *object
486 )
487 {
488    SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
489
490    SET_STATE_HANDLER(
491       fw_device,
492       scif_sas_remote_device_state_handler_table,
493       SCI_BASE_REMOTE_DEVICE_STATE_FINAL
494    );
495 }
496
497
498 SCI_BASE_STATE_T
499    scif_sas_remote_device_state_table[SCI_BASE_REMOTE_DEVICE_MAX_STATES] =
500 {
501    {
502       SCI_BASE_REMOTE_DEVICE_STATE_INITIAL,
503       scif_sas_remote_device_initial_state_enter,
504       NULL
505    },
506    {
507       SCI_BASE_REMOTE_DEVICE_STATE_STOPPED,
508       scif_sas_remote_device_stopped_state_enter,
509       NULL
510    },
511    {
512       SCI_BASE_REMOTE_DEVICE_STATE_STARTING,
513       scif_sas_remote_device_starting_state_enter,
514       scif_sas_remote_device_starting_state_exit
515    },
516    {
517       SCI_BASE_REMOTE_DEVICE_STATE_READY,
518       scif_sas_remote_device_ready_state_enter,
519       scif_sas_remote_device_ready_state_exit
520    },
521    {
522       SCI_BASE_REMOTE_DEVICE_STATE_STOPPING,
523       scif_sas_remote_device_stopping_state_enter,
524       scif_sas_remote_device_stopping_state_exit
525    },
526    {
527       SCI_BASE_REMOTE_DEVICE_STATE_FAILED,
528       scif_sas_remote_device_failed_state_enter,
529       NULL
530    },
531    {
532       SCI_BASE_REMOTE_DEVICE_STATE_RESETTING,
533       scif_sas_remote_device_resetting_state_enter,
534       NULL
535    },
536 #if !defined(DISABLE_WIDE_PORTED_TARGETS)
537    {
538       SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH,
539       scif_sas_remote_device_updating_port_width_state_enter,
540       scif_sas_remote_device_updating_port_width_state_exit
541    },
542 #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
543    {
544       SCI_BASE_REMOTE_DEVICE_STATE_FINAL,
545       scif_sas_remote_device_final_state_enter,
546       NULL
547    },
548 };
549