| 1 | |
| 2 | * This file is part of the Emulex Linux Device Driver for *
|
| 3 | * Fibre Channel Host Bus Adapters. *
|
| 4 | * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term *
|
| 5 | * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
|
| 6 | * Copyright (C) 2007-2015 Emulex. All rights reserved. *
|
| 7 | * EMULEX and SLI are trademarks of Emulex. *
|
| 8 | * www.broadcom.com *
|
| 9 | * *
|
| 10 | * This program is free software; you can redistribute it and/or *
|
| 11 | * modify it under the terms of version 2 of the GNU General *
|
| 12 | * Public License as published by the Free Software Foundation. *
|
| 13 | * This program is distributed in the hope that it will be useful. *
|
| 14 | * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
|
| 15 | * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
|
| 16 | * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
|
| 17 | * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
|
| 18 | * TO BE LEGALLY INVALID. See the GNU General Public License for *
|
| 19 | * more details, a copy of which can be found in the file COPYING *
|
| 20 | * included with this package. *
|
| 21 | ******************************************************************
|
| 22 |
|
| 23 | #include <linux/blkdev.h>
|
| 24 | #include <linux/delay.h>
|
| 25 | #include <linux/module.h>
|
| 26 | #include <linux/dma-mapping.h>
|
| 27 | #include <linux/idr.h>
|
| 28 | #include <linux/interrupt.h>
|
| 29 | #include <linux/kthread.h>
|
| 30 | #include <linux/seq_buf.h>
|
| 31 | #include <linux/slab.h>
|
| 32 | #include <linux/pci.h>
|
| 33 | #include <linux/spinlock.h>
|
| 34 | #include <linux/ctype.h>
|
| 35 | #include <linux/vmalloc.h>
|
| 36 |
|
| 37 | #include <scsi/scsi.h>
|
| 38 | #include <scsi/scsi_device.h>
|
| 39 | #include <scsi/scsi_host.h>
|
| 40 | #include <scsi/scsi_transport_fc.h>
|
| 41 | #include <scsi/fc/fc_fs.h>
|
| 42 |
|
| 43 | #include "lpfc_hw4.h"
|
| 44 | #include "lpfc_hw.h"
|
| 45 | #include "lpfc_sli.h"
|
| 46 | #include "lpfc_sli4.h"
|
| 47 | #include "lpfc_nl.h"
|
| 48 | #include "lpfc_disc.h"
|
| 49 | #include "lpfc.h"
|
| 50 | #include "lpfc_scsi.h"
|
| 51 | #include "lpfc_nvme.h"
|
| 52 | #include "lpfc_logmsg.h"
|
| 53 | #include "lpfc_crtn.h"
|
| 54 | #include "lpfc_vport.h"
|
| 55 | #include "lpfc_version.h"
|
| 56 | #include "lpfc_compat.h"
|
| 57 | #include "lpfc_debugfs.h"
|
| 58 | #include "lpfc_bsg.h"
|
| 59 |
|
| 60 | #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
|
| 61 | |
| 62 | * debugfs interface
|
| 63 | *
|
| 64 | * To access this interface the user should:
|
| 65 | * # mount -t debugfs none /sys/kernel/debug
|
| 66 | *
|
| 67 | * The lpfc debugfs directory hierarchy is:
|
| 68 | * /sys/kernel/debug/lpfc/fnX/vportY
|
| 69 | * where X is the lpfc hba function unique_id
|
| 70 | * where Y is the vport VPI on that hba
|
| 71 | *
|
| 72 | * Debugging services available per vport:
|
| 73 | * discovery_trace
|
| 74 | * This is an ACSII readable file that contains a trace of the last
|
| 75 | * lpfc_debugfs_max_disc_trc events that happened on a specific vport.
|
| 76 | * See lpfc_debugfs.h for different categories of discovery events.
|
| 77 | * To enable the discovery trace, the following module parameters must be set:
|
| 78 | * lpfc_debugfs_enable=1 Turns on lpfc debugfs filesystem support
|
| 79 | * lpfc_debugfs_max_disc_trc=X Where X is the event trace depth for
|
| 80 | * EACH vport. X MUST also be a power of 2.
|
| 81 | * lpfc_debugfs_mask_disc_trc=Y Where Y is an event mask as defined in
|
| 82 | * lpfc_debugfs.h .
|
| 83 | *
|
| 84 | * slow_ring_trace
|
| 85 | * This is an ACSII readable file that contains a trace of the last
|
| 86 | * lpfc_debugfs_max_slow_ring_trc events that happened on a specific HBA.
|
| 87 | * To enable the slow ring trace, the following module parameters must be set:
|
| 88 | * lpfc_debugfs_enable=1 Turns on lpfc debugfs filesystem support
|
| 89 | * lpfc_debugfs_max_slow_ring_trc=X Where X is the event trace depth for
|
| 90 | * the HBA. X MUST also be a power of 2.
|
| 91 |
|
| 92 | static int lpfc_debugfs_enable = 1;
|
| 93 | module_param(lpfc_debugfs_enable, int, S_IRUGO);
|
| 94 | MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
|
| 95 |
|
| 96 |
|
| 97 | static int lpfc_debugfs_max_disc_trc;
|
| 98 | module_param(lpfc_debugfs_max_disc_trc, int, S_IRUGO);
|
| 99 | MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
|
| 100 | "Set debugfs discovery trace depth");
|
| 101 |
|
| 102 |
|
| 103 | static int lpfc_debugfs_max_slow_ring_trc;
|
| 104 | module_param(lpfc_debugfs_max_slow_ring_trc, int, S_IRUGO);
|
| 105 | MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc,
|
| 106 | "Set debugfs slow ring trace depth");
|
| 107 |
|
| 108 |
|
| 109 | static int lpfc_debugfs_max_nvmeio_trc;
|
| 110 | module_param(lpfc_debugfs_max_nvmeio_trc, int, 0444);
|
| 111 | MODULE_PARM_DESC(lpfc_debugfs_max_nvmeio_trc,
|
| 112 | "Set debugfs NVME IO trace depth");
|
| 113 |
|
| 114 | static int lpfc_debugfs_mask_disc_trc;
|
| 115 | module_param(lpfc_debugfs_mask_disc_trc, int, S_IRUGO);
|
| 116 | MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
|
| 117 | "Set debugfs discovery trace mask");
|
| 118 |
|
| 119 | #include <linux/debugfs.h>
|
| 120 |
|
| 121 | static atomic_t lpfc_debugfs_seq_trc_cnt = ATOMIC_INIT(0);
|
| 122 | static unsigned long lpfc_debugfs_start_time = 0L;
|
| 123 |
|
| 124 |
|
| 125 | static struct lpfc_idiag idiag;
|
| 126 |
|
| 127 | |
| 128 | * lpfc_debugfs_disc_trc_data - Dump discovery logging to a buffer
|
| 129 | * @vport: The vport to gather the log info from.
|
| 130 | * @buf: The buffer to dump log into.
|
| 131 | * @size: The maximum amount of data to process.
|
| 132 | *
|
| 133 | * Description:
|
| 134 | * This routine gathers the lpfc discovery debugfs data from the @vport and
|
| 135 | * dumps it to @buf up to @size number of bytes. It will start at the next entry
|
| 136 | * in the log and process the log until the end of the buffer. Then it will
|
| 137 | * gather from the beginning of the log and process until the current entry.
|
| 138 | *
|
| 139 | * Notes:
|
| 140 | * Discovery logging will be disabled while while this routine dumps the log.
|
| 141 | *
|
| 142 | * Return Value:
|
| 143 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 144 | * not exceed @size.
|
| 145 | *
|
| 146 | static int
|
| 147 | lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
|
| 148 | {
|
| 149 | int i, index, len, enable;
|
| 150 | uint32_t ms;
|
| 151 | struct lpfc_debugfs_trc *dtp;
|
| 152 | char *buffer;
|
| 153 |
|
| 154 | buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL);
|
| 155 | if (!buffer)
|
| 156 | return 0;
|
| 157 |
|
| 158 | enable = lpfc_debugfs_enable;
|
| 159 | lpfc_debugfs_enable = 0;
|
| 160 |
|
| 161 | len = 0;
|
| 162 | index = (atomic_read(&vport->disc_trc_cnt) + 1) &
|
| 163 | (lpfc_debugfs_max_disc_trc - 1);
|
| 164 | for (i = index; i < lpfc_debugfs_max_disc_trc; i++) {
|
| 165 | dtp = vport->disc_trc + i;
|
| 166 | if (!dtp->fmt)
|
| 167 | continue;
|
| 168 | ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
|
| 169 | snprintf(buffer,
|
| 170 | LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
|
| 171 | dtp->seq_cnt, ms, dtp->fmt);
|
| 172 | len += scnprintf(buf+len, size-len, buffer,
|
| 173 | dtp->data1, dtp->data2, dtp->data3);
|
| 174 | }
|
| 175 | for (i = 0; i < index; i++) {
|
| 176 | dtp = vport->disc_trc + i;
|
| 177 | if (!dtp->fmt)
|
| 178 | continue;
|
| 179 | ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
|
| 180 | snprintf(buffer,
|
| 181 | LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
|
| 182 | dtp->seq_cnt, ms, dtp->fmt);
|
| 183 | len += scnprintf(buf+len, size-len, buffer,
|
| 184 | dtp->data1, dtp->data2, dtp->data3);
|
| 185 | }
|
| 186 |
|
| 187 | lpfc_debugfs_enable = enable;
|
| 188 | kfree(buffer);
|
| 189 |
|
| 190 | return len;
|
| 191 | }
|
| 192 |
|
| 193 | |
| 194 | * lpfc_debugfs_slow_ring_trc_data - Dump slow ring logging to a buffer
|
| 195 | * @phba: The HBA to gather the log info from.
|
| 196 | * @buf: The buffer to dump log into.
|
| 197 | * @size: The maximum amount of data to process.
|
| 198 | *
|
| 199 | * Description:
|
| 200 | * This routine gathers the lpfc slow ring debugfs data from the @phba and
|
| 201 | * dumps it to @buf up to @size number of bytes. It will start at the next entry
|
| 202 | * in the log and process the log until the end of the buffer. Then it will
|
| 203 | * gather from the beginning of the log and process until the current entry.
|
| 204 | *
|
| 205 | * Notes:
|
| 206 | * Slow ring logging will be disabled while while this routine dumps the log.
|
| 207 | *
|
| 208 | * Return Value:
|
| 209 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 210 | * not exceed @size.
|
| 211 | *
|
| 212 | static int
|
| 213 | lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size)
|
| 214 | {
|
| 215 | int i, index, len, enable;
|
| 216 | uint32_t ms;
|
| 217 | struct lpfc_debugfs_trc *dtp;
|
| 218 | char *buffer;
|
| 219 |
|
| 220 | buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL);
|
| 221 | if (!buffer)
|
| 222 | return 0;
|
| 223 |
|
| 224 | enable = lpfc_debugfs_enable;
|
| 225 | lpfc_debugfs_enable = 0;
|
| 226 |
|
| 227 | len = 0;
|
| 228 | index = (atomic_read(&phba->slow_ring_trc_cnt) + 1) &
|
| 229 | (lpfc_debugfs_max_slow_ring_trc - 1);
|
| 230 | for (i = index; i < lpfc_debugfs_max_slow_ring_trc; i++) {
|
| 231 | dtp = phba->slow_ring_trc + i;
|
| 232 | if (!dtp->fmt)
|
| 233 | continue;
|
| 234 | ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
|
| 235 | snprintf(buffer,
|
| 236 | LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
|
| 237 | dtp->seq_cnt, ms, dtp->fmt);
|
| 238 | len += scnprintf(buf+len, size-len, buffer,
|
| 239 | dtp->data1, dtp->data2, dtp->data3);
|
| 240 | }
|
| 241 | for (i = 0; i < index; i++) {
|
| 242 | dtp = phba->slow_ring_trc + i;
|
| 243 | if (!dtp->fmt)
|
| 244 | continue;
|
| 245 | ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
|
| 246 | snprintf(buffer,
|
| 247 | LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
|
| 248 | dtp->seq_cnt, ms, dtp->fmt);
|
| 249 | len += scnprintf(buf+len, size-len, buffer,
|
| 250 | dtp->data1, dtp->data2, dtp->data3);
|
| 251 | }
|
| 252 |
|
| 253 | lpfc_debugfs_enable = enable;
|
| 254 | kfree(buffer);
|
| 255 |
|
| 256 | return len;
|
| 257 | }
|
| 258 |
|
| 259 | static int lpfc_debugfs_last_hbq = -1;
|
| 260 |
|
| 261 | |
| 262 | * lpfc_debugfs_hbqinfo_data - Dump host buffer queue info to a buffer
|
| 263 | * @phba: The HBA to gather host buffer info from.
|
| 264 | * @buf: The buffer to dump log into.
|
| 265 | * @size: The maximum amount of data to process.
|
| 266 | *
|
| 267 | * Description:
|
| 268 | * This routine dumps the host buffer queue info from the @phba to @buf up to
|
| 269 | * @size number of bytes. A header that describes the current hbq state will be
|
| 270 | * dumped to @buf first and then info on each hbq entry will be dumped to @buf
|
| 271 | * until @size bytes have been dumped or all the hbq info has been dumped.
|
| 272 | *
|
| 273 | * Notes:
|
| 274 | * This routine will rotate through each configured HBQ each time called.
|
| 275 | *
|
| 276 | * Return Value:
|
| 277 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 278 | * not exceed @size.
|
| 279 | *
|
| 280 | static int
|
| 281 | lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
|
| 282 | {
|
| 283 | int len = 0;
|
| 284 | int i, j, found, posted, low;
|
| 285 | uint32_t phys, raw_index, getidx;
|
| 286 | struct lpfc_hbq_init *hip;
|
| 287 | struct hbq_s *hbqs;
|
| 288 | struct lpfc_hbq_entry *hbqe;
|
| 289 | struct lpfc_dmabuf *d_buf;
|
| 290 | struct hbq_dmabuf *hbq_buf;
|
| 291 |
|
| 292 | if (phba->sli_rev != 3)
|
| 293 | return 0;
|
| 294 |
|
| 295 | spin_lock_irq(&phba->hbalock);
|
| 296 |
|
| 297 |
|
| 298 | i = lpfc_sli_hbq_count();
|
| 299 | if (i > 1) {
|
| 300 | lpfc_debugfs_last_hbq++;
|
| 301 | if (lpfc_debugfs_last_hbq >= i)
|
| 302 | lpfc_debugfs_last_hbq = 0;
|
| 303 | }
|
| 304 | else
|
| 305 | lpfc_debugfs_last_hbq = 0;
|
| 306 |
|
| 307 | i = lpfc_debugfs_last_hbq;
|
| 308 |
|
| 309 | len += scnprintf(buf+len, size-len, "HBQ %d Info\n", i);
|
| 310 |
|
| 311 | hbqs = &phba->hbqs[i];
|
| 312 | posted = 0;
|
| 313 | list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list)
|
| 314 | posted++;
|
| 315 |
|
| 316 | hip = lpfc_hbq_defs[i];
|
| 317 | len += scnprintf(buf+len, size-len,
|
| 318 | "idx:%d prof:%d rn:%d bufcnt:%d icnt:%d acnt:%d posted %d\n",
|
| 319 | hip->hbq_index, hip->profile, hip->rn,
|
| 320 | hip->buffer_count, hip->init_count, hip->add_count, posted);
|
| 321 |
|
| 322 | raw_index = phba->hbq_get[i];
|
| 323 | getidx = le32_to_cpu(raw_index);
|
| 324 | len += scnprintf(buf+len, size-len,
|
| 325 | "entries:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
|
| 326 | hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx,
|
| 327 | hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx);
|
| 328 |
|
| 329 | hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt;
|
| 330 | for (j=0; j<hbqs->entry_count; j++) {
|
| 331 | len += scnprintf(buf+len, size-len,
|
| 332 | "%03d: %08x %04x %05x ", j,
|
| 333 | le32_to_cpu(hbqe->bde.addrLow),
|
| 334 | le32_to_cpu(hbqe->bde.tus.w),
|
| 335 | le32_to_cpu(hbqe->buffer_tag));
|
| 336 | i = 0;
|
| 337 | found = 0;
|
| 338 |
|
| 339 |
|
| 340 | low = hbqs->hbqPutIdx - posted;
|
| 341 | if (low >= 0) {
|
| 342 | if ((j >= hbqs->hbqPutIdx) || (j < low)) {
|
| 343 | len += scnprintf(buf + len, size - len,
|
| 344 | "Unused\n");
|
| 345 | goto skipit;
|
| 346 | }
|
| 347 | }
|
| 348 | else {
|
| 349 | if ((j >= hbqs->hbqPutIdx) &&
|
| 350 | (j < (hbqs->entry_count+low))) {
|
| 351 | len += scnprintf(buf + len, size - len,
|
| 352 | "Unused\n");
|
| 353 | goto skipit;
|
| 354 | }
|
| 355 | }
|
| 356 |
|
| 357 |
|
| 358 | list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) {
|
| 359 | hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
|
| 360 | phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff);
|
| 361 | if (phys == le32_to_cpu(hbqe->bde.addrLow)) {
|
| 362 | len += scnprintf(buf+len, size-len,
|
| 363 | "Buf%d: x%px %06x\n", i,
|
| 364 | hbq_buf->dbuf.virt, hbq_buf->tag);
|
| 365 | found = 1;
|
| 366 | break;
|
| 367 | }
|
| 368 | i++;
|
| 369 | }
|
| 370 | if (!found) {
|
| 371 | len += scnprintf(buf+len, size-len, "No DMAinfo?\n");
|
| 372 | }
|
| 373 | skipit:
|
| 374 | hbqe++;
|
| 375 | if (len > LPFC_HBQINFO_SIZE - 54)
|
| 376 | break;
|
| 377 | }
|
| 378 | spin_unlock_irq(&phba->hbalock);
|
| 379 | return len;
|
| 380 | }
|
| 381 |
|
| 382 | static int lpfc_debugfs_last_xripool;
|
| 383 |
|
| 384 | |
| 385 | * lpfc_debugfs_commonxripools_data - Dump Hardware Queue info to a buffer
|
| 386 | * @phba: The HBA to gather host buffer info from.
|
| 387 | * @buf: The buffer to dump log into.
|
| 388 | * @size: The maximum amount of data to process.
|
| 389 | *
|
| 390 | * Description:
|
| 391 | * This routine dumps the Hardware Queue info from the @phba to @buf up to
|
| 392 | * @size number of bytes. A header that describes the current hdwq state will be
|
| 393 | * dumped to @buf first and then info on each hdwq entry will be dumped to @buf
|
| 394 | * until @size bytes have been dumped or all the hdwq info has been dumped.
|
| 395 | *
|
| 396 | * Notes:
|
| 397 | * This routine will rotate through each configured Hardware Queue each
|
| 398 | * time called.
|
| 399 | *
|
| 400 | * Return Value:
|
| 401 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 402 | * not exceed @size.
|
| 403 | *
|
| 404 | static int
|
| 405 | lpfc_debugfs_commonxripools_data(struct lpfc_hba *phba, char *buf, int size)
|
| 406 | {
|
| 407 | struct lpfc_sli4_hdw_queue *qp;
|
| 408 | int len = 0;
|
| 409 | int i, out;
|
| 410 | unsigned long iflag;
|
| 411 |
|
| 412 | for (i = 0; i < phba->cfg_hdw_queue; i++) {
|
| 413 | if (len > (LPFC_DUMP_MULTIXRIPOOL_SIZE - 80))
|
| 414 | break;
|
| 415 | qp = &phba->sli4_hba.hdwq[lpfc_debugfs_last_xripool];
|
| 416 |
|
| 417 | len += scnprintf(buf + len, size - len, "HdwQ %d Info ", i);
|
| 418 | spin_lock_irqsave(&qp->abts_io_buf_list_lock, iflag);
|
| 419 | spin_lock(&qp->io_buf_list_get_lock);
|
| 420 | spin_lock(&qp->io_buf_list_put_lock);
|
| 421 | out = qp->total_io_bufs - (qp->get_io_bufs + qp->put_io_bufs +
|
| 422 | qp->abts_scsi_io_bufs + qp->abts_nvme_io_bufs);
|
| 423 | len += scnprintf(buf + len, size - len,
|
| 424 | "tot:%d get:%d put:%d mt:%d "
|
| 425 | "ABTS scsi:%d nvme:%d Out:%d\n",
|
| 426 | qp->total_io_bufs, qp->get_io_bufs, qp->put_io_bufs,
|
| 427 | qp->empty_io_bufs, qp->abts_scsi_io_bufs,
|
| 428 | qp->abts_nvme_io_bufs, out);
|
| 429 | spin_unlock(&qp->io_buf_list_put_lock);
|
| 430 | spin_unlock(&qp->io_buf_list_get_lock);
|
| 431 | spin_unlock_irqrestore(&qp->abts_io_buf_list_lock, iflag);
|
| 432 |
|
| 433 | lpfc_debugfs_last_xripool++;
|
| 434 | if (lpfc_debugfs_last_xripool >= phba->cfg_hdw_queue)
|
| 435 | lpfc_debugfs_last_xripool = 0;
|
| 436 | }
|
| 437 |
|
| 438 | return len;
|
| 439 | }
|
| 440 |
|
| 441 | |
| 442 | * lpfc_debugfs_multixripools_data - Display multi-XRI pools information
|
| 443 | * @phba: The HBA to gather host buffer info from.
|
| 444 | * @buf: The buffer to dump log into.
|
| 445 | * @size: The maximum amount of data to process.
|
| 446 | *
|
| 447 | * Description:
|
| 448 | * This routine displays current multi-XRI pools information including XRI
|
| 449 | * count in public, private and txcmplq. It also displays current high and
|
| 450 | * low watermark.
|
| 451 | *
|
| 452 | * Return Value:
|
| 453 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 454 | * not exceed @size.
|
| 455 | *
|
| 456 | static int
|
| 457 | lpfc_debugfs_multixripools_data(struct lpfc_hba *phba, char *buf, int size)
|
| 458 | {
|
| 459 | u32 i;
|
| 460 | u32 hwq_count;
|
| 461 | struct lpfc_sli4_hdw_queue *qp;
|
| 462 | struct lpfc_multixri_pool *multixri_pool;
|
| 463 | struct lpfc_pvt_pool *pvt_pool;
|
| 464 | struct lpfc_pbl_pool *pbl_pool;
|
| 465 | u32 txcmplq_cnt;
|
| 466 | size_t used;
|
| 467 | struct seq_buf s;
|
| 468 |
|
| 469 | if (phba->sli_rev != LPFC_SLI_REV4)
|
| 470 | return 0;
|
| 471 |
|
| 472 | if (!phba->sli4_hba.hdwq)
|
| 473 | return 0;
|
| 474 |
|
| 475 | if (!phba->cfg_xri_rebalancing) {
|
| 476 | i = lpfc_debugfs_commonxripools_data(phba, buf, size);
|
| 477 | return i;
|
| 478 | }
|
| 479 |
|
| 480 | used = strnlen(buf, size);
|
| 481 | seq_buf_init(&s, buf + used, size - used);
|
| 482 |
|
| 483 | |
| 484 | * Pbl: Current number of free XRIs in public pool
|
| 485 | * Pvt: Current number of free XRIs in private pool
|
| 486 | * Busy: Current number of outstanding XRIs
|
| 487 | * HWM: Current high watermark
|
| 488 | * pvt_empty: Incremented by 1 when IO submission fails (no xri)
|
| 489 | * pbl_empty: Incremented by 1 when all pbl_pool are empty during
|
| 490 | * IO submission
|
| 491 |
|
| 492 | seq_buf_printf(&s,
|
| 493 | "HWQ: Pbl Pvt Busy HWM | pvt_empty pbl_empty ");
|
| 494 |
|
| 495 | #ifdef LPFC_MXP_STAT
|
| 496 | |
| 497 | * MAXH: Max high watermark seen so far
|
| 498 | * above_lmt: Incremented by 1 if xri_owned > xri_limit during
|
| 499 | * IO submission
|
| 500 | * below_lmt: Incremented by 1 if xri_owned <= xri_limit during
|
| 501 | * IO submission
|
| 502 | * locPbl_hit: Incremented by 1 if successfully get a batch of XRI from
|
| 503 | * local pbl_pool
|
| 504 | * othPbl_hit: Incremented by 1 if successfully get a batch of XRI from
|
| 505 | * other pbl_pool
|
| 506 |
|
| 507 | seq_buf_printf(&s, "MAXH above_lmt below_lmt locPbl_hit othPbl_hit");
|
| 508 |
|
| 509 | |
| 510 | * sPbl: snapshot of Pbl 15 sec after stat gets cleared
|
| 511 | * sPvt: snapshot of Pvt 15 sec after stat gets cleared
|
| 512 | * sBusy: snapshot of Busy 15 sec after stat gets cleared
|
| 513 |
|
| 514 | seq_buf_printf(&s, " | sPbl sPvt sBusy");
|
| 515 | #endif
|
| 516 |
|
| 517 | seq_buf_printf(&s, "\n");
|
| 518 |
|
| 519 | hwq_count = phba->cfg_hdw_queue;
|
| 520 | for (i = 0; i < hwq_count; i++) {
|
| 521 | qp = &phba->sli4_hba.hdwq[i];
|
| 522 | multixri_pool = qp->p_multixri_pool;
|
| 523 | if (!multixri_pool)
|
| 524 | continue;
|
| 525 | pbl_pool = &multixri_pool->pbl_pool;
|
| 526 | pvt_pool = &multixri_pool->pvt_pool;
|
| 527 | txcmplq_cnt = qp->io_wq->pring->txcmplq_cnt;
|
| 528 |
|
| 529 | seq_buf_printf(&s,
|
| 530 | "%03d: %4d %4d %4d %4d | %10d %10d ",
|
| 531 | i, pbl_pool->count, pvt_pool->count,
|
| 532 | txcmplq_cnt, pvt_pool->high_watermark,
|
| 533 | qp->empty_io_bufs,
|
| 534 | multixri_pool->pbl_empty_count);
|
| 535 |
|
| 536 | #ifdef LPFC_MXP_STAT
|
| 537 | seq_buf_printf(&s,
|
| 538 | "%4d %10d %10d %10d %10d",
|
| 539 | multixri_pool->stat_max_hwm,
|
| 540 | multixri_pool->above_limit_count,
|
| 541 | multixri_pool->below_limit_count,
|
| 542 | multixri_pool->local_pbl_hit_count,
|
| 543 | multixri_pool->other_pbl_hit_count);
|
| 544 |
|
| 545 | seq_buf_printf(&s,
|
| 546 | " | %4d %4d %5d",
|
| 547 | multixri_pool->stat_pbl_count,
|
| 548 | multixri_pool->stat_pvt_count,
|
| 549 | multixri_pool->stat_busy_count);
|
| 550 | #endif
|
| 551 |
|
| 552 | seq_buf_printf(&s, "\n");
|
| 553 |
|
| 554 | if (seq_buf_has_overflowed(&s))
|
| 555 | break;
|
| 556 | }
|
| 557 | return strnlen(buf, size);
|
| 558 | }
|
| 559 |
|
| 560 |
|
| 561 | #ifdef LPFC_HDWQ_LOCK_STAT
|
| 562 | static int lpfc_debugfs_last_lock;
|
| 563 |
|
| 564 | |
| 565 | * lpfc_debugfs_lockstat_data - Dump Hardware Queue info to a buffer
|
| 566 | * @phba: The HBA to gather host buffer info from.
|
| 567 | * @buf: The buffer to dump log into.
|
| 568 | * @size: The maximum amount of data to process.
|
| 569 | *
|
| 570 | * Description:
|
| 571 | * This routine dumps the Hardware Queue info from the @phba to @buf up to
|
| 572 | * @size number of bytes. A header that describes the current hdwq state will be
|
| 573 | * dumped to @buf first and then info on each hdwq entry will be dumped to @buf
|
| 574 | * until @size bytes have been dumped or all the hdwq info has been dumped.
|
| 575 | *
|
| 576 | * Notes:
|
| 577 | * This routine will rotate through each configured Hardware Queue each
|
| 578 | * time called.
|
| 579 | *
|
| 580 | * Return Value:
|
| 581 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 582 | * not exceed @size.
|
| 583 | *
|
| 584 | static int
|
| 585 | lpfc_debugfs_lockstat_data(struct lpfc_hba *phba, char *buf, int size)
|
| 586 | {
|
| 587 | struct lpfc_sli4_hdw_queue *qp;
|
| 588 | int len = 0;
|
| 589 | int i;
|
| 590 |
|
| 591 | if (phba->sli_rev != LPFC_SLI_REV4)
|
| 592 | return 0;
|
| 593 |
|
| 594 | if (!phba->sli4_hba.hdwq)
|
| 595 | return 0;
|
| 596 |
|
| 597 | for (i = 0; i < phba->cfg_hdw_queue; i++) {
|
| 598 | if (len > (LPFC_HDWQINFO_SIZE - 100))
|
| 599 | break;
|
| 600 | qp = &phba->sli4_hba.hdwq[lpfc_debugfs_last_lock];
|
| 601 |
|
| 602 | len += scnprintf(buf + len, size - len, "HdwQ %03d Lock ", i);
|
| 603 | if (phba->cfg_xri_rebalancing) {
|
| 604 | len += scnprintf(buf + len, size - len,
|
| 605 | "get_pvt:%d mv_pvt:%d "
|
| 606 | "mv2pub:%d mv2pvt:%d "
|
| 607 | "put_pvt:%d put_pub:%d wq:%d\n",
|
| 608 | qp->lock_conflict.alloc_pvt_pool,
|
| 609 | qp->lock_conflict.mv_from_pvt_pool,
|
| 610 | qp->lock_conflict.mv_to_pub_pool,
|
| 611 | qp->lock_conflict.mv_to_pvt_pool,
|
| 612 | qp->lock_conflict.free_pvt_pool,
|
| 613 | qp->lock_conflict.free_pub_pool,
|
| 614 | qp->lock_conflict.wq_access);
|
| 615 | } else {
|
| 616 | len += scnprintf(buf + len, size - len,
|
| 617 | "get:%d put:%d free:%d wq:%d\n",
|
| 618 | qp->lock_conflict.alloc_xri_get,
|
| 619 | qp->lock_conflict.alloc_xri_put,
|
| 620 | qp->lock_conflict.free_xri,
|
| 621 | qp->lock_conflict.wq_access);
|
| 622 | }
|
| 623 |
|
| 624 | lpfc_debugfs_last_lock++;
|
| 625 | if (lpfc_debugfs_last_lock >= phba->cfg_hdw_queue)
|
| 626 | lpfc_debugfs_last_lock = 0;
|
| 627 | }
|
| 628 |
|
| 629 | return len;
|
| 630 | }
|
| 631 | #endif
|
| 632 |
|
| 633 | static int lpfc_debugfs_last_hba_slim_off;
|
| 634 |
|
| 635 | |
| 636 | * lpfc_debugfs_dumpHBASlim_data - Dump HBA SLIM info to a buffer
|
| 637 | * @phba: The HBA to gather SLIM info from.
|
| 638 | * @buf: The buffer to dump log into.
|
| 639 | * @size: The maximum amount of data to process.
|
| 640 | *
|
| 641 | * Description:
|
| 642 | * This routine dumps the current contents of HBA SLIM for the HBA associated
|
| 643 | * with @phba to @buf up to @size bytes of data. This is the raw HBA SLIM data.
|
| 644 | *
|
| 645 | * Notes:
|
| 646 | * This routine will only dump up to 1024 bytes of data each time called and
|
| 647 | * should be called multiple times to dump the entire HBA SLIM.
|
| 648 | *
|
| 649 | * Return Value:
|
| 650 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 651 | * not exceed @size.
|
| 652 | *
|
| 653 | static int
|
| 654 | lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
|
| 655 | {
|
| 656 | int len = 0;
|
| 657 | int i, off;
|
| 658 | uint32_t *ptr;
|
| 659 | char *buffer;
|
| 660 |
|
| 661 | buffer = kmalloc(1024, GFP_KERNEL);
|
| 662 | if (!buffer)
|
| 663 | return 0;
|
| 664 |
|
| 665 | off = 0;
|
| 666 | spin_lock_irq(&phba->hbalock);
|
| 667 |
|
| 668 | len += scnprintf(buf+len, size-len, "HBA SLIM\n");
|
| 669 | lpfc_memcpy_from_slim(buffer,
|
| 670 | phba->MBslimaddr + lpfc_debugfs_last_hba_slim_off, 1024);
|
| 671 |
|
| 672 | ptr = (uint32_t *)&buffer[0];
|
| 673 | off = lpfc_debugfs_last_hba_slim_off;
|
| 674 |
|
| 675 |
|
| 676 | lpfc_debugfs_last_hba_slim_off += 1024;
|
| 677 | if (lpfc_debugfs_last_hba_slim_off >= 4096)
|
| 678 | lpfc_debugfs_last_hba_slim_off = 0;
|
| 679 |
|
| 680 | i = 1024;
|
| 681 | while (i > 0) {
|
| 682 | len += scnprintf(buf+len, size-len,
|
| 683 | "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
| 684 | off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
|
| 685 | *(ptr+5), *(ptr+6), *(ptr+7));
|
| 686 | ptr += 8;
|
| 687 | i -= (8 * sizeof(uint32_t));
|
| 688 | off += (8 * sizeof(uint32_t));
|
| 689 | }
|
| 690 |
|
| 691 | spin_unlock_irq(&phba->hbalock);
|
| 692 | kfree(buffer);
|
| 693 |
|
| 694 | return len;
|
| 695 | }
|
| 696 |
|
| 697 | |
| 698 | * lpfc_debugfs_dumpHostSlim_data - Dump host SLIM info to a buffer
|
| 699 | * @phba: The HBA to gather Host SLIM info from.
|
| 700 | * @buf: The buffer to dump log into.
|
| 701 | * @size: The maximum amount of data to process.
|
| 702 | *
|
| 703 | * Description:
|
| 704 | * This routine dumps the current contents of host SLIM for the host associated
|
| 705 | * with @phba to @buf up to @size bytes of data. The dump will contain the
|
| 706 | * Mailbox, PCB, Rings, and Registers that are located in host memory.
|
| 707 | *
|
| 708 | * Return Value:
|
| 709 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 710 | * not exceed @size.
|
| 711 | *
|
| 712 | static int
|
| 713 | lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size)
|
| 714 | {
|
| 715 | int len = 0;
|
| 716 | int i, off;
|
| 717 | uint32_t word0, word1, word2, word3;
|
| 718 | uint32_t *ptr;
|
| 719 | struct lpfc_pgp *pgpp;
|
| 720 | struct lpfc_sli *psli = &phba->sli;
|
| 721 | struct lpfc_sli_ring *pring;
|
| 722 |
|
| 723 | off = 0;
|
| 724 | spin_lock_irq(&phba->hbalock);
|
| 725 |
|
| 726 | len += scnprintf(buf+len, size-len, "SLIM Mailbox\n");
|
| 727 | ptr = (uint32_t *)phba->slim2p.virt;
|
| 728 | i = sizeof(MAILBOX_t);
|
| 729 | while (i > 0) {
|
| 730 | len += scnprintf(buf+len, size-len,
|
| 731 | "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
| 732 | off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
|
| 733 | *(ptr+5), *(ptr+6), *(ptr+7));
|
| 734 | ptr += 8;
|
| 735 | i -= (8 * sizeof(uint32_t));
|
| 736 | off += (8 * sizeof(uint32_t));
|
| 737 | }
|
| 738 |
|
| 739 | len += scnprintf(buf+len, size-len, "SLIM PCB\n");
|
| 740 | ptr = (uint32_t *)phba->pcb;
|
| 741 | i = sizeof(PCB_t);
|
| 742 | while (i > 0) {
|
| 743 | len += scnprintf(buf+len, size-len,
|
| 744 | "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
| 745 | off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
|
| 746 | *(ptr+5), *(ptr+6), *(ptr+7));
|
| 747 | ptr += 8;
|
| 748 | i -= (8 * sizeof(uint32_t));
|
| 749 | off += (8 * sizeof(uint32_t));
|
| 750 | }
|
| 751 |
|
| 752 | if (phba->sli_rev <= LPFC_SLI_REV3) {
|
| 753 | for (i = 0; i < 4; i++) {
|
| 754 | pgpp = &phba->port_gp[i];
|
| 755 | pring = &psli->sli3_ring[i];
|
| 756 | len += scnprintf(buf+len, size-len,
|
| 757 | "Ring %d: CMD GetInx:%d "
|
| 758 | "(Max:%d Next:%d "
|
| 759 | "Local:%d flg:x%x) "
|
| 760 | "RSP PutInx:%d Max:%d\n",
|
| 761 | i, pgpp->cmdGetInx,
|
| 762 | pring->sli.sli3.numCiocb,
|
| 763 | pring->sli.sli3.next_cmdidx,
|
| 764 | pring->sli.sli3.local_getidx,
|
| 765 | pring->flag, pgpp->rspPutInx,
|
| 766 | pring->sli.sli3.numRiocb);
|
| 767 | }
|
| 768 |
|
| 769 | word0 = readl(phba->HAregaddr);
|
| 770 | word1 = readl(phba->CAregaddr);
|
| 771 | word2 = readl(phba->HSregaddr);
|
| 772 | word3 = readl(phba->HCregaddr);
|
| 773 | len += scnprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x "
|
| 774 | "HC:%08x\n", word0, word1, word2, word3);
|
| 775 | }
|
| 776 | spin_unlock_irq(&phba->hbalock);
|
| 777 | return len;
|
| 778 | }
|
| 779 |
|
| 780 | |
| 781 | * lpfc_debugfs_nodelist_data - Dump target node list to a buffer
|
| 782 | * @vport: The vport to gather target node info from.
|
| 783 | * @buf: The buffer to dump log into.
|
| 784 | * @size: The maximum amount of data to process.
|
| 785 | *
|
| 786 | * Description:
|
| 787 | * This routine dumps the current target node list associated with @vport to
|
| 788 | * @buf up to @size bytes of data. Each node entry in the dump will contain a
|
| 789 | * node state, DID, WWPN, WWNN, RPI, flags, type, and other useful fields.
|
| 790 | *
|
| 791 | * Return Value:
|
| 792 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 793 | * not exceed @size.
|
| 794 | *
|
| 795 | static int
|
| 796 | lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
|
| 797 | {
|
| 798 | int len = 0;
|
| 799 | int i, iocnt, outio, cnt;
|
| 800 | struct lpfc_hba *phba = vport->phba;
|
| 801 | struct lpfc_nodelist *ndlp;
|
| 802 | unsigned char *statep;
|
| 803 | unsigned long iflags;
|
| 804 | struct nvme_fc_local_port *localport;
|
| 805 | struct nvme_fc_remote_port *nrport = NULL;
|
| 806 | struct lpfc_nvme_rport *rport;
|
| 807 |
|
| 808 | cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE);
|
| 809 | outio = 0;
|
| 810 |
|
| 811 | len += scnprintf(buf+len, size-len, "\nFCP Nodelist Entries ...\n");
|
| 812 | spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
|
| 813 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
|
| 814 | iocnt = 0;
|
| 815 | if (!cnt) {
|
| 816 | len += scnprintf(buf+len, size-len,
|
| 817 | "Missing Nodelist Entries\n");
|
| 818 | break;
|
| 819 | }
|
| 820 | cnt--;
|
| 821 | switch (ndlp->nlp_state) {
|
| 822 | case NLP_STE_UNUSED_NODE:
|
| 823 | statep = "UNUSED";
|
| 824 | break;
|
| 825 | case NLP_STE_PLOGI_ISSUE:
|
| 826 | statep = "PLOGI ";
|
| 827 | break;
|
| 828 | case NLP_STE_ADISC_ISSUE:
|
| 829 | statep = "ADISC ";
|
| 830 | break;
|
| 831 | case NLP_STE_REG_LOGIN_ISSUE:
|
| 832 | statep = "REGLOG";
|
| 833 | break;
|
| 834 | case NLP_STE_PRLI_ISSUE:
|
| 835 | statep = "PRLI ";
|
| 836 | break;
|
| 837 | case NLP_STE_LOGO_ISSUE:
|
| 838 | statep = "LOGO ";
|
| 839 | break;
|
| 840 | case NLP_STE_UNMAPPED_NODE:
|
| 841 | statep = "UNMAP ";
|
| 842 | iocnt = 1;
|
| 843 | break;
|
| 844 | case NLP_STE_MAPPED_NODE:
|
| 845 | statep = "MAPPED";
|
| 846 | iocnt = 1;
|
| 847 | break;
|
| 848 | case NLP_STE_NPR_NODE:
|
| 849 | statep = "NPR ";
|
| 850 | break;
|
| 851 | default:
|
| 852 | statep = "UNKNOWN";
|
| 853 | }
|
| 854 | len += scnprintf(buf+len, size-len, "%s DID:x%06x ",
|
| 855 | statep, ndlp->nlp_DID);
|
| 856 | len += scnprintf(buf+len, size-len,
|
| 857 | "WWPN x%016llx ",
|
| 858 | wwn_to_u64(ndlp->nlp_portname.u.wwn));
|
| 859 | len += scnprintf(buf+len, size-len,
|
| 860 | "WWNN x%016llx ",
|
| 861 | wwn_to_u64(ndlp->nlp_nodename.u.wwn));
|
| 862 | len += scnprintf(buf+len, size-len, "RPI:x%04x ",
|
| 863 | ndlp->nlp_rpi);
|
| 864 | len += scnprintf(buf+len, size-len, "flag:x%08lx ",
|
| 865 | ndlp->nlp_flag);
|
| 866 | if (ndlp->nlp_enc_info.status) {
|
| 867 | len += scnprintf(buf + len,
|
| 868 | size - len, "ENCRYPTED");
|
| 869 | len += scnprintf(buf + len, size - len,
|
| 870 | ndlp->nlp_enc_info.level
|
| 871 | ? "(CNSA2.0) " : "(CNSA1.0) ");
|
| 872 | }
|
| 873 | if (!ndlp->nlp_type)
|
| 874 | len += scnprintf(buf+len, size-len, "UNKNOWN_TYPE ");
|
| 875 | if (ndlp->nlp_type & NLP_FC_NODE)
|
| 876 | len += scnprintf(buf+len, size-len, "FC_NODE ");
|
| 877 | if (ndlp->nlp_type & NLP_FABRIC) {
|
| 878 | len += scnprintf(buf+len, size-len, "FABRIC ");
|
| 879 | iocnt = 0;
|
| 880 | }
|
| 881 | if (ndlp->nlp_type & NLP_FCP_TARGET)
|
| 882 | len += scnprintf(buf+len, size-len, "FCP_TGT sid:%d ",
|
| 883 | ndlp->nlp_sid);
|
| 884 | if (ndlp->nlp_type & NLP_FCP_INITIATOR)
|
| 885 | len += scnprintf(buf+len, size-len, "FCP_INITIATOR ");
|
| 886 | if (ndlp->nlp_type & NLP_NVME_TARGET)
|
| 887 | len += scnprintf(buf + len,
|
| 888 | size - len, "NVME_TGT sid:%d ",
|
| 889 | NLP_NO_SID);
|
| 890 | if (ndlp->nlp_type & NLP_NVME_INITIATOR)
|
| 891 | len += scnprintf(buf + len,
|
| 892 | size - len, "NVME_INITIATOR ");
|
| 893 | len += scnprintf(buf+len, size-len, "refcnt:%d",
|
| 894 | kref_read(&ndlp->kref));
|
| 895 | if (iocnt) {
|
| 896 | i = atomic_read(&ndlp->cmd_pending);
|
| 897 | len += scnprintf(buf + len, size - len,
|
| 898 | " OutIO:x%x Qdepth x%x",
|
| 899 | i, ndlp->cmd_qdepth);
|
| 900 | outio += i;
|
| 901 | }
|
| 902 | len += scnprintf(buf+len, size-len, " xpt:x%x",
|
| 903 | ndlp->fc4_xpt_flags);
|
| 904 | if (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)
|
| 905 | len += scnprintf(buf+len, size-len, " defer:%x",
|
| 906 | ndlp->nlp_defer_did);
|
| 907 | len += scnprintf(buf+len, size-len, "\n");
|
| 908 | }
|
| 909 | spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
|
| 910 |
|
| 911 | len += scnprintf(buf + len, size - len,
|
| 912 | "\nOutstanding IO x%x\n", outio);
|
| 913 |
|
| 914 | if (phba->nvmet_support && phba->targetport && (vport == phba->pport)) {
|
| 915 | len += scnprintf(buf + len, size - len,
|
| 916 | "\nNVME Targetport Entry ...\n");
|
| 917 |
|
| 918 |
|
| 919 | if (phba->targetport->port_id)
|
| 920 | statep = "REGISTERED";
|
| 921 | else
|
| 922 | statep = "INIT";
|
| 923 | len += scnprintf(buf + len, size - len,
|
| 924 | "TGT WWNN x%llx WWPN x%llx State %s\n",
|
| 925 | wwn_to_u64(vport->fc_nodename.u.wwn),
|
| 926 | wwn_to_u64(vport->fc_portname.u.wwn),
|
| 927 | statep);
|
| 928 | len += scnprintf(buf + len, size - len,
|
| 929 | " Targetport DID x%06x\n",
|
| 930 | phba->targetport->port_id);
|
| 931 | goto out_exit;
|
| 932 | }
|
| 933 |
|
| 934 | len += scnprintf(buf + len, size - len,
|
| 935 | "\nNVME Lport/Rport Entries ...\n");
|
| 936 |
|
| 937 | localport = vport->localport;
|
| 938 | if (!localport)
|
| 939 | goto out_exit;
|
| 940 |
|
| 941 |
|
| 942 | if (localport->port_id)
|
| 943 | statep = "ONLINE";
|
| 944 | else
|
| 945 | statep = "UNKNOWN ";
|
| 946 |
|
| 947 | len += scnprintf(buf + len, size - len,
|
| 948 | "Lport DID x%06x PortState %s\n",
|
| 949 | localport->port_id, statep);
|
| 950 |
|
| 951 | len += scnprintf(buf + len, size - len, "\tRport List:\n");
|
| 952 | spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
|
| 953 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
|
| 954 |
|
| 955 | spin_lock(&ndlp->lock);
|
| 956 | rport = lpfc_ndlp_get_nrport(ndlp);
|
| 957 | if (rport)
|
| 958 | nrport = rport->remoteport;
|
| 959 | else
|
| 960 | nrport = NULL;
|
| 961 | spin_unlock(&ndlp->lock);
|
| 962 | if (!nrport)
|
| 963 | continue;
|
| 964 |
|
| 965 |
|
| 966 | switch (nrport->port_state) {
|
| 967 | case FC_OBJSTATE_ONLINE:
|
| 968 | statep = "ONLINE";
|
| 969 | break;
|
| 970 | case FC_OBJSTATE_UNKNOWN:
|
| 971 | statep = "UNKNOWN ";
|
| 972 | break;
|
| 973 | default:
|
| 974 | statep = "UNSUPPORTED";
|
| 975 | break;
|
| 976 | }
|
| 977 |
|
| 978 |
|
| 979 | len += scnprintf(buf + len, size - len,
|
| 980 | "\t%s Port ID:x%06x ",
|
| 981 | statep, nrport->port_id);
|
| 982 | len += scnprintf(buf + len, size - len, "WWPN x%llx ",
|
| 983 | nrport->port_name);
|
| 984 | len += scnprintf(buf + len, size - len, "WWNN x%llx ",
|
| 985 | nrport->node_name);
|
| 986 |
|
| 987 |
|
| 988 | if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR)
|
| 989 | len += scnprintf(buf + len, size - len,
|
| 990 | "INITIATOR ");
|
| 991 | if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET)
|
| 992 | len += scnprintf(buf + len, size - len,
|
| 993 | "TARGET ");
|
| 994 | if (nrport->port_role & FC_PORT_ROLE_NVME_DISCOVERY)
|
| 995 | len += scnprintf(buf + len, size - len,
|
| 996 | "DISCSRVC ");
|
| 997 | if (nrport->port_role & ~(FC_PORT_ROLE_NVME_INITIATOR |
|
| 998 | FC_PORT_ROLE_NVME_TARGET |
|
| 999 | FC_PORT_ROLE_NVME_DISCOVERY))
|
| 1000 | len += scnprintf(buf + len, size - len,
|
| 1001 | "UNKNOWN ROLE x%x",
|
| 1002 | nrport->port_role);
|
| 1003 |
|
| 1004 | len += scnprintf(buf + len, size - len, "\n");
|
| 1005 | }
|
| 1006 | spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
|
| 1007 | out_exit:
|
| 1008 | return len;
|
| 1009 | }
|
| 1010 |
|
| 1011 | |
| 1012 | * lpfc_debugfs_nvmestat_data - Dump target node list to a buffer
|
| 1013 | * @vport: The vport to gather target node info from.
|
| 1014 | * @buf: The buffer to dump log into.
|
| 1015 | * @size: The maximum amount of data to process.
|
| 1016 | *
|
| 1017 | * Description:
|
| 1018 | * This routine dumps the NVME statistics associated with @vport
|
| 1019 | *
|
| 1020 | * Return Value:
|
| 1021 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 1022 | * not exceed @size.
|
| 1023 | *
|
| 1024 | static int
|
| 1025 | lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
|
| 1026 | {
|
| 1027 | struct lpfc_hba *phba = vport->phba;
|
| 1028 | struct lpfc_nvmet_tgtport *tgtp;
|
| 1029 | struct lpfc_async_xchg_ctx *ctxp, *next_ctxp;
|
| 1030 | struct nvme_fc_local_port *localport;
|
| 1031 | struct lpfc_fc4_ctrl_stat *cstat;
|
| 1032 | struct lpfc_nvme_lport *lport;
|
| 1033 | uint64_t data1, data2, data3;
|
| 1034 | uint64_t tot, totin, totout;
|
| 1035 | int cnt, i;
|
| 1036 | int len = 0;
|
| 1037 |
|
| 1038 | if (phba->nvmet_support) {
|
| 1039 | if (!phba->targetport)
|
| 1040 | return len;
|
| 1041 | tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
|
| 1042 | len += scnprintf(buf + len, size - len,
|
| 1043 | "\nNVME Targetport Statistics\n");
|
| 1044 |
|
| 1045 | len += scnprintf(buf + len, size - len,
|
| 1046 | "LS: Rcv %08x Drop %08x Abort %08x\n",
|
| 1047 | atomic_read(&tgtp->rcv_ls_req_in),
|
| 1048 | atomic_read(&tgtp->rcv_ls_req_drop),
|
| 1049 | atomic_read(&tgtp->xmt_ls_abort));
|
| 1050 | if (atomic_read(&tgtp->rcv_ls_req_in) !=
|
| 1051 | atomic_read(&tgtp->rcv_ls_req_out)) {
|
| 1052 | len += scnprintf(buf + len, size - len,
|
| 1053 | "Rcv LS: in %08x != out %08x\n",
|
| 1054 | atomic_read(&tgtp->rcv_ls_req_in),
|
| 1055 | atomic_read(&tgtp->rcv_ls_req_out));
|
| 1056 | }
|
| 1057 |
|
| 1058 | len += scnprintf(buf + len, size - len,
|
| 1059 | "LS: Xmt %08x Drop %08x Cmpl %08x\n",
|
| 1060 | atomic_read(&tgtp->xmt_ls_rsp),
|
| 1061 | atomic_read(&tgtp->xmt_ls_drop),
|
| 1062 | atomic_read(&tgtp->xmt_ls_rsp_cmpl));
|
| 1063 |
|
| 1064 | len += scnprintf(buf + len, size - len,
|
| 1065 | "LS: RSP Abort %08x xb %08x Err %08x\n",
|
| 1066 | atomic_read(&tgtp->xmt_ls_rsp_aborted),
|
| 1067 | atomic_read(&tgtp->xmt_ls_rsp_xb_set),
|
| 1068 | atomic_read(&tgtp->xmt_ls_rsp_error));
|
| 1069 |
|
| 1070 | len += scnprintf(buf + len, size - len,
|
| 1071 | "FCP: Rcv %08x Defer %08x Release %08x "
|
| 1072 | "Drop %08x\n",
|
| 1073 | atomic_read(&tgtp->rcv_fcp_cmd_in),
|
| 1074 | atomic_read(&tgtp->rcv_fcp_cmd_defer),
|
| 1075 | atomic_read(&tgtp->xmt_fcp_release),
|
| 1076 | atomic_read(&tgtp->rcv_fcp_cmd_drop));
|
| 1077 |
|
| 1078 | if (atomic_read(&tgtp->rcv_fcp_cmd_in) !=
|
| 1079 | atomic_read(&tgtp->rcv_fcp_cmd_out)) {
|
| 1080 | len += scnprintf(buf + len, size - len,
|
| 1081 | "Rcv FCP: in %08x != out %08x\n",
|
| 1082 | atomic_read(&tgtp->rcv_fcp_cmd_in),
|
| 1083 | atomic_read(&tgtp->rcv_fcp_cmd_out));
|
| 1084 | }
|
| 1085 |
|
| 1086 | len += scnprintf(buf + len, size - len,
|
| 1087 | "FCP Rsp: read %08x readrsp %08x "
|
| 1088 | "write %08x rsp %08x\n",
|
| 1089 | atomic_read(&tgtp->xmt_fcp_read),
|
| 1090 | atomic_read(&tgtp->xmt_fcp_read_rsp),
|
| 1091 | atomic_read(&tgtp->xmt_fcp_write),
|
| 1092 | atomic_read(&tgtp->xmt_fcp_rsp));
|
| 1093 |
|
| 1094 | len += scnprintf(buf + len, size - len,
|
| 1095 | "FCP Rsp Cmpl: %08x err %08x drop %08x\n",
|
| 1096 | atomic_read(&tgtp->xmt_fcp_rsp_cmpl),
|
| 1097 | atomic_read(&tgtp->xmt_fcp_rsp_error),
|
| 1098 | atomic_read(&tgtp->xmt_fcp_rsp_drop));
|
| 1099 |
|
| 1100 | len += scnprintf(buf + len, size - len,
|
| 1101 | "FCP Rsp Abort: %08x xb %08x xricqe %08x\n",
|
| 1102 | atomic_read(&tgtp->xmt_fcp_rsp_aborted),
|
| 1103 | atomic_read(&tgtp->xmt_fcp_rsp_xb_set),
|
| 1104 | atomic_read(&tgtp->xmt_fcp_xri_abort_cqe));
|
| 1105 |
|
| 1106 | len += scnprintf(buf + len, size - len,
|
| 1107 | "ABORT: Xmt %08x Cmpl %08x\n",
|
| 1108 | atomic_read(&tgtp->xmt_fcp_abort),
|
| 1109 | atomic_read(&tgtp->xmt_fcp_abort_cmpl));
|
| 1110 |
|
| 1111 | len += scnprintf(buf + len, size - len,
|
| 1112 | "ABORT: Sol %08x Usol %08x Err %08x Cmpl %08x",
|
| 1113 | atomic_read(&tgtp->xmt_abort_sol),
|
| 1114 | atomic_read(&tgtp->xmt_abort_unsol),
|
| 1115 | atomic_read(&tgtp->xmt_abort_rsp),
|
| 1116 | atomic_read(&tgtp->xmt_abort_rsp_error));
|
| 1117 |
|
| 1118 | len += scnprintf(buf + len, size - len, "\n");
|
| 1119 |
|
| 1120 | cnt = 0;
|
| 1121 | spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
|
| 1122 | list_for_each_entry_safe(ctxp, next_ctxp,
|
| 1123 | &phba->sli4_hba.lpfc_abts_nvmet_ctx_list,
|
| 1124 | list) {
|
| 1125 | cnt++;
|
| 1126 | }
|
| 1127 | spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
|
| 1128 | if (cnt) {
|
| 1129 | len += scnprintf(buf + len, size - len,
|
| 1130 | "ABORT: %d ctx entries\n", cnt);
|
| 1131 | spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
|
| 1132 | list_for_each_entry_safe(ctxp, next_ctxp,
|
| 1133 | &phba->sli4_hba.lpfc_abts_nvmet_ctx_list,
|
| 1134 | list) {
|
| 1135 | if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ))
|
| 1136 | break;
|
| 1137 | len += scnprintf(buf + len, size - len,
|
| 1138 | "Entry: oxid %x state %x "
|
| 1139 | "flag %x\n",
|
| 1140 | ctxp->oxid, ctxp->state,
|
| 1141 | ctxp->flag);
|
| 1142 | }
|
| 1143 | spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
|
| 1144 | }
|
| 1145 |
|
| 1146 |
|
| 1147 | tot = atomic_read(&tgtp->rcv_fcp_cmd_drop);
|
| 1148 | tot += atomic_read(&tgtp->xmt_fcp_release);
|
| 1149 | tot = atomic_read(&tgtp->rcv_fcp_cmd_in) - tot;
|
| 1150 |
|
| 1151 | len += scnprintf(buf + len, size - len,
|
| 1152 | "IO_CTX: %08x WAIT: cur %08x tot %08x\n"
|
| 1153 | "CTX Outstanding %08llx\n",
|
| 1154 | phba->sli4_hba.nvmet_xri_cnt,
|
| 1155 | phba->sli4_hba.nvmet_io_wait_cnt,
|
| 1156 | phba->sli4_hba.nvmet_io_wait_total,
|
| 1157 | tot);
|
| 1158 | } else {
|
| 1159 | if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_NVME))
|
| 1160 | return len;
|
| 1161 |
|
| 1162 | localport = vport->localport;
|
| 1163 | if (!localport)
|
| 1164 | return len;
|
| 1165 | lport = (struct lpfc_nvme_lport *)localport->private;
|
| 1166 | if (!lport)
|
| 1167 | return len;
|
| 1168 |
|
| 1169 | len += scnprintf(buf + len, size - len,
|
| 1170 | "\nNVME HDWQ Statistics\n");
|
| 1171 |
|
| 1172 | len += scnprintf(buf + len, size - len,
|
| 1173 | "LS: Xmt %016x Cmpl %016x\n",
|
| 1174 | atomic_read(&lport->fc4NvmeLsRequests),
|
| 1175 | atomic_read(&lport->fc4NvmeLsCmpls));
|
| 1176 |
|
| 1177 | totin = 0;
|
| 1178 | totout = 0;
|
| 1179 | for (i = 0; i < phba->cfg_hdw_queue; i++) {
|
| 1180 | cstat = &phba->sli4_hba.hdwq[i].nvme_cstat;
|
| 1181 | tot = cstat->io_cmpls;
|
| 1182 | totin += tot;
|
| 1183 | data1 = cstat->input_requests;
|
| 1184 | data2 = cstat->output_requests;
|
| 1185 | data3 = cstat->control_requests;
|
| 1186 | totout += (data1 + data2 + data3);
|
| 1187 |
|
| 1188 |
|
| 1189 | if (i >= 32)
|
| 1190 | continue;
|
| 1191 |
|
| 1192 | len += scnprintf(buf + len, PAGE_SIZE - len,
|
| 1193 | "HDWQ (%d): Rd %016llx Wr %016llx "
|
| 1194 | "IO %016llx ",
|
| 1195 | i, data1, data2, data3);
|
| 1196 | len += scnprintf(buf + len, PAGE_SIZE - len,
|
| 1197 | "Cmpl %016llx OutIO %016llx\n",
|
| 1198 | tot, ((data1 + data2 + data3) - tot));
|
| 1199 | }
|
| 1200 | len += scnprintf(buf + len, PAGE_SIZE - len,
|
| 1201 | "Total FCP Cmpl %016llx Issue %016llx "
|
| 1202 | "OutIO %016llx\n",
|
| 1203 | totin, totout, totout - totin);
|
| 1204 |
|
| 1205 | len += scnprintf(buf + len, size - len,
|
| 1206 | "LS Xmt Err: Abrt %08x Err %08x "
|
| 1207 | "Cmpl Err: xb %08x Err %08x\n",
|
| 1208 | atomic_read(&lport->xmt_ls_abort),
|
| 1209 | atomic_read(&lport->xmt_ls_err),
|
| 1210 | atomic_read(&lport->cmpl_ls_xb),
|
| 1211 | atomic_read(&lport->cmpl_ls_err));
|
| 1212 |
|
| 1213 | len += scnprintf(buf + len, size - len,
|
| 1214 | "FCP Xmt Err: noxri %06x nondlp %06x "
|
| 1215 | "qdepth %06x wqerr %06x err %06x Abrt %06x\n",
|
| 1216 | atomic_read(&lport->xmt_fcp_noxri),
|
| 1217 | atomic_read(&lport->xmt_fcp_bad_ndlp),
|
| 1218 | atomic_read(&lport->xmt_fcp_qdepth),
|
| 1219 | atomic_read(&lport->xmt_fcp_wqerr),
|
| 1220 | atomic_read(&lport->xmt_fcp_err),
|
| 1221 | atomic_read(&lport->xmt_fcp_abort));
|
| 1222 |
|
| 1223 | len += scnprintf(buf + len, size - len,
|
| 1224 | "FCP Cmpl Err: xb %08x Err %08x\n",
|
| 1225 | atomic_read(&lport->cmpl_fcp_xb),
|
| 1226 | atomic_read(&lport->cmpl_fcp_err));
|
| 1227 |
|
| 1228 | }
|
| 1229 |
|
| 1230 | return len;
|
| 1231 | }
|
| 1232 |
|
| 1233 | |
| 1234 | * lpfc_debugfs_scsistat_data - Dump target node list to a buffer
|
| 1235 | * @vport: The vport to gather target node info from.
|
| 1236 | * @buf: The buffer to dump log into.
|
| 1237 | * @size: The maximum amount of data to process.
|
| 1238 | *
|
| 1239 | * Description:
|
| 1240 | * This routine dumps the SCSI statistics associated with @vport
|
| 1241 | *
|
| 1242 | * Return Value:
|
| 1243 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 1244 | * not exceed @size.
|
| 1245 | *
|
| 1246 | static int
|
| 1247 | lpfc_debugfs_scsistat_data(struct lpfc_vport *vport, char *buf, int size)
|
| 1248 | {
|
| 1249 | int len;
|
| 1250 | struct lpfc_hba *phba = vport->phba;
|
| 1251 | struct lpfc_fc4_ctrl_stat *cstat;
|
| 1252 | u64 data1, data2, data3;
|
| 1253 | u64 tot, totin, totout;
|
| 1254 | int i;
|
| 1255 | struct seq_buf s;
|
| 1256 |
|
| 1257 | if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_FCP) ||
|
| 1258 | (phba->sli_rev != LPFC_SLI_REV4))
|
| 1259 | return 0;
|
| 1260 |
|
| 1261 | seq_buf_init(&s, buf, size);
|
| 1262 | seq_buf_printf(&s, "SCSI HDWQ Statistics\n");
|
| 1263 |
|
| 1264 | totin = 0;
|
| 1265 | totout = 0;
|
| 1266 | for (i = 0; i < phba->cfg_hdw_queue; i++) {
|
| 1267 | cstat = &phba->sli4_hba.hdwq[i].scsi_cstat;
|
| 1268 | tot = cstat->io_cmpls;
|
| 1269 | totin += tot;
|
| 1270 | data1 = cstat->input_requests;
|
| 1271 | data2 = cstat->output_requests;
|
| 1272 | data3 = cstat->control_requests;
|
| 1273 | totout += (data1 + data2 + data3);
|
| 1274 |
|
| 1275 | seq_buf_printf(&s, "HDWQ (%d): Rd %016llx Wr %016llx IO %016llx ",
|
| 1276 | i, data1, data2, data3);
|
| 1277 |
|
| 1278 | seq_buf_printf(&s, "Cmpl %016llx OutIO %016llx\n",
|
| 1279 | tot, ((data1 + data2 + data3) - tot));
|
| 1280 |
|
| 1281 | if (seq_buf_has_overflowed(&s))
|
| 1282 | break;
|
| 1283 | }
|
| 1284 | seq_buf_printf(&s, "Total FCP Cmpl %016llx Issue %016llx OutIO %016llx\n",
|
| 1285 | totin, totout, totout - totin);
|
| 1286 |
|
| 1287 | len = strnlen(buf, size);
|
| 1288 |
|
| 1289 | return len;
|
| 1290 | }
|
| 1291 |
|
| 1292 | void
|
| 1293 | lpfc_io_ktime(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
|
| 1294 | {
|
| 1295 | uint64_t seg1, seg2, seg3, seg4;
|
| 1296 | uint64_t segsum;
|
| 1297 |
|
| 1298 | if (!lpfc_cmd->ts_last_cmd ||
|
| 1299 | !lpfc_cmd->ts_cmd_start ||
|
| 1300 | !lpfc_cmd->ts_cmd_wqput ||
|
| 1301 | !lpfc_cmd->ts_isr_cmpl ||
|
| 1302 | !lpfc_cmd->ts_data_io)
|
| 1303 | return;
|
| 1304 |
|
| 1305 | if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_cmd_start)
|
| 1306 | return;
|
| 1307 | if (lpfc_cmd->ts_cmd_start < lpfc_cmd->ts_last_cmd)
|
| 1308 | return;
|
| 1309 | if (lpfc_cmd->ts_cmd_wqput < lpfc_cmd->ts_cmd_start)
|
| 1310 | return;
|
| 1311 | if (lpfc_cmd->ts_isr_cmpl < lpfc_cmd->ts_cmd_wqput)
|
| 1312 | return;
|
| 1313 | if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_isr_cmpl)
|
| 1314 | return;
|
| 1315 | |
| 1316 | * Segment 1 - Time from Last FCP command cmpl is handed
|
| 1317 | * off to NVME Layer to start of next command.
|
| 1318 | * Segment 2 - Time from Driver receives a IO cmd start
|
| 1319 | * from NVME Layer to WQ put is done on IO cmd.
|
| 1320 | * Segment 3 - Time from Driver WQ put is done on IO cmd
|
| 1321 | * to MSI-X ISR for IO cmpl.
|
| 1322 | * Segment 4 - Time from MSI-X ISR for IO cmpl to when
|
| 1323 | * cmpl is handled off to the NVME Layer.
|
| 1324 |
|
| 1325 | seg1 = lpfc_cmd->ts_cmd_start - lpfc_cmd->ts_last_cmd;
|
| 1326 | if (seg1 > 5000000)
|
| 1327 | seg1 = 0;
|
| 1328 |
|
| 1329 |
|
| 1330 | seg2 = (lpfc_cmd->ts_cmd_wqput - lpfc_cmd->ts_cmd_start);
|
| 1331 | segsum = seg2;
|
| 1332 | seg3 = lpfc_cmd->ts_isr_cmpl - lpfc_cmd->ts_cmd_start;
|
| 1333 | if (segsum > seg3)
|
| 1334 | return;
|
| 1335 | seg3 -= segsum;
|
| 1336 | segsum += seg3;
|
| 1337 |
|
| 1338 | seg4 = lpfc_cmd->ts_data_io - lpfc_cmd->ts_cmd_start;
|
| 1339 | if (segsum > seg4)
|
| 1340 | return;
|
| 1341 | seg4 -= segsum;
|
| 1342 |
|
| 1343 | phba->ktime_data_samples++;
|
| 1344 | phba->ktime_seg1_total += seg1;
|
| 1345 | if (seg1 < phba->ktime_seg1_min)
|
| 1346 | phba->ktime_seg1_min = seg1;
|
| 1347 | else if (seg1 > phba->ktime_seg1_max)
|
| 1348 | phba->ktime_seg1_max = seg1;
|
| 1349 | phba->ktime_seg2_total += seg2;
|
| 1350 | if (seg2 < phba->ktime_seg2_min)
|
| 1351 | phba->ktime_seg2_min = seg2;
|
| 1352 | else if (seg2 > phba->ktime_seg2_max)
|
| 1353 | phba->ktime_seg2_max = seg2;
|
| 1354 | phba->ktime_seg3_total += seg3;
|
| 1355 | if (seg3 < phba->ktime_seg3_min)
|
| 1356 | phba->ktime_seg3_min = seg3;
|
| 1357 | else if (seg3 > phba->ktime_seg3_max)
|
| 1358 | phba->ktime_seg3_max = seg3;
|
| 1359 | phba->ktime_seg4_total += seg4;
|
| 1360 | if (seg4 < phba->ktime_seg4_min)
|
| 1361 | phba->ktime_seg4_min = seg4;
|
| 1362 | else if (seg4 > phba->ktime_seg4_max)
|
| 1363 | phba->ktime_seg4_max = seg4;
|
| 1364 |
|
| 1365 | lpfc_cmd->ts_last_cmd = 0;
|
| 1366 | lpfc_cmd->ts_cmd_start = 0;
|
| 1367 | lpfc_cmd->ts_cmd_wqput = 0;
|
| 1368 | lpfc_cmd->ts_isr_cmpl = 0;
|
| 1369 | lpfc_cmd->ts_data_io = 0;
|
| 1370 | }
|
| 1371 |
|
| 1372 | |
| 1373 | * lpfc_debugfs_ioktime_data - Dump target node list to a buffer
|
| 1374 | * @vport: The vport to gather target node info from.
|
| 1375 | * @buf: The buffer to dump log into.
|
| 1376 | * @size: The maximum amount of data to process.
|
| 1377 | *
|
| 1378 | * Description:
|
| 1379 | * This routine dumps the NVME statistics associated with @vport
|
| 1380 | *
|
| 1381 | * Return Value:
|
| 1382 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 1383 | * not exceed @size.
|
| 1384 | *
|
| 1385 | static int
|
| 1386 | lpfc_debugfs_ioktime_data(struct lpfc_vport *vport, char *buf, int size)
|
| 1387 | {
|
| 1388 | struct lpfc_hba *phba = vport->phba;
|
| 1389 | int len = 0;
|
| 1390 |
|
| 1391 | if (phba->nvmet_support == 0) {
|
| 1392 |
|
| 1393 | len += scnprintf(buf + len, PAGE_SIZE - len,
|
| 1394 | "ktime %s: Total Samples: %lld\n",
|
| 1395 | (phba->ktime_on ? "Enabled" : "Disabled"),
|
| 1396 | phba->ktime_data_samples);
|
| 1397 | if (phba->ktime_data_samples == 0)
|
| 1398 | return len;
|
| 1399 |
|
| 1400 | len += scnprintf(
|
| 1401 | buf + len, PAGE_SIZE - len,
|
| 1402 | "Segment 1: Last Cmd cmpl "
|
| 1403 | "done -to- Start of next Cmd (in driver)\n");
|
| 1404 | len += scnprintf(
|
| 1405 | buf + len, PAGE_SIZE - len,
|
| 1406 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1407 | div_u64(phba->ktime_seg1_total,
|
| 1408 | phba->ktime_data_samples),
|
| 1409 | phba->ktime_seg1_min,
|
| 1410 | phba->ktime_seg1_max);
|
| 1411 | len += scnprintf(
|
| 1412 | buf + len, PAGE_SIZE - len,
|
| 1413 | "Segment 2: Driver start of Cmd "
|
| 1414 | "-to- Firmware WQ doorbell\n");
|
| 1415 | len += scnprintf(
|
| 1416 | buf + len, PAGE_SIZE - len,
|
| 1417 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1418 | div_u64(phba->ktime_seg2_total,
|
| 1419 | phba->ktime_data_samples),
|
| 1420 | phba->ktime_seg2_min,
|
| 1421 | phba->ktime_seg2_max);
|
| 1422 | len += scnprintf(
|
| 1423 | buf + len, PAGE_SIZE - len,
|
| 1424 | "Segment 3: Firmware WQ doorbell -to- "
|
| 1425 | "MSI-X ISR cmpl\n");
|
| 1426 | len += scnprintf(
|
| 1427 | buf + len, PAGE_SIZE - len,
|
| 1428 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1429 | div_u64(phba->ktime_seg3_total,
|
| 1430 | phba->ktime_data_samples),
|
| 1431 | phba->ktime_seg3_min,
|
| 1432 | phba->ktime_seg3_max);
|
| 1433 | len += scnprintf(
|
| 1434 | buf + len, PAGE_SIZE - len,
|
| 1435 | "Segment 4: MSI-X ISR cmpl -to- "
|
| 1436 | "Cmd cmpl done\n");
|
| 1437 | len += scnprintf(
|
| 1438 | buf + len, PAGE_SIZE - len,
|
| 1439 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1440 | div_u64(phba->ktime_seg4_total,
|
| 1441 | phba->ktime_data_samples),
|
| 1442 | phba->ktime_seg4_min,
|
| 1443 | phba->ktime_seg4_max);
|
| 1444 | len += scnprintf(
|
| 1445 | buf + len, PAGE_SIZE - len,
|
| 1446 | "Total IO avg time: %08lld\n",
|
| 1447 | div_u64(phba->ktime_seg1_total +
|
| 1448 | phba->ktime_seg2_total +
|
| 1449 | phba->ktime_seg3_total +
|
| 1450 | phba->ktime_seg4_total,
|
| 1451 | phba->ktime_data_samples));
|
| 1452 | return len;
|
| 1453 | }
|
| 1454 |
|
| 1455 |
|
| 1456 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1457 | "ktime %s: Total Samples: %lld %lld\n",
|
| 1458 | (phba->ktime_on ? "Enabled" : "Disabled"),
|
| 1459 | phba->ktime_data_samples,
|
| 1460 | phba->ktime_status_samples);
|
| 1461 | if (phba->ktime_data_samples == 0)
|
| 1462 | return len;
|
| 1463 |
|
| 1464 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1465 | "Segment 1: MSI-X ISR Rcv cmd -to- "
|
| 1466 | "cmd pass to NVME Layer\n");
|
| 1467 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1468 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1469 | div_u64(phba->ktime_seg1_total,
|
| 1470 | phba->ktime_data_samples),
|
| 1471 | phba->ktime_seg1_min,
|
| 1472 | phba->ktime_seg1_max);
|
| 1473 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1474 | "Segment 2: cmd pass to NVME Layer- "
|
| 1475 | "-to- Driver rcv cmd OP (action)\n");
|
| 1476 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1477 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1478 | div_u64(phba->ktime_seg2_total,
|
| 1479 | phba->ktime_data_samples),
|
| 1480 | phba->ktime_seg2_min,
|
| 1481 | phba->ktime_seg2_max);
|
| 1482 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1483 | "Segment 3: Driver rcv cmd OP -to- "
|
| 1484 | "Firmware WQ doorbell: cmd\n");
|
| 1485 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1486 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1487 | div_u64(phba->ktime_seg3_total,
|
| 1488 | phba->ktime_data_samples),
|
| 1489 | phba->ktime_seg3_min,
|
| 1490 | phba->ktime_seg3_max);
|
| 1491 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1492 | "Segment 4: Firmware WQ doorbell: cmd "
|
| 1493 | "-to- MSI-X ISR for cmd cmpl\n");
|
| 1494 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1495 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1496 | div_u64(phba->ktime_seg4_total,
|
| 1497 | phba->ktime_data_samples),
|
| 1498 | phba->ktime_seg4_min,
|
| 1499 | phba->ktime_seg4_max);
|
| 1500 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1501 | "Segment 5: MSI-X ISR for cmd cmpl "
|
| 1502 | "-to- NVME layer passed cmd done\n");
|
| 1503 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1504 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1505 | div_u64(phba->ktime_seg5_total,
|
| 1506 | phba->ktime_data_samples),
|
| 1507 | phba->ktime_seg5_min,
|
| 1508 | phba->ktime_seg5_max);
|
| 1509 |
|
| 1510 | if (phba->ktime_status_samples == 0) {
|
| 1511 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1512 | "Total: cmd received by MSI-X ISR "
|
| 1513 | "-to- cmd completed on wire\n");
|
| 1514 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1515 | "avg:%08lld min:%08lld "
|
| 1516 | "max %08lld\n",
|
| 1517 | div_u64(phba->ktime_seg10_total,
|
| 1518 | phba->ktime_data_samples),
|
| 1519 | phba->ktime_seg10_min,
|
| 1520 | phba->ktime_seg10_max);
|
| 1521 | return len;
|
| 1522 | }
|
| 1523 |
|
| 1524 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1525 | "Segment 6: NVME layer passed cmd done "
|
| 1526 | "-to- Driver rcv rsp status OP\n");
|
| 1527 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1528 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1529 | div_u64(phba->ktime_seg6_total,
|
| 1530 | phba->ktime_status_samples),
|
| 1531 | phba->ktime_seg6_min,
|
| 1532 | phba->ktime_seg6_max);
|
| 1533 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1534 | "Segment 7: Driver rcv rsp status OP "
|
| 1535 | "-to- Firmware WQ doorbell: status\n");
|
| 1536 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1537 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1538 | div_u64(phba->ktime_seg7_total,
|
| 1539 | phba->ktime_status_samples),
|
| 1540 | phba->ktime_seg7_min,
|
| 1541 | phba->ktime_seg7_max);
|
| 1542 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1543 | "Segment 8: Firmware WQ doorbell: status"
|
| 1544 | " -to- MSI-X ISR for status cmpl\n");
|
| 1545 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1546 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1547 | div_u64(phba->ktime_seg8_total,
|
| 1548 | phba->ktime_status_samples),
|
| 1549 | phba->ktime_seg8_min,
|
| 1550 | phba->ktime_seg8_max);
|
| 1551 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1552 | "Segment 9: MSI-X ISR for status cmpl "
|
| 1553 | "-to- NVME layer passed status done\n");
|
| 1554 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1555 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1556 | div_u64(phba->ktime_seg9_total,
|
| 1557 | phba->ktime_status_samples),
|
| 1558 | phba->ktime_seg9_min,
|
| 1559 | phba->ktime_seg9_max);
|
| 1560 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1561 | "Total: cmd received by MSI-X ISR -to- "
|
| 1562 | "cmd completed on wire\n");
|
| 1563 | len += scnprintf(buf + len, PAGE_SIZE-len,
|
| 1564 | "avg:%08lld min:%08lld max %08lld\n",
|
| 1565 | div_u64(phba->ktime_seg10_total,
|
| 1566 | phba->ktime_status_samples),
|
| 1567 | phba->ktime_seg10_min,
|
| 1568 | phba->ktime_seg10_max);
|
| 1569 | return len;
|
| 1570 | }
|
| 1571 |
|
| 1572 | |
| 1573 | * lpfc_debugfs_nvmeio_trc_data - Dump NVME IO trace list to a buffer
|
| 1574 | * @phba: The phba to gather target node info from.
|
| 1575 | * @buf: The buffer to dump log into.
|
| 1576 | * @size: The maximum amount of data to process.
|
| 1577 | *
|
| 1578 | * Description:
|
| 1579 | * This routine dumps the NVME IO trace associated with @phba
|
| 1580 | *
|
| 1581 | * Return Value:
|
| 1582 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 1583 | * not exceed @size.
|
| 1584 | *
|
| 1585 | static int
|
| 1586 | lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size)
|
| 1587 | {
|
| 1588 | struct lpfc_debugfs_nvmeio_trc *dtp;
|
| 1589 | int i, state, index, skip;
|
| 1590 | int len = 0;
|
| 1591 |
|
| 1592 | state = phba->nvmeio_trc_on;
|
| 1593 |
|
| 1594 | index = (atomic_read(&phba->nvmeio_trc_cnt) + 1) &
|
| 1595 | (phba->nvmeio_trc_size - 1);
|
| 1596 | skip = phba->nvmeio_trc_output_idx;
|
| 1597 |
|
| 1598 | len += scnprintf(buf + len, size - len,
|
| 1599 | "%s IO Trace %s: next_idx %d skip %d size %d\n",
|
| 1600 | (phba->nvmet_support ? "NVME" : "NVMET"),
|
| 1601 | (state ? "Enabled" : "Disabled"),
|
| 1602 | index, skip, phba->nvmeio_trc_size);
|
| 1603 |
|
| 1604 | if (!phba->nvmeio_trc || state)
|
| 1605 | return len;
|
| 1606 |
|
| 1607 |
|
| 1608 |
|
| 1609 | for (i = index; i < phba->nvmeio_trc_size; i++) {
|
| 1610 | if (skip) {
|
| 1611 | skip--;
|
| 1612 | continue;
|
| 1613 | }
|
| 1614 | dtp = phba->nvmeio_trc + i;
|
| 1615 | phba->nvmeio_trc_output_idx++;
|
| 1616 |
|
| 1617 | if (!dtp->fmt)
|
| 1618 | continue;
|
| 1619 |
|
| 1620 | len += scnprintf(buf + len, size - len, dtp->fmt,
|
| 1621 | dtp->data1, dtp->data2, dtp->data3);
|
| 1622 |
|
| 1623 | if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) {
|
| 1624 | phba->nvmeio_trc_output_idx = 0;
|
| 1625 | len += scnprintf(buf + len, size - len,
|
| 1626 | "Trace Complete\n");
|
| 1627 | goto out;
|
| 1628 | }
|
| 1629 |
|
| 1630 | if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) {
|
| 1631 | len += scnprintf(buf + len, size - len,
|
| 1632 | "Trace Continue (%d of %d)\n",
|
| 1633 | phba->nvmeio_trc_output_idx,
|
| 1634 | phba->nvmeio_trc_size);
|
| 1635 | goto out;
|
| 1636 | }
|
| 1637 | }
|
| 1638 | for (i = 0; i < index; i++) {
|
| 1639 | if (skip) {
|
| 1640 | skip--;
|
| 1641 | continue;
|
| 1642 | }
|
| 1643 | dtp = phba->nvmeio_trc + i;
|
| 1644 | phba->nvmeio_trc_output_idx++;
|
| 1645 |
|
| 1646 | if (!dtp->fmt)
|
| 1647 | continue;
|
| 1648 |
|
| 1649 | len += scnprintf(buf + len, size - len, dtp->fmt,
|
| 1650 | dtp->data1, dtp->data2, dtp->data3);
|
| 1651 |
|
| 1652 | if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) {
|
| 1653 | phba->nvmeio_trc_output_idx = 0;
|
| 1654 | len += scnprintf(buf + len, size - len,
|
| 1655 | "Trace Complete\n");
|
| 1656 | goto out;
|
| 1657 | }
|
| 1658 |
|
| 1659 | if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) {
|
| 1660 | len += scnprintf(buf + len, size - len,
|
| 1661 | "Trace Continue (%d of %d)\n",
|
| 1662 | phba->nvmeio_trc_output_idx,
|
| 1663 | phba->nvmeio_trc_size);
|
| 1664 | goto out;
|
| 1665 | }
|
| 1666 | }
|
| 1667 |
|
| 1668 | len += scnprintf(buf + len, size - len,
|
| 1669 | "Trace Done\n");
|
| 1670 | out:
|
| 1671 | return len;
|
| 1672 | }
|
| 1673 |
|
| 1674 | |
| 1675 | * lpfc_debugfs_hdwqstat_data - Dump I/O stats to a buffer
|
| 1676 | * @vport: The vport to gather target node info from.
|
| 1677 | * @buf: The buffer to dump log into.
|
| 1678 | * @size: The maximum amount of data to process.
|
| 1679 | *
|
| 1680 | * Description:
|
| 1681 | * This routine dumps the NVME + SCSI statistics associated with @vport
|
| 1682 | *
|
| 1683 | * Return Value:
|
| 1684 | * This routine returns the amount of bytes that were dumped into @buf and will
|
| 1685 | * not exceed @size.
|
| 1686 | *
|
| 1687 | static int
|
| 1688 | lpfc_debugfs_hdwqstat_data(struct lpfc_vport *vport, char *buf, int size)
|
| 1689 | {
|
| 1690 | struct lpfc_hba *phba = vport->phba;
|
| 1691 | struct lpfc_hdwq_stat *c_stat;
|
| 1692 | int i, j, len;
|
| 1693 | uint32_t tot_xmt;
|
| 1694 | uint32_t tot_rcv;
|
| 1695 | uint32_t tot_cmpl;
|
| 1696 | size_t used = strnlen(buf, size);
|
| 1697 | struct seq_buf s;
|
| 1698 |
|
| 1699 | seq_buf_init(&s, buf + used, size - used);
|
| 1700 |
|
| 1701 | seq_buf_printf(&s, "HDWQ Stats:\n\n");
|
| 1702 |
|
| 1703 | seq_buf_printf(&s, "(NVME Accounting: %s) ",
|
| 1704 | (phba->hdwqstat_on &
|
| 1705 | (LPFC_CHECK_NVME_IO | LPFC_CHECK_NVMET_IO) ?
|
| 1706 | "Enabled" : "Disabled"));
|
| 1707 |
|
| 1708 | seq_buf_printf(&s, "(SCSI Accounting: %s) ",
|
| 1709 | (phba->hdwqstat_on & LPFC_CHECK_SCSI_IO ?
|
| 1710 | "Enabled" : "Disabled"));
|
| 1711 |
|
| 1712 | seq_buf_printf(&s, "\n\n");
|
| 1713 |
|
| 1714 | for (i = 0; i < phba->cfg_hdw_queue; i++) {
|
| 1715 | tot_rcv = 0;
|
| 1716 | tot_xmt = 0;
|
| 1717 | tot_cmpl = 0;
|
| 1718 |
|
| 1719 | for_each_present_cpu(j) {
|
| 1720 | c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, j);
|
| 1721 |
|
| 1722 |
|
| 1723 | if (i != c_stat->hdwq_no)
|
| 1724 | continue;
|
| 1725 |
|
| 1726 |
|
| 1727 | if (!c_stat->xmt_io && !c_stat->cmpl_io &&
|
| 1728 | !c_stat->rcv_io)
|
| 1729 | continue;
|
| 1730 |
|
| 1731 |
|
| 1732 | if (!tot_xmt && !tot_cmpl && !tot_rcv)
|
| 1733 | seq_buf_printf(&s, "[HDWQ %d]:\t", i);
|
| 1734 |
|
| 1735 | tot_xmt += c_stat->xmt_io;
|
| 1736 | tot_cmpl += c_stat->cmpl_io;
|
| 1737 | if (phba->nvmet_support)
|
| 1738 | tot_rcv += c_stat->rcv_io;
|
| 1739 |
|
| 1740 | seq_buf_printf(&s, "| [CPU %d]: ", j);
|
| 1741 |
|
| 1742 | if (phba->nvmet_support)
|
| 1743 | seq_buf_printf(&s,
|
| 1744 | "XMT 0x%x CMPL 0x%x RCV 0x%x |",
|
| 1745 | c_stat->xmt_io, c_stat->cmpl_io,
|
| 1746 | c_stat->rcv_io);
|
| 1747 | else
|
| 1748 | seq_buf_printf(&s,
|
| 1749 | "XMT 0x%x CMPL 0x%x |",
|
| 1750 | c_stat->xmt_io, c_stat->cmpl_io);
|
| 1751 |
|
| 1752 | if (seq_buf_has_overflowed(&s))
|
| 1753 | break;
|
| 1754 | }
|
| 1755 |
|
| 1756 | if (seq_buf_has_overflowed(&s))
|
| 1757 | break;
|
| 1758 |
|
| 1759 |
|
| 1760 | if (!tot_xmt && !tot_cmpl && !tot_rcv)
|
| 1761 | continue;
|
| 1762 |
|
| 1763 | seq_buf_printf(&s, "\t->\t[HDWQ Total: ");
|
| 1764 |
|
| 1765 | if (phba->nvmet_support)
|
| 1766 | seq_buf_printf(&s,
|
| 1767 | "XMT 0x%x CMPL 0x%x RCV 0x%x]\n\n",
|
| 1768 | tot_xmt, tot_cmpl, tot_rcv);
|
| 1769 | else
|
| 1770 | seq_buf_printf(&s,
|
| 1771 | "XMT 0x%x CMPL 0x%x]\n\n",
|
| 1772 | tot_xmt, tot_cmpl);
|
| 1773 | }
|
| 1774 |
|
| 1775 | len = strnlen(buf, size);
|
| 1776 | return len;
|
| 1777 | }
|
| 1778 |
|
| 1779 | #endif
|
| 1780 |
|
| 1781 | |
| 1782 | * lpfc_debugfs_disc_trc - Store discovery trace log
|
| 1783 | * @vport: The vport to associate this trace string with for retrieval.
|
| 1784 | * @mask: Log entry classification.
|
| 1785 | * @fmt: Format string to be displayed when dumping the log.
|
| 1786 | * @data1: 1st data parameter to be applied to @fmt.
|
| 1787 | * @data2: 2nd data parameter to be applied to @fmt.
|
| 1788 | * @data3: 3rd data parameter to be applied to @fmt.
|
| 1789 | *
|
| 1790 | * Description:
|
| 1791 | * This routine is used by the driver code to add a debugfs log entry to the
|
| 1792 | * discovery trace buffer associated with @vport. Only entries with a @mask that
|
| 1793 | * match the current debugfs discovery mask will be saved. Entries that do not
|
| 1794 | * match will be thrown away. @fmt, @data1, @data2, and @data3 are used like
|
| 1795 | * printf when displaying the log.
|
| 1796 | *
|
| 1797 | inline void
|
| 1798 | lpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt,
|
| 1799 | uint32_t data1, uint32_t data2, uint32_t data3)
|
| 1800 | {
|
| 1801 | #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
|
| 1802 | struct lpfc_debugfs_trc *dtp;
|
| 1803 | int index;
|
| 1804 |
|
| 1805 | if (!(lpfc_debugfs_mask_disc_trc & mask))
|
| 1806 | return;
|
| 1807 |
|
| 1808 | if (!lpfc_debugfs_enable || !lpfc_debugfs_max_disc_trc ||
|
| 1809 | !vport || !vport->disc_trc)
|
| 1810 | return;
|
| 1811 |
|
| 1812 | index = atomic_inc_return(&vport->disc_trc_cnt) &
|
| 1813 | (lpfc_debugfs_max_disc_trc - 1);
|
| 1814 | dtp = vport->disc_trc + index;
|
| 1815 | dtp->fmt = fmt;
|
| 1816 | dtp->data1 = data1;
|
| 1817 | dtp->data2 = data2;
|
| 1818 | dtp->data3 = data3;
|
| 1819 | dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt);
|
| 1820 | dtp->jif = jiffies;
|
| 1821 | #endif
|
| 1822 | return;
|
| 1823 | }
|
| 1824 |
|
| 1825 | |
| 1826 | * lpfc_debugfs_slow_ring_trc - Store slow ring trace log
|
| 1827 | * @phba: The phba to associate this trace string with for retrieval.
|
| 1828 | * @fmt: Format string to be displayed when dumping the log.
|
| 1829 | * @data1: 1st data parameter to be applied to @fmt.
|
| 1830 | * @data2: 2nd data parameter to be applied to @fmt.
|
| 1831 | * @data3: 3rd data parameter to be applied to @fmt.
|
| 1832 | *
|
| 1833 | * Description:
|
| 1834 | * This routine is used by the driver code to add a debugfs log entry to the
|
| 1835 | * discovery trace buffer associated with @vport. @fmt, @data1, @data2, and
|
| 1836 | * @data3 are used like printf when displaying the log.
|
| 1837 | *
|
| 1838 | inline void
|
| 1839 | lpfc_debugfs_slow_ring_trc(struct lpfc_hba *phba, char *fmt,
|
| 1840 | uint32_t data1, uint32_t data2, uint32_t data3)
|
| 1841 | {
|
| 1842 | #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
|
| 1843 | struct lpfc_debugfs_trc *dtp;
|
| 1844 | int index;
|
| 1845 |
|
| 1846 | if (!lpfc_debugfs_enable || !lpfc_debugfs_max_slow_ring_trc ||
|
| 1847 | !phba || !phba->slow_ring_trc)
|
| 1848 | return;
|
| 1849 |
|
| 1850 | index = atomic_inc_return(&phba->slow_ring_trc_cnt) &
|
| 1851 | (lpfc_debugfs_max_slow_ring_trc - 1);
|
| 1852 | dtp = phba->slow_ring_trc + index;
|
| 1853 | dtp->fmt = fmt;
|
| 1854 | dtp->data1 = data1;
|
| 1855 | dtp->data2 = data2;
|
| 1856 | dtp->data3 = data3;
|
| 1857 | dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt);
|
| 1858 | dtp->jif = jiffies;
|
| 1859 | #endif
|
| 1860 | return;
|
| 1861 | }
|
| 1862 |
|
| 1863 | |
| 1864 | * lpfc_debugfs_nvme_trc - Store NVME/NVMET trace log
|
| 1865 | * @phba: The phba to associate this trace string with for retrieval.
|
| 1866 | * @fmt: Format string to be displayed when dumping the log.
|
| 1867 | * @data1: 1st data parameter to be applied to @fmt.
|
| 1868 | * @data2: 2nd data parameter to be applied to @fmt.
|
| 1869 | * @data3: 3rd data parameter to be applied to @fmt.
|
| 1870 | *
|
| 1871 | * Description:
|
| 1872 | * This routine is used by the driver code to add a debugfs log entry to the
|
| 1873 | * nvme trace buffer associated with @phba. @fmt, @data1, @data2, and
|
| 1874 | * @data3 are used like printf when displaying the log.
|
| 1875 | *
|
| 1876 | inline void
|
| 1877 | lpfc_debugfs_nvme_trc(struct lpfc_hba *phba, char *fmt,
|
| 1878 | uint16_t data1, uint16_t data2, uint32_t data3)
|
| 1879 | {
|
| 1880 | #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
|
| 1881 | struct lpfc_debugfs_nvmeio_trc *dtp;
|
| 1882 | int index;
|
| 1883 |
|
| 1884 | if (!phba->nvmeio_trc_on || !phba->nvmeio_trc)
|
| 1885 | return;
|
| 1886 |
|
| 1887 | index = atomic_inc_return(&phba->nvmeio_trc_cnt) &
|
| 1888 | (phba->nvmeio_trc_size - 1);
|
| 1889 | dtp = phba->nvmeio_trc + index;
|
| 1890 | dtp->fmt = fmt;
|
| 1891 | dtp->data1 = data1;
|
| 1892 | dtp->data2 = data2;
|
| 1893 | dtp->data3 = data3;
|
| 1894 | #endif
|
| 1895 | }
|
| 1896 |
|
| 1897 | #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
|
| 1898 | |
| 1899 | * lpfc_debugfs_disc_trc_open - Open the discovery trace log
|
| 1900 | * @inode: The inode pointer that contains a vport pointer.
|
| 1901 | * @file: The file pointer to attach the log output.
|
| 1902 | *
|
| 1903 | * Description:
|
| 1904 | * This routine is the entry point for the debugfs open file operation. It gets
|
| 1905 | * the vport from the i_private field in @inode, allocates the necessary buffer
|
| 1906 | * for the log, fills the buffer from the in-memory log for this vport, and then
|
| 1907 | * returns a pointer to that log in the private_data field in @file.
|
| 1908 | *
|
| 1909 | * Returns:
|
| 1910 | * This function returns zero if successful. On error it will return a negative
|
| 1911 | * error value.
|
| 1912 | *
|
| 1913 | static int
|
| 1914 | lpfc_debugfs_disc_trc_open(struct inode *inode, struct file *file)
|
| 1915 | {
|
| 1916 | struct lpfc_vport *vport = inode->i_private;
|
| 1917 | struct lpfc_debug *debug;
|
| 1918 | int size;
|
| 1919 | int rc = -ENOMEM;
|
| 1920 |
|
| 1921 | if (!lpfc_debugfs_max_disc_trc) {
|
| 1922 | rc = -ENOSPC;
|
| 1923 | goto out;
|
| 1924 | }
|
| 1925 |
|
| 1926 | debug = kmalloc_obj(*debug);
|
| 1927 | if (!debug)
|
| 1928 | goto out;
|
| 1929 |
|
| 1930 |
|
| 1931 | size = (lpfc_debugfs_max_disc_trc * LPFC_DEBUG_TRC_ENTRY_SIZE);
|
| 1932 | size = PAGE_ALIGN(size);
|
| 1933 |
|
| 1934 | debug->buffer = kmalloc(size, GFP_KERNEL);
|
| 1935 | if (!debug->buffer) {
|
| 1936 | kfree(debug);
|
| 1937 | goto out;
|
| 1938 | }
|
| 1939 |
|
| 1940 | debug->len = lpfc_debugfs_disc_trc_data(vport, debug->buffer, size);
|
| 1941 | file->private_data = debug;
|
| 1942 |
|
| 1943 | rc = 0;
|
| 1944 | out:
|
| 1945 | return rc;
|
| 1946 | }
|
| 1947 |
|
| 1948 | |
| 1949 | * lpfc_debugfs_slow_ring_trc_open - Open the Slow Ring trace log
|
| 1950 | * @inode: The inode pointer that contains a vport pointer.
|
| 1951 | * @file: The file pointer to attach the log output.
|
| 1952 | *
|
| 1953 | * Description:
|
| 1954 | * This routine is the entry point for the debugfs open file operation. It gets
|
| 1955 | * the vport from the i_private field in @inode, allocates the necessary buffer
|
| 1956 | * for the log, fills the buffer from the in-memory log for this vport, and then
|
| 1957 | * returns a pointer to that log in the private_data field in @file.
|
| 1958 | *
|
| 1959 | * Returns:
|
| 1960 | * This function returns zero if successful. On error it will return a negative
|
| 1961 | * error value.
|
| 1962 | *
|
| 1963 | static int
|
| 1964 | lpfc_debugfs_slow_ring_trc_open(struct inode *inode, struct file *file)
|
| 1965 | {
|
| 1966 | struct lpfc_hba *phba = inode->i_private;
|
| 1967 | struct lpfc_debug *debug;
|
| 1968 | int size;
|
| 1969 | int rc = -ENOMEM;
|
| 1970 |
|
| 1971 | if (!lpfc_debugfs_max_slow_ring_trc) {
|
| 1972 | rc = -ENOSPC;
|
| 1973 | goto out;
|
| 1974 | }
|
| 1975 |
|
| 1976 | debug = kmalloc_obj(*debug);
|
| 1977 | if (!debug)
|
| 1978 | goto out;
|
| 1979 |
|
| 1980 |
|
| 1981 | size = (lpfc_debugfs_max_slow_ring_trc * LPFC_DEBUG_TRC_ENTRY_SIZE);
|
| 1982 | size = PAGE_ALIGN(size);
|
| 1983 |
|
| 1984 | debug->buffer = kmalloc(size, GFP_KERNEL);
|
| 1985 | if (!debug->buffer) {
|
| 1986 | kfree(debug);
|
| 1987 | goto out;
|
| 1988 | }
|
| 1989 |
|
| 1990 | debug->len = lpfc_debugfs_slow_ring_trc_data(phba, debug->buffer, size);
|
| 1991 | file->private_data = debug;
|
| 1992 |
|
| 1993 | rc = 0;
|
| 1994 | out:
|
| 1995 | return rc;
|
| 1996 | }
|
| 1997 |
|
| 1998 | |
| 1999 | * lpfc_debugfs_hbqinfo_open - Open the hbqinfo debugfs buffer
|
| 2000 | * @inode: The inode pointer that contains a vport pointer.
|
| 2001 | * @file: The file pointer to attach the log output.
|
| 2002 | *
|
| 2003 | * Description:
|
| 2004 | * This routine is the entry point for the debugfs open file operation. It gets
|
| 2005 | * the vport from the i_private field in @inode, allocates the necessary buffer
|
| 2006 | * for the log, fills the buffer from the in-memory log for this vport, and then
|
| 2007 | * returns a pointer to that log in the private_data field in @file.
|
| 2008 | *
|
| 2009 | * Returns:
|
| 2010 | * This function returns zero if successful. On error it will return a negative
|
| 2011 | * error value.
|
| 2012 | *
|
| 2013 | static int
|
| 2014 | lpfc_debugfs_hbqinfo_open(struct inode *inode, struct file *file)
|
| 2015 | {
|
| 2016 | struct lpfc_hba *phba = inode->i_private;
|
| 2017 | struct lpfc_debug *debug;
|
| 2018 | int rc = -ENOMEM;
|
| 2019 |
|
| 2020 | debug = kmalloc_obj(*debug);
|
| 2021 | if (!debug)
|
| 2022 | goto out;
|
| 2023 |
|
| 2024 |
|
| 2025 | debug->buffer = kmalloc(LPFC_HBQINFO_SIZE, GFP_KERNEL);
|
| 2026 | if (!debug->buffer) {
|
| 2027 | kfree(debug);
|
| 2028 | goto out;
|
| 2029 | }
|
| 2030 |
|
| 2031 | debug->len = lpfc_debugfs_hbqinfo_data(phba, debug->buffer,
|
| 2032 | LPFC_HBQINFO_SIZE);
|
| 2033 | file->private_data = debug;
|
| 2034 |
|
| 2035 | rc = 0;
|
| 2036 | out:
|
| 2037 | return rc;
|
| 2038 | }
|
| 2039 |
|
| 2040 | |
| 2041 | * lpfc_debugfs_multixripools_open - Open the multixripool debugfs buffer
|
| 2042 | * @inode: The inode pointer that contains a hba pointer.
|
| 2043 | * @file: The file pointer to attach the log output.
|
| 2044 | *
|
| 2045 | * Description:
|
| 2046 | * This routine is the entry point for the debugfs open file operation. It gets
|
| 2047 | * the hba from the i_private field in @inode, allocates the necessary buffer
|
| 2048 | * for the log, fills the buffer from the in-memory log for this hba, and then
|
| 2049 | * returns a pointer to that log in the private_data field in @file.
|
| 2050 | *
|
| 2051 | * Returns:
|
| 2052 | * This function returns zero if successful. On error it will return a negative
|
| 2053 | * error value.
|
| 2054 | *
|
| 2055 | static int
|
| 2056 | lpfc_debugfs_multixripools_open(struct inode *inode, struct file *file)
|
| 2057 | {
|
| 2058 | struct lpfc_hba *phba = inode->i_private;
|
| 2059 | struct lpfc_debug *debug;
|
| 2060 | int rc = -ENOMEM;
|
| 2061 |
|
| 2062 | debug = kmalloc_obj(*debug);
|
| 2063 | if (!debug)
|
| 2064 | goto out;
|
| 2065 |
|
| 2066 |
|
| 2067 | debug->buffer = kzalloc(LPFC_DUMP_MULTIXRIPOOL_SIZE, GFP_KERNEL);
|
| 2068 | if (!debug->buffer) {
|
| 2069 | kfree(debug);
|
| 2070 | goto out;
|
| 2071 | }
|
| 2072 |
|
| 2073 | debug->len = lpfc_debugfs_multixripools_data(
|
| 2074 | phba, debug->buffer, LPFC_DUMP_MULTIXRIPOOL_SIZE);
|
| 2075 |
|
| 2076 | debug->i_private = inode->i_private;
|
| 2077 | file->private_data = debug;
|
| 2078 |
|
| 2079 | rc = 0;
|
| 2080 | out:
|
| 2081 | return rc;
|
| 2082 | }
|
| 2083 |
|
| 2084 | #ifdef LPFC_HDWQ_LOCK_STAT
|
| 2085 | |
| 2086 | * lpfc_debugfs_lockstat_open - Open the lockstat debugfs buffer
|
| 2087 | * @inode: The inode pointer that contains a vport pointer.
|
| 2088 | * @file: The file pointer to attach the log output.
|
| 2089 | *
|
| 2090 | * Description:
|
| 2091 | * This routine is the entry point for the debugfs open file operation. It gets
|
| 2092 | * the vport from the i_private field in @inode, allocates the necessary buffer
|
| 2093 | * for the log, fills the buffer from the in-memory log for this vport, and then
|
| 2094 | * returns a pointer to that log in the private_data field in @file.
|
| 2095 | *
|
| 2096 | * Returns:
|
| 2097 | * This function returns zero if successful. On error it will return a negative
|
| 2098 | * error value.
|
| 2099 | *
|
| 2100 | static int
|
| 2101 | lpfc_debugfs_lockstat_open(struct inode *inode, struct file *file)
|
| 2102 | {
|
| 2103 | struct lpfc_hba *phba = inode->i_private;
|
| 2104 | struct lpfc_debug *debug;
|
| 2105 | int rc = -ENOMEM;
|
| 2106 |
|
| 2107 | debug = kmalloc_obj(*debug);
|
| 2108 | if (!debug)
|
| 2109 | goto out;
|
| 2110 |
|
| 2111 |
|
| 2112 | debug->buffer = kmalloc(LPFC_HDWQINFO_SIZE, GFP_KERNEL);
|
| 2113 | if (!debug->buffer) {
|
| 2114 | kfree(debug);
|
| 2115 | goto out;
|
| 2116 | }
|
| 2117 |
|
| 2118 | debug->len = lpfc_debugfs_lockstat_data(phba, debug->buffer,
|
| 2119 | LPFC_HBQINFO_SIZE);
|
| 2120 | file->private_data = debug;
|
| 2121 |
|
| 2122 | rc = 0;
|
| 2123 | out:
|
| 2124 | return rc;
|
| 2125 | }
|
| 2126 |
|
| 2127 | static ssize_t
|
| 2128 | lpfc_debugfs_lockstat_write(struct file *file, const char __user *buf,
|
| 2129 | size_t nbytes, loff_t *ppos)
|
| 2130 | {
|
| 2131 | struct lpfc_debug *debug = file->private_data;
|
| 2132 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 2133 | struct lpfc_sli4_hdw_queue *qp;
|
| 2134 | char mybuf[64];
|
| 2135 | char *pbuf;
|
| 2136 | int i;
|
| 2137 | size_t bsize;
|
| 2138 |
|
| 2139 | memset(mybuf, 0, sizeof(mybuf));
|
| 2140 |
|
| 2141 | bsize = min(nbytes, (sizeof(mybuf) - 1));
|
| 2142 |
|
| 2143 | if (copy_from_user(mybuf, buf, bsize))
|
| 2144 | return -EFAULT;
|
| 2145 | pbuf = &mybuf[0];
|
| 2146 |
|
| 2147 | if ((strncmp(pbuf, "reset", strlen("reset")) == 0) ||
|
| 2148 | (strncmp(pbuf, "zero", strlen("zero")) == 0)) {
|
| 2149 | for (i = 0; i < phba->cfg_hdw_queue; i++) {
|
| 2150 | qp = &phba->sli4_hba.hdwq[i];
|
| 2151 | qp->lock_conflict.alloc_xri_get = 0;
|
| 2152 | qp->lock_conflict.alloc_xri_put = 0;
|
| 2153 | qp->lock_conflict.free_xri = 0;
|
| 2154 | qp->lock_conflict.wq_access = 0;
|
| 2155 | qp->lock_conflict.alloc_pvt_pool = 0;
|
| 2156 | qp->lock_conflict.mv_from_pvt_pool = 0;
|
| 2157 | qp->lock_conflict.mv_to_pub_pool = 0;
|
| 2158 | qp->lock_conflict.mv_to_pvt_pool = 0;
|
| 2159 | qp->lock_conflict.free_pvt_pool = 0;
|
| 2160 | qp->lock_conflict.free_pub_pool = 0;
|
| 2161 | qp->lock_conflict.wq_access = 0;
|
| 2162 | }
|
| 2163 | }
|
| 2164 | return bsize;
|
| 2165 | }
|
| 2166 | #endif
|
| 2167 |
|
| 2168 | static int lpfc_debugfs_ras_log_data(struct lpfc_hba *phba,
|
| 2169 | char *buffer, int size)
|
| 2170 | {
|
| 2171 | int copied = 0;
|
| 2172 | struct lpfc_dmabuf *dmabuf, *next;
|
| 2173 |
|
| 2174 | memset(buffer, 0, size);
|
| 2175 |
|
| 2176 | spin_lock_irq(&phba->ras_fwlog_lock);
|
| 2177 | if (phba->ras_fwlog.state != ACTIVE) {
|
| 2178 | spin_unlock_irq(&phba->ras_fwlog_lock);
|
| 2179 | return -EINVAL;
|
| 2180 | }
|
| 2181 | spin_unlock_irq(&phba->ras_fwlog_lock);
|
| 2182 |
|
| 2183 | list_for_each_entry_safe(dmabuf, next,
|
| 2184 | &phba->ras_fwlog.fwlog_buff_list, list) {
|
| 2185 |
|
| 2186 | if ((copied + LPFC_RAS_MAX_ENTRY_SIZE) >= (size - 1)) {
|
| 2187 | memcpy(buffer + copied, dmabuf->virt,
|
| 2188 | size - copied - 1);
|
| 2189 | copied += size - copied - 1;
|
| 2190 | break;
|
| 2191 | }
|
| 2192 | memcpy(buffer + copied, dmabuf->virt, LPFC_RAS_MAX_ENTRY_SIZE);
|
| 2193 | copied += LPFC_RAS_MAX_ENTRY_SIZE;
|
| 2194 | }
|
| 2195 | return copied;
|
| 2196 | }
|
| 2197 |
|
| 2198 | static int
|
| 2199 | lpfc_debugfs_ras_log_release(struct inode *inode, struct file *file)
|
| 2200 | {
|
| 2201 | struct lpfc_debug *debug = file->private_data;
|
| 2202 |
|
| 2203 | vfree(debug->buffer);
|
| 2204 | kfree(debug);
|
| 2205 |
|
| 2206 | return 0;
|
| 2207 | }
|
| 2208 |
|
| 2209 | |
| 2210 | * lpfc_debugfs_ras_log_open - Open the RAS log debugfs buffer
|
| 2211 | * @inode: The inode pointer that contains a vport pointer.
|
| 2212 | * @file: The file pointer to attach the log output.
|
| 2213 | *
|
| 2214 | * Description:
|
| 2215 | * This routine is the entry point for the debugfs open file operation. It gets
|
| 2216 | * the vport from the i_private field in @inode, allocates the necessary buffer
|
| 2217 | * for the log, fills the buffer from the in-memory log for this vport, and then
|
| 2218 | * returns a pointer to that log in the private_data field in @file.
|
| 2219 | *
|
| 2220 | * Returns:
|
| 2221 | * This function returns zero if successful. On error it will return a negative
|
| 2222 | * error value.
|
| 2223 | *
|
| 2224 | static int
|
| 2225 | lpfc_debugfs_ras_log_open(struct inode *inode, struct file *file)
|
| 2226 | {
|
| 2227 | struct lpfc_hba *phba = inode->i_private;
|
| 2228 | struct lpfc_debug *debug;
|
| 2229 | int size;
|
| 2230 | int rc = -ENOMEM;
|
| 2231 |
|
| 2232 | spin_lock_irq(&phba->ras_fwlog_lock);
|
| 2233 | if (phba->ras_fwlog.state != ACTIVE) {
|
| 2234 | spin_unlock_irq(&phba->ras_fwlog_lock);
|
| 2235 | rc = -EINVAL;
|
| 2236 | goto out;
|
| 2237 | }
|
| 2238 | spin_unlock_irq(&phba->ras_fwlog_lock);
|
| 2239 |
|
| 2240 | if (check_mul_overflow(LPFC_RAS_MIN_BUFF_POST_SIZE,
|
| 2241 | phba->cfg_ras_fwlog_buffsize, &size))
|
| 2242 | goto out;
|
| 2243 |
|
| 2244 | debug = kzalloc_obj(*debug);
|
| 2245 | if (!debug)
|
| 2246 | goto out;
|
| 2247 |
|
| 2248 | debug->buffer = vmalloc(size);
|
| 2249 | if (!debug->buffer)
|
| 2250 | goto free_debug;
|
| 2251 |
|
| 2252 | debug->len = lpfc_debugfs_ras_log_data(phba, debug->buffer, size);
|
| 2253 | if (debug->len < 0) {
|
| 2254 | rc = -EINVAL;
|
| 2255 | goto free_buffer;
|
| 2256 | }
|
| 2257 | file->private_data = debug;
|
| 2258 |
|
| 2259 | return 0;
|
| 2260 |
|
| 2261 | free_buffer:
|
| 2262 | vfree(debug->buffer);
|
| 2263 | free_debug:
|
| 2264 | kfree(debug);
|
| 2265 | out:
|
| 2266 | return rc;
|
| 2267 | }
|
| 2268 |
|
| 2269 | |
| 2270 | * lpfc_debugfs_dumpHBASlim_open - Open the Dump HBA SLIM debugfs buffer
|
| 2271 | * @inode: The inode pointer that contains a vport pointer.
|
| 2272 | * @file: The file pointer to attach the log output.
|
| 2273 | *
|
| 2274 | * Description:
|
| 2275 | * This routine is the entry point for the debugfs open file operation. It gets
|
| 2276 | * the vport from the i_private field in @inode, allocates the necessary buffer
|
| 2277 | * for the log, fills the buffer from the in-memory log for this vport, and then
|
| 2278 | * returns a pointer to that log in the private_data field in @file.
|
| 2279 | *
|
| 2280 | * Returns:
|
| 2281 | * This function returns zero if successful. On error it will return a negative
|
| 2282 | * error value.
|
| 2283 | *
|
| 2284 | static int
|
| 2285 | lpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file)
|
| 2286 | {
|
| 2287 | struct lpfc_hba *phba = inode->i_private;
|
| 2288 | struct lpfc_debug *debug;
|
| 2289 | int rc = -ENOMEM;
|
| 2290 |
|
| 2291 | debug = kmalloc_obj(*debug);
|
| 2292 | if (!debug)
|
| 2293 | goto out;
|
| 2294 |
|
| 2295 |
|
| 2296 | debug->buffer = kmalloc(LPFC_DUMPHBASLIM_SIZE, GFP_KERNEL);
|
| 2297 | if (!debug->buffer) {
|
| 2298 | kfree(debug);
|
| 2299 | goto out;
|
| 2300 | }
|
| 2301 |
|
| 2302 | debug->len = lpfc_debugfs_dumpHBASlim_data(phba, debug->buffer,
|
| 2303 | LPFC_DUMPHBASLIM_SIZE);
|
| 2304 | file->private_data = debug;
|
| 2305 |
|
| 2306 | rc = 0;
|
| 2307 | out:
|
| 2308 | return rc;
|
| 2309 | }
|
| 2310 |
|
| 2311 | |
| 2312 | * lpfc_debugfs_dumpHostSlim_open - Open the Dump Host SLIM debugfs buffer
|
| 2313 | * @inode: The inode pointer that contains a vport pointer.
|
| 2314 | * @file: The file pointer to attach the log output.
|
| 2315 | *
|
| 2316 | * Description:
|
| 2317 | * This routine is the entry point for the debugfs open file operation. It gets
|
| 2318 | * the vport from the i_private field in @inode, allocates the necessary buffer
|
| 2319 | * for the log, fills the buffer from the in-memory log for this vport, and then
|
| 2320 | * returns a pointer to that log in the private_data field in @file.
|
| 2321 | *
|
| 2322 | * Returns:
|
| 2323 | * This function returns zero if successful. On error it will return a negative
|
| 2324 | * error value.
|
| 2325 | *
|
| 2326 | static int
|
| 2327 | lpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file)
|
| 2328 | {
|
| 2329 | struct lpfc_hba *phba = inode->i_private;
|
| 2330 | struct lpfc_debug *debug;
|
| 2331 | int rc = -ENOMEM;
|
| 2332 |
|
| 2333 | debug = kmalloc_obj(*debug);
|
| 2334 | if (!debug)
|
| 2335 | goto out;
|
| 2336 |
|
| 2337 |
|
| 2338 | debug->buffer = kmalloc(LPFC_DUMPHOSTSLIM_SIZE, GFP_KERNEL);
|
| 2339 | if (!debug->buffer) {
|
| 2340 | kfree(debug);
|
| 2341 | goto out;
|
| 2342 | }
|
| 2343 |
|
| 2344 | debug->len = lpfc_debugfs_dumpHostSlim_data(phba, debug->buffer,
|
| 2345 | LPFC_DUMPHOSTSLIM_SIZE);
|
| 2346 | file->private_data = debug;
|
| 2347 |
|
| 2348 | rc = 0;
|
| 2349 | out:
|
| 2350 | return rc;
|
| 2351 | }
|
| 2352 |
|
| 2353 | static ssize_t
|
| 2354 | lpfc_debugfs_dif_err_read(struct file *file, char __user *buf,
|
| 2355 | size_t nbytes, loff_t *ppos)
|
| 2356 | {
|
| 2357 | struct lpfc_hba *phba = file->private_data;
|
| 2358 | int kind = debugfs_get_aux_num(file);
|
| 2359 | char cbuf[32] = {0};
|
| 2360 | int cnt = 0;
|
| 2361 |
|
| 2362 | switch (kind) {
|
| 2363 | case writeGuard:
|
| 2364 | cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n",
|
| 2365 | phba->lpfc_injerr_wgrd_cnt);
|
| 2366 | break;
|
| 2367 | case writeApp:
|
| 2368 | cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n",
|
| 2369 | phba->lpfc_injerr_wapp_cnt);
|
| 2370 | break;
|
| 2371 | case writeRef:
|
| 2372 | cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n",
|
| 2373 | phba->lpfc_injerr_wref_cnt);
|
| 2374 | break;
|
| 2375 | case readGuard:
|
| 2376 | cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n",
|
| 2377 | phba->lpfc_injerr_rgrd_cnt);
|
| 2378 | break;
|
| 2379 | case readApp:
|
| 2380 | cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n",
|
| 2381 | phba->lpfc_injerr_rapp_cnt);
|
| 2382 | break;
|
| 2383 | case readRef:
|
| 2384 | cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n",
|
| 2385 | phba->lpfc_injerr_rref_cnt);
|
| 2386 | break;
|
| 2387 | case InjErrNPortID:
|
| 2388 | cnt = scnprintf(cbuf, sizeof(cbuf), "0x%06x\n",
|
| 2389 | phba->lpfc_injerr_nportid);
|
| 2390 | break;
|
| 2391 | case InjErrWWPN:
|
| 2392 | cnt = scnprintf(cbuf, sizeof(cbuf), "0x%016llx\n",
|
| 2393 | be64_to_cpu(phba->lpfc_injerr_wwpn.u.wwn_be));
|
| 2394 | break;
|
| 2395 | case InjErrLBA:
|
| 2396 | if (phba->lpfc_injerr_lba == LPFC_INJERR_LBA_OFF)
|
| 2397 | cnt = scnprintf(cbuf, sizeof(cbuf), "off\n");
|
| 2398 | else
|
| 2399 | cnt = scnprintf(cbuf, sizeof(cbuf), "0x%llx\n",
|
| 2400 | (uint64_t)phba->lpfc_injerr_lba);
|
| 2401 | break;
|
| 2402 | default:
|
| 2403 | lpfc_log_msg(phba, KERN_WARNING, LOG_INIT,
|
| 2404 | "0547 Unknown debugfs error injection entry\n");
|
| 2405 | break;
|
| 2406 | }
|
| 2407 |
|
| 2408 | return simple_read_from_buffer(buf, nbytes, ppos, &cbuf, cnt);
|
| 2409 | }
|
| 2410 |
|
| 2411 | static ssize_t
|
| 2412 | lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf,
|
| 2413 | size_t nbytes, loff_t *ppos)
|
| 2414 | {
|
| 2415 | struct lpfc_hba *phba = file->private_data;
|
| 2416 | int kind = debugfs_get_aux_num(file);
|
| 2417 | char dstbuf[33] = {0};
|
| 2418 | unsigned long long tmp;
|
| 2419 | unsigned long size;
|
| 2420 |
|
| 2421 | size = (nbytes < (sizeof(dstbuf) - 1)) ? nbytes : (sizeof(dstbuf) - 1);
|
| 2422 | if (copy_from_user(dstbuf, buf, size))
|
| 2423 | return -EFAULT;
|
| 2424 |
|
| 2425 | if (kstrtoull(dstbuf, 0, &tmp)) {
|
| 2426 | if (kind != InjErrLBA || !strstr(dstbuf, "off"))
|
| 2427 | return -EINVAL;
|
| 2428 | }
|
| 2429 |
|
| 2430 | switch (kind) {
|
| 2431 | case writeGuard:
|
| 2432 | phba->lpfc_injerr_wgrd_cnt = (uint32_t)tmp;
|
| 2433 | break;
|
| 2434 | case writeApp:
|
| 2435 | phba->lpfc_injerr_wapp_cnt = (uint32_t)tmp;
|
| 2436 | break;
|
| 2437 | case writeRef:
|
| 2438 | phba->lpfc_injerr_wref_cnt = (uint32_t)tmp;
|
| 2439 | break;
|
| 2440 | case readGuard:
|
| 2441 | phba->lpfc_injerr_rgrd_cnt = (uint32_t)tmp;
|
| 2442 | break;
|
| 2443 | case readApp:
|
| 2444 | phba->lpfc_injerr_rapp_cnt = (uint32_t)tmp;
|
| 2445 | break;
|
| 2446 | case readRef:
|
| 2447 | phba->lpfc_injerr_rref_cnt = (uint32_t)tmp;
|
| 2448 | break;
|
| 2449 | case InjErrLBA:
|
| 2450 | if (strstr(dstbuf, "off"))
|
| 2451 | phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
|
| 2452 | else
|
| 2453 | phba->lpfc_injerr_lba = (sector_t)tmp;
|
| 2454 | break;
|
| 2455 | case InjErrNPortID:
|
| 2456 | phba->lpfc_injerr_nportid = (uint32_t)(tmp & Mask_DID);
|
| 2457 | break;
|
| 2458 | case InjErrWWPN:
|
| 2459 | phba->lpfc_injerr_wwpn.u.wwn_be = cpu_to_be64(tmp);
|
| 2460 | break;
|
| 2461 | default:
|
| 2462 | lpfc_log_msg(phba, KERN_WARNING, LOG_INIT,
|
| 2463 | "0548 Unknown debugfs error injection entry\n");
|
| 2464 | break;
|
| 2465 | }
|
| 2466 | return nbytes;
|
| 2467 | }
|
| 2468 |
|
| 2469 | static int
|
| 2470 | lpfc_debugfs_dif_err_release(struct inode *inode, struct file *file)
|
| 2471 | {
|
| 2472 | return 0;
|
| 2473 | }
|
| 2474 |
|
| 2475 | |
| 2476 | * lpfc_debugfs_nodelist_open - Open the nodelist debugfs file
|
| 2477 | * @inode: The inode pointer that contains a vport pointer.
|
| 2478 | * @file: The file pointer to attach the log output.
|
| 2479 | *
|
| 2480 | * Description:
|
| 2481 | * This routine is the entry point for the debugfs open file operation. It gets
|
| 2482 | * the vport from the i_private field in @inode, allocates the necessary buffer
|
| 2483 | * for the log, fills the buffer from the in-memory log for this vport, and then
|
| 2484 | * returns a pointer to that log in the private_data field in @file.
|
| 2485 | *
|
| 2486 | * Returns:
|
| 2487 | * This function returns zero if successful. On error it will return a negative
|
| 2488 | * error value.
|
| 2489 | *
|
| 2490 | static int
|
| 2491 | lpfc_debugfs_nodelist_open(struct inode *inode, struct file *file)
|
| 2492 | {
|
| 2493 | struct lpfc_vport *vport = inode->i_private;
|
| 2494 | struct lpfc_debug *debug;
|
| 2495 | int rc = -ENOMEM;
|
| 2496 |
|
| 2497 | debug = kmalloc_obj(*debug);
|
| 2498 | if (!debug)
|
| 2499 | goto out;
|
| 2500 |
|
| 2501 |
|
| 2502 | debug->buffer = kmalloc(LPFC_NODELIST_SIZE, GFP_KERNEL);
|
| 2503 | if (!debug->buffer) {
|
| 2504 | kfree(debug);
|
| 2505 | goto out;
|
| 2506 | }
|
| 2507 |
|
| 2508 | debug->len = lpfc_debugfs_nodelist_data(vport, debug->buffer,
|
| 2509 | LPFC_NODELIST_SIZE);
|
| 2510 | file->private_data = debug;
|
| 2511 |
|
| 2512 | rc = 0;
|
| 2513 | out:
|
| 2514 | return rc;
|
| 2515 | }
|
| 2516 |
|
| 2517 | |
| 2518 | * lpfc_debugfs_lseek - Seek through a debugfs file
|
| 2519 | * @file: The file pointer to seek through.
|
| 2520 | * @off: The offset to seek to or the amount to seek by.
|
| 2521 | * @whence: Indicates how to seek.
|
| 2522 | *
|
| 2523 | * Description:
|
| 2524 | * This routine is the entry point for the debugfs lseek file operation. The
|
| 2525 | * @whence parameter indicates whether @off is the offset to directly seek to,
|
| 2526 | * or if it is a value to seek forward or reverse by. This function figures out
|
| 2527 | * what the new offset of the debugfs file will be and assigns that value to the
|
| 2528 | * f_pos field of @file.
|
| 2529 | *
|
| 2530 | * Returns:
|
| 2531 | * This function returns the new offset if successful and returns a negative
|
| 2532 | * error if unable to process the seek.
|
| 2533 | *
|
| 2534 | static loff_t
|
| 2535 | lpfc_debugfs_lseek(struct file *file, loff_t off, int whence)
|
| 2536 | {
|
| 2537 | struct lpfc_debug *debug = file->private_data;
|
| 2538 | return fixed_size_llseek(file, off, whence, debug->len);
|
| 2539 | }
|
| 2540 |
|
| 2541 | |
| 2542 | * lpfc_debugfs_read - Read a debugfs file
|
| 2543 | * @file: The file pointer to read from.
|
| 2544 | * @buf: The buffer to copy the data to.
|
| 2545 | * @nbytes: The number of bytes to read.
|
| 2546 | * @ppos: The position in the file to start reading from.
|
| 2547 | *
|
| 2548 | * Description:
|
| 2549 | * This routine reads data from from the buffer indicated in the private_data
|
| 2550 | * field of @file. It will start reading at @ppos and copy up to @nbytes of
|
| 2551 | * data to @buf.
|
| 2552 | *
|
| 2553 | * Returns:
|
| 2554 | * This function returns the amount of data that was read (this could be less
|
| 2555 | * than @nbytes if the end of the file was reached) or a negative error value.
|
| 2556 | *
|
| 2557 | static ssize_t
|
| 2558 | lpfc_debugfs_read(struct file *file, char __user *buf,
|
| 2559 | size_t nbytes, loff_t *ppos)
|
| 2560 | {
|
| 2561 | struct lpfc_debug *debug = file->private_data;
|
| 2562 |
|
| 2563 | return simple_read_from_buffer(buf, nbytes, ppos, debug->buffer,
|
| 2564 | debug->len);
|
| 2565 | }
|
| 2566 |
|
| 2567 | |
| 2568 | * lpfc_debugfs_release - Release the buffer used to store debugfs file data
|
| 2569 | * @inode: The inode pointer that contains a vport pointer. (unused)
|
| 2570 | * @file: The file pointer that contains the buffer to release.
|
| 2571 | *
|
| 2572 | * Description:
|
| 2573 | * This routine frees the buffer that was allocated when the debugfs file was
|
| 2574 | * opened.
|
| 2575 | *
|
| 2576 | * Returns:
|
| 2577 | * This function returns zero.
|
| 2578 | *
|
| 2579 | static int
|
| 2580 | lpfc_debugfs_release(struct inode *inode, struct file *file)
|
| 2581 | {
|
| 2582 | struct lpfc_debug *debug = file->private_data;
|
| 2583 |
|
| 2584 | kfree(debug->buffer);
|
| 2585 | kfree(debug);
|
| 2586 |
|
| 2587 | return 0;
|
| 2588 | }
|
| 2589 |
|
| 2590 | |
| 2591 | * lpfc_debugfs_multixripools_write - Clear multi-XRI pools statistics
|
| 2592 | * @file: The file pointer to read from.
|
| 2593 | * @buf: The buffer to copy the user data from.
|
| 2594 | * @nbytes: The number of bytes to get.
|
| 2595 | * @ppos: The position in the file to start reading from.
|
| 2596 | *
|
| 2597 | * Description:
|
| 2598 | * This routine clears multi-XRI pools statistics when buf contains "clear".
|
| 2599 | *
|
| 2600 | * Return Value:
|
| 2601 | * It returns the @nbytges passing in from debugfs user space when successful.
|
| 2602 | * In case of error conditions, it returns proper error code back to the user
|
| 2603 | * space.
|
| 2604 | *
|
| 2605 | static ssize_t
|
| 2606 | lpfc_debugfs_multixripools_write(struct file *file, const char __user *buf,
|
| 2607 | size_t nbytes, loff_t *ppos)
|
| 2608 | {
|
| 2609 | struct lpfc_debug *debug = file->private_data;
|
| 2610 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 2611 | char mybuf[64];
|
| 2612 | char *pbuf;
|
| 2613 | u32 i;
|
| 2614 | u32 hwq_count;
|
| 2615 | struct lpfc_sli4_hdw_queue *qp;
|
| 2616 | struct lpfc_multixri_pool *multixri_pool;
|
| 2617 |
|
| 2618 | if (nbytes > sizeof(mybuf) - 1)
|
| 2619 | nbytes = sizeof(mybuf) - 1;
|
| 2620 |
|
| 2621 | memset(mybuf, 0, sizeof(mybuf));
|
| 2622 |
|
| 2623 | if (copy_from_user(mybuf, buf, nbytes))
|
| 2624 | return -EFAULT;
|
| 2625 | pbuf = &mybuf[0];
|
| 2626 |
|
| 2627 | if ((strncmp(pbuf, "clear", strlen("clear"))) == 0) {
|
| 2628 | hwq_count = phba->cfg_hdw_queue;
|
| 2629 | for (i = 0; i < hwq_count; i++) {
|
| 2630 | qp = &phba->sli4_hba.hdwq[i];
|
| 2631 | multixri_pool = qp->p_multixri_pool;
|
| 2632 | if (!multixri_pool)
|
| 2633 | continue;
|
| 2634 |
|
| 2635 | qp->empty_io_bufs = 0;
|
| 2636 | multixri_pool->pbl_empty_count = 0;
|
| 2637 | #ifdef LPFC_MXP_STAT
|
| 2638 | multixri_pool->above_limit_count = 0;
|
| 2639 | multixri_pool->below_limit_count = 0;
|
| 2640 | multixri_pool->stat_max_hwm = 0;
|
| 2641 | multixri_pool->local_pbl_hit_count = 0;
|
| 2642 | multixri_pool->other_pbl_hit_count = 0;
|
| 2643 |
|
| 2644 | multixri_pool->stat_pbl_count = 0;
|
| 2645 | multixri_pool->stat_pvt_count = 0;
|
| 2646 | multixri_pool->stat_busy_count = 0;
|
| 2647 | multixri_pool->stat_snapshot_taken = 0;
|
| 2648 | #endif
|
| 2649 | }
|
| 2650 | return strlen(pbuf);
|
| 2651 | }
|
| 2652 |
|
| 2653 | return -EINVAL;
|
| 2654 | }
|
| 2655 |
|
| 2656 | static int
|
| 2657 | lpfc_debugfs_nvmestat_open(struct inode *inode, struct file *file)
|
| 2658 | {
|
| 2659 | struct lpfc_vport *vport = inode->i_private;
|
| 2660 | struct lpfc_debug *debug;
|
| 2661 | int rc = -ENOMEM;
|
| 2662 |
|
| 2663 | debug = kmalloc_obj(*debug);
|
| 2664 | if (!debug)
|
| 2665 | goto out;
|
| 2666 |
|
| 2667 |
|
| 2668 | debug->buffer = kmalloc(LPFC_NVMESTAT_SIZE, GFP_KERNEL);
|
| 2669 | if (!debug->buffer) {
|
| 2670 | kfree(debug);
|
| 2671 | goto out;
|
| 2672 | }
|
| 2673 |
|
| 2674 | debug->len = lpfc_debugfs_nvmestat_data(vport, debug->buffer,
|
| 2675 | LPFC_NVMESTAT_SIZE);
|
| 2676 |
|
| 2677 | debug->i_private = inode->i_private;
|
| 2678 | file->private_data = debug;
|
| 2679 |
|
| 2680 | rc = 0;
|
| 2681 | out:
|
| 2682 | return rc;
|
| 2683 | }
|
| 2684 |
|
| 2685 | static ssize_t
|
| 2686 | lpfc_debugfs_nvmestat_write(struct file *file, const char __user *buf,
|
| 2687 | size_t nbytes, loff_t *ppos)
|
| 2688 | {
|
| 2689 | struct lpfc_debug *debug = file->private_data;
|
| 2690 | struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
|
| 2691 | struct lpfc_hba *phba = vport->phba;
|
| 2692 | struct lpfc_nvmet_tgtport *tgtp;
|
| 2693 | char mybuf[64];
|
| 2694 | char *pbuf;
|
| 2695 |
|
| 2696 | if (!phba->targetport)
|
| 2697 | return -ENXIO;
|
| 2698 |
|
| 2699 | if (nbytes > sizeof(mybuf) - 1)
|
| 2700 | nbytes = sizeof(mybuf) - 1;
|
| 2701 |
|
| 2702 | memset(mybuf, 0, sizeof(mybuf));
|
| 2703 |
|
| 2704 | if (copy_from_user(mybuf, buf, nbytes))
|
| 2705 | return -EFAULT;
|
| 2706 | pbuf = &mybuf[0];
|
| 2707 |
|
| 2708 | tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
|
| 2709 | if ((strncmp(pbuf, "reset", strlen("reset")) == 0) ||
|
| 2710 | (strncmp(pbuf, "zero", strlen("zero")) == 0)) {
|
| 2711 | atomic_set(&tgtp->rcv_ls_req_in, 0);
|
| 2712 | atomic_set(&tgtp->rcv_ls_req_out, 0);
|
| 2713 | atomic_set(&tgtp->rcv_ls_req_drop, 0);
|
| 2714 | atomic_set(&tgtp->xmt_ls_abort, 0);
|
| 2715 | atomic_set(&tgtp->xmt_ls_abort_cmpl, 0);
|
| 2716 | atomic_set(&tgtp->xmt_ls_rsp, 0);
|
| 2717 | atomic_set(&tgtp->xmt_ls_drop, 0);
|
| 2718 | atomic_set(&tgtp->xmt_ls_rsp_error, 0);
|
| 2719 | atomic_set(&tgtp->xmt_ls_rsp_cmpl, 0);
|
| 2720 |
|
| 2721 | atomic_set(&tgtp->rcv_fcp_cmd_in, 0);
|
| 2722 | atomic_set(&tgtp->rcv_fcp_cmd_out, 0);
|
| 2723 | atomic_set(&tgtp->rcv_fcp_cmd_drop, 0);
|
| 2724 | atomic_set(&tgtp->xmt_fcp_drop, 0);
|
| 2725 | atomic_set(&tgtp->xmt_fcp_read_rsp, 0);
|
| 2726 | atomic_set(&tgtp->xmt_fcp_read, 0);
|
| 2727 | atomic_set(&tgtp->xmt_fcp_write, 0);
|
| 2728 | atomic_set(&tgtp->xmt_fcp_rsp, 0);
|
| 2729 | atomic_set(&tgtp->xmt_fcp_release, 0);
|
| 2730 | atomic_set(&tgtp->xmt_fcp_rsp_cmpl, 0);
|
| 2731 | atomic_set(&tgtp->xmt_fcp_rsp_error, 0);
|
| 2732 | atomic_set(&tgtp->xmt_fcp_rsp_drop, 0);
|
| 2733 |
|
| 2734 | atomic_set(&tgtp->xmt_fcp_abort, 0);
|
| 2735 | atomic_set(&tgtp->xmt_fcp_abort_cmpl, 0);
|
| 2736 | atomic_set(&tgtp->xmt_abort_sol, 0);
|
| 2737 | atomic_set(&tgtp->xmt_abort_unsol, 0);
|
| 2738 | atomic_set(&tgtp->xmt_abort_rsp, 0);
|
| 2739 | atomic_set(&tgtp->xmt_abort_rsp_error, 0);
|
| 2740 | }
|
| 2741 | return nbytes;
|
| 2742 | }
|
| 2743 |
|
| 2744 | static int
|
| 2745 | lpfc_debugfs_scsistat_open(struct inode *inode, struct file *file)
|
| 2746 | {
|
| 2747 | struct lpfc_vport *vport = inode->i_private;
|
| 2748 | struct lpfc_debug *debug;
|
| 2749 | int rc = -ENOMEM;
|
| 2750 |
|
| 2751 | debug = kmalloc_obj(*debug);
|
| 2752 | if (!debug)
|
| 2753 | goto out;
|
| 2754 |
|
| 2755 |
|
| 2756 | debug->buffer = kzalloc(LPFC_SCSISTAT_SIZE, GFP_KERNEL);
|
| 2757 | if (!debug->buffer) {
|
| 2758 | kfree(debug);
|
| 2759 | goto out;
|
| 2760 | }
|
| 2761 |
|
| 2762 | debug->len = lpfc_debugfs_scsistat_data(vport, debug->buffer,
|
| 2763 | LPFC_SCSISTAT_SIZE);
|
| 2764 |
|
| 2765 | debug->i_private = inode->i_private;
|
| 2766 | file->private_data = debug;
|
| 2767 |
|
| 2768 | rc = 0;
|
| 2769 | out:
|
| 2770 | return rc;
|
| 2771 | }
|
| 2772 |
|
| 2773 | static ssize_t
|
| 2774 | lpfc_debugfs_scsistat_write(struct file *file, const char __user *buf,
|
| 2775 | size_t nbytes, loff_t *ppos)
|
| 2776 | {
|
| 2777 | struct lpfc_debug *debug = file->private_data;
|
| 2778 | struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
|
| 2779 | struct lpfc_hba *phba = vport->phba;
|
| 2780 | char mybuf[6] = {0};
|
| 2781 | int i;
|
| 2782 |
|
| 2783 | if (copy_from_user(mybuf, buf, (nbytes >= sizeof(mybuf)) ?
|
| 2784 | (sizeof(mybuf) - 1) : nbytes))
|
| 2785 | return -EFAULT;
|
| 2786 |
|
| 2787 | if ((strncmp(&mybuf[0], "reset", strlen("reset")) == 0) ||
|
| 2788 | (strncmp(&mybuf[0], "zero", strlen("zero")) == 0)) {
|
| 2789 | for (i = 0; i < phba->cfg_hdw_queue; i++) {
|
| 2790 | memset(&phba->sli4_hba.hdwq[i].scsi_cstat, 0,
|
| 2791 | sizeof(phba->sli4_hba.hdwq[i].scsi_cstat));
|
| 2792 | }
|
| 2793 | }
|
| 2794 |
|
| 2795 | return nbytes;
|
| 2796 | }
|
| 2797 |
|
| 2798 | static int
|
| 2799 | lpfc_debugfs_ioktime_open(struct inode *inode, struct file *file)
|
| 2800 | {
|
| 2801 | struct lpfc_vport *vport = inode->i_private;
|
| 2802 | struct lpfc_debug *debug;
|
| 2803 | int rc = -ENOMEM;
|
| 2804 |
|
| 2805 | debug = kmalloc_obj(*debug);
|
| 2806 | if (!debug)
|
| 2807 | goto out;
|
| 2808 |
|
| 2809 |
|
| 2810 | debug->buffer = kmalloc(LPFC_IOKTIME_SIZE, GFP_KERNEL);
|
| 2811 | if (!debug->buffer) {
|
| 2812 | kfree(debug);
|
| 2813 | goto out;
|
| 2814 | }
|
| 2815 |
|
| 2816 | debug->len = lpfc_debugfs_ioktime_data(vport, debug->buffer,
|
| 2817 | LPFC_IOKTIME_SIZE);
|
| 2818 |
|
| 2819 | debug->i_private = inode->i_private;
|
| 2820 | file->private_data = debug;
|
| 2821 |
|
| 2822 | rc = 0;
|
| 2823 | out:
|
| 2824 | return rc;
|
| 2825 | }
|
| 2826 |
|
| 2827 | static ssize_t
|
| 2828 | lpfc_debugfs_ioktime_write(struct file *file, const char __user *buf,
|
| 2829 | size_t nbytes, loff_t *ppos)
|
| 2830 | {
|
| 2831 | struct lpfc_debug *debug = file->private_data;
|
| 2832 | struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
|
| 2833 | struct lpfc_hba *phba = vport->phba;
|
| 2834 | char mybuf[64];
|
| 2835 | char *pbuf;
|
| 2836 |
|
| 2837 | if (nbytes > sizeof(mybuf) - 1)
|
| 2838 | nbytes = sizeof(mybuf) - 1;
|
| 2839 |
|
| 2840 | memset(mybuf, 0, sizeof(mybuf));
|
| 2841 |
|
| 2842 | if (copy_from_user(mybuf, buf, nbytes))
|
| 2843 | return -EFAULT;
|
| 2844 | pbuf = &mybuf[0];
|
| 2845 |
|
| 2846 | if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) {
|
| 2847 | phba->ktime_data_samples = 0;
|
| 2848 | phba->ktime_status_samples = 0;
|
| 2849 | phba->ktime_seg1_total = 0;
|
| 2850 | phba->ktime_seg1_max = 0;
|
| 2851 | phba->ktime_seg1_min = 0xffffffff;
|
| 2852 | phba->ktime_seg2_total = 0;
|
| 2853 | phba->ktime_seg2_max = 0;
|
| 2854 | phba->ktime_seg2_min = 0xffffffff;
|
| 2855 | phba->ktime_seg3_total = 0;
|
| 2856 | phba->ktime_seg3_max = 0;
|
| 2857 | phba->ktime_seg3_min = 0xffffffff;
|
| 2858 | phba->ktime_seg4_total = 0;
|
| 2859 | phba->ktime_seg4_max = 0;
|
| 2860 | phba->ktime_seg4_min = 0xffffffff;
|
| 2861 | phba->ktime_seg5_total = 0;
|
| 2862 | phba->ktime_seg5_max = 0;
|
| 2863 | phba->ktime_seg5_min = 0xffffffff;
|
| 2864 | phba->ktime_seg6_total = 0;
|
| 2865 | phba->ktime_seg6_max = 0;
|
| 2866 | phba->ktime_seg6_min = 0xffffffff;
|
| 2867 | phba->ktime_seg7_total = 0;
|
| 2868 | phba->ktime_seg7_max = 0;
|
| 2869 | phba->ktime_seg7_min = 0xffffffff;
|
| 2870 | phba->ktime_seg8_total = 0;
|
| 2871 | phba->ktime_seg8_max = 0;
|
| 2872 | phba->ktime_seg8_min = 0xffffffff;
|
| 2873 | phba->ktime_seg9_total = 0;
|
| 2874 | phba->ktime_seg9_max = 0;
|
| 2875 | phba->ktime_seg9_min = 0xffffffff;
|
| 2876 | phba->ktime_seg10_total = 0;
|
| 2877 | phba->ktime_seg10_max = 0;
|
| 2878 | phba->ktime_seg10_min = 0xffffffff;
|
| 2879 |
|
| 2880 | phba->ktime_on = 1;
|
| 2881 | return strlen(pbuf);
|
| 2882 | } else if ((strncmp(pbuf, "off",
|
| 2883 | sizeof("off") - 1) == 0)) {
|
| 2884 | phba->ktime_on = 0;
|
| 2885 | return strlen(pbuf);
|
| 2886 | } else if ((strncmp(pbuf, "zero",
|
| 2887 | sizeof("zero") - 1) == 0)) {
|
| 2888 | phba->ktime_data_samples = 0;
|
| 2889 | phba->ktime_status_samples = 0;
|
| 2890 | phba->ktime_seg1_total = 0;
|
| 2891 | phba->ktime_seg1_max = 0;
|
| 2892 | phba->ktime_seg1_min = 0xffffffff;
|
| 2893 | phba->ktime_seg2_total = 0;
|
| 2894 | phba->ktime_seg2_max = 0;
|
| 2895 | phba->ktime_seg2_min = 0xffffffff;
|
| 2896 | phba->ktime_seg3_total = 0;
|
| 2897 | phba->ktime_seg3_max = 0;
|
| 2898 | phba->ktime_seg3_min = 0xffffffff;
|
| 2899 | phba->ktime_seg4_total = 0;
|
| 2900 | phba->ktime_seg4_max = 0;
|
| 2901 | phba->ktime_seg4_min = 0xffffffff;
|
| 2902 | phba->ktime_seg5_total = 0;
|
| 2903 | phba->ktime_seg5_max = 0;
|
| 2904 | phba->ktime_seg5_min = 0xffffffff;
|
| 2905 | phba->ktime_seg6_total = 0;
|
| 2906 | phba->ktime_seg6_max = 0;
|
| 2907 | phba->ktime_seg6_min = 0xffffffff;
|
| 2908 | phba->ktime_seg7_total = 0;
|
| 2909 | phba->ktime_seg7_max = 0;
|
| 2910 | phba->ktime_seg7_min = 0xffffffff;
|
| 2911 | phba->ktime_seg8_total = 0;
|
| 2912 | phba->ktime_seg8_max = 0;
|
| 2913 | phba->ktime_seg8_min = 0xffffffff;
|
| 2914 | phba->ktime_seg9_total = 0;
|
| 2915 | phba->ktime_seg9_max = 0;
|
| 2916 | phba->ktime_seg9_min = 0xffffffff;
|
| 2917 | phba->ktime_seg10_total = 0;
|
| 2918 | phba->ktime_seg10_max = 0;
|
| 2919 | phba->ktime_seg10_min = 0xffffffff;
|
| 2920 | return strlen(pbuf);
|
| 2921 | }
|
| 2922 | return -EINVAL;
|
| 2923 | }
|
| 2924 |
|
| 2925 | static int
|
| 2926 | lpfc_debugfs_nvmeio_trc_open(struct inode *inode, struct file *file)
|
| 2927 | {
|
| 2928 | struct lpfc_hba *phba = inode->i_private;
|
| 2929 | struct lpfc_debug *debug;
|
| 2930 | int rc = -ENOMEM;
|
| 2931 |
|
| 2932 | debug = kmalloc_obj(*debug);
|
| 2933 | if (!debug)
|
| 2934 | goto out;
|
| 2935 |
|
| 2936 |
|
| 2937 | debug->buffer = kmalloc(LPFC_NVMEIO_TRC_SIZE, GFP_KERNEL);
|
| 2938 | if (!debug->buffer) {
|
| 2939 | kfree(debug);
|
| 2940 | goto out;
|
| 2941 | }
|
| 2942 |
|
| 2943 | debug->len = lpfc_debugfs_nvmeio_trc_data(phba, debug->buffer,
|
| 2944 | LPFC_NVMEIO_TRC_SIZE);
|
| 2945 |
|
| 2946 | debug->i_private = inode->i_private;
|
| 2947 | file->private_data = debug;
|
| 2948 |
|
| 2949 | rc = 0;
|
| 2950 | out:
|
| 2951 | return rc;
|
| 2952 | }
|
| 2953 |
|
| 2954 | static ssize_t
|
| 2955 | lpfc_debugfs_nvmeio_trc_write(struct file *file, const char __user *buf,
|
| 2956 | size_t nbytes, loff_t *ppos)
|
| 2957 | {
|
| 2958 | struct lpfc_debug *debug = file->private_data;
|
| 2959 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 2960 | int i;
|
| 2961 | unsigned long sz;
|
| 2962 | char mybuf[64];
|
| 2963 | char *pbuf;
|
| 2964 |
|
| 2965 | if (nbytes > sizeof(mybuf) - 1)
|
| 2966 | nbytes = sizeof(mybuf) - 1;
|
| 2967 |
|
| 2968 | memset(mybuf, 0, sizeof(mybuf));
|
| 2969 |
|
| 2970 | if (copy_from_user(mybuf, buf, nbytes))
|
| 2971 | return -EFAULT;
|
| 2972 | pbuf = &mybuf[0];
|
| 2973 |
|
| 2974 | if ((strncmp(pbuf, "off", sizeof("off") - 1) == 0)) {
|
| 2975 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
| 2976 | "0570 nvmeio_trc_off\n");
|
| 2977 | phba->nvmeio_trc_output_idx = 0;
|
| 2978 | phba->nvmeio_trc_on = 0;
|
| 2979 | return strlen(pbuf);
|
| 2980 | } else if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) {
|
| 2981 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
| 2982 | "0571 nvmeio_trc_on\n");
|
| 2983 | phba->nvmeio_trc_output_idx = 0;
|
| 2984 | phba->nvmeio_trc_on = 1;
|
| 2985 | return strlen(pbuf);
|
| 2986 | }
|
| 2987 |
|
| 2988 |
|
| 2989 | if (phba->nvmeio_trc_on != 0)
|
| 2990 | return -EINVAL;
|
| 2991 |
|
| 2992 |
|
| 2993 | i = kstrtoul(pbuf, 0, &sz);
|
| 2994 | if (i)
|
| 2995 | return -EINVAL;
|
| 2996 | phba->nvmeio_trc_size = (uint32_t)sz;
|
| 2997 |
|
| 2998 |
|
| 2999 | i = 0;
|
| 3000 | while (sz > 1) {
|
| 3001 | sz = sz >> 1;
|
| 3002 | i++;
|
| 3003 | }
|
| 3004 | sz = (1 << i);
|
| 3005 | if (phba->nvmeio_trc_size != sz)
|
| 3006 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
| 3007 | "0572 nvmeio_trc_size changed to %ld\n",
|
| 3008 | sz);
|
| 3009 | phba->nvmeio_trc_size = (uint32_t)sz;
|
| 3010 |
|
| 3011 |
|
| 3012 | kfree(phba->nvmeio_trc);
|
| 3013 |
|
| 3014 |
|
| 3015 | phba->nvmeio_trc = kzalloc((sizeof(struct lpfc_debugfs_nvmeio_trc) *
|
| 3016 | sz), GFP_KERNEL);
|
| 3017 | if (!phba->nvmeio_trc) {
|
| 3018 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
| 3019 | "0573 Cannot create debugfs "
|
| 3020 | "nvmeio_trc buffer\n");
|
| 3021 | return -ENOMEM;
|
| 3022 | }
|
| 3023 | atomic_set(&phba->nvmeio_trc_cnt, 0);
|
| 3024 | phba->nvmeio_trc_on = 0;
|
| 3025 | phba->nvmeio_trc_output_idx = 0;
|
| 3026 |
|
| 3027 | return strlen(pbuf);
|
| 3028 | }
|
| 3029 |
|
| 3030 | static int
|
| 3031 | lpfc_debugfs_hdwqstat_open(struct inode *inode, struct file *file)
|
| 3032 | {
|
| 3033 | struct lpfc_vport *vport = inode->i_private;
|
| 3034 | struct lpfc_debug *debug;
|
| 3035 | int rc = -ENOMEM;
|
| 3036 |
|
| 3037 | debug = kmalloc_obj(*debug);
|
| 3038 | if (!debug)
|
| 3039 | goto out;
|
| 3040 |
|
| 3041 |
|
| 3042 | debug->buffer = kcalloc(1, LPFC_SCSISTAT_SIZE, GFP_KERNEL);
|
| 3043 | if (!debug->buffer) {
|
| 3044 | kfree(debug);
|
| 3045 | goto out;
|
| 3046 | }
|
| 3047 |
|
| 3048 | debug->len = lpfc_debugfs_hdwqstat_data(vport, debug->buffer,
|
| 3049 | LPFC_SCSISTAT_SIZE);
|
| 3050 |
|
| 3051 | debug->i_private = inode->i_private;
|
| 3052 | file->private_data = debug;
|
| 3053 |
|
| 3054 | rc = 0;
|
| 3055 | out:
|
| 3056 | return rc;
|
| 3057 | }
|
| 3058 |
|
| 3059 | static ssize_t
|
| 3060 | lpfc_debugfs_hdwqstat_write(struct file *file, const char __user *buf,
|
| 3061 | size_t nbytes, loff_t *ppos)
|
| 3062 | {
|
| 3063 | struct lpfc_debug *debug = file->private_data;
|
| 3064 | struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
|
| 3065 | struct lpfc_hba *phba = vport->phba;
|
| 3066 | struct lpfc_hdwq_stat *c_stat;
|
| 3067 | char mybuf[64];
|
| 3068 | char *pbuf;
|
| 3069 | int i;
|
| 3070 |
|
| 3071 | if (nbytes > sizeof(mybuf) - 1)
|
| 3072 | nbytes = sizeof(mybuf) - 1;
|
| 3073 |
|
| 3074 | memset(mybuf, 0, sizeof(mybuf));
|
| 3075 |
|
| 3076 | if (copy_from_user(mybuf, buf, nbytes))
|
| 3077 | return -EFAULT;
|
| 3078 | pbuf = &mybuf[0];
|
| 3079 |
|
| 3080 | if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) {
|
| 3081 | if (phba->nvmet_support)
|
| 3082 | phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO;
|
| 3083 | else
|
| 3084 | phba->hdwqstat_on |= (LPFC_CHECK_NVME_IO |
|
| 3085 | LPFC_CHECK_SCSI_IO);
|
| 3086 | return strlen(pbuf);
|
| 3087 | } else if ((strncmp(pbuf, "nvme_on", sizeof("nvme_on") - 1) == 0)) {
|
| 3088 | if (phba->nvmet_support)
|
| 3089 | phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO;
|
| 3090 | else
|
| 3091 | phba->hdwqstat_on |= LPFC_CHECK_NVME_IO;
|
| 3092 | return strlen(pbuf);
|
| 3093 | } else if ((strncmp(pbuf, "scsi_on", sizeof("scsi_on") - 1) == 0)) {
|
| 3094 | if (!phba->nvmet_support)
|
| 3095 | phba->hdwqstat_on |= LPFC_CHECK_SCSI_IO;
|
| 3096 | return strlen(pbuf);
|
| 3097 | } else if ((strncmp(pbuf, "nvme_off", sizeof("nvme_off") - 1) == 0)) {
|
| 3098 | phba->hdwqstat_on &= ~(LPFC_CHECK_NVME_IO |
|
| 3099 | LPFC_CHECK_NVMET_IO);
|
| 3100 | return strlen(pbuf);
|
| 3101 | } else if ((strncmp(pbuf, "scsi_off", sizeof("scsi_off") - 1) == 0)) {
|
| 3102 | phba->hdwqstat_on &= ~LPFC_CHECK_SCSI_IO;
|
| 3103 | return strlen(pbuf);
|
| 3104 | } else if ((strncmp(pbuf, "off",
|
| 3105 | sizeof("off") - 1) == 0)) {
|
| 3106 | phba->hdwqstat_on = LPFC_CHECK_OFF;
|
| 3107 | return strlen(pbuf);
|
| 3108 | } else if ((strncmp(pbuf, "zero",
|
| 3109 | sizeof("zero") - 1) == 0)) {
|
| 3110 | for_each_present_cpu(i) {
|
| 3111 | c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, i);
|
| 3112 | c_stat->xmt_io = 0;
|
| 3113 | c_stat->cmpl_io = 0;
|
| 3114 | c_stat->rcv_io = 0;
|
| 3115 | }
|
| 3116 | return strlen(pbuf);
|
| 3117 | }
|
| 3118 | return -EINVAL;
|
| 3119 | }
|
| 3120 |
|
| 3121 | |
| 3122 | * ---------------------------------
|
| 3123 | * iDiag debugfs file access methods
|
| 3124 | * ---------------------------------
|
| 3125 | *
|
| 3126 | * All access methods are through the proper SLI4 PCI function's debugfs
|
| 3127 | * iDiag directory:
|
| 3128 | *
|
| 3129 | * /sys/kernel/debug/lpfc/fn<#>/iDiag
|
| 3130 |
|
| 3131 |
|
| 3132 | |
| 3133 | * lpfc_idiag_cmd_get - Get and parse idiag debugfs comands from user space
|
| 3134 | * @buf: The pointer to the user space buffer.
|
| 3135 | * @nbytes: The number of bytes in the user space buffer.
|
| 3136 | * @idiag_cmd: pointer to the idiag command struct.
|
| 3137 | *
|
| 3138 | * This routine reads data from debugfs user space buffer and parses the
|
| 3139 | * buffer for getting the idiag command and arguments. The while space in
|
| 3140 | * between the set of data is used as the parsing separator.
|
| 3141 | *
|
| 3142 | * This routine returns 0 when successful, it returns proper error code
|
| 3143 | * back to the user space in error conditions.
|
| 3144 |
|
| 3145 | static int lpfc_idiag_cmd_get(const char __user *buf, size_t nbytes,
|
| 3146 | struct lpfc_idiag_cmd *idiag_cmd)
|
| 3147 | {
|
| 3148 | char mybuf[64];
|
| 3149 | char *pbuf, *step_str;
|
| 3150 | int i;
|
| 3151 | size_t bsize;
|
| 3152 |
|
| 3153 | memset(mybuf, 0, sizeof(mybuf));
|
| 3154 | memset(idiag_cmd, 0, sizeof(*idiag_cmd));
|
| 3155 | bsize = min(nbytes, (sizeof(mybuf)-1));
|
| 3156 |
|
| 3157 | if (copy_from_user(mybuf, buf, bsize))
|
| 3158 | return -EFAULT;
|
| 3159 | pbuf = &mybuf[0];
|
| 3160 | step_str = strsep(&pbuf, "\t ");
|
| 3161 |
|
| 3162 |
|
| 3163 | if (!step_str)
|
| 3164 | return -EINVAL;
|
| 3165 |
|
| 3166 | idiag_cmd->opcode = simple_strtol(step_str, NULL, 0);
|
| 3167 | if (idiag_cmd->opcode == 0)
|
| 3168 | return -EINVAL;
|
| 3169 |
|
| 3170 | for (i = 0; i < LPFC_IDIAG_CMD_DATA_SIZE; i++) {
|
| 3171 | step_str = strsep(&pbuf, "\t ");
|
| 3172 | if (!step_str)
|
| 3173 | return i;
|
| 3174 | idiag_cmd->data[i] = simple_strtol(step_str, NULL, 0);
|
| 3175 | }
|
| 3176 | return i;
|
| 3177 | }
|
| 3178 |
|
| 3179 | |
| 3180 | * lpfc_idiag_open - idiag open debugfs
|
| 3181 | * @inode: The inode pointer that contains a pointer to phba.
|
| 3182 | * @file: The file pointer to attach the file operation.
|
| 3183 | *
|
| 3184 | * Description:
|
| 3185 | * This routine is the entry point for the debugfs open file operation. It
|
| 3186 | * gets the reference to phba from the i_private field in @inode, it then
|
| 3187 | * allocates buffer for the file operation, performs the necessary PCI config
|
| 3188 | * space read into the allocated buffer according to the idiag user command
|
| 3189 | * setup, and then returns a pointer to buffer in the private_data field in
|
| 3190 | * @file.
|
| 3191 | *
|
| 3192 | * Returns:
|
| 3193 | * This function returns zero if successful. On error it will return an
|
| 3194 | * negative error value.
|
| 3195 | *
|
| 3196 | static int
|
| 3197 | lpfc_idiag_open(struct inode *inode, struct file *file)
|
| 3198 | {
|
| 3199 | struct lpfc_debug *debug;
|
| 3200 |
|
| 3201 | debug = kmalloc_obj(*debug);
|
| 3202 | if (!debug)
|
| 3203 | return -ENOMEM;
|
| 3204 |
|
| 3205 | debug->i_private = inode->i_private;
|
| 3206 | debug->buffer = NULL;
|
| 3207 | file->private_data = debug;
|
| 3208 |
|
| 3209 | return 0;
|
| 3210 | }
|
| 3211 |
|
| 3212 | |
| 3213 | * lpfc_idiag_release - Release idiag access file operation
|
| 3214 | * @inode: The inode pointer that contains a vport pointer. (unused)
|
| 3215 | * @file: The file pointer that contains the buffer to release.
|
| 3216 | *
|
| 3217 | * Description:
|
| 3218 | * This routine is the generic release routine for the idiag access file
|
| 3219 | * operation, it frees the buffer that was allocated when the debugfs file
|
| 3220 | * was opened.
|
| 3221 | *
|
| 3222 | * Returns:
|
| 3223 | * This function returns zero.
|
| 3224 | *
|
| 3225 | static int
|
| 3226 | lpfc_idiag_release(struct inode *inode, struct file *file)
|
| 3227 | {
|
| 3228 | struct lpfc_debug *debug = file->private_data;
|
| 3229 |
|
| 3230 |
|
| 3231 | kfree(debug->buffer);
|
| 3232 | kfree(debug);
|
| 3233 |
|
| 3234 | return 0;
|
| 3235 | }
|
| 3236 |
|
| 3237 | |
| 3238 | * lpfc_idiag_cmd_release - Release idiag cmd access file operation
|
| 3239 | * @inode: The inode pointer that contains a vport pointer. (unused)
|
| 3240 | * @file: The file pointer that contains the buffer to release.
|
| 3241 | *
|
| 3242 | * Description:
|
| 3243 | * This routine frees the buffer that was allocated when the debugfs file
|
| 3244 | * was opened. It also reset the fields in the idiag command struct in the
|
| 3245 | * case of command for write operation.
|
| 3246 | *
|
| 3247 | * Returns:
|
| 3248 | * This function returns zero.
|
| 3249 | *
|
| 3250 | static int
|
| 3251 | lpfc_idiag_cmd_release(struct inode *inode, struct file *file)
|
| 3252 | {
|
| 3253 | struct lpfc_debug *debug = file->private_data;
|
| 3254 |
|
| 3255 | if (debug->op == LPFC_IDIAG_OP_WR) {
|
| 3256 | switch (idiag.cmd.opcode) {
|
| 3257 | case LPFC_IDIAG_CMD_PCICFG_WR:
|
| 3258 | case LPFC_IDIAG_CMD_PCICFG_ST:
|
| 3259 | case LPFC_IDIAG_CMD_PCICFG_CL:
|
| 3260 | case LPFC_IDIAG_CMD_QUEACC_WR:
|
| 3261 | case LPFC_IDIAG_CMD_QUEACC_ST:
|
| 3262 | case LPFC_IDIAG_CMD_QUEACC_CL:
|
| 3263 | memset(&idiag, 0, sizeof(idiag));
|
| 3264 | break;
|
| 3265 | default:
|
| 3266 | break;
|
| 3267 | }
|
| 3268 | }
|
| 3269 |
|
| 3270 |
|
| 3271 | kfree(debug->buffer);
|
| 3272 | kfree(debug);
|
| 3273 |
|
| 3274 | return 0;
|
| 3275 | }
|
| 3276 |
|
| 3277 | |
| 3278 | * lpfc_idiag_pcicfg_read - idiag debugfs read pcicfg
|
| 3279 | * @file: The file pointer to read from.
|
| 3280 | * @buf: The buffer to copy the data to.
|
| 3281 | * @nbytes: The number of bytes to read.
|
| 3282 | * @ppos: The position in the file to start reading from.
|
| 3283 | *
|
| 3284 | * Description:
|
| 3285 | * This routine reads data from the @phba pci config space according to the
|
| 3286 | * idiag command, and copies to user @buf. Depending on the PCI config space
|
| 3287 | * read command setup, it does either a single register read of a byte
|
| 3288 | * (8 bits), a word (16 bits), or a dword (32 bits) or browsing through all
|
| 3289 | * registers from the 4K extended PCI config space.
|
| 3290 | *
|
| 3291 | * Returns:
|
| 3292 | * This function returns the amount of data that was read (this could be less
|
| 3293 | * than @nbytes if the end of the file was reached) or a negative error value.
|
| 3294 | *
|
| 3295 | static ssize_t
|
| 3296 | lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes,
|
| 3297 | loff_t *ppos)
|
| 3298 | {
|
| 3299 | struct lpfc_debug *debug = file->private_data;
|
| 3300 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 3301 | int offset_label, offset, len = 0, index = LPFC_PCI_CFG_RD_SIZE;
|
| 3302 | int where, count;
|
| 3303 | char *pbuffer;
|
| 3304 | struct pci_dev *pdev;
|
| 3305 | uint32_t u32val;
|
| 3306 | uint16_t u16val;
|
| 3307 | uint8_t u8val;
|
| 3308 |
|
| 3309 | pdev = phba->pcidev;
|
| 3310 | if (!pdev)
|
| 3311 | return 0;
|
| 3312 |
|
| 3313 |
|
| 3314 | debug->op = LPFC_IDIAG_OP_RD;
|
| 3315 |
|
| 3316 | if (!debug->buffer)
|
| 3317 | debug->buffer = kmalloc(LPFC_PCI_CFG_SIZE, GFP_KERNEL);
|
| 3318 | if (!debug->buffer)
|
| 3319 | return 0;
|
| 3320 | pbuffer = debug->buffer;
|
| 3321 |
|
| 3322 | if (*ppos)
|
| 3323 | return 0;
|
| 3324 |
|
| 3325 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) {
|
| 3326 | where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
|
| 3327 | count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
|
| 3328 | } else
|
| 3329 | return 0;
|
| 3330 |
|
| 3331 |
|
| 3332 | switch (count) {
|
| 3333 | case SIZE_U8:
|
| 3334 | pci_read_config_byte(pdev, where, &u8val);
|
| 3335 | len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
|
| 3336 | "%03x: %02x\n", where, u8val);
|
| 3337 | break;
|
| 3338 | case SIZE_U16:
|
| 3339 | pci_read_config_word(pdev, where, &u16val);
|
| 3340 | len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
|
| 3341 | "%03x: %04x\n", where, u16val);
|
| 3342 | break;
|
| 3343 | case SIZE_U32:
|
| 3344 | pci_read_config_dword(pdev, where, &u32val);
|
| 3345 | len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
|
| 3346 | "%03x: %08x\n", where, u32val);
|
| 3347 | break;
|
| 3348 | case LPFC_PCI_CFG_BROWSE:
|
| 3349 | goto pcicfg_browse;
|
| 3350 | default:
|
| 3351 |
|
| 3352 | len = 0;
|
| 3353 | break;
|
| 3354 | }
|
| 3355 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
|
| 3356 |
|
| 3357 | pcicfg_browse:
|
| 3358 |
|
| 3359 |
|
| 3360 | offset_label = idiag.offset.last_rd;
|
| 3361 | offset = offset_label;
|
| 3362 |
|
| 3363 |
|
| 3364 | len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
|
| 3365 | "%03x: ", offset_label);
|
| 3366 | while (index > 0) {
|
| 3367 | pci_read_config_dword(pdev, offset, &u32val);
|
| 3368 | len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
|
| 3369 | "%08x ", u32val);
|
| 3370 | offset += sizeof(uint32_t);
|
| 3371 | if (offset >= LPFC_PCI_CFG_SIZE) {
|
| 3372 | len += scnprintf(pbuffer+len,
|
| 3373 | LPFC_PCI_CFG_SIZE-len, "\n");
|
| 3374 | break;
|
| 3375 | }
|
| 3376 | index -= sizeof(uint32_t);
|
| 3377 | if (!index)
|
| 3378 | len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
|
| 3379 | "\n");
|
| 3380 | else if (!(index % (8 * sizeof(uint32_t)))) {
|
| 3381 | offset_label += (8 * sizeof(uint32_t));
|
| 3382 | len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
|
| 3383 | "\n%03x: ", offset_label);
|
| 3384 | }
|
| 3385 | }
|
| 3386 |
|
| 3387 |
|
| 3388 | if (index == 0) {
|
| 3389 | idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE;
|
| 3390 | if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE)
|
| 3391 | idiag.offset.last_rd = 0;
|
| 3392 | } else
|
| 3393 | idiag.offset.last_rd = 0;
|
| 3394 |
|
| 3395 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
|
| 3396 | }
|
| 3397 |
|
| 3398 | |
| 3399 | * lpfc_idiag_pcicfg_write - Syntax check and set up idiag pcicfg commands
|
| 3400 | * @file: The file pointer to read from.
|
| 3401 | * @buf: The buffer to copy the user data from.
|
| 3402 | * @nbytes: The number of bytes to get.
|
| 3403 | * @ppos: The position in the file to start reading from.
|
| 3404 | *
|
| 3405 | * This routine get the debugfs idiag command struct from user space and
|
| 3406 | * then perform the syntax check for PCI config space read or write command
|
| 3407 | * accordingly. In the case of PCI config space read command, it sets up
|
| 3408 | * the command in the idiag command struct for the debugfs read operation.
|
| 3409 | * In the case of PCI config space write operation, it executes the write
|
| 3410 | * operation into the PCI config space accordingly.
|
| 3411 | *
|
| 3412 | * It returns the @nbytges passing in from debugfs user space when successful.
|
| 3413 | * In case of error conditions, it returns proper error code back to the user
|
| 3414 | * space.
|
| 3415 |
|
| 3416 | static ssize_t
|
| 3417 | lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf,
|
| 3418 | size_t nbytes, loff_t *ppos)
|
| 3419 | {
|
| 3420 | struct lpfc_debug *debug = file->private_data;
|
| 3421 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 3422 | uint32_t where, value, count;
|
| 3423 | uint32_t u32val;
|
| 3424 | uint16_t u16val;
|
| 3425 | uint8_t u8val;
|
| 3426 | struct pci_dev *pdev;
|
| 3427 | int rc;
|
| 3428 |
|
| 3429 | pdev = phba->pcidev;
|
| 3430 | if (!pdev)
|
| 3431 | return -EFAULT;
|
| 3432 |
|
| 3433 |
|
| 3434 | debug->op = LPFC_IDIAG_OP_WR;
|
| 3435 |
|
| 3436 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
|
| 3437 | if (rc < 0)
|
| 3438 | return rc;
|
| 3439 |
|
| 3440 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) {
|
| 3441 |
|
| 3442 | if (rc != LPFC_PCI_CFG_RD_CMD_ARG)
|
| 3443 | goto error_out;
|
| 3444 |
|
| 3445 | where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
|
| 3446 | count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
|
| 3447 | if (count == LPFC_PCI_CFG_BROWSE) {
|
| 3448 | if (where % sizeof(uint32_t))
|
| 3449 | goto error_out;
|
| 3450 |
|
| 3451 | idiag.offset.last_rd = where;
|
| 3452 | } else if ((count != sizeof(uint8_t)) &&
|
| 3453 | (count != sizeof(uint16_t)) &&
|
| 3454 | (count != sizeof(uint32_t)))
|
| 3455 | goto error_out;
|
| 3456 | if (count == sizeof(uint8_t)) {
|
| 3457 | if (where > LPFC_PCI_CFG_SIZE - sizeof(uint8_t))
|
| 3458 | goto error_out;
|
| 3459 | if (where % sizeof(uint8_t))
|
| 3460 | goto error_out;
|
| 3461 | }
|
| 3462 | if (count == sizeof(uint16_t)) {
|
| 3463 | if (where > LPFC_PCI_CFG_SIZE - sizeof(uint16_t))
|
| 3464 | goto error_out;
|
| 3465 | if (where % sizeof(uint16_t))
|
| 3466 | goto error_out;
|
| 3467 | }
|
| 3468 | if (count == sizeof(uint32_t)) {
|
| 3469 | if (where > LPFC_PCI_CFG_SIZE - sizeof(uint32_t))
|
| 3470 | goto error_out;
|
| 3471 | if (where % sizeof(uint32_t))
|
| 3472 | goto error_out;
|
| 3473 | }
|
| 3474 | } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR ||
|
| 3475 | idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST ||
|
| 3476 | idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
|
| 3477 |
|
| 3478 | if (rc != LPFC_PCI_CFG_WR_CMD_ARG)
|
| 3479 | goto error_out;
|
| 3480 |
|
| 3481 | where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
|
| 3482 | count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
|
| 3483 | value = idiag.cmd.data[IDIAG_PCICFG_VALUE_INDX];
|
| 3484 |
|
| 3485 | if ((count != sizeof(uint8_t)) &&
|
| 3486 | (count != sizeof(uint16_t)) &&
|
| 3487 | (count != sizeof(uint32_t)))
|
| 3488 | goto error_out;
|
| 3489 | if (count == sizeof(uint8_t)) {
|
| 3490 | if (where > LPFC_PCI_CFG_SIZE - sizeof(uint8_t))
|
| 3491 | goto error_out;
|
| 3492 | if (where % sizeof(uint8_t))
|
| 3493 | goto error_out;
|
| 3494 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)
|
| 3495 | pci_write_config_byte(pdev, where,
|
| 3496 | (uint8_t)value);
|
| 3497 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) {
|
| 3498 | rc = pci_read_config_byte(pdev, where, &u8val);
|
| 3499 | if (!rc) {
|
| 3500 | u8val |= (uint8_t)value;
|
| 3501 | pci_write_config_byte(pdev, where,
|
| 3502 | u8val);
|
| 3503 | }
|
| 3504 | }
|
| 3505 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
|
| 3506 | rc = pci_read_config_byte(pdev, where, &u8val);
|
| 3507 | if (!rc) {
|
| 3508 | u8val &= (uint8_t)(~value);
|
| 3509 | pci_write_config_byte(pdev, where,
|
| 3510 | u8val);
|
| 3511 | }
|
| 3512 | }
|
| 3513 | }
|
| 3514 | if (count == sizeof(uint16_t)) {
|
| 3515 | if (where > LPFC_PCI_CFG_SIZE - sizeof(uint16_t))
|
| 3516 | goto error_out;
|
| 3517 | if (where % sizeof(uint16_t))
|
| 3518 | goto error_out;
|
| 3519 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)
|
| 3520 | pci_write_config_word(pdev, where,
|
| 3521 | (uint16_t)value);
|
| 3522 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) {
|
| 3523 | rc = pci_read_config_word(pdev, where, &u16val);
|
| 3524 | if (!rc) {
|
| 3525 | u16val |= (uint16_t)value;
|
| 3526 | pci_write_config_word(pdev, where,
|
| 3527 | u16val);
|
| 3528 | }
|
| 3529 | }
|
| 3530 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
|
| 3531 | rc = pci_read_config_word(pdev, where, &u16val);
|
| 3532 | if (!rc) {
|
| 3533 | u16val &= (uint16_t)(~value);
|
| 3534 | pci_write_config_word(pdev, where,
|
| 3535 | u16val);
|
| 3536 | }
|
| 3537 | }
|
| 3538 | }
|
| 3539 | if (count == sizeof(uint32_t)) {
|
| 3540 | if (where > LPFC_PCI_CFG_SIZE - sizeof(uint32_t))
|
| 3541 | goto error_out;
|
| 3542 | if (where % sizeof(uint32_t))
|
| 3543 | goto error_out;
|
| 3544 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)
|
| 3545 | pci_write_config_dword(pdev, where, value);
|
| 3546 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) {
|
| 3547 | rc = pci_read_config_dword(pdev, where,
|
| 3548 | &u32val);
|
| 3549 | if (!rc) {
|
| 3550 | u32val |= value;
|
| 3551 | pci_write_config_dword(pdev, where,
|
| 3552 | u32val);
|
| 3553 | }
|
| 3554 | }
|
| 3555 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
|
| 3556 | rc = pci_read_config_dword(pdev, where,
|
| 3557 | &u32val);
|
| 3558 | if (!rc) {
|
| 3559 | u32val &= ~value;
|
| 3560 | pci_write_config_dword(pdev, where,
|
| 3561 | u32val);
|
| 3562 | }
|
| 3563 | }
|
| 3564 | }
|
| 3565 | } else
|
| 3566 |
|
| 3567 | goto error_out;
|
| 3568 |
|
| 3569 | return nbytes;
|
| 3570 | error_out:
|
| 3571 | memset(&idiag, 0, sizeof(idiag));
|
| 3572 | return -EINVAL;
|
| 3573 | }
|
| 3574 |
|
| 3575 | |
| 3576 | * lpfc_idiag_baracc_read - idiag debugfs pci bar access read
|
| 3577 | * @file: The file pointer to read from.
|
| 3578 | * @buf: The buffer to copy the data to.
|
| 3579 | * @nbytes: The number of bytes to read.
|
| 3580 | * @ppos: The position in the file to start reading from.
|
| 3581 | *
|
| 3582 | * Description:
|
| 3583 | * This routine reads data from the @phba pci bar memory mapped space
|
| 3584 | * according to the idiag command, and copies to user @buf.
|
| 3585 | *
|
| 3586 | * Returns:
|
| 3587 | * This function returns the amount of data that was read (this could be less
|
| 3588 | * than @nbytes if the end of the file was reached) or a negative error value.
|
| 3589 | *
|
| 3590 | static ssize_t
|
| 3591 | lpfc_idiag_baracc_read(struct file *file, char __user *buf, size_t nbytes,
|
| 3592 | loff_t *ppos)
|
| 3593 | {
|
| 3594 | struct lpfc_debug *debug = file->private_data;
|
| 3595 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 3596 | int offset_label, offset, offset_run, len = 0, index;
|
| 3597 | int bar_num, acc_range, bar_size;
|
| 3598 | char *pbuffer;
|
| 3599 | void __iomem *mem_mapped_bar;
|
| 3600 | uint32_t if_type;
|
| 3601 | struct pci_dev *pdev;
|
| 3602 | uint32_t u32val;
|
| 3603 |
|
| 3604 | pdev = phba->pcidev;
|
| 3605 | if (!pdev)
|
| 3606 | return 0;
|
| 3607 |
|
| 3608 |
|
| 3609 | debug->op = LPFC_IDIAG_OP_RD;
|
| 3610 |
|
| 3611 | if (!debug->buffer)
|
| 3612 | debug->buffer = kmalloc(LPFC_PCI_BAR_RD_BUF_SIZE, GFP_KERNEL);
|
| 3613 | if (!debug->buffer)
|
| 3614 | return 0;
|
| 3615 | pbuffer = debug->buffer;
|
| 3616 |
|
| 3617 | if (*ppos)
|
| 3618 | return 0;
|
| 3619 |
|
| 3620 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) {
|
| 3621 | bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX];
|
| 3622 | offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX];
|
| 3623 | acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX];
|
| 3624 | bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX];
|
| 3625 | } else
|
| 3626 | return 0;
|
| 3627 |
|
| 3628 | if (acc_range == 0)
|
| 3629 | return 0;
|
| 3630 |
|
| 3631 | if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
|
| 3632 | if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
|
| 3633 | if (bar_num == IDIAG_BARACC_BAR_0)
|
| 3634 | mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
|
| 3635 | else if (bar_num == IDIAG_BARACC_BAR_1)
|
| 3636 | mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p;
|
| 3637 | else if (bar_num == IDIAG_BARACC_BAR_2)
|
| 3638 | mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p;
|
| 3639 | else
|
| 3640 | return 0;
|
| 3641 | } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
|
| 3642 | if (bar_num == IDIAG_BARACC_BAR_0)
|
| 3643 | mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
|
| 3644 | else
|
| 3645 | return 0;
|
| 3646 | } else
|
| 3647 | return 0;
|
| 3648 |
|
| 3649 |
|
| 3650 | if (acc_range == SINGLE_WORD) {
|
| 3651 | offset_run = offset;
|
| 3652 | u32val = readl(mem_mapped_bar + offset_run);
|
| 3653 | len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
|
| 3654 | "%05x: %08x\n", offset_run, u32val);
|
| 3655 | } else
|
| 3656 | goto baracc_browse;
|
| 3657 |
|
| 3658 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
|
| 3659 |
|
| 3660 | baracc_browse:
|
| 3661 |
|
| 3662 |
|
| 3663 | offset_label = idiag.offset.last_rd;
|
| 3664 | offset_run = offset_label;
|
| 3665 |
|
| 3666 |
|
| 3667 | len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
|
| 3668 | "%05x: ", offset_label);
|
| 3669 | index = LPFC_PCI_BAR_RD_SIZE;
|
| 3670 | while (index > 0) {
|
| 3671 | u32val = readl(mem_mapped_bar + offset_run);
|
| 3672 | len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
|
| 3673 | "%08x ", u32val);
|
| 3674 | offset_run += sizeof(uint32_t);
|
| 3675 | if (acc_range == LPFC_PCI_BAR_BROWSE) {
|
| 3676 | if (offset_run >= bar_size) {
|
| 3677 | len += scnprintf(pbuffer+len,
|
| 3678 | LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
|
| 3679 | break;
|
| 3680 | }
|
| 3681 | } else {
|
| 3682 | if (offset_run >= offset +
|
| 3683 | (acc_range * sizeof(uint32_t))) {
|
| 3684 | len += scnprintf(pbuffer+len,
|
| 3685 | LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
|
| 3686 | break;
|
| 3687 | }
|
| 3688 | }
|
| 3689 | index -= sizeof(uint32_t);
|
| 3690 | if (!index)
|
| 3691 | len += scnprintf(pbuffer+len,
|
| 3692 | LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
|
| 3693 | else if (!(index % (8 * sizeof(uint32_t)))) {
|
| 3694 | offset_label += (8 * sizeof(uint32_t));
|
| 3695 | len += scnprintf(pbuffer+len,
|
| 3696 | LPFC_PCI_BAR_RD_BUF_SIZE-len,
|
| 3697 | "\n%05x: ", offset_label);
|
| 3698 | }
|
| 3699 | }
|
| 3700 |
|
| 3701 |
|
| 3702 | if (index == 0) {
|
| 3703 | idiag.offset.last_rd += LPFC_PCI_BAR_RD_SIZE;
|
| 3704 | if (acc_range == LPFC_PCI_BAR_BROWSE) {
|
| 3705 | if (idiag.offset.last_rd >= bar_size)
|
| 3706 | idiag.offset.last_rd = 0;
|
| 3707 | } else {
|
| 3708 | if (offset_run >= offset +
|
| 3709 | (acc_range * sizeof(uint32_t)))
|
| 3710 | idiag.offset.last_rd = offset;
|
| 3711 | }
|
| 3712 | } else {
|
| 3713 | if (acc_range == LPFC_PCI_BAR_BROWSE)
|
| 3714 | idiag.offset.last_rd = 0;
|
| 3715 | else
|
| 3716 | idiag.offset.last_rd = offset;
|
| 3717 | }
|
| 3718 |
|
| 3719 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
|
| 3720 | }
|
| 3721 |
|
| 3722 | |
| 3723 | * lpfc_idiag_baracc_write - Syntax check and set up idiag bar access commands
|
| 3724 | * @file: The file pointer to read from.
|
| 3725 | * @buf: The buffer to copy the user data from.
|
| 3726 | * @nbytes: The number of bytes to get.
|
| 3727 | * @ppos: The position in the file to start reading from.
|
| 3728 | *
|
| 3729 | * This routine get the debugfs idiag command struct from user space and
|
| 3730 | * then perform the syntax check for PCI bar memory mapped space read or
|
| 3731 | * write command accordingly. In the case of PCI bar memory mapped space
|
| 3732 | * read command, it sets up the command in the idiag command struct for
|
| 3733 | * the debugfs read operation. In the case of PCI bar memorpy mapped space
|
| 3734 | * write operation, it executes the write operation into the PCI bar memory
|
| 3735 | * mapped space accordingly.
|
| 3736 | *
|
| 3737 | * It returns the @nbytges passing in from debugfs user space when successful.
|
| 3738 | * In case of error conditions, it returns proper error code back to the user
|
| 3739 | * space.
|
| 3740 |
|
| 3741 | static ssize_t
|
| 3742 | lpfc_idiag_baracc_write(struct file *file, const char __user *buf,
|
| 3743 | size_t nbytes, loff_t *ppos)
|
| 3744 | {
|
| 3745 | struct lpfc_debug *debug = file->private_data;
|
| 3746 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 3747 | uint32_t bar_num, bar_size, offset, value, acc_range;
|
| 3748 | struct pci_dev *pdev;
|
| 3749 | void __iomem *mem_mapped_bar;
|
| 3750 | uint32_t if_type;
|
| 3751 | uint32_t u32val;
|
| 3752 | int rc;
|
| 3753 |
|
| 3754 | pdev = phba->pcidev;
|
| 3755 | if (!pdev)
|
| 3756 | return -EFAULT;
|
| 3757 |
|
| 3758 |
|
| 3759 | debug->op = LPFC_IDIAG_OP_WR;
|
| 3760 |
|
| 3761 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
|
| 3762 | if (rc < 0)
|
| 3763 | return rc;
|
| 3764 |
|
| 3765 | if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
|
| 3766 | bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX];
|
| 3767 |
|
| 3768 | if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
|
| 3769 | if ((bar_num != IDIAG_BARACC_BAR_0) &&
|
| 3770 | (bar_num != IDIAG_BARACC_BAR_1) &&
|
| 3771 | (bar_num != IDIAG_BARACC_BAR_2))
|
| 3772 | goto error_out;
|
| 3773 | } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
|
| 3774 | if (bar_num != IDIAG_BARACC_BAR_0)
|
| 3775 | goto error_out;
|
| 3776 | } else
|
| 3777 | goto error_out;
|
| 3778 |
|
| 3779 | if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
|
| 3780 | if (bar_num == IDIAG_BARACC_BAR_0) {
|
| 3781 | idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
|
| 3782 | LPFC_PCI_IF0_BAR0_SIZE;
|
| 3783 | mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
|
| 3784 | } else if (bar_num == IDIAG_BARACC_BAR_1) {
|
| 3785 | idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
|
| 3786 | LPFC_PCI_IF0_BAR1_SIZE;
|
| 3787 | mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p;
|
| 3788 | } else if (bar_num == IDIAG_BARACC_BAR_2) {
|
| 3789 | idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
|
| 3790 | LPFC_PCI_IF0_BAR2_SIZE;
|
| 3791 | mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p;
|
| 3792 | } else
|
| 3793 | goto error_out;
|
| 3794 | } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
|
| 3795 | if (bar_num == IDIAG_BARACC_BAR_0) {
|
| 3796 | idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
|
| 3797 | LPFC_PCI_IF2_BAR0_SIZE;
|
| 3798 | mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
|
| 3799 | } else
|
| 3800 | goto error_out;
|
| 3801 | } else
|
| 3802 | goto error_out;
|
| 3803 |
|
| 3804 | offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX];
|
| 3805 | if (offset % sizeof(uint32_t))
|
| 3806 | goto error_out;
|
| 3807 |
|
| 3808 | bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX];
|
| 3809 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) {
|
| 3810 |
|
| 3811 | if (rc != LPFC_PCI_BAR_RD_CMD_ARG)
|
| 3812 | goto error_out;
|
| 3813 | acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX];
|
| 3814 | if (acc_range == LPFC_PCI_BAR_BROWSE) {
|
| 3815 | if (offset > bar_size - sizeof(uint32_t))
|
| 3816 | goto error_out;
|
| 3817 |
|
| 3818 | idiag.offset.last_rd = offset;
|
| 3819 | } else if (acc_range > SINGLE_WORD) {
|
| 3820 | if (offset + acc_range * sizeof(uint32_t) > bar_size)
|
| 3821 | goto error_out;
|
| 3822 |
|
| 3823 | idiag.offset.last_rd = offset;
|
| 3824 | } else if (acc_range != SINGLE_WORD)
|
| 3825 | goto error_out;
|
| 3826 | } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR ||
|
| 3827 | idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST ||
|
| 3828 | idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) {
|
| 3829 |
|
| 3830 | if (rc != LPFC_PCI_BAR_WR_CMD_ARG)
|
| 3831 | goto error_out;
|
| 3832 |
|
| 3833 | acc_range = SINGLE_WORD;
|
| 3834 | value = idiag.cmd.data[IDIAG_BARACC_REG_VAL_INDX];
|
| 3835 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR) {
|
| 3836 | writel(value, mem_mapped_bar + offset);
|
| 3837 | readl(mem_mapped_bar + offset);
|
| 3838 | }
|
| 3839 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST) {
|
| 3840 | u32val = readl(mem_mapped_bar + offset);
|
| 3841 | u32val |= value;
|
| 3842 | writel(u32val, mem_mapped_bar + offset);
|
| 3843 | readl(mem_mapped_bar + offset);
|
| 3844 | }
|
| 3845 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) {
|
| 3846 | u32val = readl(mem_mapped_bar + offset);
|
| 3847 | u32val &= ~value;
|
| 3848 | writel(u32val, mem_mapped_bar + offset);
|
| 3849 | readl(mem_mapped_bar + offset);
|
| 3850 | }
|
| 3851 | } else
|
| 3852 |
|
| 3853 | goto error_out;
|
| 3854 |
|
| 3855 | return nbytes;
|
| 3856 | error_out:
|
| 3857 | memset(&idiag, 0, sizeof(idiag));
|
| 3858 | return -EINVAL;
|
| 3859 | }
|
| 3860 |
|
| 3861 | static int
|
| 3862 | __lpfc_idiag_print_wq(struct lpfc_queue *qp, char *wqtype,
|
| 3863 | char *pbuffer, int len)
|
| 3864 | {
|
| 3865 | if (!qp)
|
| 3866 | return len;
|
| 3867 |
|
| 3868 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 3869 | "\t\t%s WQ info: ", wqtype);
|
| 3870 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 3871 | "AssocCQID[%04d]: WQ-STAT[oflow:x%x posted:x%llx]\n",
|
| 3872 | qp->assoc_qid, qp->q_cnt_1,
|
| 3873 | (unsigned long long)qp->q_cnt_4);
|
| 3874 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 3875 | "\t\tWQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
|
| 3876 | "HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]",
|
| 3877 | qp->queue_id, qp->entry_count,
|
| 3878 | qp->entry_size, qp->host_index,
|
| 3879 | qp->hba_index, qp->notify_interval);
|
| 3880 | len += scnprintf(pbuffer + len,
|
| 3881 | LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n");
|
| 3882 | return len;
|
| 3883 | }
|
| 3884 |
|
| 3885 | static int
|
| 3886 | lpfc_idiag_wqs_for_cq(struct lpfc_hba *phba, char *wqtype, char *pbuffer,
|
| 3887 | int *len, int max_cnt, int cq_id)
|
| 3888 | {
|
| 3889 | struct lpfc_queue *qp;
|
| 3890 | int qidx;
|
| 3891 |
|
| 3892 | for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
|
| 3893 | qp = phba->sli4_hba.hdwq[qidx].io_wq;
|
| 3894 | if (qp->assoc_qid != cq_id)
|
| 3895 | continue;
|
| 3896 | *len = __lpfc_idiag_print_wq(qp, wqtype, pbuffer, *len);
|
| 3897 | if (*len >= max_cnt)
|
| 3898 | return 1;
|
| 3899 | }
|
| 3900 | return 0;
|
| 3901 | }
|
| 3902 |
|
| 3903 | static int
|
| 3904 | __lpfc_idiag_print_cq(struct lpfc_queue *qp, char *cqtype,
|
| 3905 | char *pbuffer, int len)
|
| 3906 | {
|
| 3907 | if (!qp)
|
| 3908 | return len;
|
| 3909 |
|
| 3910 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 3911 | "\t%s CQ info: ", cqtype);
|
| 3912 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 3913 | "AssocEQID[%02d]: CQ STAT[max:x%x relw:x%x "
|
| 3914 | "xabt:x%x wq:x%llx]\n",
|
| 3915 | qp->assoc_qid, qp->q_cnt_1, qp->q_cnt_2,
|
| 3916 | qp->q_cnt_3, (unsigned long long)qp->q_cnt_4);
|
| 3917 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 3918 | "\tCQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
|
| 3919 | "HST-IDX[%04d], NTFI[%03d], PLMT[%03d]",
|
| 3920 | qp->queue_id, qp->entry_count,
|
| 3921 | qp->entry_size, qp->host_index,
|
| 3922 | qp->notify_interval, qp->max_proc_limit);
|
| 3923 |
|
| 3924 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 3925 | "\n");
|
| 3926 |
|
| 3927 | return len;
|
| 3928 | }
|
| 3929 |
|
| 3930 | static int
|
| 3931 | __lpfc_idiag_print_rqpair(struct lpfc_queue *qp, struct lpfc_queue *datqp,
|
| 3932 | char *rqtype, char *pbuffer, int len)
|
| 3933 | {
|
| 3934 | if (!qp || !datqp)
|
| 3935 | return len;
|
| 3936 |
|
| 3937 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 3938 | "\t\t%s RQ info: ", rqtype);
|
| 3939 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 3940 | "AssocCQID[%02d]: RQ-STAT[nopost:x%x nobuf:x%x "
|
| 3941 | "posted:x%x rcv:x%llx]\n",
|
| 3942 | qp->assoc_qid, qp->q_cnt_1, qp->q_cnt_2,
|
| 3943 | qp->q_cnt_3, (unsigned long long)qp->q_cnt_4);
|
| 3944 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 3945 | "\t\tHQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
|
| 3946 | "HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]\n",
|
| 3947 | qp->queue_id, qp->entry_count, qp->entry_size,
|
| 3948 | qp->host_index, qp->hba_index, qp->notify_interval);
|
| 3949 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 3950 | "\t\tDQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
|
| 3951 | "HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]\n",
|
| 3952 | datqp->queue_id, datqp->entry_count,
|
| 3953 | datqp->entry_size, datqp->host_index,
|
| 3954 | datqp->hba_index, datqp->notify_interval);
|
| 3955 | return len;
|
| 3956 | }
|
| 3957 |
|
| 3958 | static int
|
| 3959 | lpfc_idiag_cqs_for_eq(struct lpfc_hba *phba, char *pbuffer,
|
| 3960 | int *len, int max_cnt, int eqidx, int eq_id)
|
| 3961 | {
|
| 3962 | struct lpfc_queue *qp;
|
| 3963 | int rc;
|
| 3964 |
|
| 3965 | qp = phba->sli4_hba.hdwq[eqidx].io_cq;
|
| 3966 |
|
| 3967 | *len = __lpfc_idiag_print_cq(qp, "IO", pbuffer, *len);
|
| 3968 |
|
| 3969 |
|
| 3970 | qp->CQ_max_cqe = 0;
|
| 3971 |
|
| 3972 | if (*len >= max_cnt)
|
| 3973 | return 1;
|
| 3974 |
|
| 3975 | rc = lpfc_idiag_wqs_for_cq(phba, "IO", pbuffer, len,
|
| 3976 | max_cnt, qp->queue_id);
|
| 3977 | if (rc)
|
| 3978 | return 1;
|
| 3979 |
|
| 3980 | if ((eqidx < phba->cfg_nvmet_mrq) && phba->nvmet_support) {
|
| 3981 |
|
| 3982 | qp = phba->sli4_hba.nvmet_cqset[eqidx];
|
| 3983 | *len = __lpfc_idiag_print_cq(qp, "NVMET CQset", pbuffer, *len);
|
| 3984 |
|
| 3985 |
|
| 3986 | qp->CQ_max_cqe = 0;
|
| 3987 |
|
| 3988 | if (*len >= max_cnt)
|
| 3989 | return 1;
|
| 3990 |
|
| 3991 |
|
| 3992 | qp = phba->sli4_hba.nvmet_mrq_hdr[eqidx];
|
| 3993 | *len = __lpfc_idiag_print_rqpair(qp,
|
| 3994 | phba->sli4_hba.nvmet_mrq_data[eqidx],
|
| 3995 | "NVMET MRQ", pbuffer, *len);
|
| 3996 |
|
| 3997 | if (*len >= max_cnt)
|
| 3998 | return 1;
|
| 3999 | }
|
| 4000 |
|
| 4001 | return 0;
|
| 4002 | }
|
| 4003 |
|
| 4004 | static int
|
| 4005 | __lpfc_idiag_print_eq(struct lpfc_queue *qp, char *eqtype,
|
| 4006 | char *pbuffer, int len)
|
| 4007 | {
|
| 4008 | if (!qp)
|
| 4009 | return len;
|
| 4010 |
|
| 4011 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 4012 | "\n%s EQ info: EQ-STAT[max:x%x noE:x%x "
|
| 4013 | "cqe_proc:x%x eqe_proc:x%llx eqd %d]\n",
|
| 4014 | eqtype, qp->q_cnt_1, qp->q_cnt_2, qp->q_cnt_3,
|
| 4015 | (unsigned long long)qp->q_cnt_4, qp->q_mode);
|
| 4016 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 4017 | "EQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
|
| 4018 | "HST-IDX[%04d], NTFI[%03d], PLMT[%03d], AFFIN[%03d]",
|
| 4019 | qp->queue_id, qp->entry_count, qp->entry_size,
|
| 4020 | qp->host_index, qp->notify_interval,
|
| 4021 | qp->max_proc_limit, qp->chann);
|
| 4022 | len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 4023 | "\n");
|
| 4024 |
|
| 4025 | return len;
|
| 4026 | }
|
| 4027 |
|
| 4028 | |
| 4029 | * lpfc_idiag_queinfo_read - idiag debugfs read queue information
|
| 4030 | * @file: The file pointer to read from.
|
| 4031 | * @buf: The buffer to copy the data to.
|
| 4032 | * @nbytes: The number of bytes to read.
|
| 4033 | * @ppos: The position in the file to start reading from.
|
| 4034 | *
|
| 4035 | * Description:
|
| 4036 | * This routine reads data from the @phba SLI4 PCI function queue information,
|
| 4037 | * and copies to user @buf.
|
| 4038 | * This routine only returns 1 EQs worth of information. It remembers the last
|
| 4039 | * EQ read and jumps to the next EQ. Thus subsequent calls to queInfo will
|
| 4040 | * retrieve all EQs allocated for the phba.
|
| 4041 | *
|
| 4042 | * Returns:
|
| 4043 | * This function returns the amount of data that was read (this could be less
|
| 4044 | * than @nbytes if the end of the file was reached) or a negative error value.
|
| 4045 | *
|
| 4046 | static ssize_t
|
| 4047 | lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes,
|
| 4048 | loff_t *ppos)
|
| 4049 | {
|
| 4050 | struct lpfc_debug *debug = file->private_data;
|
| 4051 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 4052 | char *pbuffer;
|
| 4053 | int max_cnt, rc, x, len = 0;
|
| 4054 | struct lpfc_queue *qp = NULL;
|
| 4055 |
|
| 4056 | if (!debug->buffer)
|
| 4057 | debug->buffer = kmalloc(LPFC_QUE_INFO_GET_BUF_SIZE, GFP_KERNEL);
|
| 4058 | if (!debug->buffer)
|
| 4059 | return 0;
|
| 4060 | pbuffer = debug->buffer;
|
| 4061 | max_cnt = LPFC_QUE_INFO_GET_BUF_SIZE - 256;
|
| 4062 |
|
| 4063 | if (*ppos)
|
| 4064 | return 0;
|
| 4065 |
|
| 4066 | spin_lock_irq(&phba->hbalock);
|
| 4067 |
|
| 4068 |
|
| 4069 | if (phba->sli4_hba.hdwq && phba->cfg_hdw_queue) {
|
| 4070 |
|
| 4071 | x = phba->lpfc_idiag_last_eq;
|
| 4072 | phba->lpfc_idiag_last_eq++;
|
| 4073 | if (phba->lpfc_idiag_last_eq >= phba->cfg_hdw_queue)
|
| 4074 | phba->lpfc_idiag_last_eq = 0;
|
| 4075 |
|
| 4076 | len += scnprintf(pbuffer + len,
|
| 4077 | LPFC_QUE_INFO_GET_BUF_SIZE - len,
|
| 4078 | "HDWQ %d out of %d HBA HDWQs\n",
|
| 4079 | x, phba->cfg_hdw_queue);
|
| 4080 |
|
| 4081 |
|
| 4082 | qp = phba->sli4_hba.hdwq[x].hba_eq;
|
| 4083 | if (!qp)
|
| 4084 | goto out;
|
| 4085 |
|
| 4086 | len = __lpfc_idiag_print_eq(qp, "HBA", pbuffer, len);
|
| 4087 |
|
| 4088 |
|
| 4089 | qp->EQ_max_eqe = 0;
|
| 4090 |
|
| 4091 | if (len >= max_cnt)
|
| 4092 | goto too_big;
|
| 4093 |
|
| 4094 |
|
| 4095 | rc = lpfc_idiag_cqs_for_eq(phba, pbuffer, &len,
|
| 4096 | max_cnt, x, qp->queue_id);
|
| 4097 | if (rc)
|
| 4098 | goto too_big;
|
| 4099 |
|
| 4100 |
|
| 4101 | if (x)
|
| 4102 | goto out;
|
| 4103 |
|
| 4104 |
|
| 4105 | qp = phba->sli4_hba.mbx_cq;
|
| 4106 | len = __lpfc_idiag_print_cq(qp, "MBX", pbuffer, len);
|
| 4107 | if (len >= max_cnt)
|
| 4108 | goto too_big;
|
| 4109 |
|
| 4110 |
|
| 4111 | qp = phba->sli4_hba.mbx_wq;
|
| 4112 | len = __lpfc_idiag_print_wq(qp, "MBX", pbuffer, len);
|
| 4113 | if (len >= max_cnt)
|
| 4114 | goto too_big;
|
| 4115 |
|
| 4116 |
|
| 4117 | qp = phba->sli4_hba.els_cq;
|
| 4118 | len = __lpfc_idiag_print_cq(qp, "ELS", pbuffer, len);
|
| 4119 |
|
| 4120 | if (qp)
|
| 4121 | qp->CQ_max_cqe = 0;
|
| 4122 | if (len >= max_cnt)
|
| 4123 | goto too_big;
|
| 4124 |
|
| 4125 |
|
| 4126 | qp = phba->sli4_hba.els_wq;
|
| 4127 | len = __lpfc_idiag_print_wq(qp, "ELS", pbuffer, len);
|
| 4128 | if (len >= max_cnt)
|
| 4129 | goto too_big;
|
| 4130 |
|
| 4131 | qp = phba->sli4_hba.hdr_rq;
|
| 4132 | len = __lpfc_idiag_print_rqpair(qp, phba->sli4_hba.dat_rq,
|
| 4133 | "ELS RQpair", pbuffer, len);
|
| 4134 | if (len >= max_cnt)
|
| 4135 | goto too_big;
|
| 4136 |
|
| 4137 |
|
| 4138 | qp = phba->sli4_hba.nvmels_cq;
|
| 4139 | len = __lpfc_idiag_print_cq(qp, "NVME LS",
|
| 4140 | pbuffer, len);
|
| 4141 |
|
| 4142 | if (qp)
|
| 4143 | qp->CQ_max_cqe = 0;
|
| 4144 | if (len >= max_cnt)
|
| 4145 | goto too_big;
|
| 4146 |
|
| 4147 |
|
| 4148 | qp = phba->sli4_hba.nvmels_wq;
|
| 4149 | len = __lpfc_idiag_print_wq(qp, "NVME LS",
|
| 4150 | pbuffer, len);
|
| 4151 | if (len >= max_cnt)
|
| 4152 | goto too_big;
|
| 4153 |
|
| 4154 | goto out;
|
| 4155 | }
|
| 4156 |
|
| 4157 | spin_unlock_irq(&phba->hbalock);
|
| 4158 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
|
| 4159 |
|
| 4160 | too_big:
|
| 4161 | len += scnprintf(pbuffer + len,
|
| 4162 | LPFC_QUE_INFO_GET_BUF_SIZE - len, "Truncated ...\n");
|
| 4163 | out:
|
| 4164 | spin_unlock_irq(&phba->hbalock);
|
| 4165 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
|
| 4166 | }
|
| 4167 |
|
| 4168 | |
| 4169 | * lpfc_idiag_que_param_check - queue access command parameter sanity check
|
| 4170 | * @q: The pointer to queue structure.
|
| 4171 | * @index: The index into a queue entry.
|
| 4172 | * @count: The number of queue entries to access.
|
| 4173 | *
|
| 4174 | * Description:
|
| 4175 | * The routine performs sanity check on device queue access method commands.
|
| 4176 | *
|
| 4177 | * Returns:
|
| 4178 | * This function returns -EINVAL when fails the sanity check, otherwise, it
|
| 4179 | * returns 0.
|
| 4180 | *
|
| 4181 | static int
|
| 4182 | lpfc_idiag_que_param_check(struct lpfc_queue *q, int index, int count)
|
| 4183 | {
|
| 4184 |
|
| 4185 | if ((count != 1) && (count != LPFC_QUE_ACC_BROWSE))
|
| 4186 | return -EINVAL;
|
| 4187 | if (index > q->entry_count - 1)
|
| 4188 | return -EINVAL;
|
| 4189 | return 0;
|
| 4190 | }
|
| 4191 |
|
| 4192 | |
| 4193 | * lpfc_idiag_queacc_read_qe - read a single entry from the given queue index
|
| 4194 | * @pbuffer: The pointer to buffer to copy the read data into.
|
| 4195 | * @len: Length of the buffer.
|
| 4196 | * @pque: The pointer to the queue to be read.
|
| 4197 | * @index: The index into the queue entry.
|
| 4198 | *
|
| 4199 | * Description:
|
| 4200 | * This routine reads out a single entry from the given queue's index location
|
| 4201 | * and copies it into the buffer provided.
|
| 4202 | *
|
| 4203 | * Returns:
|
| 4204 | * This function returns 0 when it fails, otherwise, it returns the length of
|
| 4205 | * the data read into the buffer provided.
|
| 4206 | *
|
| 4207 | static int
|
| 4208 | lpfc_idiag_queacc_read_qe(char *pbuffer, int len, struct lpfc_queue *pque,
|
| 4209 | uint32_t index)
|
| 4210 | {
|
| 4211 | int offset, esize;
|
| 4212 | uint32_t *pentry;
|
| 4213 |
|
| 4214 | if (!pbuffer || !pque)
|
| 4215 | return 0;
|
| 4216 |
|
| 4217 | esize = pque->entry_size;
|
| 4218 | len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len,
|
| 4219 | "QE-INDEX[%04d]:\n", index);
|
| 4220 |
|
| 4221 | offset = 0;
|
| 4222 | pentry = lpfc_sli4_qe(pque, index);
|
| 4223 | while (esize > 0) {
|
| 4224 | len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len,
|
| 4225 | "%08x ", *pentry);
|
| 4226 | pentry++;
|
| 4227 | offset += sizeof(uint32_t);
|
| 4228 | esize -= sizeof(uint32_t);
|
| 4229 | if (esize > 0 && !(offset % (4 * sizeof(uint32_t))))
|
| 4230 | len += scnprintf(pbuffer+len,
|
| 4231 | LPFC_QUE_ACC_BUF_SIZE-len, "\n");
|
| 4232 | }
|
| 4233 | len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n");
|
| 4234 |
|
| 4235 | return len;
|
| 4236 | }
|
| 4237 |
|
| 4238 | |
| 4239 | * lpfc_idiag_queacc_read - idiag debugfs read port queue
|
| 4240 | * @file: The file pointer to read from.
|
| 4241 | * @buf: The buffer to copy the data to.
|
| 4242 | * @nbytes: The number of bytes to read.
|
| 4243 | * @ppos: The position in the file to start reading from.
|
| 4244 | *
|
| 4245 | * Description:
|
| 4246 | * This routine reads data from the @phba device queue memory according to the
|
| 4247 | * idiag command, and copies to user @buf. Depending on the queue dump read
|
| 4248 | * command setup, it does either a single queue entry read or browing through
|
| 4249 | * all entries of the queue.
|
| 4250 | *
|
| 4251 | * Returns:
|
| 4252 | * This function returns the amount of data that was read (this could be less
|
| 4253 | * than @nbytes if the end of the file was reached) or a negative error value.
|
| 4254 | *
|
| 4255 | static ssize_t
|
| 4256 | lpfc_idiag_queacc_read(struct file *file, char __user *buf, size_t nbytes,
|
| 4257 | loff_t *ppos)
|
| 4258 | {
|
| 4259 | struct lpfc_debug *debug = file->private_data;
|
| 4260 | uint32_t last_index, index, count;
|
| 4261 | struct lpfc_queue *pque = NULL;
|
| 4262 | char *pbuffer;
|
| 4263 | int len = 0;
|
| 4264 |
|
| 4265 |
|
| 4266 | debug->op = LPFC_IDIAG_OP_RD;
|
| 4267 |
|
| 4268 | if (!debug->buffer)
|
| 4269 | debug->buffer = kmalloc(LPFC_QUE_ACC_BUF_SIZE, GFP_KERNEL);
|
| 4270 | if (!debug->buffer)
|
| 4271 | return 0;
|
| 4272 | pbuffer = debug->buffer;
|
| 4273 |
|
| 4274 | if (*ppos)
|
| 4275 | return 0;
|
| 4276 |
|
| 4277 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) {
|
| 4278 | index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX];
|
| 4279 | count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX];
|
| 4280 | pque = (struct lpfc_queue *)idiag.ptr_private;
|
| 4281 | } else
|
| 4282 | return 0;
|
| 4283 |
|
| 4284 |
|
| 4285 | if (count == LPFC_QUE_ACC_BROWSE)
|
| 4286 | goto que_browse;
|
| 4287 |
|
| 4288 |
|
| 4289 | len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index);
|
| 4290 |
|
| 4291 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
|
| 4292 |
|
| 4293 | que_browse:
|
| 4294 |
|
| 4295 |
|
| 4296 | last_index = idiag.offset.last_rd;
|
| 4297 | index = last_index;
|
| 4298 |
|
| 4299 | while (len < LPFC_QUE_ACC_SIZE - pque->entry_size) {
|
| 4300 | len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index);
|
| 4301 | index++;
|
| 4302 | if (index > pque->entry_count - 1)
|
| 4303 | break;
|
| 4304 | }
|
| 4305 |
|
| 4306 |
|
| 4307 | if (index > pque->entry_count - 1)
|
| 4308 | index = 0;
|
| 4309 | idiag.offset.last_rd = index;
|
| 4310 |
|
| 4311 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
|
| 4312 | }
|
| 4313 |
|
| 4314 | |
| 4315 | * lpfc_idiag_queacc_write - Syntax check and set up idiag queacc commands
|
| 4316 | * @file: The file pointer to read from.
|
| 4317 | * @buf: The buffer to copy the user data from.
|
| 4318 | * @nbytes: The number of bytes to get.
|
| 4319 | * @ppos: The position in the file to start reading from.
|
| 4320 | *
|
| 4321 | * This routine get the debugfs idiag command struct from user space and then
|
| 4322 | * perform the syntax check for port queue read (dump) or write (set) command
|
| 4323 | * accordingly. In the case of port queue read command, it sets up the command
|
| 4324 | * in the idiag command struct for the following debugfs read operation. In
|
| 4325 | * the case of port queue write operation, it executes the write operation
|
| 4326 | * into the port queue entry accordingly.
|
| 4327 | *
|
| 4328 | * It returns the @nbytges passing in from debugfs user space when successful.
|
| 4329 | * In case of error conditions, it returns proper error code back to the user
|
| 4330 | * space.
|
| 4331 | *
|
| 4332 | static ssize_t
|
| 4333 | lpfc_idiag_queacc_write(struct file *file, const char __user *buf,
|
| 4334 | size_t nbytes, loff_t *ppos)
|
| 4335 | {
|
| 4336 | struct lpfc_debug *debug = file->private_data;
|
| 4337 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 4338 | uint32_t qidx, quetp, queid, index, count, offset, value;
|
| 4339 | uint32_t *pentry;
|
| 4340 | struct lpfc_queue *pque, *qp;
|
| 4341 | int rc;
|
| 4342 |
|
| 4343 |
|
| 4344 | debug->op = LPFC_IDIAG_OP_WR;
|
| 4345 |
|
| 4346 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
|
| 4347 | if (rc < 0)
|
| 4348 | return rc;
|
| 4349 |
|
| 4350 |
|
| 4351 | quetp = idiag.cmd.data[IDIAG_QUEACC_QUETP_INDX];
|
| 4352 | queid = idiag.cmd.data[IDIAG_QUEACC_QUEID_INDX];
|
| 4353 | index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX];
|
| 4354 | count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX];
|
| 4355 | offset = idiag.cmd.data[IDIAG_QUEACC_OFFST_INDX];
|
| 4356 | value = idiag.cmd.data[IDIAG_QUEACC_VALUE_INDX];
|
| 4357 |
|
| 4358 |
|
| 4359 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR ||
|
| 4360 | idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST ||
|
| 4361 | idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) {
|
| 4362 | if (rc != LPFC_QUE_ACC_WR_CMD_ARG)
|
| 4363 | goto error_out;
|
| 4364 | if (count != 1)
|
| 4365 | goto error_out;
|
| 4366 | } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) {
|
| 4367 | if (rc != LPFC_QUE_ACC_RD_CMD_ARG)
|
| 4368 | goto error_out;
|
| 4369 | } else
|
| 4370 | goto error_out;
|
| 4371 |
|
| 4372 | switch (quetp) {
|
| 4373 | case LPFC_IDIAG_EQ:
|
| 4374 |
|
| 4375 | if (phba->sli4_hba.hdwq) {
|
| 4376 | for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
|
| 4377 | qp = phba->sli4_hba.hdwq[qidx].hba_eq;
|
| 4378 | if (qp && qp->queue_id == queid) {
|
| 4379 |
|
| 4380 | rc = lpfc_idiag_que_param_check(qp,
|
| 4381 | index, count);
|
| 4382 | if (rc)
|
| 4383 | goto error_out;
|
| 4384 | idiag.ptr_private = qp;
|
| 4385 | goto pass_check;
|
| 4386 | }
|
| 4387 | }
|
| 4388 | }
|
| 4389 | goto error_out;
|
| 4390 |
|
| 4391 | case LPFC_IDIAG_CQ:
|
| 4392 |
|
| 4393 | if (phba->sli4_hba.mbx_cq &&
|
| 4394 | phba->sli4_hba.mbx_cq->queue_id == queid) {
|
| 4395 |
|
| 4396 | rc = lpfc_idiag_que_param_check(
|
| 4397 | phba->sli4_hba.mbx_cq, index, count);
|
| 4398 | if (rc)
|
| 4399 | goto error_out;
|
| 4400 | idiag.ptr_private = phba->sli4_hba.mbx_cq;
|
| 4401 | goto pass_check;
|
| 4402 | }
|
| 4403 |
|
| 4404 | if (phba->sli4_hba.els_cq &&
|
| 4405 | phba->sli4_hba.els_cq->queue_id == queid) {
|
| 4406 |
|
| 4407 | rc = lpfc_idiag_que_param_check(
|
| 4408 | phba->sli4_hba.els_cq, index, count);
|
| 4409 | if (rc)
|
| 4410 | goto error_out;
|
| 4411 | idiag.ptr_private = phba->sli4_hba.els_cq;
|
| 4412 | goto pass_check;
|
| 4413 | }
|
| 4414 |
|
| 4415 | if (phba->sli4_hba.nvmels_cq &&
|
| 4416 | phba->sli4_hba.nvmels_cq->queue_id == queid) {
|
| 4417 |
|
| 4418 | rc = lpfc_idiag_que_param_check(
|
| 4419 | phba->sli4_hba.nvmels_cq, index, count);
|
| 4420 | if (rc)
|
| 4421 | goto error_out;
|
| 4422 | idiag.ptr_private = phba->sli4_hba.nvmels_cq;
|
| 4423 | goto pass_check;
|
| 4424 | }
|
| 4425 |
|
| 4426 | if (phba->sli4_hba.hdwq) {
|
| 4427 | for (qidx = 0; qidx < phba->cfg_hdw_queue;
|
| 4428 | qidx++) {
|
| 4429 | qp = phba->sli4_hba.hdwq[qidx].io_cq;
|
| 4430 | if (qp && qp->queue_id == queid) {
|
| 4431 |
|
| 4432 | rc = lpfc_idiag_que_param_check(
|
| 4433 | qp, index, count);
|
| 4434 | if (rc)
|
| 4435 | goto error_out;
|
| 4436 | idiag.ptr_private = qp;
|
| 4437 | goto pass_check;
|
| 4438 | }
|
| 4439 | }
|
| 4440 | }
|
| 4441 | goto error_out;
|
| 4442 |
|
| 4443 | case LPFC_IDIAG_MQ:
|
| 4444 |
|
| 4445 | if (phba->sli4_hba.mbx_wq &&
|
| 4446 | phba->sli4_hba.mbx_wq->queue_id == queid) {
|
| 4447 |
|
| 4448 | rc = lpfc_idiag_que_param_check(
|
| 4449 | phba->sli4_hba.mbx_wq, index, count);
|
| 4450 | if (rc)
|
| 4451 | goto error_out;
|
| 4452 | idiag.ptr_private = phba->sli4_hba.mbx_wq;
|
| 4453 | goto pass_check;
|
| 4454 | }
|
| 4455 | goto error_out;
|
| 4456 |
|
| 4457 | case LPFC_IDIAG_WQ:
|
| 4458 |
|
| 4459 | if (phba->sli4_hba.els_wq &&
|
| 4460 | phba->sli4_hba.els_wq->queue_id == queid) {
|
| 4461 |
|
| 4462 | rc = lpfc_idiag_que_param_check(
|
| 4463 | phba->sli4_hba.els_wq, index, count);
|
| 4464 | if (rc)
|
| 4465 | goto error_out;
|
| 4466 | idiag.ptr_private = phba->sli4_hba.els_wq;
|
| 4467 | goto pass_check;
|
| 4468 | }
|
| 4469 |
|
| 4470 | if (phba->sli4_hba.nvmels_wq &&
|
| 4471 | phba->sli4_hba.nvmels_wq->queue_id == queid) {
|
| 4472 |
|
| 4473 | rc = lpfc_idiag_que_param_check(
|
| 4474 | phba->sli4_hba.nvmels_wq, index, count);
|
| 4475 | if (rc)
|
| 4476 | goto error_out;
|
| 4477 | idiag.ptr_private = phba->sli4_hba.nvmels_wq;
|
| 4478 | goto pass_check;
|
| 4479 | }
|
| 4480 |
|
| 4481 | if (phba->sli4_hba.hdwq) {
|
| 4482 |
|
| 4483 | for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
|
| 4484 | qp = phba->sli4_hba.hdwq[qidx].io_wq;
|
| 4485 | if (qp && qp->queue_id == queid) {
|
| 4486 |
|
| 4487 | rc = lpfc_idiag_que_param_check(
|
| 4488 | qp, index, count);
|
| 4489 | if (rc)
|
| 4490 | goto error_out;
|
| 4491 | idiag.ptr_private = qp;
|
| 4492 | goto pass_check;
|
| 4493 | }
|
| 4494 | }
|
| 4495 | }
|
| 4496 | goto error_out;
|
| 4497 |
|
| 4498 | case LPFC_IDIAG_RQ:
|
| 4499 |
|
| 4500 | if (phba->sli4_hba.hdr_rq &&
|
| 4501 | phba->sli4_hba.hdr_rq->queue_id == queid) {
|
| 4502 |
|
| 4503 | rc = lpfc_idiag_que_param_check(
|
| 4504 | phba->sli4_hba.hdr_rq, index, count);
|
| 4505 | if (rc)
|
| 4506 | goto error_out;
|
| 4507 | idiag.ptr_private = phba->sli4_hba.hdr_rq;
|
| 4508 | goto pass_check;
|
| 4509 | }
|
| 4510 |
|
| 4511 | if (phba->sli4_hba.dat_rq &&
|
| 4512 | phba->sli4_hba.dat_rq->queue_id == queid) {
|
| 4513 |
|
| 4514 | rc = lpfc_idiag_que_param_check(
|
| 4515 | phba->sli4_hba.dat_rq, index, count);
|
| 4516 | if (rc)
|
| 4517 | goto error_out;
|
| 4518 | idiag.ptr_private = phba->sli4_hba.dat_rq;
|
| 4519 | goto pass_check;
|
| 4520 | }
|
| 4521 | goto error_out;
|
| 4522 | default:
|
| 4523 | goto error_out;
|
| 4524 | }
|
| 4525 |
|
| 4526 | pass_check:
|
| 4527 |
|
| 4528 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) {
|
| 4529 | if (count == LPFC_QUE_ACC_BROWSE)
|
| 4530 | idiag.offset.last_rd = index;
|
| 4531 | }
|
| 4532 |
|
| 4533 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR ||
|
| 4534 | idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST ||
|
| 4535 | idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) {
|
| 4536 |
|
| 4537 | pque = (struct lpfc_queue *)idiag.ptr_private;
|
| 4538 | if (offset > pque->entry_size/sizeof(uint32_t) - 1)
|
| 4539 | goto error_out;
|
| 4540 | pentry = lpfc_sli4_qe(pque, index);
|
| 4541 | pentry += offset;
|
| 4542 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR)
|
| 4543 | *pentry = value;
|
| 4544 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST)
|
| 4545 | *pentry |= value;
|
| 4546 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL)
|
| 4547 | *pentry &= ~value;
|
| 4548 | }
|
| 4549 | return nbytes;
|
| 4550 |
|
| 4551 | error_out:
|
| 4552 |
|
| 4553 | memset(&idiag, 0, sizeof(idiag));
|
| 4554 | return -EINVAL;
|
| 4555 | }
|
| 4556 |
|
| 4557 | |
| 4558 | * lpfc_idiag_drbacc_read_reg - idiag debugfs read a doorbell register
|
| 4559 | * @phba: The pointer to hba structure.
|
| 4560 | * @pbuffer: The pointer to the buffer to copy the data to.
|
| 4561 | * @len: The length of bytes to copied.
|
| 4562 | * @drbregid: The id to doorbell registers.
|
| 4563 | *
|
| 4564 | * Description:
|
| 4565 | * This routine reads a doorbell register and copies its content to the
|
| 4566 | * user buffer pointed to by @pbuffer.
|
| 4567 | *
|
| 4568 | * Returns:
|
| 4569 | * This function returns the amount of data that was copied into @pbuffer.
|
| 4570 | *
|
| 4571 | static int
|
| 4572 | lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer,
|
| 4573 | int len, uint32_t drbregid)
|
| 4574 | {
|
| 4575 |
|
| 4576 | if (!pbuffer)
|
| 4577 | return 0;
|
| 4578 |
|
| 4579 | switch (drbregid) {
|
| 4580 | case LPFC_DRB_EQ:
|
| 4581 | len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE-len,
|
| 4582 | "EQ-DRB-REG: 0x%08x\n",
|
| 4583 | readl(phba->sli4_hba.EQDBregaddr));
|
| 4584 | break;
|
| 4585 | case LPFC_DRB_CQ:
|
| 4586 | len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE - len,
|
| 4587 | "CQ-DRB-REG: 0x%08x\n",
|
| 4588 | readl(phba->sli4_hba.CQDBregaddr));
|
| 4589 | break;
|
| 4590 | case LPFC_DRB_MQ:
|
| 4591 | len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
|
| 4592 | "MQ-DRB-REG: 0x%08x\n",
|
| 4593 | readl(phba->sli4_hba.MQDBregaddr));
|
| 4594 | break;
|
| 4595 | case LPFC_DRB_WQ:
|
| 4596 | len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
|
| 4597 | "WQ-DRB-REG: 0x%08x\n",
|
| 4598 | readl(phba->sli4_hba.WQDBregaddr));
|
| 4599 | break;
|
| 4600 | case LPFC_DRB_RQ:
|
| 4601 | len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
|
| 4602 | "RQ-DRB-REG: 0x%08x\n",
|
| 4603 | readl(phba->sli4_hba.RQDBregaddr));
|
| 4604 | break;
|
| 4605 | default:
|
| 4606 | break;
|
| 4607 | }
|
| 4608 |
|
| 4609 | return len;
|
| 4610 | }
|
| 4611 |
|
| 4612 | |
| 4613 | * lpfc_idiag_drbacc_read - idiag debugfs read port doorbell
|
| 4614 | * @file: The file pointer to read from.
|
| 4615 | * @buf: The buffer to copy the data to.
|
| 4616 | * @nbytes: The number of bytes to read.
|
| 4617 | * @ppos: The position in the file to start reading from.
|
| 4618 | *
|
| 4619 | * Description:
|
| 4620 | * This routine reads data from the @phba device doorbell register according
|
| 4621 | * to the idiag command, and copies to user @buf. Depending on the doorbell
|
| 4622 | * register read command setup, it does either a single doorbell register
|
| 4623 | * read or dump all doorbell registers.
|
| 4624 | *
|
| 4625 | * Returns:
|
| 4626 | * This function returns the amount of data that was read (this could be less
|
| 4627 | * than @nbytes if the end of the file was reached) or a negative error value.
|
| 4628 | *
|
| 4629 | static ssize_t
|
| 4630 | lpfc_idiag_drbacc_read(struct file *file, char __user *buf, size_t nbytes,
|
| 4631 | loff_t *ppos)
|
| 4632 | {
|
| 4633 | struct lpfc_debug *debug = file->private_data;
|
| 4634 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 4635 | uint32_t drb_reg_id, i;
|
| 4636 | char *pbuffer;
|
| 4637 | int len = 0;
|
| 4638 |
|
| 4639 |
|
| 4640 | debug->op = LPFC_IDIAG_OP_RD;
|
| 4641 |
|
| 4642 | if (!debug->buffer)
|
| 4643 | debug->buffer = kmalloc(LPFC_DRB_ACC_BUF_SIZE, GFP_KERNEL);
|
| 4644 | if (!debug->buffer)
|
| 4645 | return 0;
|
| 4646 | pbuffer = debug->buffer;
|
| 4647 |
|
| 4648 | if (*ppos)
|
| 4649 | return 0;
|
| 4650 |
|
| 4651 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD)
|
| 4652 | drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX];
|
| 4653 | else
|
| 4654 | return 0;
|
| 4655 |
|
| 4656 | if (drb_reg_id == LPFC_DRB_ACC_ALL)
|
| 4657 | for (i = 1; i <= LPFC_DRB_MAX; i++)
|
| 4658 | len = lpfc_idiag_drbacc_read_reg(phba,
|
| 4659 | pbuffer, len, i);
|
| 4660 | else
|
| 4661 | len = lpfc_idiag_drbacc_read_reg(phba,
|
| 4662 | pbuffer, len, drb_reg_id);
|
| 4663 |
|
| 4664 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
|
| 4665 | }
|
| 4666 |
|
| 4667 | |
| 4668 | * lpfc_idiag_drbacc_write - Syntax check and set up idiag drbacc commands
|
| 4669 | * @file: The file pointer to read from.
|
| 4670 | * @buf: The buffer to copy the user data from.
|
| 4671 | * @nbytes: The number of bytes to get.
|
| 4672 | * @ppos: The position in the file to start reading from.
|
| 4673 | *
|
| 4674 | * This routine get the debugfs idiag command struct from user space and then
|
| 4675 | * perform the syntax check for port doorbell register read (dump) or write
|
| 4676 | * (set) command accordingly. In the case of port queue read command, it sets
|
| 4677 | * up the command in the idiag command struct for the following debugfs read
|
| 4678 | * operation. In the case of port doorbell register write operation, it
|
| 4679 | * executes the write operation into the port doorbell register accordingly.
|
| 4680 | *
|
| 4681 | * It returns the @nbytges passing in from debugfs user space when successful.
|
| 4682 | * In case of error conditions, it returns proper error code back to the user
|
| 4683 | * space.
|
| 4684 | *
|
| 4685 | static ssize_t
|
| 4686 | lpfc_idiag_drbacc_write(struct file *file, const char __user *buf,
|
| 4687 | size_t nbytes, loff_t *ppos)
|
| 4688 | {
|
| 4689 | struct lpfc_debug *debug = file->private_data;
|
| 4690 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 4691 | uint32_t drb_reg_id, value, reg_val = 0;
|
| 4692 | void __iomem *drb_reg;
|
| 4693 | int rc;
|
| 4694 |
|
| 4695 |
|
| 4696 | debug->op = LPFC_IDIAG_OP_WR;
|
| 4697 |
|
| 4698 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
|
| 4699 | if (rc < 0)
|
| 4700 | return rc;
|
| 4701 |
|
| 4702 |
|
| 4703 | drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX];
|
| 4704 | value = idiag.cmd.data[IDIAG_DRBACC_VALUE_INDX];
|
| 4705 |
|
| 4706 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR ||
|
| 4707 | idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST ||
|
| 4708 | idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) {
|
| 4709 | if (rc != LPFC_DRB_ACC_WR_CMD_ARG)
|
| 4710 | goto error_out;
|
| 4711 | if (drb_reg_id > LPFC_DRB_MAX)
|
| 4712 | goto error_out;
|
| 4713 | } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) {
|
| 4714 | if (rc != LPFC_DRB_ACC_RD_CMD_ARG)
|
| 4715 | goto error_out;
|
| 4716 | if ((drb_reg_id > LPFC_DRB_MAX) &&
|
| 4717 | (drb_reg_id != LPFC_DRB_ACC_ALL))
|
| 4718 | goto error_out;
|
| 4719 | } else
|
| 4720 | goto error_out;
|
| 4721 |
|
| 4722 |
|
| 4723 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR ||
|
| 4724 | idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST ||
|
| 4725 | idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) {
|
| 4726 | switch (drb_reg_id) {
|
| 4727 | case LPFC_DRB_EQ:
|
| 4728 | drb_reg = phba->sli4_hba.EQDBregaddr;
|
| 4729 | break;
|
| 4730 | case LPFC_DRB_CQ:
|
| 4731 | drb_reg = phba->sli4_hba.CQDBregaddr;
|
| 4732 | break;
|
| 4733 | case LPFC_DRB_MQ:
|
| 4734 | drb_reg = phba->sli4_hba.MQDBregaddr;
|
| 4735 | break;
|
| 4736 | case LPFC_DRB_WQ:
|
| 4737 | drb_reg = phba->sli4_hba.WQDBregaddr;
|
| 4738 | break;
|
| 4739 | case LPFC_DRB_RQ:
|
| 4740 | drb_reg = phba->sli4_hba.RQDBregaddr;
|
| 4741 | break;
|
| 4742 | default:
|
| 4743 | goto error_out;
|
| 4744 | }
|
| 4745 |
|
| 4746 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR)
|
| 4747 | reg_val = value;
|
| 4748 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST) {
|
| 4749 | reg_val = readl(drb_reg);
|
| 4750 | reg_val |= value;
|
| 4751 | }
|
| 4752 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) {
|
| 4753 | reg_val = readl(drb_reg);
|
| 4754 | reg_val &= ~value;
|
| 4755 | }
|
| 4756 | writel(reg_val, drb_reg);
|
| 4757 | readl(drb_reg);
|
| 4758 | }
|
| 4759 | return nbytes;
|
| 4760 |
|
| 4761 | error_out:
|
| 4762 |
|
| 4763 | memset(&idiag, 0, sizeof(idiag));
|
| 4764 | return -EINVAL;
|
| 4765 | }
|
| 4766 |
|
| 4767 | |
| 4768 | * lpfc_idiag_ctlacc_read_reg - idiag debugfs read a control registers
|
| 4769 | * @phba: The pointer to hba structure.
|
| 4770 | * @pbuffer: The pointer to the buffer to copy the data to.
|
| 4771 | * @len: The length of bytes to copied.
|
| 4772 | * @ctlregid: The id to doorbell registers.
|
| 4773 | *
|
| 4774 | * Description:
|
| 4775 | * This routine reads a control register and copies its content to the
|
| 4776 | * user buffer pointed to by @pbuffer.
|
| 4777 | *
|
| 4778 | * Returns:
|
| 4779 | * This function returns the amount of data that was copied into @pbuffer.
|
| 4780 | *
|
| 4781 | static int
|
| 4782 | lpfc_idiag_ctlacc_read_reg(struct lpfc_hba *phba, char *pbuffer,
|
| 4783 | int len, uint32_t ctlregid)
|
| 4784 | {
|
| 4785 |
|
| 4786 | if (!pbuffer)
|
| 4787 | return 0;
|
| 4788 |
|
| 4789 | switch (ctlregid) {
|
| 4790 | case LPFC_CTL_PORT_SEM:
|
| 4791 | len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
|
| 4792 | "Port SemReg: 0x%08x\n",
|
| 4793 | readl(phba->sli4_hba.conf_regs_memmap_p +
|
| 4794 | LPFC_CTL_PORT_SEM_OFFSET));
|
| 4795 | break;
|
| 4796 | case LPFC_CTL_PORT_STA:
|
| 4797 | len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
|
| 4798 | "Port StaReg: 0x%08x\n",
|
| 4799 | readl(phba->sli4_hba.conf_regs_memmap_p +
|
| 4800 | LPFC_CTL_PORT_STA_OFFSET));
|
| 4801 | break;
|
| 4802 | case LPFC_CTL_PORT_CTL:
|
| 4803 | len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
|
| 4804 | "Port CtlReg: 0x%08x\n",
|
| 4805 | readl(phba->sli4_hba.conf_regs_memmap_p +
|
| 4806 | LPFC_CTL_PORT_CTL_OFFSET));
|
| 4807 | break;
|
| 4808 | case LPFC_CTL_PORT_ER1:
|
| 4809 | len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
|
| 4810 | "Port Er1Reg: 0x%08x\n",
|
| 4811 | readl(phba->sli4_hba.conf_regs_memmap_p +
|
| 4812 | LPFC_CTL_PORT_ER1_OFFSET));
|
| 4813 | break;
|
| 4814 | case LPFC_CTL_PORT_ER2:
|
| 4815 | len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
|
| 4816 | "Port Er2Reg: 0x%08x\n",
|
| 4817 | readl(phba->sli4_hba.conf_regs_memmap_p +
|
| 4818 | LPFC_CTL_PORT_ER2_OFFSET));
|
| 4819 | break;
|
| 4820 | case LPFC_CTL_PDEV_CTL:
|
| 4821 | len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
|
| 4822 | "PDev CtlReg: 0x%08x\n",
|
| 4823 | readl(phba->sli4_hba.conf_regs_memmap_p +
|
| 4824 | LPFC_CTL_PDEV_CTL_OFFSET));
|
| 4825 | break;
|
| 4826 | default:
|
| 4827 | break;
|
| 4828 | }
|
| 4829 | return len;
|
| 4830 | }
|
| 4831 |
|
| 4832 | |
| 4833 | * lpfc_idiag_ctlacc_read - idiag debugfs read port and device control register
|
| 4834 | * @file: The file pointer to read from.
|
| 4835 | * @buf: The buffer to copy the data to.
|
| 4836 | * @nbytes: The number of bytes to read.
|
| 4837 | * @ppos: The position in the file to start reading from.
|
| 4838 | *
|
| 4839 | * Description:
|
| 4840 | * This routine reads data from the @phba port and device registers according
|
| 4841 | * to the idiag command, and copies to user @buf.
|
| 4842 | *
|
| 4843 | * Returns:
|
| 4844 | * This function returns the amount of data that was read (this could be less
|
| 4845 | * than @nbytes if the end of the file was reached) or a negative error value.
|
| 4846 | *
|
| 4847 | static ssize_t
|
| 4848 | lpfc_idiag_ctlacc_read(struct file *file, char __user *buf, size_t nbytes,
|
| 4849 | loff_t *ppos)
|
| 4850 | {
|
| 4851 | struct lpfc_debug *debug = file->private_data;
|
| 4852 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 4853 | uint32_t ctl_reg_id, i;
|
| 4854 | char *pbuffer;
|
| 4855 | int len = 0;
|
| 4856 |
|
| 4857 |
|
| 4858 | debug->op = LPFC_IDIAG_OP_RD;
|
| 4859 |
|
| 4860 | if (!debug->buffer)
|
| 4861 | debug->buffer = kmalloc(LPFC_CTL_ACC_BUF_SIZE, GFP_KERNEL);
|
| 4862 | if (!debug->buffer)
|
| 4863 | return 0;
|
| 4864 | pbuffer = debug->buffer;
|
| 4865 |
|
| 4866 | if (*ppos)
|
| 4867 | return 0;
|
| 4868 |
|
| 4869 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD)
|
| 4870 | ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX];
|
| 4871 | else
|
| 4872 | return 0;
|
| 4873 |
|
| 4874 | if (ctl_reg_id == LPFC_CTL_ACC_ALL)
|
| 4875 | for (i = 1; i <= LPFC_CTL_MAX; i++)
|
| 4876 | len = lpfc_idiag_ctlacc_read_reg(phba,
|
| 4877 | pbuffer, len, i);
|
| 4878 | else
|
| 4879 | len = lpfc_idiag_ctlacc_read_reg(phba,
|
| 4880 | pbuffer, len, ctl_reg_id);
|
| 4881 |
|
| 4882 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
|
| 4883 | }
|
| 4884 |
|
| 4885 | |
| 4886 | * lpfc_idiag_ctlacc_write - Syntax check and set up idiag ctlacc commands
|
| 4887 | * @file: The file pointer to read from.
|
| 4888 | * @buf: The buffer to copy the user data from.
|
| 4889 | * @nbytes: The number of bytes to get.
|
| 4890 | * @ppos: The position in the file to start reading from.
|
| 4891 | *
|
| 4892 | * This routine get the debugfs idiag command struct from user space and then
|
| 4893 | * perform the syntax check for port and device control register read (dump)
|
| 4894 | * or write (set) command accordingly.
|
| 4895 | *
|
| 4896 | * It returns the @nbytges passing in from debugfs user space when successful.
|
| 4897 | * In case of error conditions, it returns proper error code back to the user
|
| 4898 | * space.
|
| 4899 | *
|
| 4900 | static ssize_t
|
| 4901 | lpfc_idiag_ctlacc_write(struct file *file, const char __user *buf,
|
| 4902 | size_t nbytes, loff_t *ppos)
|
| 4903 | {
|
| 4904 | struct lpfc_debug *debug = file->private_data;
|
| 4905 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 4906 | uint32_t ctl_reg_id, value, reg_val = 0;
|
| 4907 | void __iomem *ctl_reg;
|
| 4908 | int rc;
|
| 4909 |
|
| 4910 |
|
| 4911 | debug->op = LPFC_IDIAG_OP_WR;
|
| 4912 |
|
| 4913 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
|
| 4914 | if (rc < 0)
|
| 4915 | return rc;
|
| 4916 |
|
| 4917 |
|
| 4918 | ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX];
|
| 4919 | value = idiag.cmd.data[IDIAG_CTLACC_VALUE_INDX];
|
| 4920 |
|
| 4921 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR ||
|
| 4922 | idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST ||
|
| 4923 | idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
|
| 4924 | if (rc != LPFC_CTL_ACC_WR_CMD_ARG)
|
| 4925 | goto error_out;
|
| 4926 | if (ctl_reg_id > LPFC_CTL_MAX)
|
| 4927 | goto error_out;
|
| 4928 | } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD) {
|
| 4929 | if (rc != LPFC_CTL_ACC_RD_CMD_ARG)
|
| 4930 | goto error_out;
|
| 4931 | if ((ctl_reg_id > LPFC_CTL_MAX) &&
|
| 4932 | (ctl_reg_id != LPFC_CTL_ACC_ALL))
|
| 4933 | goto error_out;
|
| 4934 | } else
|
| 4935 | goto error_out;
|
| 4936 |
|
| 4937 |
|
| 4938 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR ||
|
| 4939 | idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST ||
|
| 4940 | idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
|
| 4941 | switch (ctl_reg_id) {
|
| 4942 | case LPFC_CTL_PORT_SEM:
|
| 4943 | ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
|
| 4944 | LPFC_CTL_PORT_SEM_OFFSET;
|
| 4945 | break;
|
| 4946 | case LPFC_CTL_PORT_STA:
|
| 4947 | ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
|
| 4948 | LPFC_CTL_PORT_STA_OFFSET;
|
| 4949 | break;
|
| 4950 | case LPFC_CTL_PORT_CTL:
|
| 4951 | ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
|
| 4952 | LPFC_CTL_PORT_CTL_OFFSET;
|
| 4953 | break;
|
| 4954 | case LPFC_CTL_PORT_ER1:
|
| 4955 | ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
|
| 4956 | LPFC_CTL_PORT_ER1_OFFSET;
|
| 4957 | break;
|
| 4958 | case LPFC_CTL_PORT_ER2:
|
| 4959 | ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
|
| 4960 | LPFC_CTL_PORT_ER2_OFFSET;
|
| 4961 | break;
|
| 4962 | case LPFC_CTL_PDEV_CTL:
|
| 4963 | ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
|
| 4964 | LPFC_CTL_PDEV_CTL_OFFSET;
|
| 4965 | break;
|
| 4966 | default:
|
| 4967 | goto error_out;
|
| 4968 | }
|
| 4969 |
|
| 4970 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR)
|
| 4971 | reg_val = value;
|
| 4972 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST) {
|
| 4973 | reg_val = readl(ctl_reg);
|
| 4974 | reg_val |= value;
|
| 4975 | }
|
| 4976 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
|
| 4977 | reg_val = readl(ctl_reg);
|
| 4978 | reg_val &= ~value;
|
| 4979 | }
|
| 4980 | writel(reg_val, ctl_reg);
|
| 4981 | readl(ctl_reg);
|
| 4982 | }
|
| 4983 | return nbytes;
|
| 4984 |
|
| 4985 | error_out:
|
| 4986 |
|
| 4987 | memset(&idiag, 0, sizeof(idiag));
|
| 4988 | return -EINVAL;
|
| 4989 | }
|
| 4990 |
|
| 4991 | |
| 4992 | * lpfc_idiag_mbxacc_get_setup - idiag debugfs get mailbox access setup
|
| 4993 | * @phba: Pointer to HBA context object.
|
| 4994 | * @pbuffer: Pointer to data buffer.
|
| 4995 | *
|
| 4996 | * Description:
|
| 4997 | * This routine gets the driver mailbox access debugfs setup information.
|
| 4998 | *
|
| 4999 | * Returns:
|
| 5000 | * This function returns the amount of data that was read (this could be less
|
| 5001 | * than @nbytes if the end of the file was reached) or a negative error value.
|
| 5002 | *
|
| 5003 | static int
|
| 5004 | lpfc_idiag_mbxacc_get_setup(struct lpfc_hba *phba, char *pbuffer)
|
| 5005 | {
|
| 5006 | uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd;
|
| 5007 | int len = 0;
|
| 5008 |
|
| 5009 | mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
|
| 5010 | mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
|
| 5011 | mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
|
| 5012 | mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
|
| 5013 |
|
| 5014 | len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
|
| 5015 | "mbx_dump_map: 0x%08x\n", mbx_dump_map);
|
| 5016 | len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
|
| 5017 | "mbx_dump_cnt: %04d\n", mbx_dump_cnt);
|
| 5018 | len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
|
| 5019 | "mbx_word_cnt: %04d\n", mbx_word_cnt);
|
| 5020 | len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
|
| 5021 | "mbx_mbox_cmd: 0x%02x\n", mbx_mbox_cmd);
|
| 5022 |
|
| 5023 | return len;
|
| 5024 | }
|
| 5025 |
|
| 5026 | |
| 5027 | * lpfc_idiag_mbxacc_read - idiag debugfs read on mailbox access
|
| 5028 | * @file: The file pointer to read from.
|
| 5029 | * @buf: The buffer to copy the data to.
|
| 5030 | * @nbytes: The number of bytes to read.
|
| 5031 | * @ppos: The position in the file to start reading from.
|
| 5032 | *
|
| 5033 | * Description:
|
| 5034 | * This routine reads data from the @phba driver mailbox access debugfs setup
|
| 5035 | * information.
|
| 5036 | *
|
| 5037 | * Returns:
|
| 5038 | * This function returns the amount of data that was read (this could be less
|
| 5039 | * than @nbytes if the end of the file was reached) or a negative error value.
|
| 5040 | *
|
| 5041 | static ssize_t
|
| 5042 | lpfc_idiag_mbxacc_read(struct file *file, char __user *buf, size_t nbytes,
|
| 5043 | loff_t *ppos)
|
| 5044 | {
|
| 5045 | struct lpfc_debug *debug = file->private_data;
|
| 5046 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 5047 | char *pbuffer;
|
| 5048 | int len = 0;
|
| 5049 |
|
| 5050 |
|
| 5051 | debug->op = LPFC_IDIAG_OP_RD;
|
| 5052 |
|
| 5053 | if (!debug->buffer)
|
| 5054 | debug->buffer = kmalloc(LPFC_MBX_ACC_BUF_SIZE, GFP_KERNEL);
|
| 5055 | if (!debug->buffer)
|
| 5056 | return 0;
|
| 5057 | pbuffer = debug->buffer;
|
| 5058 |
|
| 5059 | if (*ppos)
|
| 5060 | return 0;
|
| 5061 |
|
| 5062 | if ((idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP) &&
|
| 5063 | (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP))
|
| 5064 | return 0;
|
| 5065 |
|
| 5066 | len = lpfc_idiag_mbxacc_get_setup(phba, pbuffer);
|
| 5067 |
|
| 5068 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
|
| 5069 | }
|
| 5070 |
|
| 5071 | |
| 5072 | * lpfc_idiag_mbxacc_write - Syntax check and set up idiag mbxacc commands
|
| 5073 | * @file: The file pointer to read from.
|
| 5074 | * @buf: The buffer to copy the user data from.
|
| 5075 | * @nbytes: The number of bytes to get.
|
| 5076 | * @ppos: The position in the file to start reading from.
|
| 5077 | *
|
| 5078 | * This routine get the debugfs idiag command struct from user space and then
|
| 5079 | * perform the syntax check for driver mailbox command (dump) and sets up the
|
| 5080 | * necessary states in the idiag command struct accordingly.
|
| 5081 | *
|
| 5082 | * It returns the @nbytges passing in from debugfs user space when successful.
|
| 5083 | * In case of error conditions, it returns proper error code back to the user
|
| 5084 | * space.
|
| 5085 | *
|
| 5086 | static ssize_t
|
| 5087 | lpfc_idiag_mbxacc_write(struct file *file, const char __user *buf,
|
| 5088 | size_t nbytes, loff_t *ppos)
|
| 5089 | {
|
| 5090 | struct lpfc_debug *debug = file->private_data;
|
| 5091 | uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd;
|
| 5092 | int rc;
|
| 5093 |
|
| 5094 |
|
| 5095 | debug->op = LPFC_IDIAG_OP_WR;
|
| 5096 |
|
| 5097 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
|
| 5098 | if (rc < 0)
|
| 5099 | return rc;
|
| 5100 |
|
| 5101 |
|
| 5102 | mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
|
| 5103 | mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
|
| 5104 | mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
|
| 5105 | mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
|
| 5106 |
|
| 5107 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_MBXACC_DP) {
|
| 5108 | if (!(mbx_dump_map & LPFC_MBX_DMP_MBX_ALL))
|
| 5109 | goto error_out;
|
| 5110 | if ((mbx_dump_map & ~LPFC_MBX_DMP_MBX_ALL) &&
|
| 5111 | (mbx_dump_map != LPFC_MBX_DMP_ALL))
|
| 5112 | goto error_out;
|
| 5113 | if (mbx_word_cnt > sizeof(MAILBOX_t))
|
| 5114 | goto error_out;
|
| 5115 | } else if (idiag.cmd.opcode == LPFC_IDIAG_BSG_MBXACC_DP) {
|
| 5116 | if (!(mbx_dump_map & LPFC_BSG_DMP_MBX_ALL))
|
| 5117 | goto error_out;
|
| 5118 | if ((mbx_dump_map & ~LPFC_BSG_DMP_MBX_ALL) &&
|
| 5119 | (mbx_dump_map != LPFC_MBX_DMP_ALL))
|
| 5120 | goto error_out;
|
| 5121 | if (mbx_word_cnt > (BSG_MBOX_SIZE)/4)
|
| 5122 | goto error_out;
|
| 5123 | if (mbx_mbox_cmd != 0x9b)
|
| 5124 | goto error_out;
|
| 5125 | } else
|
| 5126 | goto error_out;
|
| 5127 |
|
| 5128 | if (mbx_word_cnt == 0)
|
| 5129 | goto error_out;
|
| 5130 | if (rc != LPFC_MBX_DMP_ARG)
|
| 5131 | goto error_out;
|
| 5132 | if (mbx_mbox_cmd & ~0xff)
|
| 5133 | goto error_out;
|
| 5134 |
|
| 5135 |
|
| 5136 | if (mbx_dump_cnt == 0)
|
| 5137 | goto reset_out;
|
| 5138 |
|
| 5139 | return nbytes;
|
| 5140 |
|
| 5141 | reset_out:
|
| 5142 |
|
| 5143 | memset(&idiag, 0, sizeof(idiag));
|
| 5144 | return nbytes;
|
| 5145 |
|
| 5146 | error_out:
|
| 5147 |
|
| 5148 | memset(&idiag, 0, sizeof(idiag));
|
| 5149 | return -EINVAL;
|
| 5150 | }
|
| 5151 |
|
| 5152 | |
| 5153 | * lpfc_idiag_extacc_avail_get - get the available extents information
|
| 5154 | * @phba: pointer to lpfc hba data structure.
|
| 5155 | * @pbuffer: pointer to internal buffer.
|
| 5156 | * @len: length into the internal buffer data has been copied.
|
| 5157 | *
|
| 5158 | * Description:
|
| 5159 | * This routine is to get the available extent information.
|
| 5160 | *
|
| 5161 | * Returns:
|
| 5162 | * overall length of the data read into the internal buffer.
|
| 5163 | *
|
| 5164 | static int
|
| 5165 | lpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len)
|
| 5166 | {
|
| 5167 | uint16_t ext_cnt = 0, ext_size = 0;
|
| 5168 |
|
| 5169 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5170 | "\nAvailable Extents Information:\n");
|
| 5171 |
|
| 5172 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5173 | "\tPort Available VPI extents: ");
|
| 5174 | lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VPI,
|
| 5175 | &ext_cnt, &ext_size);
|
| 5176 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5177 | "Count %3d, Size %3d\n", ext_cnt, ext_size);
|
| 5178 |
|
| 5179 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5180 | "\tPort Available VFI extents: ");
|
| 5181 | lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VFI,
|
| 5182 | &ext_cnt, &ext_size);
|
| 5183 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5184 | "Count %3d, Size %3d\n", ext_cnt, ext_size);
|
| 5185 |
|
| 5186 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5187 | "\tPort Available RPI extents: ");
|
| 5188 | lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_RPI,
|
| 5189 | &ext_cnt, &ext_size);
|
| 5190 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5191 | "Count %3d, Size %3d\n", ext_cnt, ext_size);
|
| 5192 |
|
| 5193 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5194 | "\tPort Available XRI extents: ");
|
| 5195 | lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_XRI,
|
| 5196 | &ext_cnt, &ext_size);
|
| 5197 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5198 | "Count %3d, Size %3d\n", ext_cnt, ext_size);
|
| 5199 |
|
| 5200 | return len;
|
| 5201 | }
|
| 5202 |
|
| 5203 | |
| 5204 | * lpfc_idiag_extacc_alloc_get - get the allocated extents information
|
| 5205 | * @phba: pointer to lpfc hba data structure.
|
| 5206 | * @pbuffer: pointer to internal buffer.
|
| 5207 | * @len: length into the internal buffer data has been copied.
|
| 5208 | *
|
| 5209 | * Description:
|
| 5210 | * This routine is to get the allocated extent information.
|
| 5211 | *
|
| 5212 | * Returns:
|
| 5213 | * overall length of the data read into the internal buffer.
|
| 5214 | *
|
| 5215 | static int
|
| 5216 | lpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len)
|
| 5217 | {
|
| 5218 | uint16_t ext_cnt, ext_size;
|
| 5219 | int rc;
|
| 5220 |
|
| 5221 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5222 | "\nAllocated Extents Information:\n");
|
| 5223 |
|
| 5224 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5225 | "\tHost Allocated VPI extents: ");
|
| 5226 | rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VPI,
|
| 5227 | &ext_cnt, &ext_size);
|
| 5228 | if (!rc)
|
| 5229 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5230 | "Port %d Extent %3d, Size %3d\n",
|
| 5231 | phba->brd_no, ext_cnt, ext_size);
|
| 5232 | else
|
| 5233 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5234 | "N/A\n");
|
| 5235 |
|
| 5236 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5237 | "\tHost Allocated VFI extents: ");
|
| 5238 | rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VFI,
|
| 5239 | &ext_cnt, &ext_size);
|
| 5240 | if (!rc)
|
| 5241 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5242 | "Port %d Extent %3d, Size %3d\n",
|
| 5243 | phba->brd_no, ext_cnt, ext_size);
|
| 5244 | else
|
| 5245 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5246 | "N/A\n");
|
| 5247 |
|
| 5248 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5249 | "\tHost Allocated RPI extents: ");
|
| 5250 | rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_RPI,
|
| 5251 | &ext_cnt, &ext_size);
|
| 5252 | if (!rc)
|
| 5253 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5254 | "Port %d Extent %3d, Size %3d\n",
|
| 5255 | phba->brd_no, ext_cnt, ext_size);
|
| 5256 | else
|
| 5257 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5258 | "N/A\n");
|
| 5259 |
|
| 5260 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5261 | "\tHost Allocated XRI extents: ");
|
| 5262 | rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_XRI,
|
| 5263 | &ext_cnt, &ext_size);
|
| 5264 | if (!rc)
|
| 5265 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5266 | "Port %d Extent %3d, Size %3d\n",
|
| 5267 | phba->brd_no, ext_cnt, ext_size);
|
| 5268 | else
|
| 5269 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5270 | "N/A\n");
|
| 5271 |
|
| 5272 | return len;
|
| 5273 | }
|
| 5274 |
|
| 5275 | |
| 5276 | * lpfc_idiag_extacc_drivr_get - get driver extent information
|
| 5277 | * @phba: pointer to lpfc hba data structure.
|
| 5278 | * @pbuffer: pointer to internal buffer.
|
| 5279 | * @len: length into the internal buffer data has been copied.
|
| 5280 | *
|
| 5281 | * Description:
|
| 5282 | * This routine is to get the driver extent information.
|
| 5283 | *
|
| 5284 | * Returns:
|
| 5285 | * overall length of the data read into the internal buffer.
|
| 5286 | *
|
| 5287 | static int
|
| 5288 | lpfc_idiag_extacc_drivr_get(struct lpfc_hba *phba, char *pbuffer, int len)
|
| 5289 | {
|
| 5290 | struct lpfc_rsrc_blks *rsrc_blks;
|
| 5291 | int index;
|
| 5292 |
|
| 5293 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5294 | "\nDriver Extents Information:\n");
|
| 5295 |
|
| 5296 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5297 | "\tVPI extents:\n");
|
| 5298 | index = 0;
|
| 5299 | list_for_each_entry(rsrc_blks, &phba->lpfc_vpi_blk_list, list) {
|
| 5300 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5301 | "\t\tBlock %3d: Start %4d, Count %4d\n",
|
| 5302 | index, rsrc_blks->rsrc_start,
|
| 5303 | rsrc_blks->rsrc_size);
|
| 5304 | index++;
|
| 5305 | }
|
| 5306 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5307 | "\tVFI extents:\n");
|
| 5308 | index = 0;
|
| 5309 | list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_vfi_blk_list,
|
| 5310 | list) {
|
| 5311 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5312 | "\t\tBlock %3d: Start %4d, Count %4d\n",
|
| 5313 | index, rsrc_blks->rsrc_start,
|
| 5314 | rsrc_blks->rsrc_size);
|
| 5315 | index++;
|
| 5316 | }
|
| 5317 |
|
| 5318 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5319 | "\tRPI extents:\n");
|
| 5320 | index = 0;
|
| 5321 | list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_rpi_blk_list,
|
| 5322 | list) {
|
| 5323 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5324 | "\t\tBlock %3d: Start %4d, Count %4d\n",
|
| 5325 | index, rsrc_blks->rsrc_start,
|
| 5326 | rsrc_blks->rsrc_size);
|
| 5327 | index++;
|
| 5328 | }
|
| 5329 |
|
| 5330 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5331 | "\tXRI extents:\n");
|
| 5332 | index = 0;
|
| 5333 | list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_xri_blk_list,
|
| 5334 | list) {
|
| 5335 | len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
|
| 5336 | "\t\tBlock %3d: Start %4d, Count %4d\n",
|
| 5337 | index, rsrc_blks->rsrc_start,
|
| 5338 | rsrc_blks->rsrc_size);
|
| 5339 | index++;
|
| 5340 | }
|
| 5341 |
|
| 5342 | return len;
|
| 5343 | }
|
| 5344 |
|
| 5345 | |
| 5346 | * lpfc_idiag_extacc_write - Syntax check and set up idiag extacc commands
|
| 5347 | * @file: The file pointer to read from.
|
| 5348 | * @buf: The buffer to copy the user data from.
|
| 5349 | * @nbytes: The number of bytes to get.
|
| 5350 | * @ppos: The position in the file to start reading from.
|
| 5351 | *
|
| 5352 | * This routine get the debugfs idiag command struct from user space and then
|
| 5353 | * perform the syntax check for extent information access commands and sets
|
| 5354 | * up the necessary states in the idiag command struct accordingly.
|
| 5355 | *
|
| 5356 | * It returns the @nbytges passing in from debugfs user space when successful.
|
| 5357 | * In case of error conditions, it returns proper error code back to the user
|
| 5358 | * space.
|
| 5359 | *
|
| 5360 | static ssize_t
|
| 5361 | lpfc_idiag_extacc_write(struct file *file, const char __user *buf,
|
| 5362 | size_t nbytes, loff_t *ppos)
|
| 5363 | {
|
| 5364 | struct lpfc_debug *debug = file->private_data;
|
| 5365 | uint32_t ext_map;
|
| 5366 | int rc;
|
| 5367 |
|
| 5368 |
|
| 5369 | debug->op = LPFC_IDIAG_OP_WR;
|
| 5370 |
|
| 5371 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
|
| 5372 | if (rc < 0)
|
| 5373 | return rc;
|
| 5374 |
|
| 5375 | ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX];
|
| 5376 |
|
| 5377 | if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD)
|
| 5378 | goto error_out;
|
| 5379 | if (rc != LPFC_EXT_ACC_CMD_ARG)
|
| 5380 | goto error_out;
|
| 5381 | if (!(ext_map & LPFC_EXT_ACC_ALL))
|
| 5382 | goto error_out;
|
| 5383 |
|
| 5384 | return nbytes;
|
| 5385 | error_out:
|
| 5386 |
|
| 5387 | memset(&idiag, 0, sizeof(idiag));
|
| 5388 | return -EINVAL;
|
| 5389 | }
|
| 5390 |
|
| 5391 | |
| 5392 | * lpfc_idiag_extacc_read - idiag debugfs read access to extent information
|
| 5393 | * @file: The file pointer to read from.
|
| 5394 | * @buf: The buffer to copy the data to.
|
| 5395 | * @nbytes: The number of bytes to read.
|
| 5396 | * @ppos: The position in the file to start reading from.
|
| 5397 | *
|
| 5398 | * Description:
|
| 5399 | * This routine reads data from the proper extent information according to
|
| 5400 | * the idiag command, and copies to user @buf.
|
| 5401 | *
|
| 5402 | * Returns:
|
| 5403 | * This function returns the amount of data that was read (this could be less
|
| 5404 | * than @nbytes if the end of the file was reached) or a negative error value.
|
| 5405 | *
|
| 5406 | static ssize_t
|
| 5407 | lpfc_idiag_extacc_read(struct file *file, char __user *buf, size_t nbytes,
|
| 5408 | loff_t *ppos)
|
| 5409 | {
|
| 5410 | struct lpfc_debug *debug = file->private_data;
|
| 5411 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 5412 | char *pbuffer;
|
| 5413 | uint32_t ext_map;
|
| 5414 | int len = 0;
|
| 5415 |
|
| 5416 |
|
| 5417 | debug->op = LPFC_IDIAG_OP_RD;
|
| 5418 |
|
| 5419 | if (!debug->buffer)
|
| 5420 | debug->buffer = kmalloc(LPFC_EXT_ACC_BUF_SIZE, GFP_KERNEL);
|
| 5421 | if (!debug->buffer)
|
| 5422 | return 0;
|
| 5423 | pbuffer = debug->buffer;
|
| 5424 | if (*ppos)
|
| 5425 | return 0;
|
| 5426 | if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD)
|
| 5427 | return 0;
|
| 5428 |
|
| 5429 | ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX];
|
| 5430 | if (ext_map & LPFC_EXT_ACC_AVAIL)
|
| 5431 | len = lpfc_idiag_extacc_avail_get(phba, pbuffer, len);
|
| 5432 | if (ext_map & LPFC_EXT_ACC_ALLOC)
|
| 5433 | len = lpfc_idiag_extacc_alloc_get(phba, pbuffer, len);
|
| 5434 | if (ext_map & LPFC_EXT_ACC_DRIVR)
|
| 5435 | len = lpfc_idiag_extacc_drivr_get(phba, pbuffer, len);
|
| 5436 |
|
| 5437 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
|
| 5438 | }
|
| 5439 |
|
| 5440 | static int
|
| 5441 | lpfc_cgn_buffer_open(struct inode *inode, struct file *file)
|
| 5442 | {
|
| 5443 | struct lpfc_debug *debug;
|
| 5444 | int rc = -ENOMEM;
|
| 5445 |
|
| 5446 | debug = kmalloc_obj(*debug);
|
| 5447 | if (!debug)
|
| 5448 | goto out;
|
| 5449 |
|
| 5450 | debug->buffer = vmalloc(LPFC_CGN_BUF_SIZE);
|
| 5451 | if (!debug->buffer) {
|
| 5452 | kfree(debug);
|
| 5453 | goto out;
|
| 5454 | }
|
| 5455 |
|
| 5456 | debug->i_private = inode->i_private;
|
| 5457 | file->private_data = debug;
|
| 5458 |
|
| 5459 | rc = 0;
|
| 5460 | out:
|
| 5461 | return rc;
|
| 5462 | }
|
| 5463 |
|
| 5464 | static ssize_t
|
| 5465 | lpfc_cgn_buffer_read(struct file *file, char __user *buf, size_t nbytes,
|
| 5466 | loff_t *ppos)
|
| 5467 | {
|
| 5468 | struct lpfc_debug *debug = file->private_data;
|
| 5469 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 5470 | char *buffer = debug->buffer;
|
| 5471 | uint32_t *ptr;
|
| 5472 | int cnt, len = 0;
|
| 5473 |
|
| 5474 | if (!phba->sli4_hba.pc_sli4_params.mi_ver || !phba->cgn_i) {
|
| 5475 | len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
|
| 5476 | "Congestion Mgmt is not supported\n");
|
| 5477 | goto out;
|
| 5478 | }
|
| 5479 | ptr = (uint32_t *)phba->cgn_i->virt;
|
| 5480 | len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
|
| 5481 | "Congestion Buffer Header\n");
|
| 5482 |
|
| 5483 | cnt = 32;
|
| 5484 | len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
|
| 5485 | "000: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
| 5486 | *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3),
|
| 5487 | *(ptr + 4), *(ptr + 5), *(ptr + 6), *(ptr + 7));
|
| 5488 | ptr += 8;
|
| 5489 | len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
|
| 5490 | "Congestion Buffer Data\n");
|
| 5491 | while (cnt < sizeof(struct lpfc_cgn_info)) {
|
| 5492 | if (len > (LPFC_CGN_BUF_SIZE - LPFC_DEBUG_OUT_LINE_SZ)) {
|
| 5493 | len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
|
| 5494 | "Truncated . . .\n");
|
| 5495 | goto out;
|
| 5496 | }
|
| 5497 | len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
|
| 5498 | "%03x: %08x %08x %08x %08x "
|
| 5499 | "%08x %08x %08x %08x\n",
|
| 5500 | cnt, *ptr, *(ptr + 1), *(ptr + 2),
|
| 5501 | *(ptr + 3), *(ptr + 4), *(ptr + 5),
|
| 5502 | *(ptr + 6), *(ptr + 7));
|
| 5503 | cnt += 32;
|
| 5504 | ptr += 8;
|
| 5505 | }
|
| 5506 | if (len > (LPFC_CGN_BUF_SIZE - LPFC_DEBUG_OUT_LINE_SZ)) {
|
| 5507 | len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
|
| 5508 | "Truncated . . .\n");
|
| 5509 | goto out;
|
| 5510 | }
|
| 5511 | len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
|
| 5512 | "Parameter Data\n");
|
| 5513 | ptr = (uint32_t *)&phba->cgn_p;
|
| 5514 | len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
|
| 5515 | "%08x %08x %08x %08x\n",
|
| 5516 | *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3));
|
| 5517 | out:
|
| 5518 | return simple_read_from_buffer(buf, nbytes, ppos, buffer, len);
|
| 5519 | }
|
| 5520 |
|
| 5521 | static int
|
| 5522 | lpfc_cgn_buffer_release(struct inode *inode, struct file *file)
|
| 5523 | {
|
| 5524 | struct lpfc_debug *debug = file->private_data;
|
| 5525 |
|
| 5526 | vfree(debug->buffer);
|
| 5527 | kfree(debug);
|
| 5528 |
|
| 5529 | return 0;
|
| 5530 | }
|
| 5531 |
|
| 5532 | static int
|
| 5533 | lpfc_rx_monitor_open(struct inode *inode, struct file *file)
|
| 5534 | {
|
| 5535 | struct lpfc_rx_monitor_debug *debug;
|
| 5536 | int rc = -ENOMEM;
|
| 5537 |
|
| 5538 | debug = kmalloc_obj(*debug);
|
| 5539 | if (!debug)
|
| 5540 | goto out;
|
| 5541 |
|
| 5542 | debug->buffer = vmalloc(MAX_DEBUGFS_RX_INFO_SIZE);
|
| 5543 | if (!debug->buffer) {
|
| 5544 | kfree(debug);
|
| 5545 | goto out;
|
| 5546 | }
|
| 5547 |
|
| 5548 | debug->i_private = inode->i_private;
|
| 5549 | file->private_data = debug;
|
| 5550 |
|
| 5551 | rc = 0;
|
| 5552 | out:
|
| 5553 | return rc;
|
| 5554 | }
|
| 5555 |
|
| 5556 | static ssize_t
|
| 5557 | lpfc_rx_monitor_read(struct file *file, char __user *buf, size_t nbytes,
|
| 5558 | loff_t *ppos)
|
| 5559 | {
|
| 5560 | struct lpfc_rx_monitor_debug *debug = file->private_data;
|
| 5561 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
|
| 5562 | char *buffer = debug->buffer;
|
| 5563 |
|
| 5564 | if (!phba->rx_monitor) {
|
| 5565 | scnprintf(buffer, MAX_DEBUGFS_RX_INFO_SIZE,
|
| 5566 | "Rx Monitor Info is empty.\n");
|
| 5567 | } else {
|
| 5568 | lpfc_rx_monitor_report(phba, phba->rx_monitor, buffer,
|
| 5569 | MAX_DEBUGFS_RX_INFO_SIZE,
|
| 5570 | LPFC_MAX_RXMONITOR_ENTRY);
|
| 5571 | }
|
| 5572 |
|
| 5573 | return simple_read_from_buffer(buf, nbytes, ppos, buffer,
|
| 5574 | strlen(buffer));
|
| 5575 | }
|
| 5576 |
|
| 5577 | static int
|
| 5578 | lpfc_rx_monitor_release(struct inode *inode, struct file *file)
|
| 5579 | {
|
| 5580 | struct lpfc_rx_monitor_debug *debug = file->private_data;
|
| 5581 |
|
| 5582 | vfree(debug->buffer);
|
| 5583 | kfree(debug);
|
| 5584 |
|
| 5585 | return 0;
|
| 5586 | }
|
| 5587 |
|
| 5588 | #undef lpfc_debugfs_op_disc_trc
|
| 5589 | static const struct file_operations lpfc_debugfs_op_disc_trc = {
|
| 5590 | .owner = THIS_MODULE,
|
| 5591 | .open = lpfc_debugfs_disc_trc_open,
|
| 5592 | .llseek = lpfc_debugfs_lseek,
|
| 5593 | .read = lpfc_debugfs_read,
|
| 5594 | .release = lpfc_debugfs_release,
|
| 5595 | };
|
| 5596 |
|
| 5597 | #undef lpfc_debugfs_op_nodelist
|
| 5598 | static const struct file_operations lpfc_debugfs_op_nodelist = {
|
| 5599 | .owner = THIS_MODULE,
|
| 5600 | .open = lpfc_debugfs_nodelist_open,
|
| 5601 | .llseek = lpfc_debugfs_lseek,
|
| 5602 | .read = lpfc_debugfs_read,
|
| 5603 | .release = lpfc_debugfs_release,
|
| 5604 | };
|
| 5605 |
|
| 5606 | #undef lpfc_debugfs_op_multixripools
|
| 5607 | static const struct file_operations lpfc_debugfs_op_multixripools = {
|
| 5608 | .owner = THIS_MODULE,
|
| 5609 | .open = lpfc_debugfs_multixripools_open,
|
| 5610 | .llseek = lpfc_debugfs_lseek,
|
| 5611 | .read = lpfc_debugfs_read,
|
| 5612 | .write = lpfc_debugfs_multixripools_write,
|
| 5613 | .release = lpfc_debugfs_release,
|
| 5614 | };
|
| 5615 |
|
| 5616 | #undef lpfc_debugfs_op_hbqinfo
|
| 5617 | static const struct file_operations lpfc_debugfs_op_hbqinfo = {
|
| 5618 | .owner = THIS_MODULE,
|
| 5619 | .open = lpfc_debugfs_hbqinfo_open,
|
| 5620 | .llseek = lpfc_debugfs_lseek,
|
| 5621 | .read = lpfc_debugfs_read,
|
| 5622 | .release = lpfc_debugfs_release,
|
| 5623 | };
|
| 5624 |
|
| 5625 | #ifdef LPFC_HDWQ_LOCK_STAT
|
| 5626 | #undef lpfc_debugfs_op_lockstat
|
| 5627 | static const struct file_operations lpfc_debugfs_op_lockstat = {
|
| 5628 | .owner = THIS_MODULE,
|
| 5629 | .open = lpfc_debugfs_lockstat_open,
|
| 5630 | .llseek = lpfc_debugfs_lseek,
|
| 5631 | .read = lpfc_debugfs_read,
|
| 5632 | .write = lpfc_debugfs_lockstat_write,
|
| 5633 | .release = lpfc_debugfs_release,
|
| 5634 | };
|
| 5635 | #endif
|
| 5636 |
|
| 5637 | #undef lpfc_debugfs_ras_log
|
| 5638 | static const struct file_operations lpfc_debugfs_ras_log = {
|
| 5639 | .owner = THIS_MODULE,
|
| 5640 | .open = lpfc_debugfs_ras_log_open,
|
| 5641 | .llseek = lpfc_debugfs_lseek,
|
| 5642 | .read = lpfc_debugfs_read,
|
| 5643 | .release = lpfc_debugfs_ras_log_release,
|
| 5644 | };
|
| 5645 |
|
| 5646 | #undef lpfc_debugfs_op_dumpHBASlim
|
| 5647 | static const struct file_operations lpfc_debugfs_op_dumpHBASlim = {
|
| 5648 | .owner = THIS_MODULE,
|
| 5649 | .open = lpfc_debugfs_dumpHBASlim_open,
|
| 5650 | .llseek = lpfc_debugfs_lseek,
|
| 5651 | .read = lpfc_debugfs_read,
|
| 5652 | .release = lpfc_debugfs_release,
|
| 5653 | };
|
| 5654 |
|
| 5655 | #undef lpfc_debugfs_op_dumpHostSlim
|
| 5656 | static const struct file_operations lpfc_debugfs_op_dumpHostSlim = {
|
| 5657 | .owner = THIS_MODULE,
|
| 5658 | .open = lpfc_debugfs_dumpHostSlim_open,
|
| 5659 | .llseek = lpfc_debugfs_lseek,
|
| 5660 | .read = lpfc_debugfs_read,
|
| 5661 | .release = lpfc_debugfs_release,
|
| 5662 | };
|
| 5663 |
|
| 5664 | #undef lpfc_debugfs_op_nvmestat
|
| 5665 | static const struct file_operations lpfc_debugfs_op_nvmestat = {
|
| 5666 | .owner = THIS_MODULE,
|
| 5667 | .open = lpfc_debugfs_nvmestat_open,
|
| 5668 | .llseek = lpfc_debugfs_lseek,
|
| 5669 | .read = lpfc_debugfs_read,
|
| 5670 | .write = lpfc_debugfs_nvmestat_write,
|
| 5671 | .release = lpfc_debugfs_release,
|
| 5672 | };
|
| 5673 |
|
| 5674 | #undef lpfc_debugfs_op_scsistat
|
| 5675 | static const struct file_operations lpfc_debugfs_op_scsistat = {
|
| 5676 | .owner = THIS_MODULE,
|
| 5677 | .open = lpfc_debugfs_scsistat_open,
|
| 5678 | .llseek = lpfc_debugfs_lseek,
|
| 5679 | .read = lpfc_debugfs_read,
|
| 5680 | .write = lpfc_debugfs_scsistat_write,
|
| 5681 | .release = lpfc_debugfs_release,
|
| 5682 | };
|
| 5683 |
|
| 5684 | #undef lpfc_debugfs_op_ioktime
|
| 5685 | static const struct file_operations lpfc_debugfs_op_ioktime = {
|
| 5686 | .owner = THIS_MODULE,
|
| 5687 | .open = lpfc_debugfs_ioktime_open,
|
| 5688 | .llseek = lpfc_debugfs_lseek,
|
| 5689 | .read = lpfc_debugfs_read,
|
| 5690 | .write = lpfc_debugfs_ioktime_write,
|
| 5691 | .release = lpfc_debugfs_release,
|
| 5692 | };
|
| 5693 |
|
| 5694 | #undef lpfc_debugfs_op_nvmeio_trc
|
| 5695 | static const struct file_operations lpfc_debugfs_op_nvmeio_trc = {
|
| 5696 | .owner = THIS_MODULE,
|
| 5697 | .open = lpfc_debugfs_nvmeio_trc_open,
|
| 5698 | .llseek = lpfc_debugfs_lseek,
|
| 5699 | .read = lpfc_debugfs_read,
|
| 5700 | .write = lpfc_debugfs_nvmeio_trc_write,
|
| 5701 | .release = lpfc_debugfs_release,
|
| 5702 | };
|
| 5703 |
|
| 5704 | #undef lpfc_debugfs_op_hdwqstat
|
| 5705 | static const struct file_operations lpfc_debugfs_op_hdwqstat = {
|
| 5706 | .owner = THIS_MODULE,
|
| 5707 | .open = lpfc_debugfs_hdwqstat_open,
|
| 5708 | .llseek = lpfc_debugfs_lseek,
|
| 5709 | .read = lpfc_debugfs_read,
|
| 5710 | .write = lpfc_debugfs_hdwqstat_write,
|
| 5711 | .release = lpfc_debugfs_release,
|
| 5712 | };
|
| 5713 |
|
| 5714 | #undef lpfc_debugfs_op_dif_err
|
| 5715 | static const struct file_operations lpfc_debugfs_op_dif_err = {
|
| 5716 | .owner = THIS_MODULE,
|
| 5717 | .open = simple_open,
|
| 5718 | .llseek = lpfc_debugfs_lseek,
|
| 5719 | .read = lpfc_debugfs_dif_err_read,
|
| 5720 | .write = lpfc_debugfs_dif_err_write,
|
| 5721 | .release = lpfc_debugfs_dif_err_release,
|
| 5722 | };
|
| 5723 |
|
| 5724 | #undef lpfc_debugfs_op_slow_ring_trc
|
| 5725 | static const struct file_operations lpfc_debugfs_op_slow_ring_trc = {
|
| 5726 | .owner = THIS_MODULE,
|
| 5727 | .open = lpfc_debugfs_slow_ring_trc_open,
|
| 5728 | .llseek = lpfc_debugfs_lseek,
|
| 5729 | .read = lpfc_debugfs_read,
|
| 5730 | .release = lpfc_debugfs_release,
|
| 5731 | };
|
| 5732 |
|
| 5733 | static struct dentry *lpfc_debugfs_root = NULL;
|
| 5734 | static unsigned int lpfc_debugfs_hba_count;
|
| 5735 |
|
| 5736 | |
| 5737 | * File operations for the iDiag debugfs
|
| 5738 |
|
| 5739 | #undef lpfc_idiag_op_pciCfg
|
| 5740 | static const struct file_operations lpfc_idiag_op_pciCfg = {
|
| 5741 | .owner = THIS_MODULE,
|
| 5742 | .open = lpfc_idiag_open,
|
| 5743 | .llseek = lpfc_debugfs_lseek,
|
| 5744 | .read = lpfc_idiag_pcicfg_read,
|
| 5745 | .write = lpfc_idiag_pcicfg_write,
|
| 5746 | .release = lpfc_idiag_cmd_release,
|
| 5747 | };
|
| 5748 |
|
| 5749 | #undef lpfc_idiag_op_barAcc
|
| 5750 | static const struct file_operations lpfc_idiag_op_barAcc = {
|
| 5751 | .owner = THIS_MODULE,
|
| 5752 | .open = lpfc_idiag_open,
|
| 5753 | .llseek = lpfc_debugfs_lseek,
|
| 5754 | .read = lpfc_idiag_baracc_read,
|
| 5755 | .write = lpfc_idiag_baracc_write,
|
| 5756 | .release = lpfc_idiag_cmd_release,
|
| 5757 | };
|
| 5758 |
|
| 5759 | #undef lpfc_idiag_op_queInfo
|
| 5760 | static const struct file_operations lpfc_idiag_op_queInfo = {
|
| 5761 | .owner = THIS_MODULE,
|
| 5762 | .open = lpfc_idiag_open,
|
| 5763 | .read = lpfc_idiag_queinfo_read,
|
| 5764 | .release = lpfc_idiag_release,
|
| 5765 | };
|
| 5766 |
|
| 5767 | #undef lpfc_idiag_op_queAcc
|
| 5768 | static const struct file_operations lpfc_idiag_op_queAcc = {
|
| 5769 | .owner = THIS_MODULE,
|
| 5770 | .open = lpfc_idiag_open,
|
| 5771 | .llseek = lpfc_debugfs_lseek,
|
| 5772 | .read = lpfc_idiag_queacc_read,
|
| 5773 | .write = lpfc_idiag_queacc_write,
|
| 5774 | .release = lpfc_idiag_cmd_release,
|
| 5775 | };
|
| 5776 |
|
| 5777 | #undef lpfc_idiag_op_drbAcc
|
| 5778 | static const struct file_operations lpfc_idiag_op_drbAcc = {
|
| 5779 | .owner = THIS_MODULE,
|
| 5780 | .open = lpfc_idiag_open,
|
| 5781 | .llseek = lpfc_debugfs_lseek,
|
| 5782 | .read = lpfc_idiag_drbacc_read,
|
| 5783 | .write = lpfc_idiag_drbacc_write,
|
| 5784 | .release = lpfc_idiag_cmd_release,
|
| 5785 | };
|
| 5786 |
|
| 5787 | #undef lpfc_idiag_op_ctlAcc
|
| 5788 | static const struct file_operations lpfc_idiag_op_ctlAcc = {
|
| 5789 | .owner = THIS_MODULE,
|
| 5790 | .open = lpfc_idiag_open,
|
| 5791 | .llseek = lpfc_debugfs_lseek,
|
| 5792 | .read = lpfc_idiag_ctlacc_read,
|
| 5793 | .write = lpfc_idiag_ctlacc_write,
|
| 5794 | .release = lpfc_idiag_cmd_release,
|
| 5795 | };
|
| 5796 |
|
| 5797 | #undef lpfc_idiag_op_mbxAcc
|
| 5798 | static const struct file_operations lpfc_idiag_op_mbxAcc = {
|
| 5799 | .owner = THIS_MODULE,
|
| 5800 | .open = lpfc_idiag_open,
|
| 5801 | .llseek = lpfc_debugfs_lseek,
|
| 5802 | .read = lpfc_idiag_mbxacc_read,
|
| 5803 | .write = lpfc_idiag_mbxacc_write,
|
| 5804 | .release = lpfc_idiag_cmd_release,
|
| 5805 | };
|
| 5806 |
|
| 5807 | #undef lpfc_idiag_op_extAcc
|
| 5808 | static const struct file_operations lpfc_idiag_op_extAcc = {
|
| 5809 | .owner = THIS_MODULE,
|
| 5810 | .open = lpfc_idiag_open,
|
| 5811 | .llseek = lpfc_debugfs_lseek,
|
| 5812 | .read = lpfc_idiag_extacc_read,
|
| 5813 | .write = lpfc_idiag_extacc_write,
|
| 5814 | .release = lpfc_idiag_cmd_release,
|
| 5815 | };
|
| 5816 | #undef lpfc_cgn_buffer_op
|
| 5817 | static const struct file_operations lpfc_cgn_buffer_op = {
|
| 5818 | .owner = THIS_MODULE,
|
| 5819 | .open = lpfc_cgn_buffer_open,
|
| 5820 | .llseek = lpfc_debugfs_lseek,
|
| 5821 | .read = lpfc_cgn_buffer_read,
|
| 5822 | .release = lpfc_cgn_buffer_release,
|
| 5823 | };
|
| 5824 |
|
| 5825 | #undef lpfc_rx_monitor_op
|
| 5826 | static const struct file_operations lpfc_rx_monitor_op = {
|
| 5827 | .owner = THIS_MODULE,
|
| 5828 | .open = lpfc_rx_monitor_open,
|
| 5829 | .llseek = lpfc_debugfs_lseek,
|
| 5830 | .read = lpfc_rx_monitor_read,
|
| 5831 | .release = lpfc_rx_monitor_release,
|
| 5832 | };
|
| 5833 | #endif
|
| 5834 |
|
| 5835 | |
| 5836 | * @phba: Pointer to HBA context object.
|
| 5837 | * @dmabuf: Pointer to a DMA buffer descriptor.
|
| 5838 | *
|
| 5839 | * Description:
|
| 5840 | * This routine dump a bsg pass-through non-embedded mailbox command with
|
| 5841 | * external buffer.
|
| 5842 | *
|
| 5843 | void
|
| 5844 | lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *phba, enum nemb_type nemb_tp,
|
| 5845 | enum mbox_type mbox_tp, enum dma_type dma_tp,
|
| 5846 | enum sta_type sta_tp,
|
| 5847 | struct lpfc_dmabuf *dmabuf, uint32_t ext_buf)
|
| 5848 | {
|
| 5849 | #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
|
| 5850 | uint32_t *mbx_mbox_cmd, *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt;
|
| 5851 | char line_buf[LPFC_MBX_ACC_LBUF_SZ];
|
| 5852 | int len = 0;
|
| 5853 | uint32_t do_dump = 0;
|
| 5854 | uint32_t *pword;
|
| 5855 | uint32_t i;
|
| 5856 |
|
| 5857 | if (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP)
|
| 5858 | return;
|
| 5859 |
|
| 5860 | mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
|
| 5861 | mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
|
| 5862 | mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
|
| 5863 | mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
|
| 5864 |
|
| 5865 | if (!(*mbx_dump_map & LPFC_MBX_DMP_ALL) ||
|
| 5866 | (*mbx_dump_cnt == 0) ||
|
| 5867 | (*mbx_word_cnt == 0))
|
| 5868 | return;
|
| 5869 |
|
| 5870 | if (*mbx_mbox_cmd != 0x9B)
|
| 5871 | return;
|
| 5872 |
|
| 5873 | if ((mbox_tp == mbox_rd) && (dma_tp == dma_mbox)) {
|
| 5874 | if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_MBX) {
|
| 5875 | do_dump |= LPFC_BSG_DMP_MBX_RD_MBX;
|
| 5876 | pr_err("\nRead mbox command (x%x), "
|
| 5877 | "nemb:0x%x, extbuf_cnt:%d:\n",
|
| 5878 | sta_tp, nemb_tp, ext_buf);
|
| 5879 | }
|
| 5880 | }
|
| 5881 | if ((mbox_tp == mbox_rd) && (dma_tp == dma_ebuf)) {
|
| 5882 | if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_BUF) {
|
| 5883 | do_dump |= LPFC_BSG_DMP_MBX_RD_BUF;
|
| 5884 | pr_err("\nRead mbox buffer (x%x), "
|
| 5885 | "nemb:0x%x, extbuf_seq:%d:\n",
|
| 5886 | sta_tp, nemb_tp, ext_buf);
|
| 5887 | }
|
| 5888 | }
|
| 5889 | if ((mbox_tp == mbox_wr) && (dma_tp == dma_mbox)) {
|
| 5890 | if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_MBX) {
|
| 5891 | do_dump |= LPFC_BSG_DMP_MBX_WR_MBX;
|
| 5892 | pr_err("\nWrite mbox command (x%x), "
|
| 5893 | "nemb:0x%x, extbuf_cnt:%d:\n",
|
| 5894 | sta_tp, nemb_tp, ext_buf);
|
| 5895 | }
|
| 5896 | }
|
| 5897 | if ((mbox_tp == mbox_wr) && (dma_tp == dma_ebuf)) {
|
| 5898 | if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_BUF) {
|
| 5899 | do_dump |= LPFC_BSG_DMP_MBX_WR_BUF;
|
| 5900 | pr_err("\nWrite mbox buffer (x%x), "
|
| 5901 | "nemb:0x%x, extbuf_seq:%d:\n",
|
| 5902 | sta_tp, nemb_tp, ext_buf);
|
| 5903 | }
|
| 5904 | }
|
| 5905 |
|
| 5906 |
|
| 5907 | if (do_dump) {
|
| 5908 | pword = (uint32_t *)dmabuf->virt;
|
| 5909 | for (i = 0; i < *mbx_word_cnt; i++) {
|
| 5910 | if (!(i % 8)) {
|
| 5911 | if (i != 0)
|
| 5912 | pr_err("%s\n", line_buf);
|
| 5913 | len = 0;
|
| 5914 | len += scnprintf(line_buf+len,
|
| 5915 | LPFC_MBX_ACC_LBUF_SZ-len,
|
| 5916 | "%03d: ", i);
|
| 5917 | }
|
| 5918 | len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
|
| 5919 | "%08x ", (uint32_t)*pword);
|
| 5920 | pword++;
|
| 5921 | }
|
| 5922 | if ((i - 1) % 8)
|
| 5923 | pr_err("%s\n", line_buf);
|
| 5924 | (*mbx_dump_cnt)--;
|
| 5925 | }
|
| 5926 |
|
| 5927 |
|
| 5928 | if (*mbx_dump_cnt == 0)
|
| 5929 | memset(&idiag, 0, sizeof(idiag));
|
| 5930 | return;
|
| 5931 | #endif
|
| 5932 | }
|
| 5933 |
|
| 5934 | |
| 5935 | * @phba: Pointer to HBA context object.
|
| 5936 | * @dmabuf: Pointer to a DMA buffer descriptor.
|
| 5937 | *
|
| 5938 | * Description:
|
| 5939 | * This routine dump a pass-through non-embedded mailbox command from issue
|
| 5940 | * mailbox command.
|
| 5941 | *
|
| 5942 | void
|
| 5943 | lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox)
|
| 5944 | {
|
| 5945 | #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
|
| 5946 | uint32_t *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt, *mbx_mbox_cmd;
|
| 5947 | char line_buf[LPFC_MBX_ACC_LBUF_SZ];
|
| 5948 | int len = 0;
|
| 5949 | uint32_t *pword;
|
| 5950 | uint8_t *pbyte;
|
| 5951 | uint32_t i, j;
|
| 5952 |
|
| 5953 | if (idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP)
|
| 5954 | return;
|
| 5955 |
|
| 5956 | mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
|
| 5957 | mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
|
| 5958 | mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
|
| 5959 | mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
|
| 5960 |
|
| 5961 | if (!(*mbx_dump_map & LPFC_MBX_DMP_MBX_ALL) ||
|
| 5962 | (*mbx_dump_cnt == 0) ||
|
| 5963 | (*mbx_word_cnt == 0))
|
| 5964 | return;
|
| 5965 |
|
| 5966 | if ((*mbx_mbox_cmd != LPFC_MBX_ALL_CMD) &&
|
| 5967 | (*mbx_mbox_cmd != pmbox->mbxCommand))
|
| 5968 | return;
|
| 5969 |
|
| 5970 |
|
| 5971 | if (*mbx_dump_map & LPFC_MBX_DMP_MBX_WORD) {
|
| 5972 | pr_err("Mailbox command:0x%x dump by word:\n",
|
| 5973 | pmbox->mbxCommand);
|
| 5974 | pword = (uint32_t *)pmbox;
|
| 5975 | for (i = 0; i < *mbx_word_cnt; i++) {
|
| 5976 | if (!(i % 8)) {
|
| 5977 | if (i != 0)
|
| 5978 | pr_err("%s\n", line_buf);
|
| 5979 | len = 0;
|
| 5980 | memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ);
|
| 5981 | len += scnprintf(line_buf+len,
|
| 5982 | LPFC_MBX_ACC_LBUF_SZ-len,
|
| 5983 | "%03d: ", i);
|
| 5984 | }
|
| 5985 | len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
|
| 5986 | "%08x ",
|
| 5987 | ((uint32_t)*pword) & 0xffffffff);
|
| 5988 | pword++;
|
| 5989 | }
|
| 5990 | if ((i - 1) % 8)
|
| 5991 | pr_err("%s\n", line_buf);
|
| 5992 | pr_err("\n");
|
| 5993 | }
|
| 5994 | if (*mbx_dump_map & LPFC_MBX_DMP_MBX_BYTE) {
|
| 5995 | pr_err("Mailbox command:0x%x dump by byte:\n",
|
| 5996 | pmbox->mbxCommand);
|
| 5997 | pbyte = (uint8_t *)pmbox;
|
| 5998 | for (i = 0; i < *mbx_word_cnt; i++) {
|
| 5999 | if (!(i % 8)) {
|
| 6000 | if (i != 0)
|
| 6001 | pr_err("%s\n", line_buf);
|
| 6002 | len = 0;
|
| 6003 | memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ);
|
| 6004 | len += scnprintf(line_buf+len,
|
| 6005 | LPFC_MBX_ACC_LBUF_SZ-len,
|
| 6006 | "%03d: ", i);
|
| 6007 | }
|
| 6008 | for (j = 0; j < 4; j++) {
|
| 6009 | len += scnprintf(line_buf+len,
|
| 6010 | LPFC_MBX_ACC_LBUF_SZ-len,
|
| 6011 | "%02x",
|
| 6012 | ((uint8_t)*pbyte) & 0xff);
|
| 6013 | pbyte++;
|
| 6014 | }
|
| 6015 | len += scnprintf(line_buf+len,
|
| 6016 | LPFC_MBX_ACC_LBUF_SZ-len, " ");
|
| 6017 | }
|
| 6018 | if ((i - 1) % 8)
|
| 6019 | pr_err("%s\n", line_buf);
|
| 6020 | pr_err("\n");
|
| 6021 | }
|
| 6022 | (*mbx_dump_cnt)--;
|
| 6023 |
|
| 6024 |
|
| 6025 | if (*mbx_dump_cnt == 0)
|
| 6026 | memset(&idiag, 0, sizeof(idiag));
|
| 6027 | return;
|
| 6028 | #endif
|
| 6029 | }
|
| 6030 |
|
| 6031 | |
| 6032 | * lpfc_debugfs_initialize - Initialize debugfs for a vport
|
| 6033 | * @vport: The vport pointer to initialize.
|
| 6034 | *
|
| 6035 | * Description:
|
| 6036 | * When Debugfs is configured this routine sets up the lpfc debugfs file system.
|
| 6037 | * If not already created, this routine will create the lpfc directory, and
|
| 6038 | * lpfcX directory (for this HBA), and vportX directory for this vport. It will
|
| 6039 | * also create each file used to access lpfc specific debugfs information.
|
| 6040 | *
|
| 6041 | inline void
|
| 6042 | lpfc_debugfs_initialize(struct lpfc_vport *vport)
|
| 6043 | {
|
| 6044 | #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
|
| 6045 | struct lpfc_hba *phba = vport->phba;
|
| 6046 | char name[64];
|
| 6047 | uint32_t num, i;
|
| 6048 | bool pport_setup = false;
|
| 6049 |
|
| 6050 | if (!lpfc_debugfs_enable)
|
| 6051 | return;
|
| 6052 |
|
| 6053 |
|
| 6054 | if (!lpfc_debugfs_root) {
|
| 6055 | lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL);
|
| 6056 | lpfc_debugfs_hba_count = 0;
|
| 6057 | if (IS_ERR(lpfc_debugfs_root)) {
|
| 6058 | lpfc_vlog_msg(vport, KERN_WARNING, LOG_INIT,
|
| 6059 | "0527 Cannot create debugfs lpfc\n");
|
| 6060 | return;
|
| 6061 | }
|
| 6062 | }
|
| 6063 | if (!lpfc_debugfs_start_time)
|
| 6064 | lpfc_debugfs_start_time = jiffies;
|
| 6065 |
|
| 6066 |
|
| 6067 | snprintf(name, sizeof(name), "fn%d", phba->brd_no);
|
| 6068 | if (!phba->hba_debugfs_root) {
|
| 6069 | pport_setup = true;
|
| 6070 | phba->hba_debugfs_root =
|
| 6071 | debugfs_create_dir(name, lpfc_debugfs_root);
|
| 6072 | phba->debugfs_vport_count = 0;
|
| 6073 | if (IS_ERR(phba->hba_debugfs_root)) {
|
| 6074 | lpfc_vlog_msg(vport, KERN_WARNING, LOG_INIT,
|
| 6075 | "0528 Cannot create debugfs %s\n", name);
|
| 6076 | return;
|
| 6077 | }
|
| 6078 | lpfc_debugfs_hba_count++;
|
| 6079 |
|
| 6080 |
|
| 6081 | debugfs_create_file("multixripools", 0644,
|
| 6082 | phba->hba_debugfs_root, phba,
|
| 6083 | &lpfc_debugfs_op_multixripools);
|
| 6084 |
|
| 6085 |
|
| 6086 | debugfs_create_file("cgn_buffer", 0644, phba->hba_debugfs_root,
|
| 6087 | phba, &lpfc_cgn_buffer_op);
|
| 6088 |
|
| 6089 |
|
| 6090 | debugfs_create_file("rx_monitor", 0644, phba->hba_debugfs_root,
|
| 6091 | phba, &lpfc_rx_monitor_op);
|
| 6092 |
|
| 6093 |
|
| 6094 | debugfs_create_file("ras_log", 0644, phba->hba_debugfs_root,
|
| 6095 | phba, &lpfc_debugfs_ras_log);
|
| 6096 |
|
| 6097 |
|
| 6098 | debugfs_create_file("hbqinfo", 0644, phba->hba_debugfs_root,
|
| 6099 | phba, &lpfc_debugfs_op_hbqinfo);
|
| 6100 |
|
| 6101 | #ifdef LPFC_HDWQ_LOCK_STAT
|
| 6102 |
|
| 6103 | debugfs_create_file("lockstat", 0644, phba->hba_debugfs_root,
|
| 6104 | phba, &lpfc_debugfs_op_lockstat);
|
| 6105 | #endif
|
| 6106 | if (phba->sli_rev < LPFC_SLI_REV4) {
|
| 6107 |
|
| 6108 | debugfs_create_file("dumpHBASlim", 0644,
|
| 6109 | phba->hba_debugfs_root, phba,
|
| 6110 | &lpfc_debugfs_op_dumpHBASlim);
|
| 6111 | }
|
| 6112 |
|
| 6113 | if (phba->sli_rev < LPFC_SLI_REV4) {
|
| 6114 |
|
| 6115 | debugfs_create_file("dumpHostSlim", 0644,
|
| 6116 | phba->hba_debugfs_root, phba,
|
| 6117 | &lpfc_debugfs_op_dumpHostSlim);
|
| 6118 | }
|
| 6119 |
|
| 6120 |
|
| 6121 | debugfs_create_file_aux_num("InjErrLBA", 0644,
|
| 6122 | phba->hba_debugfs_root, phba,
|
| 6123 | InjErrLBA,
|
| 6124 | &lpfc_debugfs_op_dif_err);
|
| 6125 | phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
|
| 6126 |
|
| 6127 | debugfs_create_file_aux_num("InjErrNPortID", 0644,
|
| 6128 | phba->hba_debugfs_root, phba,
|
| 6129 | InjErrNPortID,
|
| 6130 | &lpfc_debugfs_op_dif_err);
|
| 6131 |
|
| 6132 | debugfs_create_file_aux_num("InjErrWWPN", 0644,
|
| 6133 | phba->hba_debugfs_root, phba,
|
| 6134 | InjErrWWPN,
|
| 6135 | &lpfc_debugfs_op_dif_err);
|
| 6136 |
|
| 6137 | debugfs_create_file_aux_num("writeGuardInjErr", 0644,
|
| 6138 | phba->hba_debugfs_root, phba,
|
| 6139 | writeGuard,
|
| 6140 | &lpfc_debugfs_op_dif_err);
|
| 6141 |
|
| 6142 | debugfs_create_file_aux_num("writeAppInjErr", 0644,
|
| 6143 | phba->hba_debugfs_root, phba,
|
| 6144 | writeApp, &lpfc_debugfs_op_dif_err);
|
| 6145 |
|
| 6146 | debugfs_create_file_aux_num("writeRefInjErr", 0644,
|
| 6147 | phba->hba_debugfs_root, phba,
|
| 6148 | writeRef, &lpfc_debugfs_op_dif_err);
|
| 6149 |
|
| 6150 | debugfs_create_file_aux_num("readGuardInjErr", 0644,
|
| 6151 | phba->hba_debugfs_root, phba,
|
| 6152 | readGuard,
|
| 6153 | &lpfc_debugfs_op_dif_err);
|
| 6154 |
|
| 6155 | debugfs_create_file_aux_num("readAppInjErr", 0644,
|
| 6156 | phba->hba_debugfs_root, phba,
|
| 6157 | readApp, &lpfc_debugfs_op_dif_err);
|
| 6158 |
|
| 6159 | debugfs_create_file_aux_num("readRefInjErr", 0644,
|
| 6160 | phba->hba_debugfs_root, phba,
|
| 6161 | readRef, &lpfc_debugfs_op_dif_err);
|
| 6162 |
|
| 6163 |
|
| 6164 | if (lpfc_debugfs_max_slow_ring_trc) {
|
| 6165 | num = lpfc_debugfs_max_slow_ring_trc - 1;
|
| 6166 | if (num & lpfc_debugfs_max_slow_ring_trc) {
|
| 6167 |
|
| 6168 | num = lpfc_debugfs_max_slow_ring_trc;
|
| 6169 | i = 0;
|
| 6170 | while (num > 1) {
|
| 6171 | num = num >> 1;
|
| 6172 | i++;
|
| 6173 | }
|
| 6174 | lpfc_debugfs_max_slow_ring_trc = (1 << i);
|
| 6175 | pr_info("lpfc_debugfs_max_slow_ring_trc "
|
| 6176 | "changed to %d\n",
|
| 6177 | lpfc_debugfs_max_slow_ring_trc);
|
| 6178 | }
|
| 6179 | }
|
| 6180 |
|
| 6181 | debugfs_create_file("slow_ring_trace", 0644,
|
| 6182 | phba->hba_debugfs_root, phba,
|
| 6183 | &lpfc_debugfs_op_slow_ring_trc);
|
| 6184 | if (!phba->slow_ring_trc) {
|
| 6185 | phba->slow_ring_trc = kzalloc_objs(struct lpfc_debugfs_trc,
|
| 6186 | lpfc_debugfs_max_slow_ring_trc);
|
| 6187 | if (!phba->slow_ring_trc) {
|
| 6188 | lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
|
| 6189 | "0416 Cannot create debugfs "
|
| 6190 | "slow_ring buffer\n");
|
| 6191 | goto out;
|
| 6192 | }
|
| 6193 | atomic_set(&phba->slow_ring_trc_cnt, 0);
|
| 6194 | }
|
| 6195 |
|
| 6196 | debugfs_create_file("nvmeio_trc", 0644, phba->hba_debugfs_root,
|
| 6197 | phba, &lpfc_debugfs_op_nvmeio_trc);
|
| 6198 |
|
| 6199 | atomic_set(&phba->nvmeio_trc_cnt, 0);
|
| 6200 | if (lpfc_debugfs_max_nvmeio_trc) {
|
| 6201 | num = lpfc_debugfs_max_nvmeio_trc - 1;
|
| 6202 | if (num & lpfc_debugfs_max_nvmeio_trc) {
|
| 6203 |
|
| 6204 | num = lpfc_debugfs_max_nvmeio_trc;
|
| 6205 | i = 0;
|
| 6206 | while (num > 1) {
|
| 6207 | num = num >> 1;
|
| 6208 | i++;
|
| 6209 | }
|
| 6210 | lpfc_debugfs_max_nvmeio_trc = (1 << i);
|
| 6211 | pr_info("lpfc_debugfs_max_nvmeio_trc changed "
|
| 6212 | "to %d\n",
|
| 6213 | lpfc_debugfs_max_nvmeio_trc);
|
| 6214 | }
|
| 6215 | phba->nvmeio_trc_size = lpfc_debugfs_max_nvmeio_trc;
|
| 6216 |
|
| 6217 |
|
| 6218 | phba->nvmeio_trc = kzalloc(
|
| 6219 | (sizeof(struct lpfc_debugfs_nvmeio_trc) *
|
| 6220 | phba->nvmeio_trc_size), GFP_KERNEL);
|
| 6221 |
|
| 6222 | if (!phba->nvmeio_trc) {
|
| 6223 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
| 6224 | "0576 Cannot create debugfs "
|
| 6225 | "nvmeio_trc buffer\n");
|
| 6226 | goto nvmeio_off;
|
| 6227 | }
|
| 6228 | phba->nvmeio_trc_on = 1;
|
| 6229 | phba->nvmeio_trc_output_idx = 0;
|
| 6230 | } else {
|
| 6231 | nvmeio_off:
|
| 6232 | phba->nvmeio_trc_size = 0;
|
| 6233 | phba->nvmeio_trc_on = 0;
|
| 6234 | phba->nvmeio_trc_output_idx = 0;
|
| 6235 | phba->nvmeio_trc = NULL;
|
| 6236 | }
|
| 6237 | }
|
| 6238 |
|
| 6239 | snprintf(name, sizeof(name), "vport%d", vport->vpi);
|
| 6240 | if (!vport->vport_debugfs_root) {
|
| 6241 | vport->vport_debugfs_root =
|
| 6242 | debugfs_create_dir(name, phba->hba_debugfs_root);
|
| 6243 | if (IS_ERR(vport->vport_debugfs_root)) {
|
| 6244 | lpfc_vlog_msg(vport, KERN_WARNING, LOG_INIT,
|
| 6245 | "0529 Cannot create debugfs %s\n", name);
|
| 6246 | return;
|
| 6247 | }
|
| 6248 | phba->debugfs_vport_count++;
|
| 6249 | }
|
| 6250 |
|
| 6251 | if (lpfc_debugfs_max_disc_trc) {
|
| 6252 | num = lpfc_debugfs_max_disc_trc - 1;
|
| 6253 | if (num & lpfc_debugfs_max_disc_trc) {
|
| 6254 |
|
| 6255 | num = lpfc_debugfs_max_disc_trc;
|
| 6256 | i = 0;
|
| 6257 | while (num > 1) {
|
| 6258 | num = num >> 1;
|
| 6259 | i++;
|
| 6260 | }
|
| 6261 | lpfc_debugfs_max_disc_trc = (1 << i);
|
| 6262 | pr_info("lpfc_debugfs_max_disc_trc changed to %d\n",
|
| 6263 | lpfc_debugfs_max_disc_trc);
|
| 6264 | }
|
| 6265 | }
|
| 6266 |
|
| 6267 | vport->disc_trc = kzalloc(
|
| 6268 | (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc),
|
| 6269 | GFP_KERNEL);
|
| 6270 |
|
| 6271 | if (!vport->disc_trc) {
|
| 6272 | lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
|
| 6273 | "0418 Cannot create debugfs disc trace "
|
| 6274 | "buffer\n");
|
| 6275 | goto out;
|
| 6276 | }
|
| 6277 | atomic_set(&vport->disc_trc_cnt, 0);
|
| 6278 |
|
| 6279 | debugfs_create_file("discovery_trace", 0644, vport->vport_debugfs_root,
|
| 6280 | vport, &lpfc_debugfs_op_disc_trc);
|
| 6281 |
|
| 6282 | debugfs_create_file("nodelist", 0644, vport->vport_debugfs_root, vport,
|
| 6283 | &lpfc_debugfs_op_nodelist);
|
| 6284 |
|
| 6285 | debugfs_create_file("nvmestat", 0644, vport->vport_debugfs_root, vport,
|
| 6286 | &lpfc_debugfs_op_nvmestat);
|
| 6287 |
|
| 6288 | debugfs_create_file("scsistat", 0644, vport->vport_debugfs_root, vport,
|
| 6289 | &lpfc_debugfs_op_scsistat);
|
| 6290 |
|
| 6291 | debugfs_create_file("ioktime", 0644, vport->vport_debugfs_root, vport,
|
| 6292 | &lpfc_debugfs_op_ioktime);
|
| 6293 |
|
| 6294 | debugfs_create_file("hdwqstat", 0644, vport->vport_debugfs_root, vport,
|
| 6295 | &lpfc_debugfs_op_hdwqstat);
|
| 6296 |
|
| 6297 | |
| 6298 | * The following section is for additional directories/files for the
|
| 6299 | * physical port.
|
| 6300 |
|
| 6301 |
|
| 6302 | if (!pport_setup)
|
| 6303 | return;
|
| 6304 |
|
| 6305 | |
| 6306 | * iDiag debugfs root entry points for SLI4 device only
|
| 6307 |
|
| 6308 | if (phba->sli_rev < LPFC_SLI_REV4)
|
| 6309 | return;
|
| 6310 |
|
| 6311 | if (!phba->idiag_root) {
|
| 6312 | phba->idiag_root =
|
| 6313 | debugfs_create_dir("iDiag", phba->hba_debugfs_root);
|
| 6314 |
|
| 6315 | memset(&idiag, 0, sizeof(idiag));
|
| 6316 | }
|
| 6317 |
|
| 6318 |
|
| 6319 | debugfs_create_file("pciCfg", 0644, phba->idiag_root, phba,
|
| 6320 | &lpfc_idiag_op_pciCfg);
|
| 6321 | idiag.offset.last_rd = 0;
|
| 6322 |
|
| 6323 |
|
| 6324 | debugfs_create_file("barAcc", 0644, phba->idiag_root, phba,
|
| 6325 | &lpfc_idiag_op_barAcc);
|
| 6326 | idiag.offset.last_rd = 0;
|
| 6327 |
|
| 6328 |
|
| 6329 | debugfs_create_file("queInfo", 0444, phba->idiag_root, phba,
|
| 6330 | &lpfc_idiag_op_queInfo);
|
| 6331 |
|
| 6332 |
|
| 6333 | debugfs_create_file("queAcc", 0644, phba->idiag_root, phba,
|
| 6334 | &lpfc_idiag_op_queAcc);
|
| 6335 |
|
| 6336 |
|
| 6337 | debugfs_create_file("drbAcc", 0644, phba->idiag_root, phba,
|
| 6338 | &lpfc_idiag_op_drbAcc);
|
| 6339 |
|
| 6340 |
|
| 6341 | debugfs_create_file("ctlAcc", 0644, phba->idiag_root, phba,
|
| 6342 | &lpfc_idiag_op_ctlAcc);
|
| 6343 |
|
| 6344 |
|
| 6345 | debugfs_create_file("mbxAcc", 0644, phba->idiag_root, phba,
|
| 6346 | &lpfc_idiag_op_mbxAcc);
|
| 6347 |
|
| 6348 |
|
| 6349 | if (phba->sli4_hba.extents_in_use) {
|
| 6350 | debugfs_create_file("extAcc", 0644, phba->idiag_root, phba,
|
| 6351 | &lpfc_idiag_op_extAcc);
|
| 6352 | }
|
| 6353 | out:
|
| 6354 |
|
| 6355 | return;
|
| 6356 | #endif
|
| 6357 | }
|
| 6358 |
|
| 6359 | |
| 6360 | * lpfc_debugfs_terminate - Tear down debugfs infrastructure for this vport
|
| 6361 | * @vport: The vport pointer to remove from debugfs.
|
| 6362 | *
|
| 6363 | * Description:
|
| 6364 | * When Debugfs is configured this routine removes debugfs file system elements
|
| 6365 | * that are specific to this vport. It also checks to see if there are any
|
| 6366 | * users left for the debugfs directories associated with the HBA and driver. If
|
| 6367 | * this is the last user of the HBA directory or driver directory then it will
|
| 6368 | * remove those from the debugfs infrastructure as well.
|
| 6369 | *
|
| 6370 | inline void
|
| 6371 | lpfc_debugfs_terminate(struct lpfc_vport *vport)
|
| 6372 | {
|
| 6373 | #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
|
| 6374 | struct lpfc_hba *phba = vport->phba;
|
| 6375 |
|
| 6376 | kfree(vport->disc_trc);
|
| 6377 | vport->disc_trc = NULL;
|
| 6378 |
|
| 6379 | if (vport->vport_debugfs_root) {
|
| 6380 | debugfs_remove(vport->vport_debugfs_root);
|
| 6381 | vport->vport_debugfs_root = NULL;
|
| 6382 | phba->debugfs_vport_count--;
|
| 6383 | }
|
| 6384 |
|
| 6385 | if (!phba->debugfs_vport_count) {
|
| 6386 | kfree(phba->slow_ring_trc);
|
| 6387 | phba->slow_ring_trc = NULL;
|
| 6388 |
|
| 6389 | kfree(phba->nvmeio_trc);
|
| 6390 | phba->nvmeio_trc = NULL;
|
| 6391 |
|
| 6392 | if (phba->hba_debugfs_root) {
|
| 6393 | debugfs_remove(phba->hba_debugfs_root);
|
| 6394 | phba->hba_debugfs_root = NULL;
|
| 6395 | lpfc_debugfs_hba_count--;
|
| 6396 | }
|
| 6397 |
|
| 6398 | if (!lpfc_debugfs_hba_count) {
|
| 6399 | debugfs_remove(lpfc_debugfs_root);
|
| 6400 | lpfc_debugfs_root = NULL;
|
| 6401 | }
|
| 6402 | }
|
| 6403 | #endif
|
| 6404 | return;
|
| 6405 | }
|
| 6406 |
|
| 6407 | |
| 6408 | * Driver debug utility routines outside of debugfs. The debug utility
|
| 6409 | * routines implemented here is intended to be used in the instrumented
|
| 6410 | * debug driver for debugging host or port issues.
|
| 6411 |
|
| 6412 |
|
| 6413 | |
| 6414 | * lpfc_debug_dump_all_queues - dump all the queues with a hba
|
| 6415 | * @phba: Pointer to HBA context object.
|
| 6416 | *
|
| 6417 | * This function dumps entries of all the queues asociated with the @phba.
|
| 6418 | *
|
| 6419 | void
|
| 6420 | lpfc_debug_dump_all_queues(struct lpfc_hba *phba)
|
| 6421 | {
|
| 6422 | int idx;
|
| 6423 |
|
| 6424 | |
| 6425 | * Dump Work Queues (WQs)
|
| 6426 |
|
| 6427 | lpfc_debug_dump_wq(phba, DUMP_MBX, 0);
|
| 6428 | lpfc_debug_dump_wq(phba, DUMP_ELS, 0);
|
| 6429 | lpfc_debug_dump_wq(phba, DUMP_NVMELS, 0);
|
| 6430 |
|
| 6431 | for (idx = 0; idx < phba->cfg_hdw_queue; idx++)
|
| 6432 | lpfc_debug_dump_wq(phba, DUMP_IO, idx);
|
| 6433 |
|
| 6434 | lpfc_debug_dump_hdr_rq(phba);
|
| 6435 | lpfc_debug_dump_dat_rq(phba);
|
| 6436 | |
| 6437 | * Dump Complete Queues (CQs)
|
| 6438 |
|
| 6439 | lpfc_debug_dump_cq(phba, DUMP_MBX, 0);
|
| 6440 | lpfc_debug_dump_cq(phba, DUMP_ELS, 0);
|
| 6441 | lpfc_debug_dump_cq(phba, DUMP_NVMELS, 0);
|
| 6442 |
|
| 6443 | for (idx = 0; idx < phba->cfg_hdw_queue; idx++)
|
| 6444 | lpfc_debug_dump_cq(phba, DUMP_IO, idx);
|
| 6445 |
|
| 6446 | |
| 6447 | * Dump Event Queues (EQs)
|
| 6448 |
|
| 6449 | for (idx = 0; idx < phba->cfg_hdw_queue; idx++)
|
| 6450 | lpfc_debug_dump_hba_eq(phba, idx);
|
| 6451 | }
|