18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * scsi_logging.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014 SUSE Linux Products GmbH
68c2ecf20Sopenharmony_ci * Copyright (C) 2014 Hannes Reinecke <hare@suse.de>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/atomic.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
138c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
148c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
158c2ecf20Sopenharmony_ci#include <scsi/scsi_eh.h>
168c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic char *scsi_log_reserve_buffer(size_t *len)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	*len = 128;
218c2ecf20Sopenharmony_ci	return kmalloc(*len, GFP_ATOMIC);
228c2ecf20Sopenharmony_ci}
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic void scsi_log_release_buffer(char *bufptr)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	kfree(bufptr);
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic inline const char *scmd_name(const struct scsi_cmnd *scmd)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	return scmd->request->rq_disk ?
328c2ecf20Sopenharmony_ci		scmd->request->rq_disk->disk_name : NULL;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic size_t sdev_format_header(char *logbuf, size_t logbuf_len,
368c2ecf20Sopenharmony_ci				 const char *name, int tag)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	size_t off = 0;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (name)
418c2ecf20Sopenharmony_ci		off += scnprintf(logbuf + off, logbuf_len - off,
428c2ecf20Sopenharmony_ci				 "[%s] ", name);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (WARN_ON(off >= logbuf_len))
458c2ecf20Sopenharmony_ci		return off;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (tag >= 0)
488c2ecf20Sopenharmony_ci		off += scnprintf(logbuf + off, logbuf_len - off,
498c2ecf20Sopenharmony_ci				 "tag#%d ", tag);
508c2ecf20Sopenharmony_ci	return off;
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_civoid sdev_prefix_printk(const char *level, const struct scsi_device *sdev,
548c2ecf20Sopenharmony_ci			const char *name, const char *fmt, ...)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	va_list args;
578c2ecf20Sopenharmony_ci	char *logbuf;
588c2ecf20Sopenharmony_ci	size_t off = 0, logbuf_len;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (!sdev)
618c2ecf20Sopenharmony_ci		return;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	logbuf = scsi_log_reserve_buffer(&logbuf_len);
648c2ecf20Sopenharmony_ci	if (!logbuf)
658c2ecf20Sopenharmony_ci		return;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (name)
688c2ecf20Sopenharmony_ci		off += scnprintf(logbuf + off, logbuf_len - off,
698c2ecf20Sopenharmony_ci				 "[%s] ", name);
708c2ecf20Sopenharmony_ci	if (!WARN_ON(off >= logbuf_len)) {
718c2ecf20Sopenharmony_ci		va_start(args, fmt);
728c2ecf20Sopenharmony_ci		off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args);
738c2ecf20Sopenharmony_ci		va_end(args);
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci	dev_printk(level, &sdev->sdev_gendev, "%s", logbuf);
768c2ecf20Sopenharmony_ci	scsi_log_release_buffer(logbuf);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sdev_prefix_printk);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_civoid scmd_printk(const char *level, const struct scsi_cmnd *scmd,
818c2ecf20Sopenharmony_ci		const char *fmt, ...)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	va_list args;
848c2ecf20Sopenharmony_ci	char *logbuf;
858c2ecf20Sopenharmony_ci	size_t off = 0, logbuf_len;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	if (!scmd || !scmd->cmnd)
888c2ecf20Sopenharmony_ci		return;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	logbuf = scsi_log_reserve_buffer(&logbuf_len);
918c2ecf20Sopenharmony_ci	if (!logbuf)
928c2ecf20Sopenharmony_ci		return;
938c2ecf20Sopenharmony_ci	off = sdev_format_header(logbuf, logbuf_len, scmd_name(scmd),
948c2ecf20Sopenharmony_ci				 scmd->request->tag);
958c2ecf20Sopenharmony_ci	if (off < logbuf_len) {
968c2ecf20Sopenharmony_ci		va_start(args, fmt);
978c2ecf20Sopenharmony_ci		off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args);
988c2ecf20Sopenharmony_ci		va_end(args);
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci	dev_printk(level, &scmd->device->sdev_gendev, "%s", logbuf);
1018c2ecf20Sopenharmony_ci	scsi_log_release_buffer(logbuf);
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scmd_printk);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic size_t scsi_format_opcode_name(char *buffer, size_t buf_len,
1068c2ecf20Sopenharmony_ci				      const unsigned char *cdbp)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	int sa, cdb0;
1098c2ecf20Sopenharmony_ci	const char *cdb_name = NULL, *sa_name = NULL;
1108c2ecf20Sopenharmony_ci	size_t off;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	cdb0 = cdbp[0];
1138c2ecf20Sopenharmony_ci	if (cdb0 == VARIABLE_LENGTH_CMD) {
1148c2ecf20Sopenharmony_ci		int len = scsi_varlen_cdb_length(cdbp);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci		if (len < 10) {
1178c2ecf20Sopenharmony_ci			off = scnprintf(buffer, buf_len,
1188c2ecf20Sopenharmony_ci					"short variable length command, len=%d",
1198c2ecf20Sopenharmony_ci					len);
1208c2ecf20Sopenharmony_ci			return off;
1218c2ecf20Sopenharmony_ci		}
1228c2ecf20Sopenharmony_ci		sa = (cdbp[8] << 8) + cdbp[9];
1238c2ecf20Sopenharmony_ci	} else
1248c2ecf20Sopenharmony_ci		sa = cdbp[1] & 0x1f;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if (!scsi_opcode_sa_name(cdb0, sa, &cdb_name, &sa_name)) {
1278c2ecf20Sopenharmony_ci		if (cdb_name)
1288c2ecf20Sopenharmony_ci			off = scnprintf(buffer, buf_len, "%s", cdb_name);
1298c2ecf20Sopenharmony_ci		else {
1308c2ecf20Sopenharmony_ci			off = scnprintf(buffer, buf_len, "opcode=0x%x", cdb0);
1318c2ecf20Sopenharmony_ci			if (WARN_ON(off >= buf_len))
1328c2ecf20Sopenharmony_ci				return off;
1338c2ecf20Sopenharmony_ci			if (cdb0 >= VENDOR_SPECIFIC_CDB)
1348c2ecf20Sopenharmony_ci				off += scnprintf(buffer + off, buf_len - off,
1358c2ecf20Sopenharmony_ci						 " (vendor)");
1368c2ecf20Sopenharmony_ci			else if (cdb0 >= 0x60 && cdb0 < 0x7e)
1378c2ecf20Sopenharmony_ci				off += scnprintf(buffer + off, buf_len - off,
1388c2ecf20Sopenharmony_ci						 " (reserved)");
1398c2ecf20Sopenharmony_ci		}
1408c2ecf20Sopenharmony_ci	} else {
1418c2ecf20Sopenharmony_ci		if (sa_name)
1428c2ecf20Sopenharmony_ci			off = scnprintf(buffer, buf_len, "%s", sa_name);
1438c2ecf20Sopenharmony_ci		else if (cdb_name)
1448c2ecf20Sopenharmony_ci			off = scnprintf(buffer, buf_len, "%s, sa=0x%x",
1458c2ecf20Sopenharmony_ci					cdb_name, sa);
1468c2ecf20Sopenharmony_ci		else
1478c2ecf20Sopenharmony_ci			off = scnprintf(buffer, buf_len,
1488c2ecf20Sopenharmony_ci					"opcode=0x%x, sa=0x%x", cdb0, sa);
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci	WARN_ON(off >= buf_len);
1518c2ecf20Sopenharmony_ci	return off;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cisize_t __scsi_format_command(char *logbuf, size_t logbuf_len,
1558c2ecf20Sopenharmony_ci			     const unsigned char *cdb, size_t cdb_len)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	int len, k;
1588c2ecf20Sopenharmony_ci	size_t off;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	off = scsi_format_opcode_name(logbuf, logbuf_len, cdb);
1618c2ecf20Sopenharmony_ci	if (off >= logbuf_len)
1628c2ecf20Sopenharmony_ci		return off;
1638c2ecf20Sopenharmony_ci	len = scsi_command_size(cdb);
1648c2ecf20Sopenharmony_ci	if (cdb_len < len)
1658c2ecf20Sopenharmony_ci		len = cdb_len;
1668c2ecf20Sopenharmony_ci	/* print out all bytes in cdb */
1678c2ecf20Sopenharmony_ci	for (k = 0; k < len; ++k) {
1688c2ecf20Sopenharmony_ci		if (off > logbuf_len - 3)
1698c2ecf20Sopenharmony_ci			break;
1708c2ecf20Sopenharmony_ci		off += scnprintf(logbuf + off, logbuf_len - off,
1718c2ecf20Sopenharmony_ci				 " %02x", cdb[k]);
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci	return off;
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__scsi_format_command);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_civoid scsi_print_command(struct scsi_cmnd *cmd)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	int k;
1808c2ecf20Sopenharmony_ci	char *logbuf;
1818c2ecf20Sopenharmony_ci	size_t off, logbuf_len;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	if (!cmd->cmnd)
1848c2ecf20Sopenharmony_ci		return;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	logbuf = scsi_log_reserve_buffer(&logbuf_len);
1878c2ecf20Sopenharmony_ci	if (!logbuf)
1888c2ecf20Sopenharmony_ci		return;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	off = sdev_format_header(logbuf, logbuf_len,
1918c2ecf20Sopenharmony_ci				 scmd_name(cmd), cmd->request->tag);
1928c2ecf20Sopenharmony_ci	if (off >= logbuf_len)
1938c2ecf20Sopenharmony_ci		goto out_printk;
1948c2ecf20Sopenharmony_ci	off += scnprintf(logbuf + off, logbuf_len - off, "CDB: ");
1958c2ecf20Sopenharmony_ci	if (WARN_ON(off >= logbuf_len))
1968c2ecf20Sopenharmony_ci		goto out_printk;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	off += scsi_format_opcode_name(logbuf + off, logbuf_len - off,
1998c2ecf20Sopenharmony_ci				       cmd->cmnd);
2008c2ecf20Sopenharmony_ci	if (off >= logbuf_len)
2018c2ecf20Sopenharmony_ci		goto out_printk;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/* print out all bytes in cdb */
2048c2ecf20Sopenharmony_ci	if (cmd->cmd_len > 16) {
2058c2ecf20Sopenharmony_ci		/* Print opcode in one line and use separate lines for CDB */
2068c2ecf20Sopenharmony_ci		off += scnprintf(logbuf + off, logbuf_len - off, "\n");
2078c2ecf20Sopenharmony_ci		dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
2088c2ecf20Sopenharmony_ci		for (k = 0; k < cmd->cmd_len; k += 16) {
2098c2ecf20Sopenharmony_ci			size_t linelen = min(cmd->cmd_len - k, 16);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci			off = sdev_format_header(logbuf, logbuf_len,
2128c2ecf20Sopenharmony_ci						 scmd_name(cmd),
2138c2ecf20Sopenharmony_ci						 cmd->request->tag);
2148c2ecf20Sopenharmony_ci			if (!WARN_ON(off > logbuf_len - 58)) {
2158c2ecf20Sopenharmony_ci				off += scnprintf(logbuf + off, logbuf_len - off,
2168c2ecf20Sopenharmony_ci						 "CDB[%02x]: ", k);
2178c2ecf20Sopenharmony_ci				hex_dump_to_buffer(&cmd->cmnd[k], linelen,
2188c2ecf20Sopenharmony_ci						   16, 1, logbuf + off,
2198c2ecf20Sopenharmony_ci						   logbuf_len - off, false);
2208c2ecf20Sopenharmony_ci			}
2218c2ecf20Sopenharmony_ci			dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s",
2228c2ecf20Sopenharmony_ci				   logbuf);
2238c2ecf20Sopenharmony_ci		}
2248c2ecf20Sopenharmony_ci		goto out;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci	if (!WARN_ON(off > logbuf_len - 49)) {
2278c2ecf20Sopenharmony_ci		off += scnprintf(logbuf + off, logbuf_len - off, " ");
2288c2ecf20Sopenharmony_ci		hex_dump_to_buffer(cmd->cmnd, cmd->cmd_len, 16, 1,
2298c2ecf20Sopenharmony_ci				   logbuf + off, logbuf_len - off,
2308c2ecf20Sopenharmony_ci				   false);
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ciout_printk:
2338c2ecf20Sopenharmony_ci	dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
2348c2ecf20Sopenharmony_ciout:
2358c2ecf20Sopenharmony_ci	scsi_log_release_buffer(logbuf);
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_print_command);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic size_t
2408c2ecf20Sopenharmony_ciscsi_format_extd_sense(char *buffer, size_t buf_len,
2418c2ecf20Sopenharmony_ci		       unsigned char asc, unsigned char ascq)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	size_t off = 0;
2448c2ecf20Sopenharmony_ci	const char *extd_sense_fmt = NULL;
2458c2ecf20Sopenharmony_ci	const char *extd_sense_str = scsi_extd_sense_format(asc, ascq,
2468c2ecf20Sopenharmony_ci							    &extd_sense_fmt);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (extd_sense_str) {
2498c2ecf20Sopenharmony_ci		off = scnprintf(buffer, buf_len, "Add. Sense: %s",
2508c2ecf20Sopenharmony_ci				extd_sense_str);
2518c2ecf20Sopenharmony_ci		if (extd_sense_fmt)
2528c2ecf20Sopenharmony_ci			off += scnprintf(buffer + off, buf_len - off,
2538c2ecf20Sopenharmony_ci					 "(%s%x)", extd_sense_fmt, ascq);
2548c2ecf20Sopenharmony_ci	} else {
2558c2ecf20Sopenharmony_ci		if (asc >= 0x80)
2568c2ecf20Sopenharmony_ci			off = scnprintf(buffer, buf_len, "<<vendor>>");
2578c2ecf20Sopenharmony_ci		off += scnprintf(buffer + off, buf_len - off,
2588c2ecf20Sopenharmony_ci				 "ASC=0x%x ", asc);
2598c2ecf20Sopenharmony_ci		if (ascq >= 0x80)
2608c2ecf20Sopenharmony_ci			off += scnprintf(buffer + off, buf_len - off,
2618c2ecf20Sopenharmony_ci					 "<<vendor>>");
2628c2ecf20Sopenharmony_ci		off += scnprintf(buffer + off, buf_len - off,
2638c2ecf20Sopenharmony_ci				 "ASCQ=0x%x ", ascq);
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci	return off;
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic size_t
2698c2ecf20Sopenharmony_ciscsi_format_sense_hdr(char *buffer, size_t buf_len,
2708c2ecf20Sopenharmony_ci		      const struct scsi_sense_hdr *sshdr)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	const char *sense_txt;
2738c2ecf20Sopenharmony_ci	size_t off;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	off = scnprintf(buffer, buf_len, "Sense Key : ");
2768c2ecf20Sopenharmony_ci	sense_txt = scsi_sense_key_string(sshdr->sense_key);
2778c2ecf20Sopenharmony_ci	if (sense_txt)
2788c2ecf20Sopenharmony_ci		off += scnprintf(buffer + off, buf_len - off,
2798c2ecf20Sopenharmony_ci				 "%s ", sense_txt);
2808c2ecf20Sopenharmony_ci	else
2818c2ecf20Sopenharmony_ci		off += scnprintf(buffer + off, buf_len - off,
2828c2ecf20Sopenharmony_ci				 "0x%x ", sshdr->sense_key);
2838c2ecf20Sopenharmony_ci	off += scnprintf(buffer + off, buf_len - off,
2848c2ecf20Sopenharmony_ci		scsi_sense_is_deferred(sshdr) ? "[deferred] " : "[current] ");
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (sshdr->response_code >= 0x72)
2878c2ecf20Sopenharmony_ci		off += scnprintf(buffer + off, buf_len - off, "[descriptor] ");
2888c2ecf20Sopenharmony_ci	return off;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic void
2928c2ecf20Sopenharmony_ciscsi_log_dump_sense(const struct scsi_device *sdev, const char *name, int tag,
2938c2ecf20Sopenharmony_ci		    const unsigned char *sense_buffer, int sense_len)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	char *logbuf;
2968c2ecf20Sopenharmony_ci	size_t logbuf_len;
2978c2ecf20Sopenharmony_ci	int i;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	logbuf = scsi_log_reserve_buffer(&logbuf_len);
3008c2ecf20Sopenharmony_ci	if (!logbuf)
3018c2ecf20Sopenharmony_ci		return;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	for (i = 0; i < sense_len; i += 16) {
3048c2ecf20Sopenharmony_ci		int len = min(sense_len - i, 16);
3058c2ecf20Sopenharmony_ci		size_t off;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		off = sdev_format_header(logbuf, logbuf_len,
3088c2ecf20Sopenharmony_ci					 name, tag);
3098c2ecf20Sopenharmony_ci		hex_dump_to_buffer(&sense_buffer[i], len, 16, 1,
3108c2ecf20Sopenharmony_ci				   logbuf + off, logbuf_len - off,
3118c2ecf20Sopenharmony_ci				   false);
3128c2ecf20Sopenharmony_ci		dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf);
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci	scsi_log_release_buffer(logbuf);
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic void
3188c2ecf20Sopenharmony_ciscsi_log_print_sense_hdr(const struct scsi_device *sdev, const char *name,
3198c2ecf20Sopenharmony_ci			 int tag, const struct scsi_sense_hdr *sshdr)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	char *logbuf;
3228c2ecf20Sopenharmony_ci	size_t off, logbuf_len;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	logbuf = scsi_log_reserve_buffer(&logbuf_len);
3258c2ecf20Sopenharmony_ci	if (!logbuf)
3268c2ecf20Sopenharmony_ci		return;
3278c2ecf20Sopenharmony_ci	off = sdev_format_header(logbuf, logbuf_len, name, tag);
3288c2ecf20Sopenharmony_ci	off += scsi_format_sense_hdr(logbuf + off, logbuf_len - off, sshdr);
3298c2ecf20Sopenharmony_ci	dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf);
3308c2ecf20Sopenharmony_ci	scsi_log_release_buffer(logbuf);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	logbuf = scsi_log_reserve_buffer(&logbuf_len);
3338c2ecf20Sopenharmony_ci	if (!logbuf)
3348c2ecf20Sopenharmony_ci		return;
3358c2ecf20Sopenharmony_ci	off = sdev_format_header(logbuf, logbuf_len, name, tag);
3368c2ecf20Sopenharmony_ci	off += scsi_format_extd_sense(logbuf + off, logbuf_len - off,
3378c2ecf20Sopenharmony_ci				      sshdr->asc, sshdr->ascq);
3388c2ecf20Sopenharmony_ci	dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf);
3398c2ecf20Sopenharmony_ci	scsi_log_release_buffer(logbuf);
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic void
3438c2ecf20Sopenharmony_ciscsi_log_print_sense(const struct scsi_device *sdev, const char *name, int tag,
3448c2ecf20Sopenharmony_ci		     const unsigned char *sense_buffer, int sense_len)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct scsi_sense_hdr sshdr;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (scsi_normalize_sense(sense_buffer, sense_len, &sshdr))
3498c2ecf20Sopenharmony_ci		scsi_log_print_sense_hdr(sdev, name, tag, &sshdr);
3508c2ecf20Sopenharmony_ci	else
3518c2ecf20Sopenharmony_ci		scsi_log_dump_sense(sdev, name, tag, sense_buffer, sense_len);
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci/*
3558c2ecf20Sopenharmony_ci * Print normalized SCSI sense header with a prefix.
3568c2ecf20Sopenharmony_ci */
3578c2ecf20Sopenharmony_civoid
3588c2ecf20Sopenharmony_ciscsi_print_sense_hdr(const struct scsi_device *sdev, const char *name,
3598c2ecf20Sopenharmony_ci		     const struct scsi_sense_hdr *sshdr)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	scsi_log_print_sense_hdr(sdev, name, -1, sshdr);
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_print_sense_hdr);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci/* Normalize and print sense buffer with name prefix */
3668c2ecf20Sopenharmony_civoid __scsi_print_sense(const struct scsi_device *sdev, const char *name,
3678c2ecf20Sopenharmony_ci			const unsigned char *sense_buffer, int sense_len)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	scsi_log_print_sense(sdev, name, -1, sense_buffer, sense_len);
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__scsi_print_sense);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci/* Normalize and print sense buffer in SCSI command */
3748c2ecf20Sopenharmony_civoid scsi_print_sense(const struct scsi_cmnd *cmd)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	scsi_log_print_sense(cmd->device, scmd_name(cmd), cmd->request->tag,
3778c2ecf20Sopenharmony_ci			     cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_print_sense);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_civoid scsi_print_result(const struct scsi_cmnd *cmd, const char *msg,
3828c2ecf20Sopenharmony_ci		       int disposition)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	char *logbuf;
3858c2ecf20Sopenharmony_ci	size_t off, logbuf_len;
3868c2ecf20Sopenharmony_ci	const char *mlret_string = scsi_mlreturn_string(disposition);
3878c2ecf20Sopenharmony_ci	const char *hb_string = scsi_hostbyte_string(cmd->result);
3888c2ecf20Sopenharmony_ci	const char *db_string = scsi_driverbyte_string(cmd->result);
3898c2ecf20Sopenharmony_ci	unsigned long cmd_age = (jiffies - cmd->jiffies_at_alloc) / HZ;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	logbuf = scsi_log_reserve_buffer(&logbuf_len);
3928c2ecf20Sopenharmony_ci	if (!logbuf)
3938c2ecf20Sopenharmony_ci		return;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	off = sdev_format_header(logbuf, logbuf_len,
3968c2ecf20Sopenharmony_ci				 scmd_name(cmd), cmd->request->tag);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	if (off >= logbuf_len)
3998c2ecf20Sopenharmony_ci		goto out_printk;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (msg) {
4028c2ecf20Sopenharmony_ci		off += scnprintf(logbuf + off, logbuf_len - off,
4038c2ecf20Sopenharmony_ci				 "%s: ", msg);
4048c2ecf20Sopenharmony_ci		if (WARN_ON(off >= logbuf_len))
4058c2ecf20Sopenharmony_ci			goto out_printk;
4068c2ecf20Sopenharmony_ci	}
4078c2ecf20Sopenharmony_ci	if (mlret_string)
4088c2ecf20Sopenharmony_ci		off += scnprintf(logbuf + off, logbuf_len - off,
4098c2ecf20Sopenharmony_ci				 "%s ", mlret_string);
4108c2ecf20Sopenharmony_ci	else
4118c2ecf20Sopenharmony_ci		off += scnprintf(logbuf + off, logbuf_len - off,
4128c2ecf20Sopenharmony_ci				 "UNKNOWN(0x%02x) ", disposition);
4138c2ecf20Sopenharmony_ci	if (WARN_ON(off >= logbuf_len))
4148c2ecf20Sopenharmony_ci		goto out_printk;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	off += scnprintf(logbuf + off, logbuf_len - off, "Result: ");
4178c2ecf20Sopenharmony_ci	if (WARN_ON(off >= logbuf_len))
4188c2ecf20Sopenharmony_ci		goto out_printk;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (hb_string)
4218c2ecf20Sopenharmony_ci		off += scnprintf(logbuf + off, logbuf_len - off,
4228c2ecf20Sopenharmony_ci				 "hostbyte=%s ", hb_string);
4238c2ecf20Sopenharmony_ci	else
4248c2ecf20Sopenharmony_ci		off += scnprintf(logbuf + off, logbuf_len - off,
4258c2ecf20Sopenharmony_ci				 "hostbyte=0x%02x ", host_byte(cmd->result));
4268c2ecf20Sopenharmony_ci	if (WARN_ON(off >= logbuf_len))
4278c2ecf20Sopenharmony_ci		goto out_printk;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	if (db_string)
4308c2ecf20Sopenharmony_ci		off += scnprintf(logbuf + off, logbuf_len - off,
4318c2ecf20Sopenharmony_ci				 "driverbyte=%s ", db_string);
4328c2ecf20Sopenharmony_ci	else
4338c2ecf20Sopenharmony_ci		off += scnprintf(logbuf + off, logbuf_len - off,
4348c2ecf20Sopenharmony_ci				 "driverbyte=0x%02x ",
4358c2ecf20Sopenharmony_ci				 driver_byte(cmd->result));
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	off += scnprintf(logbuf + off, logbuf_len - off,
4388c2ecf20Sopenharmony_ci			 "cmd_age=%lus", cmd_age);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ciout_printk:
4418c2ecf20Sopenharmony_ci	dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
4428c2ecf20Sopenharmony_ci	scsi_log_release_buffer(logbuf);
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_print_result);
445