Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_ras.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2018, 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 /**
34  * @file
35  *
36  */
37 #include "ocs.h"
38 #include "ocs_ras.h"
39 
40 
42 
43 static uint32_t
45 {
46  uint8_t pci_bus;
47  uint8_t pci_dev;
48  uint8_t pci_func;
49 
50  // Gather PCI bus info to group together all SLI ports of a SLI device.
51  ocs_get_bus_dev_func(ocs, &pci_bus, &pci_dev, &pci_func);
52  return (uint32_t)pci_bus << 8 | (uint32_t)pci_dev;
53 
54 }
55 
56 
59 {
60  uint32_t pci_busdev;
61  ocs_ras_adapter_desc_t *adapter_desc;
62 
63  // Gather PCI bus info to bind together all SLI ports of a SLI device together
64  pci_busdev = ocs_ras_get_sli_dev_pci_info(ocs);
65 
66  ocs_lock(&ocs_ras_subsystem_g.lock);
67  ocs_list_foreach(&ocs_ras_subsystem_g.adapter_list, adapter_desc) {
68  if (adapter_desc->pci_busdev == pci_busdev) {
69  // Found the adapter to which this SLI port belongs
70  ocs_unlock(&ocs_ras_subsystem_g.lock);
71  return adapter_desc;
72  }
73  }
74  ocs_unlock(&ocs_ras_subsystem_g.lock);
75  return NULL;
76 }
77 
78 static bool
79 ocs_ras_get_virt_buf_info(ocs_t *ocs, ocs_ras_adapter_desc_t *adapter_desc, int32_t *active_idx, int32_t *offset)
80 {
81  uint32_t *ptr = (uint32_t *)adapter_desc->lwpd_buffer.virt;
82  uint32_t loffset;
83  uint32_t wrap_seq;
84  uint32_t buf_sz;
85  bool logs_wrapped;
86 
87  loffset = ocs_be32toh(ptr[0]);
88  wrap_seq = ocs_be32toh(ptr[1]);
89  buf_sz = (adapter_desc->log_buf_size / adapter_desc->log_buf_count);
90 
91  *active_idx = loffset / buf_sz;
92  *offset = loffset % buf_sz;
93  if (wrap_seq)
94  logs_wrapped = true;
95  else
96  logs_wrapped = false;
97 
98  return logs_wrapped;
99 }
100 
101 
102 static ocs_diag_log_buf_t *
103 ocs_ras_get_virtual_buf(ocs_t *ocs, int32_t *buf_count)
104 {
105  ocs_diag_log_buf_t *buf_desc_tbl;
106  ocs_ras_adapter_desc_t *adapter_desc;
107  int32_t active_idx;
108  int32_t start_idx;
109  int32_t start_offset;
110  uint32_t valid_log_sz;
111  int32_t offset;
112  bool logs_wrapped;
113  int32_t tbl_size;
114  int32_t i;
115 
116  adapter_desc = ocs_ras_lookup_adapter(ocs);
117  if (!adapter_desc)
118  return NULL;
119 
120  logs_wrapped = ocs_ras_get_virt_buf_info(ocs, adapter_desc, &active_idx, &offset);
121 
122  if (!active_idx && !offset && !logs_wrapped) {
123  // Log buffer is empty
124  *buf_count = 0;
125  return NULL;
126  }
127 
128  // 4 scenarios to determine buffer descriptor table - a) logs wrapper or not. b) offset is at zero or not
129  if (logs_wrapped) {
130  tbl_size = adapter_desc->log_buf_count;
131  valid_log_sz = adapter_desc->log_buf_size;
132  start_idx = active_idx;
133  start_offset = adapter_desc->buf_unit_size - offset;
134  } else {
135  tbl_size = active_idx;
136  valid_log_sz = active_idx * adapter_desc->buf_unit_size + offset;
137  start_idx = 0;
138  start_offset = 0;
139  }
140  if (offset)
141  tbl_size++;
142 
143  buf_desc_tbl = ocs_vmalloc(ocs, tbl_size * sizeof(ocs_diag_log_buf_t), OCS_M_ZERO);
144  if (!buf_desc_tbl)
145  return NULL;
146 
147  for (i = 0; i < tbl_size; i++) {
148  buf_desc_tbl[i].addr = (char *)adapter_desc->buffers[(start_idx + i) % adapter_desc->log_buf_count].virt;
149  buf_desc_tbl[i].offset = start_offset;
150  if (start_offset) {
151  buf_desc_tbl[i].length = adapter_desc->buf_unit_size - start_offset;
152  start_offset = 0;
153  } else {
154  buf_desc_tbl[i].length =
155  valid_log_sz > adapter_desc->buf_unit_size ?
156  adapter_desc->buf_unit_size : valid_log_sz;
157  }
158  valid_log_sz -= buf_desc_tbl[i].length;
159 
160  if (!valid_log_sz)
161  break;
162  }
163 
164  if (valid_log_sz) {
165  ocs_log_err(ocs, "[RAS] BUG: residual log size %d\n", valid_log_sz);
166  }
167  *buf_count = tbl_size;
168  return buf_desc_tbl;
169 }
170 
171 uintptr_t
172 ocs_ras_get_lwpd_dma_addr(ocs_os_handle_t *ocs_os)
173 {
174  ocs_t *ocs = (ocs_t *)ocs_os;
175  ocs_ras_adapter_desc_t *adapter_desc;
176 
177  adapter_desc = ocs_ras_lookup_adapter(ocs);
178  if (!adapter_desc)
179  return (uintptr_t)NULL;
180 
181  return adapter_desc->lwpd_buffer.phys;
182 }
183 
184 uint32_t *
185 ocs_ras_get_dma_addr_list(ocs_os_handle_t *ocs_os, int32_t *buf_count)
186 {
187  int32_t i;
188  int32_t tbl_size;
189  uint32_t *addr_tbl;
190  ocs_t *ocs = (ocs_t *)ocs_os;
191  ocs_ras_adapter_desc_t *adapter_desc;
192 
193  *buf_count = 0;
194  adapter_desc = ocs_ras_lookup_adapter(ocs);
195  if (!adapter_desc)
196  return NULL;
197 
198  tbl_size = adapter_desc->log_buf_count;
199  if (!tbl_size)
200  return NULL;
201 
202  addr_tbl = ocs_vmalloc(ocs, tbl_size * 8, OCS_M_ZERO);
203  if (!addr_tbl)
204  return NULL;
205 
206  for (i = 0; i < tbl_size; i++) {
207  addr_tbl[i * 2] = (uint32_t)(adapter_desc->buffers[i].phys & OCS_RAS_DMA_ADDR_LOW_MASK);
208  addr_tbl[i * 2 + 1] = (uint32_t)(adapter_desc->buffers[i].phys >> OCS_RAS_DMA_ADDR_HI_SHIFT);
209  }
210  *buf_count = tbl_size;
211 
212  return addr_tbl;
213 }
214 
215 
216 static int
217 ocs_ras_gather_logs(void *log_buf, int32_t user_buf_len, ocs_diag_log_buf_t *buf_desc_tbl, int32_t buf_count)
218 {
219  int32_t i;
220  int32_t bytes_copied = 0;
221  char *ptr = (char *)log_buf;
222 
223  for (i = 0; i < buf_count; i++) {
224  if (bytes_copied + (int32_t)buf_desc_tbl[i].length > user_buf_len) {
225  bytes_copied = -EINVAL;
226  break;
227  }
228  ocs_memcpy(ptr + bytes_copied, buf_desc_tbl[i].addr + buf_desc_tbl[i].offset, buf_desc_tbl[i].length);
229  bytes_copied += buf_desc_tbl[i].length;
230 
231  }
232  return bytes_copied;
233 }
234 
235 
236 int
237 ocs_ras_copy_logs(ocs_t *ocs, void *user_buf, int32_t user_buf_len)
238 {
239  ocs_diag_log_buf_t *buf_desc_tbl;
240  int32_t buf_count;
241  int rc;
242 
243  buf_desc_tbl = ocs_ras_get_virtual_buf(ocs, &buf_count);
244  if (!buf_desc_tbl || !buf_count || !user_buf)
245  return -EIO;
246 
247  rc = ocs_ras_gather_logs(user_buf, user_buf_len, buf_desc_tbl, buf_count);
248 
249  ocs_vfree(ocs, buf_desc_tbl, sizeof(ocs_diag_log_buf_t) * buf_count);
250  return rc;
251 }
252 
253 
254 static int32_t
256 {
257  int32_t i;
258  int32_t rc;
259  int32_t buf_count;
260 
261  rc = ocs_dma_alloc(ocs, &adapter_desc->lwpd_buffer, 64, 8);
262  if (rc) {
263  return rc;
264  }
265  adapter_desc->lwpd_allocated = true;
266 
267  buf_count = adapter_desc->log_buf_size / adapter_desc->buf_unit_size;
268  for (i = 0; i < buf_count; i++) {
269  rc = ocs_dma_alloc(ocs, &adapter_desc->buffers[i], adapter_desc->buf_unit_size, 4096);
270  if (rc)
271  return rc;
272  adapter_desc->log_buf_count++;
273  }
274  return 0;
275 }
276 
277 
278 static void
280 {
281  uint32_t i;
282 
283  if (adapter_desc->lwpd_allocated) {
284  ocs_dma_free_unbound(&adapter_desc->lwpd_buffer);
285  adapter_desc->lwpd_allocated = false;
286  }
287 
288  for (i = 0; i < adapter_desc->log_buf_count; i++) {
289  ocs_dma_free_unbound(&adapter_desc->buffers[i]);
290  }
291  adapter_desc->log_buf_count = 0;
292 }
293 
294 static void
296 {
297  ocs_lock(&ocs_ras_subsystem_g.lock);
298  ocs_list_remove(&ocs_ras_subsystem_g.adapter_list, adapter_desc);
299  ocs_unlock(&ocs_ras_subsystem_g.lock);
300 
301  ocs_ras_free_dma_buffers(adapter_desc);
302  ocs_free(NULL, adapter_desc, sizeof(*adapter_desc));
303 }
304 
305 static void
307 {
309 }
310 
311 
312 extern int ocs_hal_stop_fw_diagnostic_logging(ocs_hal_t *hal);
313 
314 int
315 ocs_ras_free_resc(ocs_os_handle_t *ocs_os)
316 {
317  ocs_t *ocs = (ocs_t *)ocs_os;
318  ocs_ras_adapter_desc_t *adapter_desc;
319  int rc = 0;
320 
321  if (ocs_ras_subsystem_g.init_done != OCS_RAS_MOD_INIT_DONE) {
322  ocs_log_debug(ocs, "[RAS] FW logging subsystem is not initialized.\n");
323  return -EPERM;
324  }
325 
326  adapter_desc = ocs_ras_lookup_adapter(ocs);
327  if (!adapter_desc) {
328  ocs_log_debug(ocs, "[RAS] no resources to free.\n");
329  return -ENODEV;
330  }
331 
332  if (ocs_ref_read_count(&adapter_desc->refcnt) == 1) {
333  // This is the last SLI port for this adapter, disable firmware diagnostic logging.
334  rc = ocs_hal_stop_fw_diagnostic_logging(&ocs->hal);
335  }
336  ocs_ref_put(&adapter_desc->refcnt);
337 
338  return rc;
339 }
340 
341 
342 int32_t
343 ocs_ras_allocate_resc(ocs_os_handle_t *ocs_os)
344 {
345  ocs_t *ocs = (ocs_t *)ocs_os;
346  ocs_ras_adapter_desc_t *adapter_desc;
347 
348  if (!ocs_ras_subsystem_g.log_buf_size) {
349  // Nothing to do, RAS diagnostic logging is disabled.
350  ocs_log_err(ocs, "[RAS] FW logging is disabled\n");
351  return -EPERM;
352  }
353 
354  adapter_desc = ocs_ras_lookup_adapter(ocs);
355  if (adapter_desc) {
356  ocs_ref_get(&adapter_desc->refcnt);
357  return -EEXIST;
358  }
359 
360  adapter_desc = ocs_malloc(ocs, sizeof(*adapter_desc), OCS_M_ZERO | OCS_M_NOWAIT);
361  if (!adapter_desc)
362  return -ENOMEM;
363 
364  adapter_desc->pci_busdev = ocs_ras_get_sli_dev_pci_info(ocs);
365  ocs_ref_init(&adapter_desc->refcnt, ocs_ras_put_adapter_descriptor, adapter_desc);
366  adapter_desc->log_buf_size = ocs_ras_subsystem_g.log_buf_size;
367  if (adapter_desc->log_buf_size / OCS_RAS_BUFFER_UNIT_MIN <=
369  adapter_desc->buf_unit_size = OCS_RAS_BUFFER_UNIT_MIN;
370  } else {
371  adapter_desc->buf_unit_size = OCS_RAS_BUFFER_UNIT_MAX;
372  }
373  adapter_desc->log_buf_count = 0;
374  adapter_desc->fw_log_level = ocs_ras_subsystem_g.fw_log_level;
375 
376  if (ocs_ras_alloc_dma_buffers(ocs, adapter_desc)) {
377  ocs_log_err(ocs, "[RAS] unable to allocate resources\n");
378  goto err_log_buffer;
379  }
380 
381  ocs_lock(&ocs_ras_subsystem_g.lock);
382  ocs_list_add_tail(&ocs_ras_subsystem_g.adapter_list, adapter_desc);
383  ocs_unlock(&ocs_ras_subsystem_g.lock);
384 
385  return 0;
386 
387 err_log_buffer:
388  ocs_ras_free_adapter_descriptor(adapter_desc);
389  return -ENOMEM;
390 }
391 
392 
393 
394 void
395 ocs_ras_init(uint32_t fw_log_level, uint32_t log_buf_size)
396 {
397  if (ocs_ras_subsystem_g.init_done == OCS_RAS_MOD_INIT_DONE) {
398  ocs_log_debug(NULL, "[RAS] subsystem already initialized.\n");
399  return;
400  }
401 
402  ocs_ras_subsystem_g.log_buf_size = log_buf_size;
403  ocs_ras_subsystem_g.fw_log_level = fw_log_level;
404  ocs_ras_subsystem_g.num_adapters = 0;
405  ocs_lock_init(NULL, &ocs_ras_subsystem_g.lock, "ras diag logging lock");
406  ocs_list_init(&ocs_ras_subsystem_g.adapter_list, ocs_ras_adapter_desc_t, link);
407  ocs_ras_subsystem_g.init_done = OCS_RAS_MOD_INIT_DONE;
408 }
static int32_t ocs_ras_alloc_dma_buffers(ocs_t *ocs, ocs_ras_adapter_desc_t *adapter_desc)
Definition: ocs_ras.c:255
uint32_t length
Definition: ocs_ras.h:67
#define OCS_RAS_MOD_INIT_DONE
Definition: ocs_ras.h:62
int ocs_ras_copy_logs(ocs_t *ocs, void *user_buf, int32_t user_buf_len)
Definition: ocs_ras.c:237
uint32_t buf_unit_size
Definition: ocs_ras.h:76
static void ocs_ras_free_adapter_descriptor(ocs_ras_adapter_desc_t *adapter_desc)
Definition: ocs_ras.c:295
uintptr_t ocs_ras_get_lwpd_dma_addr(ocs_os_handle_t *ocs_os)
Definition: ocs_ras.c:172
static ocs_ras_adapter_desc_t * ocs_ras_lookup_adapter(ocs_t *ocs)
Definition: ocs_ras.c:58
uint32_t fw_log_level
Definition: ocs_ras.h:89
ocs_ref_t refcnt
Definition: ocs_ras.h:74
static bool ocs_ras_get_virt_buf_info(ocs_t *ocs, ocs_ras_adapter_desc_t *adapter_desc, int32_t *active_idx, int32_t *offset)
Definition: ocs_ras.c:79
static void ocs_ras_free_dma_buffers(ocs_ras_adapter_desc_t *adapter_desc)
Definition: ocs_ras.c:279
static ocs_diag_log_buf_t * ocs_ras_get_virtual_buf(ocs_t *ocs, int32_t *buf_count)
Definition: ocs_ras.c:103
uint32_t pci_busdev
Definition: ocs_ras.h:73
uint32_t log_buf_size
Definition: ocs_ras.h:77
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
#define ocs_list_init(head, type, link)
Definition: ocs_list.h:113
#define OCS_RAS_BUFFER_COUNT_MAX
Definition: ocs_ras.h:44
ocs_list_t adapter_list
Definition: ocs_ras.h:92
static void ocs_ras_put_adapter_descriptor(void *cb_arg)
Definition: ocs_ras.c:306
ocs_dma_t lwpd_buffer
Definition: ocs_ras.h:81
uint32_t * ocs_ras_get_dma_addr_list(ocs_os_handle_t *ocs_os, int32_t *buf_count)
Definition: ocs_ras.c:185
int ocs_hal_stop_fw_diagnostic_logging(ocs_hal_t *hal)
Stop firmware diagnostic logging (RAS).
Definition: ocs_hal.c:7016
#define OCS_RAS_BUFFER_UNIT_MAX
Definition: ocs_ras.h:52
#define OCS_RAS_BUFFER_UNIT_MIN
Definition: ocs_ras.h:51
void ocs_ras_init(uint32_t fw_log_level, uint32_t log_buf_size)
Definition: ocs_ras.c:395
uint32_t log_buf_count
Definition: ocs_ras.h:78
int ocs_ras_free_resc(ocs_os_handle_t *ocs_os)
Definition: ocs_ras.c:315
static void ocs_list_add_tail(ocs_list_t *list, void *item)
Add an item to the tail of the list.
Definition: ocs_list.h:263
#define OCS_RAS_DMA_ADDR_LOW_MASK
Definition: ocs_ras.h:59
static uint32_t ocs_ras_get_sli_dev_pci_info(ocs_t *ocs)
Definition: ocs_ras.c:44
int32_t ocs_get_bus_dev_func(ocs_t *ocs, uint8_t *bus, uint8_t *dev, uint8_t *func)
static int ocs_ras_gather_logs(void *log_buf, int32_t user_buf_len, ocs_diag_log_buf_t *buf_desc_tbl, int32_t buf_count)
Definition: ocs_ras.c:217
ocs_dma_t buffers[OCS_RAS_BUFFER_COUNT_MAX]
Definition: ocs_ras.h:82
uint32_t fw_log_level
Definition: ocs_ras.h:79
ocs_lock_t lock
Definition: ocs_ras.h:91
uint32_t offset
Definition: ocs_ras.h:66
#define ocs_list_foreach(list, item)
Iterate a linked list.
Definition: ocs_list.h:428
static ocs_ras_subsystem_t ocs_ras_subsystem_g
Definition: ocs_ras.c:41
int32_t ocs_ras_allocate_resc(ocs_os_handle_t *ocs_os)
Definition: ocs_ras.c:343
uint32_t num_adapters
Definition: ocs_ras.h:90
uint32_t log_buf_size
Definition: ocs_ras.h:88
#define OCS_RAS_DMA_ADDR_HI_SHIFT
Definition: ocs_ras.h:60