1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (C) 2014 SUSE Linux Products GmbH
6 * Copyright (C) 2014 Hannes Reinecke <hare@suse.de>
9 #include <linux/kernel.h>
10 #include <linux/atomic.h>
12 #include <scsi/scsi.h>
13 #include <scsi/scsi_cmnd.h>
14 #include <scsi/scsi_device.h>
15 #include <scsi/scsi_eh.h>
16 #include <scsi/scsi_dbg.h>
18 #define SCSI_LOG_SPOOLSIZE 4096
20 #if (SCSI_LOG_SPOOLSIZE / SCSI_LOG_BUFSIZE) > BITS_PER_LONG
21 #warning SCSI logging bitmask too large
25 char buffer
[SCSI_LOG_SPOOLSIZE
];
29 static DEFINE_PER_CPU(struct scsi_log_buf
, scsi_format_log
);
31 static char *scsi_log_reserve_buffer(size_t *len
)
33 struct scsi_log_buf
*buf
;
34 unsigned long map_bits
= sizeof(buf
->buffer
) / SCSI_LOG_BUFSIZE
;
35 unsigned long idx
= 0;
38 buf
= this_cpu_ptr(&scsi_format_log
);
39 idx
= find_first_zero_bit(&buf
->map
, map_bits
);
40 if (likely(idx
< map_bits
)) {
41 while (test_and_set_bit(idx
, &buf
->map
)) {
42 idx
= find_next_zero_bit(&buf
->map
, map_bits
, idx
);
47 if (WARN_ON(idx
>= map_bits
)) {
51 *len
= SCSI_LOG_BUFSIZE
;
52 return buf
->buffer
+ idx
* SCSI_LOG_BUFSIZE
;
55 static void scsi_log_release_buffer(char *bufptr
)
57 struct scsi_log_buf
*buf
;
61 buf
= this_cpu_ptr(&scsi_format_log
);
62 if (bufptr
>= buf
->buffer
&&
63 bufptr
< buf
->buffer
+ SCSI_LOG_SPOOLSIZE
) {
64 idx
= (bufptr
- buf
->buffer
) / SCSI_LOG_BUFSIZE
;
65 ret
= test_and_clear_bit(idx
, &buf
->map
);
71 static inline const char *scmd_name(const struct scsi_cmnd
*scmd
)
73 return scmd
->request
->rq_disk
?
74 scmd
->request
->rq_disk
->disk_name
: NULL
;
77 static size_t sdev_format_header(char *logbuf
, size_t logbuf_len
,
78 const char *name
, int tag
)
83 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
,
86 if (WARN_ON(off
>= logbuf_len
))
90 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
,
95 void sdev_prefix_printk(const char *level
, const struct scsi_device
*sdev
,
96 const char *name
, const char *fmt
, ...)
100 size_t off
= 0, logbuf_len
;
105 logbuf
= scsi_log_reserve_buffer(&logbuf_len
);
110 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
,
112 if (!WARN_ON(off
>= logbuf_len
)) {
114 off
+= vscnprintf(logbuf
+ off
, logbuf_len
- off
, fmt
, args
);
117 dev_printk(level
, &sdev
->sdev_gendev
, "%s", logbuf
);
118 scsi_log_release_buffer(logbuf
);
120 EXPORT_SYMBOL(sdev_prefix_printk
);
122 void scmd_printk(const char *level
, const struct scsi_cmnd
*scmd
,
123 const char *fmt
, ...)
127 size_t off
= 0, logbuf_len
;
129 if (!scmd
|| !scmd
->cmnd
)
132 logbuf
= scsi_log_reserve_buffer(&logbuf_len
);
135 off
= sdev_format_header(logbuf
, logbuf_len
, scmd_name(scmd
),
137 if (off
< logbuf_len
) {
139 off
+= vscnprintf(logbuf
+ off
, logbuf_len
- off
, fmt
, args
);
142 dev_printk(level
, &scmd
->device
->sdev_gendev
, "%s", logbuf
);
143 scsi_log_release_buffer(logbuf
);
145 EXPORT_SYMBOL(scmd_printk
);
147 static size_t scsi_format_opcode_name(char *buffer
, size_t buf_len
,
148 const unsigned char *cdbp
)
151 const char *cdb_name
= NULL
, *sa_name
= NULL
;
155 if (cdb0
== VARIABLE_LENGTH_CMD
) {
156 int len
= scsi_varlen_cdb_length(cdbp
);
159 off
= scnprintf(buffer
, buf_len
,
160 "short variable length command, len=%d",
164 sa
= (cdbp
[8] << 8) + cdbp
[9];
168 if (!scsi_opcode_sa_name(cdb0
, sa
, &cdb_name
, &sa_name
)) {
170 off
= scnprintf(buffer
, buf_len
, "%s", cdb_name
);
172 off
= scnprintf(buffer
, buf_len
, "opcode=0x%x", cdb0
);
173 if (WARN_ON(off
>= buf_len
))
175 if (cdb0
>= VENDOR_SPECIFIC_CDB
)
176 off
+= scnprintf(buffer
+ off
, buf_len
- off
,
178 else if (cdb0
>= 0x60 && cdb0
< 0x7e)
179 off
+= scnprintf(buffer
+ off
, buf_len
- off
,
184 off
= scnprintf(buffer
, buf_len
, "%s", sa_name
);
186 off
= scnprintf(buffer
, buf_len
, "%s, sa=0x%x",
189 off
= scnprintf(buffer
, buf_len
,
190 "opcode=0x%x, sa=0x%x", cdb0
, sa
);
192 WARN_ON(off
>= buf_len
);
196 size_t __scsi_format_command(char *logbuf
, size_t logbuf_len
,
197 const unsigned char *cdb
, size_t cdb_len
)
202 off
= scsi_format_opcode_name(logbuf
, logbuf_len
, cdb
);
203 if (off
>= logbuf_len
)
205 len
= scsi_command_size(cdb
);
208 /* print out all bytes in cdb */
209 for (k
= 0; k
< len
; ++k
) {
210 if (off
> logbuf_len
- 3)
212 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
,
217 EXPORT_SYMBOL(__scsi_format_command
);
219 void scsi_print_command(struct scsi_cmnd
*cmd
)
223 size_t off
, logbuf_len
;
228 logbuf
= scsi_log_reserve_buffer(&logbuf_len
);
232 off
= sdev_format_header(logbuf
, logbuf_len
,
233 scmd_name(cmd
), cmd
->request
->tag
);
234 if (off
>= logbuf_len
)
236 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
, "CDB: ");
237 if (WARN_ON(off
>= logbuf_len
))
240 off
+= scsi_format_opcode_name(logbuf
+ off
, logbuf_len
- off
,
242 if (off
>= logbuf_len
)
245 /* print out all bytes in cdb */
246 if (cmd
->cmd_len
> 16) {
247 /* Print opcode in one line and use separate lines for CDB */
248 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
, "\n");
249 dev_printk(KERN_INFO
, &cmd
->device
->sdev_gendev
, "%s", logbuf
);
250 scsi_log_release_buffer(logbuf
);
251 for (k
= 0; k
< cmd
->cmd_len
; k
+= 16) {
252 size_t linelen
= min(cmd
->cmd_len
- k
, 16);
254 logbuf
= scsi_log_reserve_buffer(&logbuf_len
);
257 off
= sdev_format_header(logbuf
, logbuf_len
,
260 if (!WARN_ON(off
> logbuf_len
- 58)) {
261 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
,
263 hex_dump_to_buffer(&cmd
->cmnd
[k
], linelen
,
265 logbuf_len
- off
, false);
267 dev_printk(KERN_INFO
, &cmd
->device
->sdev_gendev
, "%s",
269 scsi_log_release_buffer(logbuf
);
273 if (!WARN_ON(off
> logbuf_len
- 49)) {
274 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
, " ");
275 hex_dump_to_buffer(cmd
->cmnd
, cmd
->cmd_len
, 16, 1,
276 logbuf
+ off
, logbuf_len
- off
,
280 dev_printk(KERN_INFO
, &cmd
->device
->sdev_gendev
, "%s", logbuf
);
281 scsi_log_release_buffer(logbuf
);
283 EXPORT_SYMBOL(scsi_print_command
);
286 scsi_format_extd_sense(char *buffer
, size_t buf_len
,
287 unsigned char asc
, unsigned char ascq
)
290 const char *extd_sense_fmt
= NULL
;
291 const char *extd_sense_str
= scsi_extd_sense_format(asc
, ascq
,
294 if (extd_sense_str
) {
295 off
= scnprintf(buffer
, buf_len
, "Add. Sense: %s",
298 off
+= scnprintf(buffer
+ off
, buf_len
- off
,
299 "(%s%x)", extd_sense_fmt
, ascq
);
302 off
= scnprintf(buffer
, buf_len
, "<<vendor>>");
303 off
+= scnprintf(buffer
+ off
, buf_len
- off
,
306 off
+= scnprintf(buffer
+ off
, buf_len
- off
,
308 off
+= scnprintf(buffer
+ off
, buf_len
- off
,
315 scsi_format_sense_hdr(char *buffer
, size_t buf_len
,
316 const struct scsi_sense_hdr
*sshdr
)
318 const char *sense_txt
;
321 off
= scnprintf(buffer
, buf_len
, "Sense Key : ");
322 sense_txt
= scsi_sense_key_string(sshdr
->sense_key
);
324 off
+= scnprintf(buffer
+ off
, buf_len
- off
,
327 off
+= scnprintf(buffer
+ off
, buf_len
- off
,
328 "0x%x ", sshdr
->sense_key
);
329 off
+= scnprintf(buffer
+ off
, buf_len
- off
,
330 scsi_sense_is_deferred(sshdr
) ? "[deferred] " : "[current] ");
332 if (sshdr
->response_code
>= 0x72)
333 off
+= scnprintf(buffer
+ off
, buf_len
- off
, "[descriptor] ");
338 scsi_log_dump_sense(const struct scsi_device
*sdev
, const char *name
, int tag
,
339 const unsigned char *sense_buffer
, int sense_len
)
345 logbuf
= scsi_log_reserve_buffer(&logbuf_len
);
349 for (i
= 0; i
< sense_len
; i
+= 16) {
350 int len
= min(sense_len
- i
, 16);
353 off
= sdev_format_header(logbuf
, logbuf_len
,
355 hex_dump_to_buffer(&sense_buffer
[i
], len
, 16, 1,
356 logbuf
+ off
, logbuf_len
- off
,
358 dev_printk(KERN_INFO
, &sdev
->sdev_gendev
, "%s", logbuf
);
360 scsi_log_release_buffer(logbuf
);
364 scsi_log_print_sense_hdr(const struct scsi_device
*sdev
, const char *name
,
365 int tag
, const struct scsi_sense_hdr
*sshdr
)
368 size_t off
, logbuf_len
;
370 logbuf
= scsi_log_reserve_buffer(&logbuf_len
);
373 off
= sdev_format_header(logbuf
, logbuf_len
, name
, tag
);
374 off
+= scsi_format_sense_hdr(logbuf
+ off
, logbuf_len
- off
, sshdr
);
375 dev_printk(KERN_INFO
, &sdev
->sdev_gendev
, "%s", logbuf
);
376 scsi_log_release_buffer(logbuf
);
378 logbuf
= scsi_log_reserve_buffer(&logbuf_len
);
381 off
= sdev_format_header(logbuf
, logbuf_len
, name
, tag
);
382 off
+= scsi_format_extd_sense(logbuf
+ off
, logbuf_len
- off
,
383 sshdr
->asc
, sshdr
->ascq
);
384 dev_printk(KERN_INFO
, &sdev
->sdev_gendev
, "%s", logbuf
);
385 scsi_log_release_buffer(logbuf
);
389 scsi_log_print_sense(const struct scsi_device
*sdev
, const char *name
, int tag
,
390 const unsigned char *sense_buffer
, int sense_len
)
392 struct scsi_sense_hdr sshdr
;
394 if (scsi_normalize_sense(sense_buffer
, sense_len
, &sshdr
))
395 scsi_log_print_sense_hdr(sdev
, name
, tag
, &sshdr
);
397 scsi_log_dump_sense(sdev
, name
, tag
, sense_buffer
, sense_len
);
401 * Print normalized SCSI sense header with a prefix.
404 scsi_print_sense_hdr(const struct scsi_device
*sdev
, const char *name
,
405 const struct scsi_sense_hdr
*sshdr
)
407 scsi_log_print_sense_hdr(sdev
, name
, -1, sshdr
);
409 EXPORT_SYMBOL(scsi_print_sense_hdr
);
411 /* Normalize and print sense buffer with name prefix */
412 void __scsi_print_sense(const struct scsi_device
*sdev
, const char *name
,
413 const unsigned char *sense_buffer
, int sense_len
)
415 scsi_log_print_sense(sdev
, name
, -1, sense_buffer
, sense_len
);
417 EXPORT_SYMBOL(__scsi_print_sense
);
419 /* Normalize and print sense buffer in SCSI command */
420 void scsi_print_sense(const struct scsi_cmnd
*cmd
)
422 scsi_log_print_sense(cmd
->device
, scmd_name(cmd
), cmd
->request
->tag
,
423 cmd
->sense_buffer
, SCSI_SENSE_BUFFERSIZE
);
425 EXPORT_SYMBOL(scsi_print_sense
);
427 void scsi_print_result(const struct scsi_cmnd
*cmd
, const char *msg
,
431 size_t off
, logbuf_len
;
432 const char *mlret_string
= scsi_mlreturn_string(disposition
);
433 const char *hb_string
= scsi_hostbyte_string(cmd
->result
);
434 const char *db_string
= scsi_driverbyte_string(cmd
->result
);
436 logbuf
= scsi_log_reserve_buffer(&logbuf_len
);
440 off
= sdev_format_header(logbuf
, logbuf_len
,
441 scmd_name(cmd
), cmd
->request
->tag
);
443 if (off
>= logbuf_len
)
447 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
,
449 if (WARN_ON(off
>= logbuf_len
))
453 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
,
454 "%s ", mlret_string
);
456 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
,
457 "UNKNOWN(0x%02x) ", disposition
);
458 if (WARN_ON(off
>= logbuf_len
))
461 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
, "Result: ");
462 if (WARN_ON(off
>= logbuf_len
))
466 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
,
467 "hostbyte=%s ", hb_string
);
469 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
,
470 "hostbyte=0x%02x ", host_byte(cmd
->result
));
471 if (WARN_ON(off
>= logbuf_len
))
475 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
,
476 "driverbyte=%s", db_string
);
478 off
+= scnprintf(logbuf
+ off
, logbuf_len
- off
,
479 "driverbyte=0x%02x", driver_byte(cmd
->result
));
481 dev_printk(KERN_INFO
, &cmd
->device
->sdev_gendev
, "%s", logbuf
);
482 scsi_log_release_buffer(logbuf
);
484 EXPORT_SYMBOL(scsi_print_result
);