Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_debug.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 /**
34  * @file
35  * Provides general purpose debug facilities
36  */
37 /*!
38 @defgroup debug Debug Support Functions
39 */
40 
41 #include "ocs.h"
42 
43 #define OCS_DEBUG_ENABLE(x) (x ? ~0 : 0)
44 
45 // change '0' to '1' to enable debug feature
46 #define OCS_DEBUG_MASK \
47  (OCS_DEBUG_ENABLE(1) & OCS_DEBUG_ALWAYS) | \
48  (OCS_DEBUG_ENABLE(0) & OCS_DEBUG_ENABLE_MQ_DUMP) | \
49  (OCS_DEBUG_ENABLE(0) & OCS_DEBUG_ENABLE_CQ_DUMP) | \
50  (OCS_DEBUG_ENABLE(0) & OCS_DEBUG_ENABLE_WQ_DUMP) | \
51  (OCS_DEBUG_ENABLE(0) & OCS_DEBUG_ENABLE_EQ_DUMP) | \
52  (OCS_DEBUG_ENABLE(0) & OCS_DEBUG_ENABLE_SPARAM_DUMP)
53 
54 static uint32_t ocs_debug_mask = OCS_DEBUG_MASK;
55 
56 static int
57 _isprint(int c) {
58  return ((c > 32) && (c < 127));
59 }
60 
61 /**
62  * @ingroup debug
63  * @brief enable debug options
64  *
65  * Enables debug options by or-ing in <b>mask</b> into the currently enabled
66  * debug mask.
67  *
68  * @param mask mask bits to enable
69  *
70  * @return none
71  */
72 
73 void ocs_debug_enable(uint32_t mask) {
74  ocs_debug_mask |= mask;
75 }
76 
77 /**
78  * @ingroup debug
79  * @brief disable debug options
80  *
81  * Disables debug options by clearing bits in <b>mask</b> into the currently enabled
82  * debug mask.
83  *
84  * @param mask mask bits to enable
85  *
86  * @return none
87  */
88 
89 void ocs_debug_disable(uint32_t mask) {
90  ocs_debug_mask &= ~mask;
91 }
92 
93 /**
94  * @ingroup debug
95  * @brief return true if debug bits are enabled
96  *
97  * Returns true if the request debug bits are set.
98  *
99  * @param mask debug bit mask
100  *
101  * @return true if corresponding bits are set
102  *
103  * @note Passing in a mask value of zero always returns true
104  */
105 
106 int ocs_debug_is_enabled(uint32_t mask) {
107  return (ocs_debug_mask & mask) == mask;
108 }
109 
110 
111 /**
112  * @ingroup debug
113  * @brief Dump 32 bit hex/ascii data
114  *
115  * Dumps using ocs_log a buffer of data as 32 bit hex and ascii
116  *
117  * @param mask debug enable bits
118  * @param os os handle
119  * @param label text label for the display (may be NULL)
120  * @param buf pointer to data buffer
121  * @param buf_length length of data buffer
122  *
123  * @return none
124  *
125  */
126 
127 void
128 ocs_dump32(uint32_t mask, ocs_os_handle_t os, const char *label, void *buf, uint32_t buf_length)
129 {
130  uint32_t word_count = buf_length / sizeof(uint32_t);
131  uint32_t i;
132  uint32_t columns = 8;
133  uint32_t n;
134  uint32_t *wbuf;
135  char *cbuf;
136  uint32_t addr = 0;
137  char linebuf[200];
138  char *pbuf = linebuf;
139 
140  if (!ocs_debug_is_enabled(mask))
141  return;
142 
143  if (label)
144  ocs_log_info(os, "%s\n", label);
145 
146  wbuf = buf;
147  while (word_count > 0) {
148  pbuf = linebuf;
149  pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%08X: ", addr);
150 
151  n = word_count;
152  if (n > columns)
153  n = columns;
154 
155  for (i = 0; i < n; i ++)
156  pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%08X ", wbuf[i]);
157 
158  for (; i < columns; i ++)
159  pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%8s ", "");
160 
161  pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), " ");
162  cbuf = (char*)wbuf;
163  for (i = 0; i < n*sizeof(uint32_t); i ++)
164  pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%c", _isprint(cbuf[i]) ? cbuf[i] : '.');
165  pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "\n");
166 
167  ocs_log_info(os, "%s", linebuf);
168 
169  wbuf += n;
170  word_count -= n;
171  addr += n*sizeof(uint32_t);
172  }
173 }
174 
175 
176 #if defined(OCS_DEBUG_QUEUE_HISTORY)
177 
178 /* each bit corresponds to word to capture */
179 #define OCS_Q_HIST_WQE_WORD_MASK_DEFAULT (BIT(4) | BIT(6) | BIT(7) | BIT(9) | BIT(12))
180 #define OCS_Q_HIST_TRECV_CONT_WQE_WORD_MASK (BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(9) | BIT(12))
181 #define OCS_Q_HIST_IWRITE_WQE_WORD_MASK (BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(9))
182 #define OCS_Q_HIST_IREAD_WQE_WORD_MASK (BIT(4) | BIT(6) | BIT(7) | BIT(9))
183 #define OCS_Q_HIST_ABORT_WQE_WORD_MASK (BIT(3) | BIT(7) | BIT(8) | BIT(9))
184 #define OCS_Q_HIST_WCQE_WORD_MASK (BIT(0) | BIT(3))
185 #define OCS_Q_HIST_WCQE_WORD_MASK_ERR (BIT(0) | BIT(1) | BIT(2) | BIT(3))
186 #define OCS_Q_HIST_CQXABT_WORD_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
187 
188 /* if set, will provide extra queue information in each entry */
189 #define OCS_Q_HIST_ENABLE_Q_INFO 0
190 uint8_t ocs_queue_history_q_info_enabled(void)
191 {
192  return OCS_Q_HIST_ENABLE_Q_INFO;
193 }
194 
195 /* if set, will provide timestamps in each entry */
196 #define OCS_Q_HIST_ENABLE_TIMESTAMPS 0
197 uint8_t ocs_queue_history_timestamp_enabled(void)
198 {
199  return OCS_Q_HIST_ENABLE_TIMESTAMPS;
200 }
201 
202 /* Add WQEs and masks to override default WQE mask */
203 ocs_q_hist_wqe_mask_t ocs_q_hist_wqe_masks[] = {
204  /* WQE command Word mask */
205  {SLI4_WQE_ABORT, OCS_Q_HIST_ABORT_WQE_WORD_MASK},
206  {SLI4_WQE_FCP_IREAD64, OCS_Q_HIST_IREAD_WQE_WORD_MASK},
207  {SLI4_WQE_FCP_IWRITE64, OCS_Q_HIST_IWRITE_WQE_WORD_MASK},
208  {SLI4_WQE_FCP_CONT_TRECEIVE64, OCS_Q_HIST_TRECV_CONT_WQE_WORD_MASK},
209 };
210 
211 /* CQE masks */
212 ocs_q_hist_cqe_mask_t ocs_q_hist_cqe_masks[] = {
213  /* CQE type Q_hist_type mask (success) mask (non-success) */
214  {SLI_QENTRY_WQ, OCS_Q_HIST_TYPE_CWQE, OCS_Q_HIST_WCQE_WORD_MASK, OCS_Q_HIST_WCQE_WORD_MASK_ERR},
215  {SLI_QENTRY_XABT, OCS_Q_HIST_TYPE_CXABT, OCS_Q_HIST_CQXABT_WORD_MASK, OCS_Q_HIST_WCQE_WORD_MASK},
216 };
217 
218 static uint32_t ocs_q_hist_get_wqe_mask(sli4_generic_wqe_t *wqe)
219 {
220  uint32_t i;
221  for (i = 0; i < ARRAY_SIZE(ocs_q_hist_wqe_masks); i++) {
222  if (ocs_q_hist_wqe_masks[i].command == wqe->command) {
223  return ocs_q_hist_wqe_masks[i].mask;
224  }
225  }
226  /* return default WQE mask */
227  return OCS_Q_HIST_WQE_WORD_MASK_DEFAULT;
228 }
229 
230 /**
231  * @ingroup debug
232  * @brief Initialize resources for queue history
233  *
234  * @param os os handle
235  * @param q_hist Pointer to the queue history object.
236  *
237  * @return none
238  */
239 void
240 ocs_queue_history_init(ocs_t *ocs, ocs_hal_q_hist_t *q_hist)
241 {
242  q_hist->ocs = ocs;
243  if (q_hist->q_hist != NULL) {
244  /* Setup is already done */
245  ocs_log_debug(ocs, "q_hist not NULL, skipping init\n");
246  return;
247  }
248 
249  q_hist->q_hist = ocs_malloc(ocs, sizeof(*q_hist->q_hist) * OCS_Q_HIST_SIZE,
250  OCS_M_ZERO | OCS_M_NOWAIT | OCS_M_NONUMA);
251  if (q_hist->q_hist == NULL) {
252  ocs_log_err(ocs, "Could not allocate queue history buffer\n");
253  } else {
254  ocs_lock_init(ocs, &q_hist->q_hist_lock, "queue history lock[%d]", ocs_instance(ocs));
255  }
256 
257  q_hist->q_hist_index = 0;
258 }
259 
260 /**
261  * @ingroup debug
262  * @brief Free resources for queue history
263  *
264  * @param q_hist Pointer to the queue history object.
265  *
266  * @return none
267  */
268 void
269 ocs_queue_history_free(ocs_hal_q_hist_t *q_hist)
270 {
271  ocs_t *ocs = q_hist->ocs;
272 
273  if (q_hist->q_hist != NULL) {
274  ocs_free(ocs, q_hist->q_hist, sizeof(*q_hist->q_hist)*OCS_Q_HIST_SIZE);
275  ocs_lock_free(&q_hist->q_hist_lock);
276  q_hist->q_hist = NULL;
277  }
278 }
279 
280 static void
281 ocs_queue_history_add_q_info(ocs_hal_q_hist_t *q_hist, uint32_t qid, uint32_t qindex)
282 {
283  if (ocs_queue_history_q_info_enabled()) {
284  /* write qid, index */
285  q_hist->q_hist[q_hist->q_hist_index] = (qid << 16) | qindex;
286  q_hist->q_hist_index++;
287  q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
288  }
289 }
290 
291 static void
292 ocs_queue_history_add_timestamp(ocs_hal_q_hist_t *q_hist)
293 {
294  if (ocs_queue_history_timestamp_enabled()) {
295  /* write tsc */
296  uint64_t tsc_value;
297  tsc_value = ocs_get_tsc();
298  q_hist->q_hist[q_hist->q_hist_index] = ((tsc_value >> 32 ) & 0xFFFFFFFF);
299  q_hist->q_hist_index++;
300  q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
301  q_hist->q_hist[q_hist->q_hist_index] = (tsc_value & 0xFFFFFFFF);
302  q_hist->q_hist_index++;
303  q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
304  }
305 }
306 
307 /**
308  * @ingroup debug
309  * @brief Log work queue entry (WQE) into history array
310  *
311  * @param q_hist Pointer to the queue history object.
312  * @param entryw Work queue entry in words
313  * @param qid Queue ID
314  * @param qindex Queue index
315  *
316  * @return none
317  */
318 void
319 ocs_queue_history_wq(ocs_hal_q_hist_t *q_hist, uint32_t *entryw, uint32_t qid, uint32_t qindex)
320 {
321  int i;
322  ocs_q_hist_ftr_t ftr;
323  uint32_t wqe_word_mask = ocs_q_hist_get_wqe_mask((sli4_generic_wqe_t *)entryw);
324 
325  if (q_hist->q_hist == NULL) {
326  /* Can't save anything */
327  return;
328  }
329 
330  ftr.word = 0;
331  ftr.s.type = OCS_Q_HIST_TYPE_WQE;
332  ocs_lock(&q_hist->q_hist_lock);
333  /* Capture words in reverse order since we'll be interpretting them LIFO */
334  for (i = ((sizeof(wqe_word_mask)*8) - 1); i >= 0; i--){
335  if ((wqe_word_mask >> i) & 1) {
336  q_hist->q_hist[q_hist->q_hist_index] = entryw[i];
337  q_hist->q_hist_index++;
338  q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
339  }
340  }
341 
342  ocs_queue_history_add_q_info(q_hist, qid, qindex);
343  ocs_queue_history_add_timestamp(q_hist);
344 
345  /* write footer */
346  if (wqe_word_mask) {
347  ftr.s.mask = wqe_word_mask;
348  q_hist->q_hist[q_hist->q_hist_index] = ftr.word;
349  q_hist->q_hist_index++;
350  q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
351  }
352 
353  ocs_unlock(&q_hist->q_hist_lock);
354 }
355 
356 /**
357  * @ingroup debug
358  * @brief Log misc words
359  *
360  * @param q_hist Pointer to the queue history object.
361  * @param entryw array of words
362  * @param num_words number of words in entryw
363  *
364  * @return none
365  */
366 void
367 ocs_queue_history_misc(ocs_hal_q_hist_t *q_hist, uint32_t *entryw, uint32_t num_words)
368 {
369  int i;
370  ocs_q_hist_ftr_t ftr;
371  uint32_t mask = 0;
372 
373  if (q_hist->q_hist == NULL) {
374  /* Can't save anything */
375  return;
376  }
377 
378  ftr.word = 0;
379  ftr.s.type = OCS_Q_HIST_TYPE_MISC;
380  ocs_lock(&q_hist->q_hist_lock);
381  /* Capture words in reverse order since we'll be interpretting them LIFO */
382  for (i = num_words-1; i >= 0; i--) {
383  q_hist->q_hist[q_hist->q_hist_index] = entryw[i];
384  q_hist->q_hist_index++;
385  q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
386  mask |= BIT(i);
387  }
388 
389  ocs_queue_history_add_timestamp(q_hist);
390 
391  /* write footer */
392  if (num_words) {
393  ftr.s.mask = mask;
394  q_hist->q_hist[q_hist->q_hist_index] = ftr.word;
395  q_hist->q_hist_index++;
396  q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
397  }
398 
399  ocs_unlock(&q_hist->q_hist_lock);
400 }
401 
402 /**
403  * @ingroup debug
404  * @brief Log work queue completion (CQE) entry into history
405  * array
406  *
407  * @param q_hist Pointer to the queue history object.
408  * @param ctype Type of completion entry
409  * @param entryw Completion queue entry in words
410  * @param status Completion queue status
411  * @param qid Queue ID
412  * @param qindex Queue index
413  *
414  * @return none
415  */
416 void
417 ocs_queue_history_cqe(ocs_hal_q_hist_t *q_hist, uint8_t ctype, uint32_t *entryw, uint8_t status, uint32_t qid, uint32_t qindex)
418 {
419  int i;
420  unsigned j;
421  uint32_t cqe_word_mask = 0;
422  ocs_q_hist_ftr_t ftr;
423 
424  if (q_hist->q_hist == NULL) {
425  /* Can't save anything */
426  return;
427  }
428 
429  ftr.word = 0;
430  for (j = 0; j < ARRAY_SIZE(ocs_q_hist_cqe_masks); j++) {
431  if (ocs_q_hist_cqe_masks[j].ctype == ctype) {
432  ftr.s.type = ocs_q_hist_cqe_masks[j].type;
433  if (status != 0) {
434  cqe_word_mask = ocs_q_hist_cqe_masks[j].mask_err;
435  } else {
436  cqe_word_mask = ocs_q_hist_cqe_masks[j].mask;
437  }
438  }
439  }
440  ocs_lock(&q_hist->q_hist_lock);
441  /* Capture words in reverse order since we'll be interpretting them LIFO */
442  for (i = ((sizeof(cqe_word_mask)*8) - 1); i >= 0; i--){
443  if ((cqe_word_mask >> i) & 1) {
444  q_hist->q_hist[q_hist->q_hist_index] = entryw[i];
445  q_hist->q_hist_index++;
446  q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
447  }
448  }
449  ocs_queue_history_add_q_info(q_hist, qid, qindex);
450  ocs_queue_history_add_timestamp(q_hist);
451 
452  /* write footer */
453  if (cqe_word_mask) {
454  ftr.s.mask = cqe_word_mask;
455  q_hist->q_hist[q_hist->q_hist_index] = ftr.word;
456  q_hist->q_hist_index++;
457  q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
458  }
459 
460  ocs_unlock(&q_hist->q_hist_lock);
461 }
462 
463 /**
464  * @brief Get previous index
465  *
466  * @param index Index from which previous index is derived.
467  */
468 uint32_t
469 ocs_queue_history_prev_index(uint32_t index)
470 {
471  if (index == 0) {
472  return OCS_Q_HIST_SIZE - 1;
473  } else {
474  return index - 1;
475  }
476 }
477 
478 #endif // OCS_DEBUG_QUEUE_HISTORY
479 
480 /**
481  * @brief Display service parameters
482  *
483  * <description>
484  *
485  * @param prelabel leading display label
486  * @param reqlabel display label
487  * @param dest destination 0=ocs_log, 1=textbuf
488  * @param textbuf text buffer destination (if dest==1)
489  * @param sparams pointer to service parameter
490  *
491  * @return none
492  */
493 
494 void
495 ocs_display_sparams(const char *prelabel, const char *reqlabel, int dest, void *textbuf, void *sparams)
496 {
497  char label[64];
498 
499  if (sparams == NULL) {
500  return;
501  }
502 
503  switch(dest) {
504  case 0:
505  if (prelabel != NULL) {
506  ocs_snprintf(label, sizeof(label), "[%s] sparam: %s", prelabel, reqlabel);
507  } else {
508  ocs_snprintf(label, sizeof(label), "sparam: %s", reqlabel);
509  }
510 
511  ocs_dump32(OCS_DEBUG_ENABLE_SPARAM_DUMP, NULL, label, sparams, sizeof(fc_plogi_payload_t));
512  break;
513  case 1:
514  ocs_ddump_buffer((ocs_textbuf_t*) textbuf, reqlabel, 0, sparams, sizeof(fc_plogi_payload_t));
515  break;
516  }
517 }
518 
#define ocs_queue_history_misc(...)
Definition: ocs_debug.h:162
uint32_t ocs_instance(void *os)
Return instance index of an opaque ocs structure.
#define SLI4_WQE_FCP_CONT_TRECEIVE64
Definition: sli4_fc.h:402
static int _isprint(int c)
Definition: ocs_debug.c:57
#define ocs_queue_history_wq(...)
Definition: ocs_debug.h:160
#define ocs_queue_history_init(...)
Definition: ocs_debug.h:163
#define OCS_DEBUG_ENABLE_SPARAM_DUMP
Definition: ocs_debug.h:172
#define ocs_queue_history_cqe(...)
Definition: ocs_debug.h:161
const char const char void ocs_ddump_buffer(ocs_textbuf_t *textbuf, const char *name, uint32_t instance, void *buffer, uint32_t size)
Generate driver dump data for an arbitrary buffer of DWORDS.
Definition: ocs_ddumplib.c:154
#define OCS_DEBUG_MASK
Definition: ocs_debug.c:46
void ocs_display_sparams(const char *prelabel, const char *reqlabel, int dest, void *textbuf, void *sparams)
Display service parameters.
Definition: ocs_debug.c:495
void ocs_dump32(uint32_t mask, ocs_os_handle_t os, const char *label, void *buf, uint32_t buf_length)
Dump 32 bit hex/ascii data.
Definition: ocs_dump32.c:72
#define SLI4_WQE_FCP_IREAD64
Definition: sli4_fc.h:398
#define ocs_queue_history_free(...)
Definition: ocs_debug.h:164
uint32_t command
Definition: sli4_fc.h:447
#define SLI4_WQE_ABORT
Definition: sli4_fc.h:395
void ocs_debug_enable(uint32_t mask)
enable debug options
Definition: ocs_debug.c:73
int ocs_debug_is_enabled(uint32_t mask)
return true if debug bits are enabled
Definition: ocs_debug.c:106
#define SLI4_WQE_FCP_IWRITE64
Definition: sli4_fc.h:399
static uint32_t ocs_debug_mask
Definition: ocs_debug.c:54
void ocs_debug_disable(uint32_t mask)
disable debug options
Definition: ocs_debug.c:89
Generic WQE.
Definition: sli4_fc.h:442