root/drivers/scsi/scsi_logging.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. scsi_log_reserve_buffer
  2. scsi_log_release_buffer
  3. scmd_name
  4. sdev_format_header
  5. sdev_prefix_printk
  6. scmd_printk
  7. scsi_format_opcode_name
  8. __scsi_format_command
  9. scsi_print_command
  10. scsi_format_extd_sense
  11. scsi_format_sense_hdr
  12. scsi_log_dump_sense
  13. scsi_log_print_sense_hdr
  14. scsi_log_print_sense
  15. scsi_print_sense_hdr
  16. __scsi_print_sense
  17. scsi_print_sense
  18. scsi_print_result

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * scsi_logging.c
   4  *
   5  * Copyright (C) 2014 SUSE Linux Products GmbH
   6  * Copyright (C) 2014 Hannes Reinecke <hare@suse.de>
   7  */
   8 
   9 #include <linux/kernel.h>
  10 #include <linux/atomic.h>
  11 
  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>
  17 
  18 static char *scsi_log_reserve_buffer(size_t *len)
  19 {
  20         *len = 128;
  21         return kmalloc(*len, GFP_ATOMIC);
  22 }
  23 
  24 static void scsi_log_release_buffer(char *bufptr)
  25 {
  26         kfree(bufptr);
  27 }
  28 
  29 static inline const char *scmd_name(const struct scsi_cmnd *scmd)
  30 {
  31         return scmd->request->rq_disk ?
  32                 scmd->request->rq_disk->disk_name : NULL;
  33 }
  34 
  35 static size_t sdev_format_header(char *logbuf, size_t logbuf_len,
  36                                  const char *name, int tag)
  37 {
  38         size_t off = 0;
  39 
  40         if (name)
  41                 off += scnprintf(logbuf + off, logbuf_len - off,
  42                                  "[%s] ", name);
  43 
  44         if (WARN_ON(off >= logbuf_len))
  45                 return off;
  46 
  47         if (tag >= 0)
  48                 off += scnprintf(logbuf + off, logbuf_len - off,
  49                                  "tag#%d ", tag);
  50         return off;
  51 }
  52 
  53 void sdev_prefix_printk(const char *level, const struct scsi_device *sdev,
  54                         const char *name, const char *fmt, ...)
  55 {
  56         va_list args;
  57         char *logbuf;
  58         size_t off = 0, logbuf_len;
  59 
  60         if (!sdev)
  61                 return;
  62 
  63         logbuf = scsi_log_reserve_buffer(&logbuf_len);
  64         if (!logbuf)
  65                 return;
  66 
  67         if (name)
  68                 off += scnprintf(logbuf + off, logbuf_len - off,
  69                                  "[%s] ", name);
  70         if (!WARN_ON(off >= logbuf_len)) {
  71                 va_start(args, fmt);
  72                 off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args);
  73                 va_end(args);
  74         }
  75         dev_printk(level, &sdev->sdev_gendev, "%s", logbuf);
  76         scsi_log_release_buffer(logbuf);
  77 }
  78 EXPORT_SYMBOL(sdev_prefix_printk);
  79 
  80 void scmd_printk(const char *level, const struct scsi_cmnd *scmd,
  81                 const char *fmt, ...)
  82 {
  83         va_list args;
  84         char *logbuf;
  85         size_t off = 0, logbuf_len;
  86 
  87         if (!scmd || !scmd->cmnd)
  88                 return;
  89 
  90         logbuf = scsi_log_reserve_buffer(&logbuf_len);
  91         if (!logbuf)
  92                 return;
  93         off = sdev_format_header(logbuf, logbuf_len, scmd_name(scmd),
  94                                  scmd->request->tag);
  95         if (off < logbuf_len) {
  96                 va_start(args, fmt);
  97                 off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args);
  98                 va_end(args);
  99         }
 100         dev_printk(level, &scmd->device->sdev_gendev, "%s", logbuf);
 101         scsi_log_release_buffer(logbuf);
 102 }
 103 EXPORT_SYMBOL(scmd_printk);
 104 
 105 static size_t scsi_format_opcode_name(char *buffer, size_t buf_len,
 106                                       const unsigned char *cdbp)
 107 {
 108         int sa, cdb0;
 109         const char *cdb_name = NULL, *sa_name = NULL;
 110         size_t off;
 111 
 112         cdb0 = cdbp[0];
 113         if (cdb0 == VARIABLE_LENGTH_CMD) {
 114                 int len = scsi_varlen_cdb_length(cdbp);
 115 
 116                 if (len < 10) {
 117                         off = scnprintf(buffer, buf_len,
 118                                         "short variable length command, len=%d",
 119                                         len);
 120                         return off;
 121                 }
 122                 sa = (cdbp[8] << 8) + cdbp[9];
 123         } else
 124                 sa = cdbp[1] & 0x1f;
 125 
 126         if (!scsi_opcode_sa_name(cdb0, sa, &cdb_name, &sa_name)) {
 127                 if (cdb_name)
 128                         off = scnprintf(buffer, buf_len, "%s", cdb_name);
 129                 else {
 130                         off = scnprintf(buffer, buf_len, "opcode=0x%x", cdb0);
 131                         if (WARN_ON(off >= buf_len))
 132                                 return off;
 133                         if (cdb0 >= VENDOR_SPECIFIC_CDB)
 134                                 off += scnprintf(buffer + off, buf_len - off,
 135                                                  " (vendor)");
 136                         else if (cdb0 >= 0x60 && cdb0 < 0x7e)
 137                                 off += scnprintf(buffer + off, buf_len - off,
 138                                                  " (reserved)");
 139                 }
 140         } else {
 141                 if (sa_name)
 142                         off = scnprintf(buffer, buf_len, "%s", sa_name);
 143                 else if (cdb_name)
 144                         off = scnprintf(buffer, buf_len, "%s, sa=0x%x",
 145                                         cdb_name, sa);
 146                 else
 147                         off = scnprintf(buffer, buf_len,
 148                                         "opcode=0x%x, sa=0x%x", cdb0, sa);
 149         }
 150         WARN_ON(off >= buf_len);
 151         return off;
 152 }
 153 
 154 size_t __scsi_format_command(char *logbuf, size_t logbuf_len,
 155                              const unsigned char *cdb, size_t cdb_len)
 156 {
 157         int len, k;
 158         size_t off;
 159 
 160         off = scsi_format_opcode_name(logbuf, logbuf_len, cdb);
 161         if (off >= logbuf_len)
 162                 return off;
 163         len = scsi_command_size(cdb);
 164         if (cdb_len < len)
 165                 len = cdb_len;
 166         /* print out all bytes in cdb */
 167         for (k = 0; k < len; ++k) {
 168                 if (off > logbuf_len - 3)
 169                         break;
 170                 off += scnprintf(logbuf + off, logbuf_len - off,
 171                                  " %02x", cdb[k]);
 172         }
 173         return off;
 174 }
 175 EXPORT_SYMBOL(__scsi_format_command);
 176 
 177 void scsi_print_command(struct scsi_cmnd *cmd)
 178 {
 179         int k;
 180         char *logbuf;
 181         size_t off, logbuf_len;
 182 
 183         if (!cmd->cmnd)
 184                 return;
 185 
 186         logbuf = scsi_log_reserve_buffer(&logbuf_len);
 187         if (!logbuf)
 188                 return;
 189 
 190         off = sdev_format_header(logbuf, logbuf_len,
 191                                  scmd_name(cmd), cmd->request->tag);
 192         if (off >= logbuf_len)
 193                 goto out_printk;
 194         off += scnprintf(logbuf + off, logbuf_len - off, "CDB: ");
 195         if (WARN_ON(off >= logbuf_len))
 196                 goto out_printk;
 197 
 198         off += scsi_format_opcode_name(logbuf + off, logbuf_len - off,
 199                                        cmd->cmnd);
 200         if (off >= logbuf_len)
 201                 goto out_printk;
 202 
 203         /* print out all bytes in cdb */
 204         if (cmd->cmd_len > 16) {
 205                 /* Print opcode in one line and use separate lines for CDB */
 206                 off += scnprintf(logbuf + off, logbuf_len - off, "\n");
 207                 dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
 208                 scsi_log_release_buffer(logbuf);
 209                 for (k = 0; k < cmd->cmd_len; k += 16) {
 210                         size_t linelen = min(cmd->cmd_len - k, 16);
 211 
 212                         logbuf = scsi_log_reserve_buffer(&logbuf_len);
 213                         if (!logbuf)
 214                                 break;
 215                         off = sdev_format_header(logbuf, logbuf_len,
 216                                                  scmd_name(cmd),
 217                                                  cmd->request->tag);
 218                         if (!WARN_ON(off > logbuf_len - 58)) {
 219                                 off += scnprintf(logbuf + off, logbuf_len - off,
 220                                                  "CDB[%02x]: ", k);
 221                                 hex_dump_to_buffer(&cmd->cmnd[k], linelen,
 222                                                    16, 1, logbuf + off,
 223                                                    logbuf_len - off, false);
 224                         }
 225                         dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s",
 226                                    logbuf);
 227                         scsi_log_release_buffer(logbuf);
 228                 }
 229                 return;
 230         }
 231         if (!WARN_ON(off > logbuf_len - 49)) {
 232                 off += scnprintf(logbuf + off, logbuf_len - off, " ");
 233                 hex_dump_to_buffer(cmd->cmnd, cmd->cmd_len, 16, 1,
 234                                    logbuf + off, logbuf_len - off,
 235                                    false);
 236         }
 237 out_printk:
 238         dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
 239         scsi_log_release_buffer(logbuf);
 240 }
 241 EXPORT_SYMBOL(scsi_print_command);
 242 
 243 static size_t
 244 scsi_format_extd_sense(char *buffer, size_t buf_len,
 245                        unsigned char asc, unsigned char ascq)
 246 {
 247         size_t off = 0;
 248         const char *extd_sense_fmt = NULL;
 249         const char *extd_sense_str = scsi_extd_sense_format(asc, ascq,
 250                                                             &extd_sense_fmt);
 251 
 252         if (extd_sense_str) {
 253                 off = scnprintf(buffer, buf_len, "Add. Sense: %s",
 254                                 extd_sense_str);
 255                 if (extd_sense_fmt)
 256                         off += scnprintf(buffer + off, buf_len - off,
 257                                          "(%s%x)", extd_sense_fmt, ascq);
 258         } else {
 259                 if (asc >= 0x80)
 260                         off = scnprintf(buffer, buf_len, "<<vendor>>");
 261                 off += scnprintf(buffer + off, buf_len - off,
 262                                  "ASC=0x%x ", asc);
 263                 if (ascq >= 0x80)
 264                         off += scnprintf(buffer + off, buf_len - off,
 265                                          "<<vendor>>");
 266                 off += scnprintf(buffer + off, buf_len - off,
 267                                  "ASCQ=0x%x ", ascq);
 268         }
 269         return off;
 270 }
 271 
 272 static size_t
 273 scsi_format_sense_hdr(char *buffer, size_t buf_len,
 274                       const struct scsi_sense_hdr *sshdr)
 275 {
 276         const char *sense_txt;
 277         size_t off;
 278 
 279         off = scnprintf(buffer, buf_len, "Sense Key : ");
 280         sense_txt = scsi_sense_key_string(sshdr->sense_key);
 281         if (sense_txt)
 282                 off += scnprintf(buffer + off, buf_len - off,
 283                                  "%s ", sense_txt);
 284         else
 285                 off += scnprintf(buffer + off, buf_len - off,
 286                                  "0x%x ", sshdr->sense_key);
 287         off += scnprintf(buffer + off, buf_len - off,
 288                 scsi_sense_is_deferred(sshdr) ? "[deferred] " : "[current] ");
 289 
 290         if (sshdr->response_code >= 0x72)
 291                 off += scnprintf(buffer + off, buf_len - off, "[descriptor] ");
 292         return off;
 293 }
 294 
 295 static void
 296 scsi_log_dump_sense(const struct scsi_device *sdev, const char *name, int tag,
 297                     const unsigned char *sense_buffer, int sense_len)
 298 {
 299         char *logbuf;
 300         size_t logbuf_len;
 301         int i;
 302 
 303         logbuf = scsi_log_reserve_buffer(&logbuf_len);
 304         if (!logbuf)
 305                 return;
 306 
 307         for (i = 0; i < sense_len; i += 16) {
 308                 int len = min(sense_len - i, 16);
 309                 size_t off;
 310 
 311                 off = sdev_format_header(logbuf, logbuf_len,
 312                                          name, tag);
 313                 hex_dump_to_buffer(&sense_buffer[i], len, 16, 1,
 314                                    logbuf + off, logbuf_len - off,
 315                                    false);
 316                 dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf);
 317         }
 318         scsi_log_release_buffer(logbuf);
 319 }
 320 
 321 static void
 322 scsi_log_print_sense_hdr(const struct scsi_device *sdev, const char *name,
 323                          int tag, const struct scsi_sense_hdr *sshdr)
 324 {
 325         char *logbuf;
 326         size_t off, logbuf_len;
 327 
 328         logbuf = scsi_log_reserve_buffer(&logbuf_len);
 329         if (!logbuf)
 330                 return;
 331         off = sdev_format_header(logbuf, logbuf_len, name, tag);
 332         off += scsi_format_sense_hdr(logbuf + off, logbuf_len - off, sshdr);
 333         dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf);
 334         scsi_log_release_buffer(logbuf);
 335 
 336         logbuf = scsi_log_reserve_buffer(&logbuf_len);
 337         if (!logbuf)
 338                 return;
 339         off = sdev_format_header(logbuf, logbuf_len, name, tag);
 340         off += scsi_format_extd_sense(logbuf + off, logbuf_len - off,
 341                                       sshdr->asc, sshdr->ascq);
 342         dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf);
 343         scsi_log_release_buffer(logbuf);
 344 }
 345 
 346 static void
 347 scsi_log_print_sense(const struct scsi_device *sdev, const char *name, int tag,
 348                      const unsigned char *sense_buffer, int sense_len)
 349 {
 350         struct scsi_sense_hdr sshdr;
 351 
 352         if (scsi_normalize_sense(sense_buffer, sense_len, &sshdr))
 353                 scsi_log_print_sense_hdr(sdev, name, tag, &sshdr);
 354         else
 355                 scsi_log_dump_sense(sdev, name, tag, sense_buffer, sense_len);
 356 }
 357 
 358 /*
 359  * Print normalized SCSI sense header with a prefix.
 360  */
 361 void
 362 scsi_print_sense_hdr(const struct scsi_device *sdev, const char *name,
 363                      const struct scsi_sense_hdr *sshdr)
 364 {
 365         scsi_log_print_sense_hdr(sdev, name, -1, sshdr);
 366 }
 367 EXPORT_SYMBOL(scsi_print_sense_hdr);
 368 
 369 /* Normalize and print sense buffer with name prefix */
 370 void __scsi_print_sense(const struct scsi_device *sdev, const char *name,
 371                         const unsigned char *sense_buffer, int sense_len)
 372 {
 373         scsi_log_print_sense(sdev, name, -1, sense_buffer, sense_len);
 374 }
 375 EXPORT_SYMBOL(__scsi_print_sense);
 376 
 377 /* Normalize and print sense buffer in SCSI command */
 378 void scsi_print_sense(const struct scsi_cmnd *cmd)
 379 {
 380         scsi_log_print_sense(cmd->device, scmd_name(cmd), cmd->request->tag,
 381                              cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
 382 }
 383 EXPORT_SYMBOL(scsi_print_sense);
 384 
 385 void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg,
 386                        int disposition)
 387 {
 388         char *logbuf;
 389         size_t off, logbuf_len;
 390         const char *mlret_string = scsi_mlreturn_string(disposition);
 391         const char *hb_string = scsi_hostbyte_string(cmd->result);
 392         const char *db_string = scsi_driverbyte_string(cmd->result);
 393 
 394         logbuf = scsi_log_reserve_buffer(&logbuf_len);
 395         if (!logbuf)
 396                 return;
 397 
 398         off = sdev_format_header(logbuf, logbuf_len,
 399                                  scmd_name(cmd), cmd->request->tag);
 400 
 401         if (off >= logbuf_len)
 402                 goto out_printk;
 403 
 404         if (msg) {
 405                 off += scnprintf(logbuf + off, logbuf_len - off,
 406                                  "%s: ", msg);
 407                 if (WARN_ON(off >= logbuf_len))
 408                         goto out_printk;
 409         }
 410         if (mlret_string)
 411                 off += scnprintf(logbuf + off, logbuf_len - off,
 412                                  "%s ", mlret_string);
 413         else
 414                 off += scnprintf(logbuf + off, logbuf_len - off,
 415                                  "UNKNOWN(0x%02x) ", disposition);
 416         if (WARN_ON(off >= logbuf_len))
 417                 goto out_printk;
 418 
 419         off += scnprintf(logbuf + off, logbuf_len - off, "Result: ");
 420         if (WARN_ON(off >= logbuf_len))
 421                 goto out_printk;
 422 
 423         if (hb_string)
 424                 off += scnprintf(logbuf + off, logbuf_len - off,
 425                                  "hostbyte=%s ", hb_string);
 426         else
 427                 off += scnprintf(logbuf + off, logbuf_len - off,
 428                                  "hostbyte=0x%02x ", host_byte(cmd->result));
 429         if (WARN_ON(off >= logbuf_len))
 430                 goto out_printk;
 431 
 432         if (db_string)
 433                 off += scnprintf(logbuf + off, logbuf_len - off,
 434                                  "driverbyte=%s", db_string);
 435         else
 436                 off += scnprintf(logbuf + off, logbuf_len - off,
 437                                  "driverbyte=0x%02x", driver_byte(cmd->result));
 438 out_printk:
 439         dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
 440         scsi_log_release_buffer(logbuf);
 441 }
 442 EXPORT_SYMBOL(scsi_print_result);

/* [<][>][^][v][top][bottom][index][help] */