162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * zfcp device driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Debug traces for zfcp.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright IBM Corp. 2002, 2023
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define KMSG_COMPONENT "zfcp"
1162306a36Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/ctype.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <asm/debug.h>
1762306a36Sopenharmony_ci#include "zfcp_dbf.h"
1862306a36Sopenharmony_ci#include "zfcp_ext.h"
1962306a36Sopenharmony_ci#include "zfcp_fc.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic u32 dbfsize = 4;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cimodule_param(dbfsize, uint, 0400);
2462306a36Sopenharmony_ciMODULE_PARM_DESC(dbfsize,
2562306a36Sopenharmony_ci		 "number of pages for each debug feature area (default 4)");
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic u32 dbflevel = 3;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cimodule_param(dbflevel, uint, 0400);
3062306a36Sopenharmony_ciMODULE_PARM_DESC(dbflevel,
3162306a36Sopenharmony_ci		 "log level for each debug feature area "
3262306a36Sopenharmony_ci		 "(default 3, range 0..6)");
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic inline unsigned int zfcp_dbf_plen(unsigned int offset)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	return sizeof(struct zfcp_dbf_pay) + offset - ZFCP_DBF_PAY_MAX_REC;
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic inline
4062306a36Sopenharmony_civoid zfcp_dbf_pl_write(struct zfcp_dbf *dbf, void *data, u16 length, char *area,
4162306a36Sopenharmony_ci		       u64 req_id)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	struct zfcp_dbf_pay *pl = &dbf->pay_buf;
4462306a36Sopenharmony_ci	u16 offset = 0, rec_length;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	spin_lock(&dbf->pay_lock);
4762306a36Sopenharmony_ci	memset(pl, 0, sizeof(*pl));
4862306a36Sopenharmony_ci	pl->fsf_req_id = req_id;
4962306a36Sopenharmony_ci	memcpy(pl->area, area, ZFCP_DBF_TAG_LEN);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	while (offset < length) {
5262306a36Sopenharmony_ci		rec_length = min((u16) ZFCP_DBF_PAY_MAX_REC,
5362306a36Sopenharmony_ci				 (u16) (length - offset));
5462306a36Sopenharmony_ci		memcpy(pl->data, data + offset, rec_length);
5562306a36Sopenharmony_ci		debug_event(dbf->pay, 1, pl, zfcp_dbf_plen(rec_length));
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci		offset += rec_length;
5862306a36Sopenharmony_ci		pl->counter++;
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	spin_unlock(&dbf->pay_lock);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/**
6562306a36Sopenharmony_ci * zfcp_dbf_hba_fsf_res - trace event for fsf responses
6662306a36Sopenharmony_ci * @tag: tag indicating which kind of FSF response has been received
6762306a36Sopenharmony_ci * @level: trace level to be used for event
6862306a36Sopenharmony_ci * @req: request for which a response was received
6962306a36Sopenharmony_ci */
7062306a36Sopenharmony_civoid zfcp_dbf_hba_fsf_res(char *tag, int level, struct zfcp_fsf_req *req)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	struct zfcp_dbf *dbf = req->adapter->dbf;
7362306a36Sopenharmony_ci	struct fsf_qtcb_prefix *q_pref = &req->qtcb->prefix;
7462306a36Sopenharmony_ci	struct fsf_qtcb_header *q_head = &req->qtcb->header;
7562306a36Sopenharmony_ci	struct zfcp_dbf_hba *rec = &dbf->hba_buf;
7662306a36Sopenharmony_ci	unsigned long flags;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	spin_lock_irqsave(&dbf->hba_lock, flags);
7962306a36Sopenharmony_ci	memset(rec, 0, sizeof(*rec));
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
8262306a36Sopenharmony_ci	rec->id = ZFCP_DBF_HBA_RES;
8362306a36Sopenharmony_ci	rec->fsf_req_id = req->req_id;
8462306a36Sopenharmony_ci	rec->fsf_req_status = req->status;
8562306a36Sopenharmony_ci	rec->fsf_cmd = q_head->fsf_command;
8662306a36Sopenharmony_ci	rec->fsf_seq_no = q_pref->req_seq_no;
8762306a36Sopenharmony_ci	rec->u.res.req_issued = req->issued;
8862306a36Sopenharmony_ci	rec->u.res.prot_status = q_pref->prot_status;
8962306a36Sopenharmony_ci	rec->u.res.fsf_status = q_head->fsf_status;
9062306a36Sopenharmony_ci	rec->u.res.port_handle = q_head->port_handle;
9162306a36Sopenharmony_ci	rec->u.res.lun_handle = q_head->lun_handle;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	memcpy(rec->u.res.prot_status_qual, &q_pref->prot_status_qual,
9462306a36Sopenharmony_ci	       FSF_PROT_STATUS_QUAL_SIZE);
9562306a36Sopenharmony_ci	memcpy(rec->u.res.fsf_status_qual, &q_head->fsf_status_qual,
9662306a36Sopenharmony_ci	       FSF_STATUS_QUALIFIER_SIZE);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	rec->pl_len = q_head->log_length;
9962306a36Sopenharmony_ci	zfcp_dbf_pl_write(dbf, (char *)q_pref + q_head->log_start,
10062306a36Sopenharmony_ci			  rec->pl_len, "fsf_res", req->req_id);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	debug_event(dbf->hba, level, rec, sizeof(*rec));
10362306a36Sopenharmony_ci	spin_unlock_irqrestore(&dbf->hba_lock, flags);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/**
10762306a36Sopenharmony_ci * zfcp_dbf_hba_fsf_fces - trace event for fsf responses related to
10862306a36Sopenharmony_ci *			   FC Endpoint Security (FCES)
10962306a36Sopenharmony_ci * @tag: tag indicating which kind of FC Endpoint Security event has occurred
11062306a36Sopenharmony_ci * @req: request for which a response was received
11162306a36Sopenharmony_ci * @wwpn: remote port or ZFCP_DBF_INVALID_WWPN
11262306a36Sopenharmony_ci * @fc_security_old: old FC Endpoint Security of FCP device or connection
11362306a36Sopenharmony_ci * @fc_security_new: new FC Endpoint Security of FCP device or connection
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_civoid zfcp_dbf_hba_fsf_fces(char *tag, const struct zfcp_fsf_req *req, u64 wwpn,
11662306a36Sopenharmony_ci			   u32 fc_security_old, u32 fc_security_new)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct zfcp_dbf *dbf = req->adapter->dbf;
11962306a36Sopenharmony_ci	struct fsf_qtcb_prefix *q_pref = &req->qtcb->prefix;
12062306a36Sopenharmony_ci	struct fsf_qtcb_header *q_head = &req->qtcb->header;
12162306a36Sopenharmony_ci	struct zfcp_dbf_hba *rec = &dbf->hba_buf;
12262306a36Sopenharmony_ci	static int const level = 3;
12362306a36Sopenharmony_ci	unsigned long flags;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (unlikely(!debug_level_enabled(dbf->hba, level)))
12662306a36Sopenharmony_ci		return;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	spin_lock_irqsave(&dbf->hba_lock, flags);
12962306a36Sopenharmony_ci	memset(rec, 0, sizeof(*rec));
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
13262306a36Sopenharmony_ci	rec->id = ZFCP_DBF_HBA_FCES;
13362306a36Sopenharmony_ci	rec->fsf_req_id = req->req_id;
13462306a36Sopenharmony_ci	rec->fsf_req_status = req->status;
13562306a36Sopenharmony_ci	rec->fsf_cmd = q_head->fsf_command;
13662306a36Sopenharmony_ci	rec->fsf_seq_no = q_pref->req_seq_no;
13762306a36Sopenharmony_ci	rec->u.fces.req_issued = req->issued;
13862306a36Sopenharmony_ci	rec->u.fces.fsf_status = q_head->fsf_status;
13962306a36Sopenharmony_ci	rec->u.fces.port_handle = q_head->port_handle;
14062306a36Sopenharmony_ci	rec->u.fces.wwpn = wwpn;
14162306a36Sopenharmony_ci	rec->u.fces.fc_security_old = fc_security_old;
14262306a36Sopenharmony_ci	rec->u.fces.fc_security_new = fc_security_new;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	debug_event(dbf->hba, level, rec, sizeof(*rec));
14562306a36Sopenharmony_ci	spin_unlock_irqrestore(&dbf->hba_lock, flags);
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci/**
14962306a36Sopenharmony_ci * zfcp_dbf_hba_fsf_reqid - trace only the tag and a request ID
15062306a36Sopenharmony_ci * @tag: tag documenting the source
15162306a36Sopenharmony_ci * @level: trace level
15262306a36Sopenharmony_ci * @adapter: adapter instance the request ID belongs to
15362306a36Sopenharmony_ci * @req_id: the request ID to trace
15462306a36Sopenharmony_ci */
15562306a36Sopenharmony_civoid zfcp_dbf_hba_fsf_reqid(const char *const tag, const int level,
15662306a36Sopenharmony_ci			    struct zfcp_adapter *const adapter,
15762306a36Sopenharmony_ci			    const u64 req_id)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	struct zfcp_dbf *const dbf = adapter->dbf;
16062306a36Sopenharmony_ci	struct zfcp_dbf_hba *const rec = &dbf->hba_buf;
16162306a36Sopenharmony_ci	struct zfcp_dbf_hba_res *const res = &rec->u.res;
16262306a36Sopenharmony_ci	unsigned long flags;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (unlikely(!debug_level_enabled(dbf->hba, level)))
16562306a36Sopenharmony_ci		return;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	spin_lock_irqsave(&dbf->hba_lock, flags);
16862306a36Sopenharmony_ci	memset(rec, 0, sizeof(*rec));
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	rec->id = ZFCP_DBF_HBA_RES;
17362306a36Sopenharmony_ci	rec->fsf_req_id = req_id;
17462306a36Sopenharmony_ci	rec->fsf_req_status = ~0u;
17562306a36Sopenharmony_ci	rec->fsf_cmd = ~0u;
17662306a36Sopenharmony_ci	rec->fsf_seq_no = ~0u;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	res->req_issued = ~0ull;
17962306a36Sopenharmony_ci	res->prot_status = ~0u;
18062306a36Sopenharmony_ci	memset(res->prot_status_qual, 0xff, sizeof(res->prot_status_qual));
18162306a36Sopenharmony_ci	res->fsf_status = ~0u;
18262306a36Sopenharmony_ci	memset(res->fsf_status_qual, 0xff, sizeof(res->fsf_status_qual));
18362306a36Sopenharmony_ci	res->port_handle = ~0u;
18462306a36Sopenharmony_ci	res->lun_handle = ~0u;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	debug_event(dbf->hba, level, rec, sizeof(*rec));
18762306a36Sopenharmony_ci	spin_unlock_irqrestore(&dbf->hba_lock, flags);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/**
19162306a36Sopenharmony_ci * zfcp_dbf_hba_fsf_uss - trace event for an unsolicited status buffer
19262306a36Sopenharmony_ci * @tag: tag indicating which kind of unsolicited status has been received
19362306a36Sopenharmony_ci * @req: request providing the unsolicited status
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_civoid zfcp_dbf_hba_fsf_uss(char *tag, struct zfcp_fsf_req *req)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct zfcp_dbf *dbf = req->adapter->dbf;
19862306a36Sopenharmony_ci	struct fsf_status_read_buffer *srb = req->data;
19962306a36Sopenharmony_ci	struct zfcp_dbf_hba *rec = &dbf->hba_buf;
20062306a36Sopenharmony_ci	static int const level = 2;
20162306a36Sopenharmony_ci	unsigned long flags;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (unlikely(!debug_level_enabled(dbf->hba, level)))
20462306a36Sopenharmony_ci		return;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	spin_lock_irqsave(&dbf->hba_lock, flags);
20762306a36Sopenharmony_ci	memset(rec, 0, sizeof(*rec));
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
21062306a36Sopenharmony_ci	rec->id = ZFCP_DBF_HBA_USS;
21162306a36Sopenharmony_ci	rec->fsf_req_id = req->req_id;
21262306a36Sopenharmony_ci	rec->fsf_req_status = req->status;
21362306a36Sopenharmony_ci	rec->fsf_cmd = FSF_QTCB_UNSOLICITED_STATUS;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if (!srb)
21662306a36Sopenharmony_ci		goto log;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	rec->u.uss.status_type = srb->status_type;
21962306a36Sopenharmony_ci	rec->u.uss.status_subtype = srb->status_subtype;
22062306a36Sopenharmony_ci	rec->u.uss.d_id = ntoh24(srb->d_id);
22162306a36Sopenharmony_ci	rec->u.uss.lun = srb->fcp_lun;
22262306a36Sopenharmony_ci	memcpy(&rec->u.uss.queue_designator, &srb->queue_designator,
22362306a36Sopenharmony_ci	       sizeof(rec->u.uss.queue_designator));
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/* status read buffer payload length */
22662306a36Sopenharmony_ci	rec->pl_len = (!srb->length) ? 0 : srb->length -
22762306a36Sopenharmony_ci			offsetof(struct fsf_status_read_buffer, payload);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (rec->pl_len)
23062306a36Sopenharmony_ci		zfcp_dbf_pl_write(dbf, srb->payload.data, rec->pl_len,
23162306a36Sopenharmony_ci				  "fsf_uss", req->req_id);
23262306a36Sopenharmony_cilog:
23362306a36Sopenharmony_ci	debug_event(dbf->hba, level, rec, sizeof(*rec));
23462306a36Sopenharmony_ci	spin_unlock_irqrestore(&dbf->hba_lock, flags);
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci/**
23862306a36Sopenharmony_ci * zfcp_dbf_hba_bit_err - trace event for bit error conditions
23962306a36Sopenharmony_ci * @tag: tag indicating which kind of bit error unsolicited status was received
24062306a36Sopenharmony_ci * @req: request which caused the bit_error condition
24162306a36Sopenharmony_ci */
24262306a36Sopenharmony_civoid zfcp_dbf_hba_bit_err(char *tag, struct zfcp_fsf_req *req)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	struct zfcp_dbf *dbf = req->adapter->dbf;
24562306a36Sopenharmony_ci	struct zfcp_dbf_hba *rec = &dbf->hba_buf;
24662306a36Sopenharmony_ci	struct fsf_status_read_buffer *sr_buf = req->data;
24762306a36Sopenharmony_ci	static int const level = 1;
24862306a36Sopenharmony_ci	unsigned long flags;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (unlikely(!debug_level_enabled(dbf->hba, level)))
25162306a36Sopenharmony_ci		return;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	spin_lock_irqsave(&dbf->hba_lock, flags);
25462306a36Sopenharmony_ci	memset(rec, 0, sizeof(*rec));
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
25762306a36Sopenharmony_ci	rec->id = ZFCP_DBF_HBA_BIT;
25862306a36Sopenharmony_ci	rec->fsf_req_id = req->req_id;
25962306a36Sopenharmony_ci	rec->fsf_req_status = req->status;
26062306a36Sopenharmony_ci	rec->fsf_cmd = FSF_QTCB_UNSOLICITED_STATUS;
26162306a36Sopenharmony_ci	memcpy(&rec->u.be, &sr_buf->payload.bit_error,
26262306a36Sopenharmony_ci	       sizeof(struct fsf_bit_error_payload));
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	debug_event(dbf->hba, level, rec, sizeof(*rec));
26562306a36Sopenharmony_ci	spin_unlock_irqrestore(&dbf->hba_lock, flags);
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci/**
26962306a36Sopenharmony_ci * zfcp_dbf_hba_def_err - trace event for deferred error messages
27062306a36Sopenharmony_ci * @adapter: pointer to struct zfcp_adapter
27162306a36Sopenharmony_ci * @req_id: request id which caused the deferred error message
27262306a36Sopenharmony_ci * @scount: number of sbals incl. the signaling sbal
27362306a36Sopenharmony_ci * @pl: array of all involved sbals
27462306a36Sopenharmony_ci */
27562306a36Sopenharmony_civoid zfcp_dbf_hba_def_err(struct zfcp_adapter *adapter, u64 req_id, u16 scount,
27662306a36Sopenharmony_ci			  void **pl)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	struct zfcp_dbf *dbf = adapter->dbf;
27962306a36Sopenharmony_ci	struct zfcp_dbf_pay *payload = &dbf->pay_buf;
28062306a36Sopenharmony_ci	unsigned long flags;
28162306a36Sopenharmony_ci	static int const level = 1;
28262306a36Sopenharmony_ci	u16 length;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (unlikely(!debug_level_enabled(dbf->pay, level)))
28562306a36Sopenharmony_ci		return;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	if (!pl)
28862306a36Sopenharmony_ci		return;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	spin_lock_irqsave(&dbf->pay_lock, flags);
29162306a36Sopenharmony_ci	memset(payload, 0, sizeof(*payload));
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	memcpy(payload->area, "def_err", 7);
29462306a36Sopenharmony_ci	payload->fsf_req_id = req_id;
29562306a36Sopenharmony_ci	payload->counter = 0;
29662306a36Sopenharmony_ci	length = min((u16)sizeof(struct qdio_buffer),
29762306a36Sopenharmony_ci		     (u16)ZFCP_DBF_PAY_MAX_REC);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	while (payload->counter < scount && (char *)pl[payload->counter]) {
30062306a36Sopenharmony_ci		memcpy(payload->data, (char *)pl[payload->counter], length);
30162306a36Sopenharmony_ci		debug_event(dbf->pay, level, payload, zfcp_dbf_plen(length));
30262306a36Sopenharmony_ci		payload->counter++;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	spin_unlock_irqrestore(&dbf->pay_lock, flags);
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec,
30962306a36Sopenharmony_ci				struct zfcp_adapter *adapter,
31062306a36Sopenharmony_ci				struct zfcp_port *port,
31162306a36Sopenharmony_ci				struct scsi_device *sdev)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	rec->adapter_status = atomic_read(&adapter->status);
31462306a36Sopenharmony_ci	if (port) {
31562306a36Sopenharmony_ci		rec->port_status = atomic_read(&port->status);
31662306a36Sopenharmony_ci		rec->wwpn = port->wwpn;
31762306a36Sopenharmony_ci		rec->d_id = port->d_id;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci	if (sdev) {
32062306a36Sopenharmony_ci		rec->lun_status = atomic_read(&sdev_to_zfcp(sdev)->status);
32162306a36Sopenharmony_ci		rec->lun = zfcp_scsi_dev_lun(sdev);
32262306a36Sopenharmony_ci	} else
32362306a36Sopenharmony_ci		rec->lun = ZFCP_DBF_INVALID_LUN;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci/**
32762306a36Sopenharmony_ci * zfcp_dbf_rec_trig - trace event related to triggered recovery
32862306a36Sopenharmony_ci * @tag: identifier for event
32962306a36Sopenharmony_ci * @adapter: adapter on which the erp_action should run
33062306a36Sopenharmony_ci * @port: remote port involved in the erp_action
33162306a36Sopenharmony_ci * @sdev: scsi device involved in the erp_action
33262306a36Sopenharmony_ci * @want: wanted erp_action
33362306a36Sopenharmony_ci * @need: required erp_action
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * The adapter->erp_lock has to be held.
33662306a36Sopenharmony_ci */
33762306a36Sopenharmony_civoid zfcp_dbf_rec_trig(char *tag, struct zfcp_adapter *adapter,
33862306a36Sopenharmony_ci		       struct zfcp_port *port, struct scsi_device *sdev,
33962306a36Sopenharmony_ci		       u8 want, u8 need)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct zfcp_dbf *dbf = adapter->dbf;
34262306a36Sopenharmony_ci	struct zfcp_dbf_rec *rec = &dbf->rec_buf;
34362306a36Sopenharmony_ci	static int const level = 1;
34462306a36Sopenharmony_ci	struct list_head *entry;
34562306a36Sopenharmony_ci	unsigned long flags;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	lockdep_assert_held(&adapter->erp_lock);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (unlikely(!debug_level_enabled(dbf->rec, level)))
35062306a36Sopenharmony_ci		return;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	spin_lock_irqsave(&dbf->rec_lock, flags);
35362306a36Sopenharmony_ci	memset(rec, 0, sizeof(*rec));
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	rec->id = ZFCP_DBF_REC_TRIG;
35662306a36Sopenharmony_ci	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
35762306a36Sopenharmony_ci	zfcp_dbf_set_common(rec, adapter, port, sdev);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	list_for_each(entry, &adapter->erp_ready_head)
36062306a36Sopenharmony_ci		rec->u.trig.ready++;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	list_for_each(entry, &adapter->erp_running_head)
36362306a36Sopenharmony_ci		rec->u.trig.running++;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	rec->u.trig.want = want;
36662306a36Sopenharmony_ci	rec->u.trig.need = need;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	debug_event(dbf->rec, level, rec, sizeof(*rec));
36962306a36Sopenharmony_ci	spin_unlock_irqrestore(&dbf->rec_lock, flags);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci/**
37362306a36Sopenharmony_ci * zfcp_dbf_rec_trig_lock - trace event related to triggered recovery with lock
37462306a36Sopenharmony_ci * @tag: identifier for event
37562306a36Sopenharmony_ci * @adapter: adapter on which the erp_action should run
37662306a36Sopenharmony_ci * @port: remote port involved in the erp_action
37762306a36Sopenharmony_ci * @sdev: scsi device involved in the erp_action
37862306a36Sopenharmony_ci * @want: wanted erp_action
37962306a36Sopenharmony_ci * @need: required erp_action
38062306a36Sopenharmony_ci *
38162306a36Sopenharmony_ci * The adapter->erp_lock must not be held.
38262306a36Sopenharmony_ci */
38362306a36Sopenharmony_civoid zfcp_dbf_rec_trig_lock(char *tag, struct zfcp_adapter *adapter,
38462306a36Sopenharmony_ci			    struct zfcp_port *port, struct scsi_device *sdev,
38562306a36Sopenharmony_ci			    u8 want, u8 need)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	unsigned long flags;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	read_lock_irqsave(&adapter->erp_lock, flags);
39062306a36Sopenharmony_ci	zfcp_dbf_rec_trig(tag, adapter, port, sdev, want, need);
39162306a36Sopenharmony_ci	read_unlock_irqrestore(&adapter->erp_lock, flags);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci/**
39562306a36Sopenharmony_ci * zfcp_dbf_rec_run_lvl - trace event related to running recovery
39662306a36Sopenharmony_ci * @level: trace level to be used for event
39762306a36Sopenharmony_ci * @tag: identifier for event
39862306a36Sopenharmony_ci * @erp: erp_action running
39962306a36Sopenharmony_ci */
40062306a36Sopenharmony_civoid zfcp_dbf_rec_run_lvl(int level, char *tag, struct zfcp_erp_action *erp)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	struct zfcp_dbf *dbf = erp->adapter->dbf;
40362306a36Sopenharmony_ci	struct zfcp_dbf_rec *rec = &dbf->rec_buf;
40462306a36Sopenharmony_ci	unsigned long flags;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	if (!debug_level_enabled(dbf->rec, level))
40762306a36Sopenharmony_ci		return;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	spin_lock_irqsave(&dbf->rec_lock, flags);
41062306a36Sopenharmony_ci	memset(rec, 0, sizeof(*rec));
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	rec->id = ZFCP_DBF_REC_RUN;
41362306a36Sopenharmony_ci	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
41462306a36Sopenharmony_ci	zfcp_dbf_set_common(rec, erp->adapter, erp->port, erp->sdev);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	rec->u.run.fsf_req_id = erp->fsf_req_id;
41762306a36Sopenharmony_ci	rec->u.run.rec_status = erp->status;
41862306a36Sopenharmony_ci	rec->u.run.rec_step = erp->step;
41962306a36Sopenharmony_ci	rec->u.run.rec_action = erp->type;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	if (erp->sdev)
42262306a36Sopenharmony_ci		rec->u.run.rec_count =
42362306a36Sopenharmony_ci			atomic_read(&sdev_to_zfcp(erp->sdev)->erp_counter);
42462306a36Sopenharmony_ci	else if (erp->port)
42562306a36Sopenharmony_ci		rec->u.run.rec_count = atomic_read(&erp->port->erp_counter);
42662306a36Sopenharmony_ci	else
42762306a36Sopenharmony_ci		rec->u.run.rec_count = atomic_read(&erp->adapter->erp_counter);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	debug_event(dbf->rec, level, rec, sizeof(*rec));
43062306a36Sopenharmony_ci	spin_unlock_irqrestore(&dbf->rec_lock, flags);
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci/**
43462306a36Sopenharmony_ci * zfcp_dbf_rec_run - trace event related to running recovery
43562306a36Sopenharmony_ci * @tag: identifier for event
43662306a36Sopenharmony_ci * @erp: erp_action running
43762306a36Sopenharmony_ci */
43862306a36Sopenharmony_civoid zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	zfcp_dbf_rec_run_lvl(1, tag, erp);
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci/**
44462306a36Sopenharmony_ci * zfcp_dbf_rec_run_wka - trace wka port event with info like running recovery
44562306a36Sopenharmony_ci * @tag: identifier for event
44662306a36Sopenharmony_ci * @wka_port: well known address port
44762306a36Sopenharmony_ci * @req_id: request ID to correlate with potential HBA trace record
44862306a36Sopenharmony_ci */
44962306a36Sopenharmony_civoid zfcp_dbf_rec_run_wka(char *tag, struct zfcp_fc_wka_port *wka_port,
45062306a36Sopenharmony_ci			  u64 req_id)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	struct zfcp_dbf *dbf = wka_port->adapter->dbf;
45362306a36Sopenharmony_ci	struct zfcp_dbf_rec *rec = &dbf->rec_buf;
45462306a36Sopenharmony_ci	static int const level = 1;
45562306a36Sopenharmony_ci	unsigned long flags;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (unlikely(!debug_level_enabled(dbf->rec, level)))
45862306a36Sopenharmony_ci		return;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	spin_lock_irqsave(&dbf->rec_lock, flags);
46162306a36Sopenharmony_ci	memset(rec, 0, sizeof(*rec));
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	rec->id = ZFCP_DBF_REC_RUN;
46462306a36Sopenharmony_ci	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
46562306a36Sopenharmony_ci	rec->port_status = wka_port->status;
46662306a36Sopenharmony_ci	rec->d_id = wka_port->d_id;
46762306a36Sopenharmony_ci	rec->lun = ZFCP_DBF_INVALID_LUN;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	rec->u.run.fsf_req_id = req_id;
47062306a36Sopenharmony_ci	rec->u.run.rec_status = ~0;
47162306a36Sopenharmony_ci	rec->u.run.rec_step = ~0;
47262306a36Sopenharmony_ci	rec->u.run.rec_action = ~0;
47362306a36Sopenharmony_ci	rec->u.run.rec_count = ~0;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	debug_event(dbf->rec, level, rec, sizeof(*rec));
47662306a36Sopenharmony_ci	spin_unlock_irqrestore(&dbf->rec_lock, flags);
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci#define ZFCP_DBF_SAN_LEVEL 1
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic inline
48262306a36Sopenharmony_civoid zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf,
48362306a36Sopenharmony_ci		  char *paytag, struct scatterlist *sg, u8 id, u16 len,
48462306a36Sopenharmony_ci		  u64 req_id, u32 d_id, u16 cap_len)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct zfcp_dbf_san *rec = &dbf->san_buf;
48762306a36Sopenharmony_ci	u16 rec_len;
48862306a36Sopenharmony_ci	unsigned long flags;
48962306a36Sopenharmony_ci	struct zfcp_dbf_pay *payload = &dbf->pay_buf;
49062306a36Sopenharmony_ci	u16 pay_sum = 0;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	spin_lock_irqsave(&dbf->san_lock, flags);
49362306a36Sopenharmony_ci	memset(rec, 0, sizeof(*rec));
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	rec->id = id;
49662306a36Sopenharmony_ci	rec->fsf_req_id = req_id;
49762306a36Sopenharmony_ci	rec->d_id = d_id;
49862306a36Sopenharmony_ci	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
49962306a36Sopenharmony_ci	rec->pl_len = len; /* full length even if we cap pay below */
50062306a36Sopenharmony_ci	if (!sg)
50162306a36Sopenharmony_ci		goto out;
50262306a36Sopenharmony_ci	rec_len = min_t(unsigned int, sg->length, ZFCP_DBF_SAN_MAX_PAYLOAD);
50362306a36Sopenharmony_ci	memcpy(rec->payload, sg_virt(sg), rec_len); /* part of 1st sg entry */
50462306a36Sopenharmony_ci	if (len <= rec_len)
50562306a36Sopenharmony_ci		goto out; /* skip pay record if full content in rec->payload */
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	/* if (len > rec_len):
50862306a36Sopenharmony_ci	 * dump data up to cap_len ignoring small duplicate in rec->payload
50962306a36Sopenharmony_ci	 */
51062306a36Sopenharmony_ci	spin_lock(&dbf->pay_lock);
51162306a36Sopenharmony_ci	memset(payload, 0, sizeof(*payload));
51262306a36Sopenharmony_ci	memcpy(payload->area, paytag, ZFCP_DBF_TAG_LEN);
51362306a36Sopenharmony_ci	payload->fsf_req_id = req_id;
51462306a36Sopenharmony_ci	payload->counter = 0;
51562306a36Sopenharmony_ci	for (; sg && pay_sum < cap_len; sg = sg_next(sg)) {
51662306a36Sopenharmony_ci		u16 pay_len, offset = 0;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci		while (offset < sg->length && pay_sum < cap_len) {
51962306a36Sopenharmony_ci			pay_len = min((u16)ZFCP_DBF_PAY_MAX_REC,
52062306a36Sopenharmony_ci				      (u16)(sg->length - offset));
52162306a36Sopenharmony_ci			/* cap_len <= pay_sum < cap_len+ZFCP_DBF_PAY_MAX_REC */
52262306a36Sopenharmony_ci			memcpy(payload->data, sg_virt(sg) + offset, pay_len);
52362306a36Sopenharmony_ci			debug_event(dbf->pay, ZFCP_DBF_SAN_LEVEL, payload,
52462306a36Sopenharmony_ci				    zfcp_dbf_plen(pay_len));
52562306a36Sopenharmony_ci			payload->counter++;
52662306a36Sopenharmony_ci			offset += pay_len;
52762306a36Sopenharmony_ci			pay_sum += pay_len;
52862306a36Sopenharmony_ci		}
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci	spin_unlock(&dbf->pay_lock);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ciout:
53362306a36Sopenharmony_ci	debug_event(dbf->san, ZFCP_DBF_SAN_LEVEL, rec, sizeof(*rec));
53462306a36Sopenharmony_ci	spin_unlock_irqrestore(&dbf->san_lock, flags);
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci/**
53862306a36Sopenharmony_ci * zfcp_dbf_san_req - trace event for issued SAN request
53962306a36Sopenharmony_ci * @tag: identifier for event
54062306a36Sopenharmony_ci * @fsf: request containing issued CT or ELS data
54162306a36Sopenharmony_ci * @d_id: N_Port_ID where SAN request is sent to
54262306a36Sopenharmony_ci * d_id: destination ID
54362306a36Sopenharmony_ci */
54462306a36Sopenharmony_civoid zfcp_dbf_san_req(char *tag, struct zfcp_fsf_req *fsf, u32 d_id)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	struct zfcp_dbf *dbf = fsf->adapter->dbf;
54762306a36Sopenharmony_ci	struct zfcp_fsf_ct_els *ct_els = fsf->data;
54862306a36Sopenharmony_ci	u16 length;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (unlikely(!debug_level_enabled(dbf->san, ZFCP_DBF_SAN_LEVEL)))
55162306a36Sopenharmony_ci		return;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	length = (u16)zfcp_qdio_real_bytes(ct_els->req);
55462306a36Sopenharmony_ci	zfcp_dbf_san(tag, dbf, "san_req", ct_els->req, ZFCP_DBF_SAN_REQ,
55562306a36Sopenharmony_ci		     length, fsf->req_id, d_id, length);
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic u16 zfcp_dbf_san_res_cap_len_if_gpn_ft(char *tag,
55962306a36Sopenharmony_ci					      struct zfcp_fsf_req *fsf,
56062306a36Sopenharmony_ci					      u16 len)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	struct zfcp_fsf_ct_els *ct_els = fsf->data;
56362306a36Sopenharmony_ci	struct fc_ct_hdr *reqh = sg_virt(ct_els->req);
56462306a36Sopenharmony_ci	struct fc_ns_gid_ft *reqn = (struct fc_ns_gid_ft *)(reqh + 1);
56562306a36Sopenharmony_ci	struct scatterlist *resp_entry = ct_els->resp;
56662306a36Sopenharmony_ci	struct fc_ct_hdr *resph;
56762306a36Sopenharmony_ci	struct fc_gpn_ft_resp *acc;
56862306a36Sopenharmony_ci	int max_entries, x, last = 0;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	if (!(memcmp(tag, "fsscth2", 7) == 0
57162306a36Sopenharmony_ci	      && ct_els->d_id == FC_FID_DIR_SERV
57262306a36Sopenharmony_ci	      && reqh->ct_rev == FC_CT_REV
57362306a36Sopenharmony_ci	      && reqh->ct_in_id[0] == 0
57462306a36Sopenharmony_ci	      && reqh->ct_in_id[1] == 0
57562306a36Sopenharmony_ci	      && reqh->ct_in_id[2] == 0
57662306a36Sopenharmony_ci	      && reqh->ct_fs_type == FC_FST_DIR
57762306a36Sopenharmony_ci	      && reqh->ct_fs_subtype == FC_NS_SUBTYPE
57862306a36Sopenharmony_ci	      && reqh->ct_options == 0
57962306a36Sopenharmony_ci	      && reqh->_ct_resvd1 == 0
58062306a36Sopenharmony_ci	      && reqh->ct_cmd == cpu_to_be16(FC_NS_GPN_FT)
58162306a36Sopenharmony_ci	      /* reqh->ct_mr_size can vary so do not match but read below */
58262306a36Sopenharmony_ci	      && reqh->_ct_resvd2 == 0
58362306a36Sopenharmony_ci	      && reqh->ct_reason == 0
58462306a36Sopenharmony_ci	      && reqh->ct_explan == 0
58562306a36Sopenharmony_ci	      && reqh->ct_vendor == 0
58662306a36Sopenharmony_ci	      && reqn->fn_resvd == 0
58762306a36Sopenharmony_ci	      && reqn->fn_domain_id_scope == 0
58862306a36Sopenharmony_ci	      && reqn->fn_area_id_scope == 0
58962306a36Sopenharmony_ci	      && reqn->fn_fc4_type == FC_TYPE_FCP))
59062306a36Sopenharmony_ci		return len; /* not GPN_FT response so do not cap */
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	acc = sg_virt(resp_entry);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	/* cap all but accept CT responses to at least the CT header */
59562306a36Sopenharmony_ci	resph = (struct fc_ct_hdr *)acc;
59662306a36Sopenharmony_ci	if ((ct_els->status) ||
59762306a36Sopenharmony_ci	    (resph->ct_cmd != cpu_to_be16(FC_FS_ACC)))
59862306a36Sopenharmony_ci		return max(FC_CT_HDR_LEN, ZFCP_DBF_SAN_MAX_PAYLOAD);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	max_entries = (be16_to_cpu(reqh->ct_mr_size) * 4 /
60162306a36Sopenharmony_ci		       sizeof(struct fc_gpn_ft_resp))
60262306a36Sopenharmony_ci		+ 1 /* zfcp_fc_scan_ports: bytes correct, entries off-by-one
60362306a36Sopenharmony_ci		     * to account for header as 1st pseudo "entry" */;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* the basic CT_IU preamble is the same size as one entry in the GPN_FT
60662306a36Sopenharmony_ci	 * response, allowing us to skip special handling for it - just skip it
60762306a36Sopenharmony_ci	 */
60862306a36Sopenharmony_ci	for (x = 1; x < max_entries && !last; x++) {
60962306a36Sopenharmony_ci		if (x % (ZFCP_FC_GPN_FT_ENT_PAGE + 1))
61062306a36Sopenharmony_ci			acc++;
61162306a36Sopenharmony_ci		else
61262306a36Sopenharmony_ci			acc = sg_virt(++resp_entry);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		last = acc->fp_flags & FC_NS_FID_LAST;
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci	len = min(len, (u16)(x * sizeof(struct fc_gpn_ft_resp)));
61762306a36Sopenharmony_ci	return len; /* cap after last entry */
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci/**
62162306a36Sopenharmony_ci * zfcp_dbf_san_res - trace event for received SAN request
62262306a36Sopenharmony_ci * @tag: identifier for event
62362306a36Sopenharmony_ci * @fsf: request containing received CT or ELS data
62462306a36Sopenharmony_ci */
62562306a36Sopenharmony_civoid zfcp_dbf_san_res(char *tag, struct zfcp_fsf_req *fsf)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	struct zfcp_dbf *dbf = fsf->adapter->dbf;
62862306a36Sopenharmony_ci	struct zfcp_fsf_ct_els *ct_els = fsf->data;
62962306a36Sopenharmony_ci	u16 length;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	if (unlikely(!debug_level_enabled(dbf->san, ZFCP_DBF_SAN_LEVEL)))
63262306a36Sopenharmony_ci		return;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	length = (u16)zfcp_qdio_real_bytes(ct_els->resp);
63562306a36Sopenharmony_ci	zfcp_dbf_san(tag, dbf, "san_res", ct_els->resp, ZFCP_DBF_SAN_RES,
63662306a36Sopenharmony_ci		     length, fsf->req_id, ct_els->d_id,
63762306a36Sopenharmony_ci		     zfcp_dbf_san_res_cap_len_if_gpn_ft(tag, fsf, length));
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci/**
64162306a36Sopenharmony_ci * zfcp_dbf_san_in_els - trace event for incoming ELS
64262306a36Sopenharmony_ci * @tag: identifier for event
64362306a36Sopenharmony_ci * @fsf: request containing received ELS data
64462306a36Sopenharmony_ci */
64562306a36Sopenharmony_civoid zfcp_dbf_san_in_els(char *tag, struct zfcp_fsf_req *fsf)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	struct zfcp_dbf *dbf = fsf->adapter->dbf;
64862306a36Sopenharmony_ci	struct fsf_status_read_buffer *srb =
64962306a36Sopenharmony_ci		(struct fsf_status_read_buffer *) fsf->data;
65062306a36Sopenharmony_ci	u16 length;
65162306a36Sopenharmony_ci	struct scatterlist sg;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	if (unlikely(!debug_level_enabled(dbf->san, ZFCP_DBF_SAN_LEVEL)))
65462306a36Sopenharmony_ci		return;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	length = (u16)(srb->length -
65762306a36Sopenharmony_ci			offsetof(struct fsf_status_read_buffer, payload));
65862306a36Sopenharmony_ci	sg_init_one(&sg, srb->payload.data, length);
65962306a36Sopenharmony_ci	zfcp_dbf_san(tag, dbf, "san_els", &sg, ZFCP_DBF_SAN_ELS, length,
66062306a36Sopenharmony_ci		     fsf->req_id, ntoh24(srb->d_id), length);
66162306a36Sopenharmony_ci}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci/**
66462306a36Sopenharmony_ci * zfcp_dbf_scsi_common() - Common trace event helper for scsi.
66562306a36Sopenharmony_ci * @tag: Identifier for event.
66662306a36Sopenharmony_ci * @level: trace level of event.
66762306a36Sopenharmony_ci * @sdev: Pointer to SCSI device as context for this event.
66862306a36Sopenharmony_ci * @sc: Pointer to SCSI command, or NULL with task management function (TMF).
66962306a36Sopenharmony_ci * @fsf: Pointer to FSF request, or NULL.
67062306a36Sopenharmony_ci */
67162306a36Sopenharmony_civoid zfcp_dbf_scsi_common(char *tag, int level, struct scsi_device *sdev,
67262306a36Sopenharmony_ci			  struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	struct zfcp_adapter *adapter =
67562306a36Sopenharmony_ci		(struct zfcp_adapter *) sdev->host->hostdata[0];
67662306a36Sopenharmony_ci	struct zfcp_dbf *dbf = adapter->dbf;
67762306a36Sopenharmony_ci	struct zfcp_dbf_scsi *rec = &dbf->scsi_buf;
67862306a36Sopenharmony_ci	struct fcp_resp_with_ext *fcp_rsp;
67962306a36Sopenharmony_ci	struct fcp_resp_rsp_info *fcp_rsp_info;
68062306a36Sopenharmony_ci	unsigned long flags;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	spin_lock_irqsave(&dbf->scsi_lock, flags);
68362306a36Sopenharmony_ci	memset(rec, 0, sizeof(*rec));
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
68662306a36Sopenharmony_ci	rec->id = ZFCP_DBF_SCSI_CMND;
68762306a36Sopenharmony_ci	if (sc) {
68862306a36Sopenharmony_ci		rec->scsi_result = sc->result;
68962306a36Sopenharmony_ci		rec->scsi_retries = sc->retries;
69062306a36Sopenharmony_ci		rec->scsi_allowed = sc->allowed;
69162306a36Sopenharmony_ci		rec->scsi_id = sc->device->id;
69262306a36Sopenharmony_ci		rec->scsi_lun = (u32)sc->device->lun;
69362306a36Sopenharmony_ci		rec->scsi_lun_64_hi = (u32)(sc->device->lun >> 32);
69462306a36Sopenharmony_ci		rec->host_scribble = (u64)sc->host_scribble;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci		memcpy(rec->scsi_opcode, sc->cmnd,
69762306a36Sopenharmony_ci		       min_t(int, sc->cmd_len, ZFCP_DBF_SCSI_OPCODE));
69862306a36Sopenharmony_ci	} else {
69962306a36Sopenharmony_ci		rec->scsi_result = ~0;
70062306a36Sopenharmony_ci		rec->scsi_retries = ~0;
70162306a36Sopenharmony_ci		rec->scsi_allowed = ~0;
70262306a36Sopenharmony_ci		rec->scsi_id = sdev->id;
70362306a36Sopenharmony_ci		rec->scsi_lun = (u32)sdev->lun;
70462306a36Sopenharmony_ci		rec->scsi_lun_64_hi = (u32)(sdev->lun >> 32);
70562306a36Sopenharmony_ci		rec->host_scribble = ~0;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci		memset(rec->scsi_opcode, 0xff, ZFCP_DBF_SCSI_OPCODE);
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	if (fsf) {
71162306a36Sopenharmony_ci		rec->fsf_req_id = fsf->req_id;
71262306a36Sopenharmony_ci		rec->pl_len = FCP_RESP_WITH_EXT;
71362306a36Sopenharmony_ci		fcp_rsp = &(fsf->qtcb->bottom.io.fcp_rsp.iu);
71462306a36Sopenharmony_ci		/* mandatory parts of FCP_RSP IU in this SCSI record */
71562306a36Sopenharmony_ci		memcpy(&rec->fcp_rsp, fcp_rsp, FCP_RESP_WITH_EXT);
71662306a36Sopenharmony_ci		if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) {
71762306a36Sopenharmony_ci			fcp_rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
71862306a36Sopenharmony_ci			rec->fcp_rsp_info = fcp_rsp_info->rsp_code;
71962306a36Sopenharmony_ci			rec->pl_len += be32_to_cpu(fcp_rsp->ext.fr_rsp_len);
72062306a36Sopenharmony_ci		}
72162306a36Sopenharmony_ci		if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) {
72262306a36Sopenharmony_ci			rec->pl_len += be32_to_cpu(fcp_rsp->ext.fr_sns_len);
72362306a36Sopenharmony_ci		}
72462306a36Sopenharmony_ci		/* complete FCP_RSP IU in associated PAYload record
72562306a36Sopenharmony_ci		 * but only if there are optional parts
72662306a36Sopenharmony_ci		 */
72762306a36Sopenharmony_ci		if (fcp_rsp->resp.fr_flags != 0)
72862306a36Sopenharmony_ci			zfcp_dbf_pl_write(
72962306a36Sopenharmony_ci				dbf, fcp_rsp,
73062306a36Sopenharmony_ci				/* at least one full PAY record
73162306a36Sopenharmony_ci				 * but not beyond hardware response field
73262306a36Sopenharmony_ci				 */
73362306a36Sopenharmony_ci				min_t(u16, max_t(u16, rec->pl_len,
73462306a36Sopenharmony_ci						 ZFCP_DBF_PAY_MAX_REC),
73562306a36Sopenharmony_ci				      FSF_FCP_RSP_SIZE),
73662306a36Sopenharmony_ci				"fcp_riu", fsf->req_id);
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	debug_event(dbf->scsi, level, rec, sizeof(*rec));
74062306a36Sopenharmony_ci	spin_unlock_irqrestore(&dbf->scsi_lock, flags);
74162306a36Sopenharmony_ci}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci/**
74462306a36Sopenharmony_ci * zfcp_dbf_scsi_eh() - Trace event for special cases of scsi_eh callbacks.
74562306a36Sopenharmony_ci * @tag: Identifier for event.
74662306a36Sopenharmony_ci * @adapter: Pointer to zfcp adapter as context for this event.
74762306a36Sopenharmony_ci * @scsi_id: SCSI ID/target to indicate scope of task management function (TMF).
74862306a36Sopenharmony_ci * @ret: Return value of calling function.
74962306a36Sopenharmony_ci *
75062306a36Sopenharmony_ci * This SCSI trace variant does not depend on any of:
75162306a36Sopenharmony_ci * scsi_cmnd, zfcp_fsf_req, scsi_device.
75262306a36Sopenharmony_ci */
75362306a36Sopenharmony_civoid zfcp_dbf_scsi_eh(char *tag, struct zfcp_adapter *adapter,
75462306a36Sopenharmony_ci		      unsigned int scsi_id, int ret)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	struct zfcp_dbf *dbf = adapter->dbf;
75762306a36Sopenharmony_ci	struct zfcp_dbf_scsi *rec = &dbf->scsi_buf;
75862306a36Sopenharmony_ci	unsigned long flags;
75962306a36Sopenharmony_ci	static int const level = 1;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	if (unlikely(!debug_level_enabled(adapter->dbf->scsi, level)))
76262306a36Sopenharmony_ci		return;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	spin_lock_irqsave(&dbf->scsi_lock, flags);
76562306a36Sopenharmony_ci	memset(rec, 0, sizeof(*rec));
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
76862306a36Sopenharmony_ci	rec->id = ZFCP_DBF_SCSI_CMND;
76962306a36Sopenharmony_ci	rec->scsi_result = ret; /* re-use field, int is 4 bytes and fits */
77062306a36Sopenharmony_ci	rec->scsi_retries = ~0;
77162306a36Sopenharmony_ci	rec->scsi_allowed = ~0;
77262306a36Sopenharmony_ci	rec->fcp_rsp_info = ~0;
77362306a36Sopenharmony_ci	rec->scsi_id = scsi_id;
77462306a36Sopenharmony_ci	rec->scsi_lun = (u32)ZFCP_DBF_INVALID_LUN;
77562306a36Sopenharmony_ci	rec->scsi_lun_64_hi = (u32)(ZFCP_DBF_INVALID_LUN >> 32);
77662306a36Sopenharmony_ci	rec->host_scribble = ~0;
77762306a36Sopenharmony_ci	memset(rec->scsi_opcode, 0xff, ZFCP_DBF_SCSI_OPCODE);
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	debug_event(dbf->scsi, level, rec, sizeof(*rec));
78062306a36Sopenharmony_ci	spin_unlock_irqrestore(&dbf->scsi_lock, flags);
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic debug_info_t *zfcp_dbf_reg(const char *name, int size, int rec_size)
78462306a36Sopenharmony_ci{
78562306a36Sopenharmony_ci	struct debug_info *d;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	d = debug_register(name, size, 1, rec_size);
78862306a36Sopenharmony_ci	if (!d)
78962306a36Sopenharmony_ci		return NULL;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	debug_register_view(d, &debug_hex_ascii_view);
79262306a36Sopenharmony_ci	debug_set_level(d, dbflevel);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	return d;
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic void zfcp_dbf_unregister(struct zfcp_dbf *dbf)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	if (!dbf)
80062306a36Sopenharmony_ci		return;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	debug_unregister(dbf->scsi);
80362306a36Sopenharmony_ci	debug_unregister(dbf->san);
80462306a36Sopenharmony_ci	debug_unregister(dbf->hba);
80562306a36Sopenharmony_ci	debug_unregister(dbf->pay);
80662306a36Sopenharmony_ci	debug_unregister(dbf->rec);
80762306a36Sopenharmony_ci	kfree(dbf);
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci/**
81162306a36Sopenharmony_ci * zfcp_dbf_adapter_register - registers debug feature for an adapter
81262306a36Sopenharmony_ci * @adapter: pointer to adapter for which debug features should be registered
81362306a36Sopenharmony_ci * return: -ENOMEM on error, 0 otherwise
81462306a36Sopenharmony_ci */
81562306a36Sopenharmony_ciint zfcp_dbf_adapter_register(struct zfcp_adapter *adapter)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	char name[DEBUG_MAX_NAME_LEN];
81862306a36Sopenharmony_ci	struct zfcp_dbf *dbf;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	dbf = kzalloc(sizeof(struct zfcp_dbf), GFP_KERNEL);
82162306a36Sopenharmony_ci	if (!dbf)
82262306a36Sopenharmony_ci		return -ENOMEM;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	spin_lock_init(&dbf->pay_lock);
82562306a36Sopenharmony_ci	spin_lock_init(&dbf->hba_lock);
82662306a36Sopenharmony_ci	spin_lock_init(&dbf->san_lock);
82762306a36Sopenharmony_ci	spin_lock_init(&dbf->scsi_lock);
82862306a36Sopenharmony_ci	spin_lock_init(&dbf->rec_lock);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	/* debug feature area which records recovery activity */
83162306a36Sopenharmony_ci	sprintf(name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev));
83262306a36Sopenharmony_ci	dbf->rec = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_rec));
83362306a36Sopenharmony_ci	if (!dbf->rec)
83462306a36Sopenharmony_ci		goto err_out;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/* debug feature area which records HBA (FSF and QDIO) conditions */
83762306a36Sopenharmony_ci	sprintf(name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev));
83862306a36Sopenharmony_ci	dbf->hba = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_hba));
83962306a36Sopenharmony_ci	if (!dbf->hba)
84062306a36Sopenharmony_ci		goto err_out;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	/* debug feature area which records payload info */
84362306a36Sopenharmony_ci	sprintf(name, "zfcp_%s_pay", dev_name(&adapter->ccw_device->dev));
84462306a36Sopenharmony_ci	dbf->pay = zfcp_dbf_reg(name, dbfsize * 2, sizeof(struct zfcp_dbf_pay));
84562306a36Sopenharmony_ci	if (!dbf->pay)
84662306a36Sopenharmony_ci		goto err_out;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	/* debug feature area which records SAN command failures and recovery */
84962306a36Sopenharmony_ci	sprintf(name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev));
85062306a36Sopenharmony_ci	dbf->san = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_san));
85162306a36Sopenharmony_ci	if (!dbf->san)
85262306a36Sopenharmony_ci		goto err_out;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	/* debug feature area which records SCSI command failures and recovery */
85562306a36Sopenharmony_ci	sprintf(name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev));
85662306a36Sopenharmony_ci	dbf->scsi = zfcp_dbf_reg(name, dbfsize, sizeof(struct zfcp_dbf_scsi));
85762306a36Sopenharmony_ci	if (!dbf->scsi)
85862306a36Sopenharmony_ci		goto err_out;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	adapter->dbf = dbf;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	return 0;
86362306a36Sopenharmony_cierr_out:
86462306a36Sopenharmony_ci	zfcp_dbf_unregister(dbf);
86562306a36Sopenharmony_ci	return -ENOMEM;
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci/**
86962306a36Sopenharmony_ci * zfcp_dbf_adapter_unregister - unregisters debug feature for an adapter
87062306a36Sopenharmony_ci * @adapter: pointer to adapter for which debug features should be unregistered
87162306a36Sopenharmony_ci */
87262306a36Sopenharmony_civoid zfcp_dbf_adapter_unregister(struct zfcp_adapter *adapter)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	struct zfcp_dbf *dbf = adapter->dbf;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	adapter->dbf = NULL;
87762306a36Sopenharmony_ci	zfcp_dbf_unregister(dbf);
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
880