Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_recovery.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 #include "ocs.h"
34 #include "ocs_recovery.h"
35 
36 /* Define FW error recovery context */
38 
39 /**
40  * @brief Handle the EQ processing for all the ocs instances of the adapter
41  */
42 static void ocs_adapter_event_processing(ocs_t *ocs, bool port_reset, bool start)
43 {
44 #if !defined(OCSU_FC_RAMD) && !defined(OCSU_FC_WORKLOAD) && !defined(OCS_USPACE_SPDK)
45  ocs_t *other_ocs = NULL;
46  uint8_t bus, dev, func;
47  uint8_t other_bus, other_dev, other_func;
48  uint32_t index = 0;
49 
50  ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
51  while ((other_ocs = ocs_get_instance(index++)) != NULL) {
52  ocs_get_bus_dev_func(other_ocs, &other_bus, &other_dev, &other_func);
53  if ((bus == other_bus) && (dev == other_dev)) {
54  if (port_reset && (func != other_func)) {
55  /* For FDD, handle the EQ processing only on the specified pci func */
56  continue;
57  }
58 
59  if (start) {
60  ocs_log_info(other_ocs, "Start EQ processing\n");
61  ocs_start_event_processing(&other_ocs->ocs_os);
62  } else {
63  ocs_log_info(other_ocs, "Stop EQ processing\n");
64  ocs_stop_event_processing(&other_ocs->ocs_os);
65  }
66  }
67  }
68 #endif
69 }
70 
71 /**
72  * @brief Set OCS HAL state to inactive for all the ocs instances of the adapter
73  */
74 static void ocs_adapter_hal_inactive(ocs_t *ocs, bool port_reset)
75 {
76  ocs_t *other_ocs = NULL;
77  uint8_t bus, dev, func;
78  uint8_t other_bus, other_dev, other_func;
79  uint32_t index = 0;
80 
81  ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
82  while ((other_ocs = ocs_get_instance(index++)) != NULL) {
83  ocs_get_bus_dev_func(other_ocs, &other_bus, &other_dev, &other_func);
84  if ((bus == other_bus) && (dev == other_dev)) {
85  if (port_reset && (func != other_func)) {
86  continue;
87  }
88 
89  if (OCS_HAL_STATE_ACTIVE == other_ocs->hal.state) {
90  other_ocs->hal.state = OCS_HAL_STATE_QUEUES_ALLOCATED;
91  }
92  }
93  }
94 }
95 
96 /**
97  * @brief Shutdown sport(s) for all the ocs instances of the adapter
98  */
99 static void ocs_adapter_sport_shutdown(ocs_t *ocs, bool port_reset)
100 {
101  ocs_t *other_ocs;
102  uint8_t bus, dev, func;
103  uint8_t other_bus, other_dev, other_func;
104  uint32_t index = 0;
105 
106  ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
107  while ((other_ocs = ocs_get_instance(index++)) != NULL) {
108  ocs_get_bus_dev_func(other_ocs, &other_bus, &other_dev, &other_func);
109  if ((bus == other_bus) && (dev == other_dev)) {
110  if (port_reset && (func != other_func)) {
111  continue;
112  }
113 
114  ocs_scsi_tgt_cancel_io(other_ocs);
115 #if !defined(OCSU_FC_RAMD) && !defined(OCSU_FC_WORKLOAD) && !defined(OCS_USPACE_SPDK)
116  if (other_ocs->domain) {
117  ocs_sport_t *sport = NULL;
118 
119  ocs_domain_lock(other_ocs->domain);
120  ocs_list_foreach(&other_ocs->domain->sport_list, sport) {
121  ocs_sport_nodes_shutdown(other_ocs, sport);
122  }
123  ocs_domain_unlock(other_ocs->domain);
124  }
125 #endif
126  }
127  }
128 }
129 
130 /**
131  * @brief Shutdown xport(s) for all the ocs instances of the adapter
132  */
133 static void ocs_adapter_xport_shutdown(ocs_t *ocs, bool port_reset)
134 {
135  ocs_t *other_ocs;
136  uint8_t bus, dev, func;
137  uint8_t other_bus, other_dev, other_func;
138  uint32_t index = 0;
139 
140  ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
141  while ((other_ocs = ocs_get_instance(index++)) != NULL) {
142  ocs_get_bus_dev_func(other_ocs, &other_bus, &other_dev, &other_func);
143  if ((bus == other_bus) && (dev == other_dev)) {
144  if (port_reset && (func != other_func)) {
145  continue;
146  }
147 
148  ocs_log_debug(other_ocs, "Initiate transport shutdown\n");
149  if (ocs_xport_control(other_ocs->xport, OCS_XPORT_SHUTDOWN)) {
150  ocs_log_err(other_ocs, "Tranport shutdown failed\n");
151  }
152  }
153  }
154 }
155 
156 /**
157  * @brief Bring the links online
158  */
159 static int32_t ocs_adapter_xport_online(ocs_t *ocs, bool port_reset)
160 {
161  ocs_t *other_ocs;
162  uint8_t bus, dev, func;
163  uint8_t other_bus, other_dev, other_func;
164  int32_t rc, ret = 0;
165  uint32_t index = 0;
166 
167  ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
168  while ((other_ocs = ocs_get_instance(index++)) != NULL) {
169  ocs_get_bus_dev_func(other_ocs, &other_bus, &other_dev, &other_func);
170  if ((bus == other_bus) && (dev == other_dev)) {
171  if (port_reset && (func != other_func)) {
172  continue;
173  }
174 
175  rc = ocs_scsi_tgt_port_online(other_ocs);
176  if (rc) {
177  ocs_log_err(other_ocs, "Unable to bring-up the link\n");
178  ret = rc;
179  }
180  }
181  }
182 
183  return ret;
184 }
185 
186 /**
187  * @brief Stop FW error recovery thread
188  *
189  * @return void
190  */
192 {
193  ocs_thread_terminate(&ocs_recovery.thread);
194  ocs_lock_free(&ocs_recovery.lock);
195  ocs_log_info(NULL, "FW error recovery thread terminated\n");
196 }
197 
198 /**
199  * @brief Set recovery state
200  */
201 static void ocs_recovery_state_set(uint32_t state)
202 {
203  ocs_lock(&ocs_recovery.lock);
204  ocs_recovery.state = state;
205  ocs_unlock(&ocs_recovery.lock);
206 }
207 
208 /**
209  * @brief Check recovery state
210  *
211  * @return TRUE if the state matches, FALSE otherwise
212  */
213 static int32_t ocs_recovery_state_check(uint32_t state)
214 {
215  int32_t rc = FALSE;
216 
217  ocs_lock(&ocs_recovery.lock);
218  if (ocs_recovery.state == state) {
219  rc = TRUE;
220  }
221  ocs_unlock(&ocs_recovery.lock);
222 
223  return rc;
224 }
225 
226 /**
227  * @brief Set fW dump state
228  *
229  * @return void
230  */
231 void ocs_fw_dump_state_set(ocs_t *ocs, uint32_t state)
232 {
233  ocs_t *other_ocs;
234  uint8_t bus, dev, func;
235  uint8_t other_bus, other_dev, other_func;
236  uint32_t index = 0;
237 
238  ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
239  while ((other_ocs = ocs_get_instance(index++)) != NULL) {
240  ocs_get_bus_dev_func(other_ocs, &other_bus, &other_dev, &other_func);
241  if ((bus == other_bus) && (dev == other_dev)) {
242  if ((FW_CHIP_DUMP_STATE_VALID == state) && (0 != other_func)) {
243  /* For CLD, set the dump state only on pci func 0 */
244  continue;
245  }
246 
247  if ((FW_FUNC_DUMP_STATE_VALID == state) && (func != other_func)) {
248  /* For FDD, set the dump state only on the specified pci func */
249  continue;
250  }
251 
252  ocs_lock(&other_ocs->fw_dump.lock);
253  other_ocs->fw_dump.state = state;
254  ocs_unlock(&other_ocs->fw_dump.lock);
255  }
256  }
257 }
258 
259 /**
260  * @brief Save dump data to OCS buffer; saved_buff will be copied to the
261  * user space buffer when an application requests for it
262  */
263 static int32_t ocs_fw_dump_save(ocs_t *ocs, uint8_t dump_level)
264 {
265  ocs_t *other_ocs;
266  ocs_dma_t *dump_buffers = NULL;
267  uint8_t *saved_buff = NULL;
268  uint8_t bus, dev, func;
269  uint8_t other_bus, other_dev, other_func;
270  uint32_t index = 0;
271  uint32_t offset = 0;
272  uint32_t num_buffers = 0;
273  uint32_t saved_buff_size = 0;
274 
275  if (FW_FUNC_DESC_DUMP == dump_level) {
276  dump_buffers = ocs->fw_dump.func_dump_buffers;
277  num_buffers = ocs->fw_dump.num_func_dump_buffers;
278  saved_buff = ocs->fw_dump.saved_buff;
279  saved_buff_size = ocs->fw_dump.size;
280  } else {
281  ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
282  while ((other_ocs = ocs_get_instance(index++)) != NULL) {
283  ocs_get_bus_dev_func(other_ocs, &other_bus, &other_dev, &other_func);
284  if ((bus == other_bus) && (dev == other_dev) && (0 == other_func)) {
285  dump_buffers = other_ocs->fw_dump.chip_dump_buffers;
286  num_buffers = other_ocs->fw_dump.num_chip_dump_buffers;
287  saved_buff = other_ocs->fw_dump.saved_buff;
288  saved_buff_size = other_ocs->fw_dump.size;
289  break;
290  }
291  }
292  }
293 
294  if (!dump_buffers || !num_buffers || !saved_buff) {
295  ocs_log_err(ocs, "Failed to locate dump buffers\n");
296  return -1;
297  }
298 
299  ocs_memset(saved_buff, 0, saved_buff_size);
300  for (index = 0; index < num_buffers; index++) {
301  if (ocs_memcpy(saved_buff + offset, dump_buffers[index].virt,
302  dump_buffers[index].size) == NULL) {
303  ocs_log_err(ocs, "ocs_memcpy() failed\n");
304  return -1;
305  }
306 
307  offset += dump_buffers[index].size;
308  }
309 
310  ocs_log_info(ocs, "FW dump is saved\n");
311  return 0;
312 }
313 
314 /**
315  * @brief Request FW dump
316  *
317  * @param ocs Pointer to ocs instance
318  * @param dump_level Gendump request level can be either chip-level or fdb
319  *
320  * @return OCS_FW_DUMP_STATUS_SUCCESS on success,
321  * OCS_FW_DUMP_STATUS_IN_PROGRESS if dump is already in progress, or
322  * OCS_FW_DUMP_STATUS_FAILED on failure.
323  */
324 static int32_t ocs_fw_dump_req(ocs_t *ocs, uint8_t dump_level)
325 {
326  int32_t rc = OCS_FW_DUMP_STATUS_SUCCESS;
327  uint32_t skip_dump = FALSE;
328 
329  /* Validate SLI pause errors */
330  if (sli_is_paused(&ocs->hal.sli)) {
331  sli_validate_pause_errors(&ocs->hal.sli, &skip_dump);
332  if (skip_dump) {
333  /* Don't collect the FW dump */
334  dump_level = FW_DUMP_LEVEL_NONE;
335  }
336  }
337 
338  rc = ocs_trigger_dump(ocs, dump_level);
339  if (OCS_FW_DUMP_STATUS_SUCCESS == rc) {
340  ocs_fw_dump_save(ocs, dump_level);
341  ocs_fw_dump_state_set(ocs, dump_level);
342  } else {
344  }
345 
346  return rc;
347 }
348 
349 /**
350  * @brief Initiate FW dump and do reset
351  *
352  * @param ocs Pointer to ocs instance
353  * @param reset_mode Gendump request mode can be auto-recovery / manual / port-migration
354  * @param dump_level Gendump request level can be either chip-level or fdb
355  * @param trigger_dump Trigger FW dump
356  *
357  * @return OCS_RECOVERY_STATUS_SUCCESS on success,
358  * OCS_RECOVERY_STATUS_IN_PROGRESS if recovery is already in progress, or
359  * OCS_RECOVERY_STATUS_FAILED on failure.
360  */
361 int32_t ocs_recovery_reset(ocs_t *ocs, uint32_t reset_mode, uint8_t dump_level, bool trigger_dump)
362 {
363  bool port_reset = FALSE;
364  uint8_t bus, dev, func;
365  int32_t rc;
366 
367  /* Check if recovery state started */
370 
372  ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
373 
374  /* Check if we have to generate the FW dump */
375  if (OCS_RESET_MODE_PORT_MIGRATION != reset_mode) {
376  /* Collect the driver dump before triggering the FW dump */
377  ocs_adapter_ddump_clear_and_save(ocs, bus, dev,
380  OCS_DDUMP_FLAGS_MQES, -1, TRUE);
381 
382  if (trigger_dump) {
383  /* Generate the FW dump only if it's not available */
384  rc = ocs_fw_dump_req(ocs, dump_level);
385  if (OCS_FW_DUMP_STATUS_IN_PROGRESS == rc) {
387  ocs_log_info(ocs, "FW dump is already in progress\n");
388  return rc;
389  }
390 
391  if (OCS_FW_DUMP_STATUS_FAILED == rc) {
393  ocs_log_err(ocs, "FW dump has failed\n");
394  goto exit_err;
395  }
396  }
397 
398  if (FW_FUNC_DESC_DUMP == dump_level) {
399  port_reset = TRUE;
400  }
401  } else {
402  rc = ocs_hal_port_migration(&ocs->hal);
403  if (rc) {
404  ocs_log_err(ocs, "Port migration has failed\n");
405  goto exit_err;
406  }
407  port_reset = TRUE;
408  }
409 
411 
412  /* Wait for all the pending events to be processed */
413  ocs_adapter_event_processing(ocs, port_reset, FALSE);
414 
415  /* Check and set HAL state inactive so that we don't post any more WQE's */
416  ocs_adapter_hal_inactive(ocs, port_reset);
417 
418  /* Shutdown sport(s) for all the ocs instances of the adapter */
419  ocs_adapter_sport_shutdown(ocs, port_reset);
420 
421  /* Shutdown xport(s) on all the ports to remove domain / sport forcefully */
422  ocs_adapter_xport_shutdown(ocs, port_reset);
423 
424  /* now reset the port / adapter */
425  if (port_reset) {
426  rc = ocs_port_reset(ocs);
427  ocs_log_info(ocs, "OCS port (%02d:%02d:%02d) reset has %s\n",
428  bus, dev, func, (rc ? "failed" : "succeeded"));
429  } else {
430  rc = ocs_adapter_reset(ocs);
431  ocs_log_info(ocs, "OCS adapter (%02d:%02d) reset has %s\n",
432  bus, dev, (rc ? "failed" : "succeeded"));
433  }
434 
435  /* Re-enable the interrupts */
436  ocs_adapter_event_processing(ocs, port_reset, TRUE);
437 
438  /* Bring links on each port to the previous state */
439  rc = ocs_adapter_xport_online(ocs, port_reset);
440  if (rc) {
441  ocs_log_err(ocs, "Failed to bring ports online\n");
442  }
443 
444 exit_err:
445  /* Set recovery state to default, irrespective of the rc */
447  return rc;
448 }
449 
450 static int32_t ocs_initiate_gendump(ocs_t *ocs, uint8_t dump_level)
451 {
452  int32_t rc = OCS_FW_DUMP_STATUS_SUCCESS;
453 
454  /**
455  * If FW dump exists already due to recovery processs,
456  * return it. Else, do gendump and reset the adapter.
457  */
458  if (ocs_fw_dump_state_check(ocs, dump_level)) {
459  ocs_log_debug(ocs, "FW dump is already present\n");
460  return rc;
461  }
462 
463  rc = ocs_recovery_reset(ocs, OCS_RECOVERY_MODE_MANUAL, dump_level, true);
464  if (rc) {
466  ocs_log_debug(ocs, "FW dump is already in progress\n");
468  } else {
469  ocs_log_err(ocs, "FW dump failed\n");
471  }
472  } else {
473  ocs_log_info(ocs, "FW dump is generated\n");
475  }
476 
477  return rc;
478 }
479 
480 int32_t ocs_gendump(ocs_t *ocs, uint8_t dump_level)
481 {
482  int32_t rc = OCS_FW_DUMP_STATUS_FAILED;
483 
484  if (FW_DUMP_TYPE_FLASH != ocs->fw_dump.type) {
485  ocs_log_err(ocs, "Flash gendump is disabled\n");
486  return rc;
487  }
488 
489  rc = ocs_initiate_gendump(ocs, dump_level);
490  if (rc) {
491  ocs_log_err(ocs, "ocs_initiate_gendump() failed\n");
492  }
493 
494  return rc;
495 }
496 
497 /**
498  * @brief Waits for FW_DUMP_PRESENT flag to be set in fw_dump.flags context,
499  * and if recovery is started, waits for recovery completion.
500  *
501  * @return returns 0 for success, a negative error code value for failure
502  */
503 static int32_t ocs_fw_dump_ready_wait(ocs_t *ocs, uint8_t dump_state)
504 {
505  int32_t rc = 0;
506  int32_t ms_waited = 0;
507  int32_t wait_time = SLI4_FW_DUMP_TIMEOUT_MSEC;
508 
509  ocs_log_info(ocs, "Waiting for FW dump to be completed\n");
510  while (!ocs_fw_dump_state_check(ocs, dump_state) && (ms_waited < wait_time)) {
511  ocs_delay_usec(10000);
512  ms_waited += 10;
513  }
514 
515  if (!ocs_fw_dump_state_check(ocs, dump_state)) {
516  ocs_log_err(ocs, "FW dump timedout=%d(msec)\n", ms_waited);
517  rc = -1;
518  goto exit_err;
519  }
520 
521  ms_waited = 0;
522  wait_time = SLI4_FW_READY_TIMEOUT_MSEC;
523  /* Wait for recovery process is completed */
525  while (!ocs_recovery_state_check(OCS_RECOVERY_STATE_IDLE) && (ms_waited < wait_time)) {
526  ocs_delay_usec(10000);
527  ms_waited += 10;
528  }
529 
531  ocs_log_err(ocs, "Recovery timedout=%d(msec)\n", ms_waited);
532  rc = -1;
533  goto exit_err;
534  }
535  }
536 
537 exit_err:
538  return rc;
539 }
540 
541 /**
542  * @brief Copy dump buffers to user space buffer
543  */
544 static inline int32_t ocs_fw_dump_copy_to_user(ocs_t *ocs, uint8_t *user_buff,
545  uint32_t user_buflen, uint8_t dump_state)
546 {
547  uint8_t *saved_buff = ocs->fw_dump.saved_buff;
548  uint32_t size = ocs->fw_dump.size;
549 
550  if (!ocs_fw_dump_state_check(ocs, dump_state)) {
551  ocs_log_warn(ocs, "FW dump is not present in the OCS buffers\n");
552  return -1;
553  }
554 
555  /* Copy the dump from the saved buffer to the user buffer */
556  ocs_assert(user_buflen >= size, -1);
557  if (ocs_copy_to_user(user_buff, saved_buff, size)) {
558  ocs_log_err(ocs, "ocs_copy_to_user() failed\n");
559  return -1;
560  }
561 
562  return 0;
563 }
564 
565 /**
566  * @brief Create a Lancer dump into a memory buffer
567  * @par Description
568  * This function creates a DMA buffer to hold a Lancer dump,
569  * sets the dump location to point to that buffer, then calls
570  * ocs_gen_dump to cause a dump to be transfered to the buffer.
571  * After the dump is complete it copies the dump to the provided
572  * user space buffer.
573  *
574  * @param ocs Pointer to ocs structure
575  * @param buf User space buffer in which to store the dump
576  * @param buflen Length of the user buffer in bytes
577  * @param dump_level Gendump request level can be either chip-level or fdb
578  *
579  * @return Returns 0 on success, non-zero on error.
580  */
581 int32_t ocs_dump_to_host(ocs_t *ocs, void *buf, uint32_t buflen, uint8_t dump_level)
582 {
583  ocs_t *other_ocs;
584  ocs_dma_t *dump_buffers = NULL;
585  uint8_t bus, dev, func;
586  uint8_t other_bus, other_dev, other_func;
587  int32_t rc = 0;
588  uint32_t index = 0;
589  uint32_t num_buffers = 0;
590 
591  if (FW_DUMP_TYPE_DUMPTOHOST != ocs->fw_dump.type) {
592  ocs_log_err(ocs, "Dump to host is disabled\n");
593  return -1;
594  }
595 
596  if (!buflen) {
597  ocs_log_err(ocs, "Zero buffer length is invalid\n");
598  return -1;
599  }
600 
601  if (FW_FUNC_DESC_DUMP == dump_level) {
602  dump_buffers = ocs->fw_dump.func_dump_buffers;
603  num_buffers = ocs->fw_dump.num_func_dump_buffers;
604  } else {
605  ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
606  while ((other_ocs = ocs_get_instance(index++)) != NULL) {
607  ocs_get_bus_dev_func(other_ocs, &other_bus, &other_dev, &other_func);
608  if ((bus == other_bus) && (dev == other_dev) && (0 == other_func)) {
609  dump_buffers = other_ocs->fw_dump.chip_dump_buffers;
610  num_buffers = other_ocs->fw_dump.num_chip_dump_buffers;
611  break;
612  }
613  }
614  }
615 
616  if (!dump_buffers || !num_buffers) {
617  ocs_log_err(ocs, "No pre-allocated FW dump memory\n");
618  return -1;
619  }
620 
621  rc = ocs_initiate_gendump(ocs, dump_level);
622  if (OCS_FW_DUMP_STATUS_FAILED == rc) {
623  ocs_log_err(ocs, "ocs_initiate_gendump() failed\n");
624  goto done;
625  }
626 
627  if (OCS_FW_DUMP_STATUS_IN_PROGRESS == rc) {
628  ocs_log_debug(ocs, "Waiting for the already triggered FW dump to complete\n");
629  rc = ocs_fw_dump_ready_wait(ocs, dump_level);
630  }
631 
632  if (OCS_FW_DUMP_STATUS_SUCCESS == rc) {
633  /* Copy the dump from the DMA buffer into the user buffer */
634  rc = ocs_fw_dump_copy_to_user(ocs, (uint8_t *)buf, buflen, dump_level);
635  if (rc) {
636  ocs_log_err(ocs, "FW dump copy to user failed\n");
637  } else {
638  ocs_log_info(ocs, "FW dump to host is successful\n");
639  }
640  }
641 
642 done:
644  return rc;
645 }
646 
647 /**
648  * @brief Recover adapter from chip error.
649  */
650 static int32_t ocs_adapter_recover(ocs_t *ocs, uint32_t mode)
651 {
652  uint8_t bus, dev, func;
653  int32_t rc = 0;
654  uint32_t err1 = sli_reg_read(&ocs->hal.sli, SLI4_REG_SLIPORT_ERROR1);
655  uint32_t err2 = sli_reg_read(&ocs->hal.sli, SLI4_REG_SLIPORT_ERROR2);
656  uint8_t dump_level = FW_CHIP_LEVEL_DUMP;
657  bool trigger_dump = true;
658 
659 
661  ocs_log_info(ocs, "Adapter recovery is already in progress\n");
662  return rc;
663  }
664 
665  ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
666  ocs_log_crit(ocs, "OCS adapter %02d:%02d recovery started for UE "
667  "status=%#x error1=%#x error2=%#x\n", bus, dev,
668  sli_reg_read(&ocs->hal.sli, SLI4_REG_SLIPORT_STATUS),
669  err1, err2);
670 
671  switch (err1) {
672  /* Add the err1 codes here that impact only a single function */
673  case SLI4_SLIPORT_ERROR1_RQ_EMPTY_TIMEOUT:
674  dump_level = FW_FUNC_DESC_DUMP;
675  trigger_dump = false;
676  /* fall-through */
677  default:
678  break;
679  }
680  /* gendump and reset adapter */
681  rc = ocs_recovery_reset(ocs, mode, dump_level, trigger_dump);
684  }
685 
686  return rc;
687 }
688 
689 /**
690  * @ingroup os
691  * @brief OCS FW error recovery thread
692  *
693  * @return 0 if success; < 0 otherwise.
694  */
695 static int32_t ocs_recovery_thread(ocs_thread_t *th)
696 {
697  ocs_t *ocs;
698  int32_t rc, index;
699  uint32_t fw_err_detected;
700 
701  while (!ocs_thread_terminate_requested(th)) {
702  ocs_msleep(1000);
703 
705  continue;
706 
707  index = 0;
708  fw_err_detected = FALSE;
709  while ((ocs = ocs_get_instance(index++)) != NULL) {
710  if (sli_fw_error_status(&ocs->hal.sli) > 0) {
711  fw_err_detected = TRUE;
712  break;
713  } else {
714  fw_err_detected = FALSE;
715  }
716  }
717 
718  if (!fw_err_detected)
719  continue;
720 
722  if (rc == 0) {
724  ocs_log_info(ocs, "FW error recovery is already in progress\n");
725  } else {
726  ocs_log_info(ocs, "FW error recovery is successful\n");
727  }
728  } else {
729  ocs_log_err(ocs, "FW error recovery has failed\n");
730  }
731  }
732 
734  return 0;
735 }
736 
737 /**
738  * @brief Create a FW error recovery thread
739  *
740  * @return returns 0 for success, a negative error code value for failure.
741  */
743 {
744  int32_t rc;
745 
746  ocs_lock_init(NULL, &ocs_recovery.lock, "fw_err_recovery_lock");
747  ocs_recovery.state = OCS_RECOVERY_STATE_IDLE;
748 
749  rc = ocs_thread_create(NULL, &ocs_recovery.thread,
750  ocs_recovery_thread, "ocs_recovery",
751  NULL, OCS_THREAD_RUN);
752  if (rc < 0) {
753  ocs_log_err(NULL, "Failed to create FW err detection thread\n");
754  }
755 
756  return rc;
757 }
758 
759 /**
760  * @brief Initialize fw dump context
761  */
762 void ocs_fw_dump_init(ocs_t *ocs, int32_t fw_dump_type)
763 {
764  /* Init fw dump lock */
765  ocs_lock_init(ocs, &ocs->fw_dump.lock, "fw_dump_lock[%d]", ocs_instance(ocs));
766  ocs->fw_dump.state = FW_DUMP_STATE_NONE;
767  ocs->fw_dump.type = fw_dump_type;
768  ocs->fw_dump.chip_dump_buffers = NULL;
769  ocs->fw_dump.func_dump_buffers = NULL;
770  ocs->fw_dump.num_chip_dump_buffers = 0;
771  ocs->fw_dump.num_func_dump_buffers = 0;
772 }
int32_t ocs_scsi_tgt_port_online(ocs_t *ocs)
#define OCS_DDUMP_FLAGS_WQES
Definition: ocs_ddump.h:38
int32_t ocs_adapter_ddump_clear_and_save(ocs_t *ocs, uint8_t bus, uint8_t dev, uint32_t flags, uint32_t qentries, uint32_t alloc_flag)
int32_t sli_fw_error_status(sli4_t *sli4)
Read the SLIPORT_SEMAPHORE and SLIPORT_STATUS registers to check if the port status indicates that a ...
Definition: sli4.c:4070
#define OCS_RECOVERY_STATUS_IN_PROGRESS
Definition: ocs_recovery.h:47
ocs_t * ocs_get_instance(uint32_t index)
Returns a pointer to the ocs structure given the instance index.
Definition: ocs_driver.c:141
#define OCS_FW_DUMP_STATUS_SUCCESS
Definition: ocs_gendump.h:48
#define OCS_RECOVERY_STATUS_FAILED
Definition: ocs_recovery.h:48
static int32_t ocs_adapter_recover(ocs_t *ocs, uint32_t mode)
Recover adapter from chip error.
Definition: ocs_recovery.c:650
static int32_t ocs_recovery_state_check(uint32_t state)
Check recovery state.
Definition: ocs_recovery.c:213
int32_t ocs_trigger_dump(ocs_t *ocs, uint8_t dump_level)
Definition: ocs_gendump.c:203
static int32_t ocs_fw_dump_save(ocs_t *ocs, uint8_t dump_level)
Save dump data to OCS buffer; saved_buff will be copied to the user space buffer when an application ...
Definition: ocs_recovery.c:263
void ocs_fw_err_recovery_stop(void)
Stop FW error recovery thread.
Definition: ocs_recovery.c:191
static void ocs_adapter_sport_shutdown(ocs_t *ocs, bool port_reset)
Shutdown sport(s) for all the ocs instances of the adapter.
Definition: ocs_recovery.c:99
int32_t ocs_fw_dump_state_check(ocs_t *ocs, uint32_t state)
Check the fw dump state.
Definition: ocs_gendump.c:277
void ocs_fw_dump_init(ocs_t *ocs, int32_t fw_dump_type)
Initialize fw dump context.
Definition: ocs_recovery.c:762
static int32_t ocs_fw_dump_ready_wait(ocs_t *ocs, uint8_t dump_state)
Waits for FW_DUMP_PRESENT flag to be set in fw_dump.flags context, and if recovery is started...
Definition: ocs_recovery.c:503
#define FW_FUNC_DUMP_STATE_VALID
Definition: ocs_gendump.h:61
#define OCS_RECOVERY_STATE_IN_PROGRESS
Definition: ocs_recovery.h:43
#define OCS_RECOVERY_STATE_IDLE
Definition: ocs_recovery.h:42
#define OCS_RESET_MODE_PORT_MIGRATION
Definition: ocs_recovery.h:39
static void ocs_adapter_hal_inactive(ocs_t *ocs, bool port_reset)
Set OCS HAL state to inactive for all the ocs instances of the adapter.
Definition: ocs_recovery.c:74
#define OCS_FW_DUMP_STATUS_IN_PROGRESS
Definition: ocs_gendump.h:49
#define OCS_RECOVERY_MODE_AUTO
Definition: ocs_recovery.h:38
uint32_t sli_reg_read(sli4_t *sli, sli4_regname_e reg)
Read the given SLI register.
Definition: sli4.c:210
int32_t ocs_xport_control(ocs_xport_t *xport, ocs_xport_ctrl_e cmd,...)
Perform transport attach function.
Definition: ocs_xport.c:100
int32_t ocs_fw_err_recovery_setup(void)
Create a FW error recovery thread.
Definition: ocs_recovery.c:742
#define OCS_RECOVERY_MODE_MANUAL
Definition: ocs_recovery.h:37
int32_t ocs_start_event_processing(ocs_os_t *ocs_os)
#define FW_DUMP_LEVEL_NONE
Definition: ocs_gendump.h:54
static int32_t ocs_fw_dump_req(ocs_t *ocs, uint8_t dump_level)
Request FW dump.
Definition: ocs_recovery.c:324
static int32_t ocs_recovery_thread(ocs_thread_t *th)
OCS FW error recovery thread.
Definition: ocs_recovery.c:695
static int32_t ocs_fw_dump_copy_to_user(ocs_t *ocs, uint8_t *user_buff, uint32_t user_buflen, uint8_t dump_state)
Copy dump buffers to user space buffer.
Definition: ocs_recovery.c:544
int32_t ocs_adapter_reset(ocs_t *ocs)
Definition: ocs_gendump.c:63
#define FW_CHIP_DUMP_STATE_VALID
Definition: ocs_gendump.h:60
uint32_t ocs_instance(void *os)
Return the instance index of an opaque ocs structure.
Definition: ocs_driver.c:160
#define OCS_RECOVERY_STATUS_SUCCESS
Definition: ocs_recovery.h:46
#define FW_DUMP_TYPE_DUMPTOHOST
Definition: ocs_gendump.h:64
#define FW_FUNC_DESC_DUMP
Definition: ocs_gendump.h:56
void ocs_scsi_tgt_cancel_io(ocs_t *ocs)
int32_t ocs_dump_to_host(ocs_t *ocs, void *buf, uint32_t buflen, uint8_t dump_level)
Create a Lancer dump into a memory buffer.
Definition: ocs_recovery.c:581
#define FW_CHIP_LEVEL_DUMP
Definition: ocs_gendump.h:55
int32_t ocs_gendump(ocs_t *ocs, uint8_t dump_level)
Definition: ocs_recovery.c:480
static void ocs_adapter_xport_shutdown(ocs_t *ocs, bool port_reset)
Shutdown xport(s) for all the ocs instances of the adapter.
Definition: ocs_recovery.c:133
int32_t ocs_recovery_reset(ocs_t *ocs, uint32_t reset_mode, uint8_t dump_level, bool trigger_dump)
Initiate FW dump and do reset.
Definition: ocs_recovery.c:361
void ocs_fw_dump_state_set(ocs_t *ocs, uint32_t state)
Set fW dump state.
Definition: ocs_recovery.c:231
void ocs_stop_event_processing(ocs_os_t *ocs_os)
static void ocs_domain_lock(ocs_domain_t *domain)
Definition: ocs_common.h:186
int32_t ocs_get_bus_dev_func(ocs_t *ocs, uint8_t *bus, uint8_t *dev, uint8_t *func)
static void ocs_recovery_state_set(uint32_t state)
Set recovery state.
Definition: ocs_recovery.c:201
#define ocs_assert(cond,...)
Definition: ocs_debug.h:163
static int32_t ocs_initiate_gendump(ocs_t *ocs, uint8_t dump_level)
Definition: ocs_recovery.c:450
int32_t ocs_port_reset(ocs_t *ocs)
Definition: ocs_gendump.c:39
static void ocs_adapter_event_processing(ocs_t *ocs, bool port_reset, bool start)
Handle the EQ processing for all the ocs instances of the adapter.
Definition: ocs_recovery.c:42
#define FW_DUMP_STATE_NONE
Definition: ocs_gendump.h:59
#define OCS_FW_DUMP_STATUS_FAILED
Definition: ocs_gendump.h:51
#define ocs_list_foreach(list, item)
Iterate a linked list.
Definition: ocs_list.h:428
#define OCS_DDUMP_FLAGS_CQES
Definition: ocs_ddump.h:39
static void ocs_domain_unlock(ocs_domain_t *domain)
Definition: ocs_common.h:191
#define FW_DUMP_TYPE_FLASH
Definition: ocs_gendump.h:65
static int32_t ocs_adapter_xport_online(ocs_t *ocs, bool port_reset)
Bring the links online.
Definition: ocs_recovery.c:159
ocs_fw_error_recovery_t ocs_recovery
Definition: ocs_recovery.c:37
#define OCS_DDUMP_FLAGS_MQES
Definition: ocs_ddump.h:40