summaryrefslogtreecommitdiffstats
path: root/drivers/s390/scsi/zfcp_dbf.h
blob: 04081b1b62b4b1568ecad4fa0c05b0e917f36bb6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
/*
 * This file is part of the zfcp device driver for
 * FCP adapters for IBM System z9 and zSeries.
 *
 * Copyright IBM Corp. 2008, 2009
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifndef ZFCP_DBF_H
#define ZFCP_DBF_H

#include <scsi/fc/fc_fcp.h>
#include "zfcp_ext.h"
#include "zfcp_fsf.h"
#include "zfcp_def.h"

#define ZFCP_DBF_TAG_SIZE      4
#define ZFCP_DBF_ID_SIZE       7

#define ZFCP_DBF_INVALID_LUN	0xFFFFFFFFFFFFFFFFull

struct zfcp_dbf_dump {
	u8 tag[ZFCP_DBF_TAG_SIZE];
	u32 total_size;		/* size of total dump data */
	u32 offset;		/* how much data has being already dumped */
	u32 size;		/* how much data comes with this record */
	u8 data[];		/* dump data */
} __attribute__ ((packed));

struct zfcp_dbf_rec_record_thread {
	u32 total;
	u32 ready;
	u32 running;
};

struct zfcp_dbf_rec_record_target {
	u64 ref;
	u32 status;
	u32 d_id;
	u64 wwpn;
	u64 fcp_lun;
	u32 erp_count;
};

struct zfcp_dbf_rec_record_trigger {
	u8 want;
	u8 need;
	u32 as;
	u32 ps;
	u32 ls;
	u64 ref;
	u64 action;
	u64 wwpn;
	u64 fcp_lun;
};

struct zfcp_dbf_rec_record_action {
	u32 status;
	u32 step;
	u64 action;
	u64 fsf_req;
};

struct zfcp_dbf_rec_record {
	u8 id;
	char id2[7];
	union {
		struct zfcp_dbf_rec_record_action action;
		struct zfcp_dbf_rec_record_thread thread;
		struct zfcp_dbf_rec_record_target target;
		struct zfcp_dbf_rec_record_trigger trigger;
	} u;
};

enum {
	ZFCP_REC_DBF_ID_ACTION,
	ZFCP_REC_DBF_ID_THREAD,
	ZFCP_REC_DBF_ID_TARGET,
	ZFCP_REC_DBF_ID_TRIGGER,
};

struct zfcp_dbf_hba_record_response {
	u32 fsf_command;
	u64 fsf_reqid;
	u32 fsf_seqno;
	u64 fsf_issued;
	u32 fsf_prot_status;
	u32 fsf_status;
	u8 fsf_prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE];
	u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
	u32 fsf_req_status;
	u8 sbal_first;
	u8 sbal_last;
	u8 sbal_response;
	u8 pool;
	u64 erp_action;
	union {
		struct {
			u64 cmnd;
			u32 data_dir;
		} fcp;
		struct {
			u64 wwpn;
			u32 d_id;
			u32 port_handle;
		} port;
		struct {
			u64 wwpn;
			u64 fcp_lun;
			u32 port_handle;
			u32 lun_handle;
		} unit;
		struct {
			u32 d_id;
		} els;
	} u;
} __attribute__ ((packed));

struct zfcp_dbf_hba_record_status {
	u8 failed;
	u32 status_type;
	u32 status_subtype;
	struct fsf_queue_designator
	 queue_designator;
	u32 payload_size;
#define ZFCP_DBF_UNSOL_PAYLOAD				80
#define ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL		32
#define ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD	56
#define ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT	2 * sizeof(u32)
	u8 payload[ZFCP_DBF_UNSOL_PAYLOAD];
} __attribute__ ((packed));

struct zfcp_dbf_hba_record_qdio {
	u32 qdio_error;
	u8 sbal_index;
	u8 sbal_count;
} __attribute__ ((packed));

struct zfcp_dbf_hba_record {
	u8 tag[ZFCP_DBF_TAG_SIZE];
	u8 tag2[ZFCP_DBF_TAG_SIZE];
	union {
		struct zfcp_dbf_hba_record_response response;
		struct zfcp_dbf_hba_record_status status;
		struct zfcp_dbf_hba_record_qdio qdio;
		struct fsf_bit_error_payload berr;
	} u;
} __attribute__ ((packed));

struct zfcp_dbf_san_record_ct_request {
	u16 cmd_req_code;
	u8 revision;
	u8 gs_type;
	u8 gs_subtype;
	u8 options;
	u16 max_res_size;
	u32 len;
	u32 d_id;
} __attribute__ ((packed));

struct zfcp_dbf_san_record_ct_response {
	u16 cmd_rsp_code;
	u8 revision;
	u8 reason_code;
	u8 expl;
	u8 vendor_unique;
	u16 max_res_size;
	u32 len;
} __attribute__ ((packed));

struct zfcp_dbf_san_record_els {
	u32 d_id;
} __attribute__ ((packed));

struct zfcp_dbf_san_record {
	u8 tag[ZFCP_DBF_TAG_SIZE];
	u64 fsf_reqid;
	u32 fsf_seqno;
	union {
		struct zfcp_dbf_san_record_ct_request ct_req;
		struct zfcp_dbf_san_record_ct_response ct_resp;
		struct zfcp_dbf_san_record_els els;
	} u;
} __attribute__ ((packed));

#define ZFCP_DBF_SAN_MAX_PAYLOAD 1024

struct zfcp_dbf_scsi_record {
	u8 tag[ZFCP_DBF_TAG_SIZE];
	u8 tag2[ZFCP_DBF_TAG_SIZE];
	u32 scsi_id;
	u32 scsi_lun;
	u32 scsi_result;
	u64 scsi_cmnd;
#define ZFCP_DBF_SCSI_OPCODE	16
	u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE];
	u8 scsi_retries;
	u8 scsi_allowed;
	u64 fsf_reqid;
	u32 fsf_seqno;
	u64 fsf_issued;
	u64 old_fsf_reqid;
	u8 rsp_validity;
	u8 rsp_scsi_status;
	u32 rsp_resid;
	u8 rsp_code;
#define ZFCP_DBF_SCSI_FCP_SNS_INFO	16
#define ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO	256
	u32 sns_info_len;
	u8 sns_info[ZFCP_DBF_SCSI_FCP_SNS_INFO];
} __attribute__ ((packed));

struct zfcp_dbf {
	debug_info_t			*rec;
	debug_info_t			*hba;
	debug_info_t			*san;
	debug_info_t			*scsi;
	spinlock_t			rec_lock;
	spinlock_t			hba_lock;
	spinlock_t			san_lock;
	spinlock_t			scsi_lock;
	struct zfcp_dbf_rec_record	rec_buf;
	struct zfcp_dbf_hba_record	hba_buf;
	struct zfcp_dbf_san_record	san_buf;
	struct zfcp_dbf_scsi_record	scsi_buf;
	struct zfcp_adapter		*adapter;
};

static inline
void zfcp_dbf_hba_fsf_resp(const char *tag2, int level,
			   struct zfcp_fsf_req *req, struct zfcp_dbf *dbf)
{
	if (level <= dbf->hba->level)
		_zfcp_dbf_hba_fsf_response(tag2, level, req, dbf);
}

/**
 * zfcp_dbf_hba_fsf_response - trace event for request completion
 * @fsf_req: request that has been completed
 */
static inline void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req)
{
	struct zfcp_dbf *dbf = req->adapter->dbf;
	struct fsf_qtcb *qtcb = req->qtcb;

	if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
	    (qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) {
		zfcp_dbf_hba_fsf_resp("perr", 1, req, dbf);

	} else if (qtcb->header.fsf_status != FSF_GOOD) {
		zfcp_dbf_hba_fsf_resp("ferr", 1, req, dbf);

	} else if ((req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) ||
		   (req->fsf_command == FSF_QTCB_OPEN_LUN)) {
		zfcp_dbf_hba_fsf_resp("open", 4, req, dbf);

	} else if (qtcb->header.log_length) {
		zfcp_dbf_hba_fsf_resp("qtcb", 5, req, dbf);

	} else {
		zfcp_dbf_hba_fsf_resp("norm", 6, req, dbf);
	}
 }

/**
 * zfcp_dbf_hba_fsf_unsol - trace event for an unsolicited status buffer
 * @tag: tag indicating which kind of unsolicited status has been received
 * @dbf: reference to dbf structure
 * @status_buffer: buffer containing payload of unsolicited status
 */
static inline
void zfcp_dbf_hba_fsf_unsol(const char *tag, struct zfcp_dbf *dbf,
			    struct fsf_status_read_buffer *buf)
{
	int level = 2;

	if (level <= dbf->hba->level)
		_zfcp_dbf_hba_fsf_unsol(tag, level, dbf, buf);
}

static inline
void zfcp_dbf_scsi(const char *tag, const char *tag2, int level,
		   struct zfcp_dbf *dbf, struct scsi_cmnd *scmd,
		   struct zfcp_fsf_req *req, unsigned long old_id)
{
	if (level <= dbf->scsi->level)
		_zfcp_dbf_scsi(tag, tag2, level, dbf, scmd, req, old_id);
}

/**
 * zfcp_dbf_scsi_result - trace event for SCSI command completion
 * @dbf: adapter dbf trace
 * @scmd: SCSI command pointer
 * @req: FSF request used to issue SCSI command
 */
static inline
void zfcp_dbf_scsi_result(struct zfcp_dbf *dbf, struct scsi_cmnd *scmd,
			  struct zfcp_fsf_req *req)
{
	if (scmd->result != 0)
		zfcp_dbf_scsi("rslt", "erro", 3, dbf, scmd, req, 0);
	else if (scmd->retries > 0)
		zfcp_dbf_scsi("rslt", "retr", 4, dbf, scmd, req, 0);
	else
		zfcp_dbf_scsi("rslt", "norm", 6, dbf, scmd, req, 0);
}

/**
 * zfcp_dbf_scsi_fail_send - trace event for failure to send SCSI command
 * @dbf: adapter dbf trace
 * @scmd: SCSI command pointer
 */
static inline
void zfcp_dbf_scsi_fail_send(struct zfcp_dbf *dbf, struct scsi_cmnd *scmd)
{
	zfcp_dbf_scsi("rslt", "fail", 4, dbf, scmd, NULL, 0);
}

/**
 * zfcp_dbf_scsi_abort - trace event for SCSI command abort
 * @tag: tag indicating success or failure of abort operation
 * @adapter: adapter thas has been used to issue SCSI command to be aborted
 * @scmd: SCSI command to be aborted
 * @new_req: request containing abort (might be NULL)
 * @old_id: identifier of request containg SCSI command to be aborted
 */
static inline
void zfcp_dbf_scsi_abort(const char *tag, struct zfcp_dbf *dbf,
			 struct scsi_cmnd *scmd, struct zfcp_fsf_req *new_req,
			 unsigned long old_id)
{
	zfcp_dbf_scsi("abrt", tag, 1, dbf, scmd, new_req, old_id);
}

/**
 * zfcp_dbf_scsi_devreset - trace event for Logical Unit or Target Reset
 * @tag: tag indicating success or failure of reset operation
 * @scmnd: SCSI command which caused this error recovery
 * @flag: indicates type of reset (Target Reset, Logical Unit Reset)
 */
static inline
void zfcp_dbf_scsi_devreset(const char *tag, struct scsi_cmnd *scmnd, u8 flag)
{
	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scmnd->device);

	zfcp_dbf_scsi(flag == FCP_TMF_TGT_RESET ? "trst" : "lrst", tag, 1,
		      zfcp_sdev->port->adapter->dbf, scmnd, NULL, 0);
}

#endif /* ZFCP_DBF_H */