Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * scsi_logging.c
0004  *
0005  * Copyright (C) 2014 SUSE Linux Products GmbH
0006  * Copyright (C) 2014 Hannes Reinecke <hare@suse.de>
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/atomic.h>
0011 
0012 #include <scsi/scsi.h>
0013 #include <scsi/scsi_cmnd.h>
0014 #include <scsi/scsi_device.h>
0015 #include <scsi/scsi_eh.h>
0016 #include <scsi/scsi_dbg.h>
0017 
0018 static char *scsi_log_reserve_buffer(size_t *len)
0019 {
0020     *len = 128;
0021     return kmalloc(*len, GFP_ATOMIC);
0022 }
0023 
0024 static void scsi_log_release_buffer(char *bufptr)
0025 {
0026     kfree(bufptr);
0027 }
0028 
0029 static inline const char *scmd_name(const struct scsi_cmnd *scmd)
0030 {
0031     struct request *rq = scsi_cmd_to_rq((struct scsi_cmnd *)scmd);
0032 
0033     if (!rq->q || !rq->q->disk)
0034         return NULL;
0035     return rq->q->disk->disk_name;
0036 }
0037 
0038 static size_t sdev_format_header(char *logbuf, size_t logbuf_len,
0039                  const char *name, int tag)
0040 {
0041     size_t off = 0;
0042 
0043     if (name)
0044         off += scnprintf(logbuf + off, logbuf_len - off,
0045                  "[%s] ", name);
0046 
0047     if (WARN_ON(off >= logbuf_len))
0048         return off;
0049 
0050     if (tag >= 0)
0051         off += scnprintf(logbuf + off, logbuf_len - off,
0052                  "tag#%d ", tag);
0053     return off;
0054 }
0055 
0056 void sdev_prefix_printk(const char *level, const struct scsi_device *sdev,
0057             const char *name, const char *fmt, ...)
0058 {
0059     va_list args;
0060     char *logbuf;
0061     size_t off = 0, logbuf_len;
0062 
0063     if (!sdev)
0064         return;
0065 
0066     logbuf = scsi_log_reserve_buffer(&logbuf_len);
0067     if (!logbuf)
0068         return;
0069 
0070     if (name)
0071         off += scnprintf(logbuf + off, logbuf_len - off,
0072                  "[%s] ", name);
0073     if (!WARN_ON(off >= logbuf_len)) {
0074         va_start(args, fmt);
0075         off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args);
0076         va_end(args);
0077     }
0078     dev_printk(level, &sdev->sdev_gendev, "%s", logbuf);
0079     scsi_log_release_buffer(logbuf);
0080 }
0081 EXPORT_SYMBOL(sdev_prefix_printk);
0082 
0083 void scmd_printk(const char *level, const struct scsi_cmnd *scmd,
0084         const char *fmt, ...)
0085 {
0086     va_list args;
0087     char *logbuf;
0088     size_t off = 0, logbuf_len;
0089 
0090     if (!scmd)
0091         return;
0092 
0093     logbuf = scsi_log_reserve_buffer(&logbuf_len);
0094     if (!logbuf)
0095         return;
0096     off = sdev_format_header(logbuf, logbuf_len, scmd_name(scmd),
0097                  scsi_cmd_to_rq((struct scsi_cmnd *)scmd)->tag);
0098     if (off < logbuf_len) {
0099         va_start(args, fmt);
0100         off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args);
0101         va_end(args);
0102     }
0103     dev_printk(level, &scmd->device->sdev_gendev, "%s", logbuf);
0104     scsi_log_release_buffer(logbuf);
0105 }
0106 EXPORT_SYMBOL(scmd_printk);
0107 
0108 static size_t scsi_format_opcode_name(char *buffer, size_t buf_len,
0109                       const unsigned char *cdbp)
0110 {
0111     int sa, cdb0;
0112     const char *cdb_name = NULL, *sa_name = NULL;
0113     size_t off;
0114 
0115     cdb0 = cdbp[0];
0116     if (cdb0 == VARIABLE_LENGTH_CMD) {
0117         int len = scsi_varlen_cdb_length(cdbp);
0118 
0119         if (len < 10) {
0120             off = scnprintf(buffer, buf_len,
0121                     "short variable length command, len=%d",
0122                     len);
0123             return off;
0124         }
0125         sa = (cdbp[8] << 8) + cdbp[9];
0126     } else
0127         sa = cdbp[1] & 0x1f;
0128 
0129     if (!scsi_opcode_sa_name(cdb0, sa, &cdb_name, &sa_name)) {
0130         if (cdb_name)
0131             off = scnprintf(buffer, buf_len, "%s", cdb_name);
0132         else {
0133             off = scnprintf(buffer, buf_len, "opcode=0x%x", cdb0);
0134             if (WARN_ON(off >= buf_len))
0135                 return off;
0136             if (cdb0 >= VENDOR_SPECIFIC_CDB)
0137                 off += scnprintf(buffer + off, buf_len - off,
0138                          " (vendor)");
0139             else if (cdb0 >= 0x60 && cdb0 < 0x7e)
0140                 off += scnprintf(buffer + off, buf_len - off,
0141                          " (reserved)");
0142         }
0143     } else {
0144         if (sa_name)
0145             off = scnprintf(buffer, buf_len, "%s", sa_name);
0146         else if (cdb_name)
0147             off = scnprintf(buffer, buf_len, "%s, sa=0x%x",
0148                     cdb_name, sa);
0149         else
0150             off = scnprintf(buffer, buf_len,
0151                     "opcode=0x%x, sa=0x%x", cdb0, sa);
0152     }
0153     WARN_ON(off >= buf_len);
0154     return off;
0155 }
0156 
0157 size_t __scsi_format_command(char *logbuf, size_t logbuf_len,
0158                  const unsigned char *cdb, size_t cdb_len)
0159 {
0160     int len, k;
0161     size_t off;
0162 
0163     off = scsi_format_opcode_name(logbuf, logbuf_len, cdb);
0164     if (off >= logbuf_len)
0165         return off;
0166     len = scsi_command_size(cdb);
0167     if (cdb_len < len)
0168         len = cdb_len;
0169     /* print out all bytes in cdb */
0170     for (k = 0; k < len; ++k) {
0171         if (off > logbuf_len - 3)
0172             break;
0173         off += scnprintf(logbuf + off, logbuf_len - off,
0174                  " %02x", cdb[k]);
0175     }
0176     return off;
0177 }
0178 EXPORT_SYMBOL(__scsi_format_command);
0179 
0180 void scsi_print_command(struct scsi_cmnd *cmd)
0181 {
0182     int k;
0183     char *logbuf;
0184     size_t off, logbuf_len;
0185 
0186     logbuf = scsi_log_reserve_buffer(&logbuf_len);
0187     if (!logbuf)
0188         return;
0189 
0190     off = sdev_format_header(logbuf, logbuf_len,
0191                  scmd_name(cmd), scsi_cmd_to_rq(cmd)->tag);
0192     if (off >= logbuf_len)
0193         goto out_printk;
0194     off += scnprintf(logbuf + off, logbuf_len - off, "CDB: ");
0195     if (WARN_ON(off >= logbuf_len))
0196         goto out_printk;
0197 
0198     off += scsi_format_opcode_name(logbuf + off, logbuf_len - off,
0199                        cmd->cmnd);
0200     if (off >= logbuf_len)
0201         goto out_printk;
0202 
0203     /* print out all bytes in cdb */
0204     if (cmd->cmd_len > 16) {
0205         /* Print opcode in one line and use separate lines for CDB */
0206         off += scnprintf(logbuf + off, logbuf_len - off, "\n");
0207         dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
0208         for (k = 0; k < cmd->cmd_len; k += 16) {
0209             size_t linelen = min(cmd->cmd_len - k, 16);
0210 
0211             off = sdev_format_header(logbuf, logbuf_len,
0212                          scmd_name(cmd),
0213                          scsi_cmd_to_rq(cmd)->tag);
0214             if (!WARN_ON(off > logbuf_len - 58)) {
0215                 off += scnprintf(logbuf + off, logbuf_len - off,
0216                          "CDB[%02x]: ", k);
0217                 hex_dump_to_buffer(&cmd->cmnd[k], linelen,
0218                            16, 1, logbuf + off,
0219                            logbuf_len - off, false);
0220             }
0221             dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s",
0222                    logbuf);
0223         }
0224         goto out;
0225     }
0226     if (!WARN_ON(off > logbuf_len - 49)) {
0227         off += scnprintf(logbuf + off, logbuf_len - off, " ");
0228         hex_dump_to_buffer(cmd->cmnd, cmd->cmd_len, 16, 1,
0229                    logbuf + off, logbuf_len - off,
0230                    false);
0231     }
0232 out_printk:
0233     dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
0234 out:
0235     scsi_log_release_buffer(logbuf);
0236 }
0237 EXPORT_SYMBOL(scsi_print_command);
0238 
0239 static size_t
0240 scsi_format_extd_sense(char *buffer, size_t buf_len,
0241                unsigned char asc, unsigned char ascq)
0242 {
0243     size_t off = 0;
0244     const char *extd_sense_fmt = NULL;
0245     const char *extd_sense_str = scsi_extd_sense_format(asc, ascq,
0246                                 &extd_sense_fmt);
0247 
0248     if (extd_sense_str) {
0249         off = scnprintf(buffer, buf_len, "Add. Sense: %s",
0250                 extd_sense_str);
0251         if (extd_sense_fmt)
0252             off += scnprintf(buffer + off, buf_len - off,
0253                      "(%s%x)", extd_sense_fmt, ascq);
0254     } else {
0255         if (asc >= 0x80)
0256             off = scnprintf(buffer, buf_len, "<<vendor>>");
0257         off += scnprintf(buffer + off, buf_len - off,
0258                  "ASC=0x%x ", asc);
0259         if (ascq >= 0x80)
0260             off += scnprintf(buffer + off, buf_len - off,
0261                      "<<vendor>>");
0262         off += scnprintf(buffer + off, buf_len - off,
0263                  "ASCQ=0x%x ", ascq);
0264     }
0265     return off;
0266 }
0267 
0268 static size_t
0269 scsi_format_sense_hdr(char *buffer, size_t buf_len,
0270               const struct scsi_sense_hdr *sshdr)
0271 {
0272     const char *sense_txt;
0273     size_t off;
0274 
0275     off = scnprintf(buffer, buf_len, "Sense Key : ");
0276     sense_txt = scsi_sense_key_string(sshdr->sense_key);
0277     if (sense_txt)
0278         off += scnprintf(buffer + off, buf_len - off,
0279                  "%s ", sense_txt);
0280     else
0281         off += scnprintf(buffer + off, buf_len - off,
0282                  "0x%x ", sshdr->sense_key);
0283     off += scnprintf(buffer + off, buf_len - off,
0284         scsi_sense_is_deferred(sshdr) ? "[deferred] " : "[current] ");
0285 
0286     if (sshdr->response_code >= 0x72)
0287         off += scnprintf(buffer + off, buf_len - off, "[descriptor] ");
0288     return off;
0289 }
0290 
0291 static void
0292 scsi_log_dump_sense(const struct scsi_device *sdev, const char *name, int tag,
0293             const unsigned char *sense_buffer, int sense_len)
0294 {
0295     char *logbuf;
0296     size_t logbuf_len;
0297     int i;
0298 
0299     logbuf = scsi_log_reserve_buffer(&logbuf_len);
0300     if (!logbuf)
0301         return;
0302 
0303     for (i = 0; i < sense_len; i += 16) {
0304         int len = min(sense_len - i, 16);
0305         size_t off;
0306 
0307         off = sdev_format_header(logbuf, logbuf_len,
0308                      name, tag);
0309         hex_dump_to_buffer(&sense_buffer[i], len, 16, 1,
0310                    logbuf + off, logbuf_len - off,
0311                    false);
0312         dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf);
0313     }
0314     scsi_log_release_buffer(logbuf);
0315 }
0316 
0317 static void
0318 scsi_log_print_sense_hdr(const struct scsi_device *sdev, const char *name,
0319              int tag, const struct scsi_sense_hdr *sshdr)
0320 {
0321     char *logbuf;
0322     size_t off, logbuf_len;
0323 
0324     logbuf = scsi_log_reserve_buffer(&logbuf_len);
0325     if (!logbuf)
0326         return;
0327     off = sdev_format_header(logbuf, logbuf_len, name, tag);
0328     off += scsi_format_sense_hdr(logbuf + off, logbuf_len - off, sshdr);
0329     dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf);
0330     scsi_log_release_buffer(logbuf);
0331 
0332     logbuf = scsi_log_reserve_buffer(&logbuf_len);
0333     if (!logbuf)
0334         return;
0335     off = sdev_format_header(logbuf, logbuf_len, name, tag);
0336     off += scsi_format_extd_sense(logbuf + off, logbuf_len - off,
0337                       sshdr->asc, sshdr->ascq);
0338     dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf);
0339     scsi_log_release_buffer(logbuf);
0340 }
0341 
0342 static void
0343 scsi_log_print_sense(const struct scsi_device *sdev, const char *name, int tag,
0344              const unsigned char *sense_buffer, int sense_len)
0345 {
0346     struct scsi_sense_hdr sshdr;
0347 
0348     if (scsi_normalize_sense(sense_buffer, sense_len, &sshdr))
0349         scsi_log_print_sense_hdr(sdev, name, tag, &sshdr);
0350     else
0351         scsi_log_dump_sense(sdev, name, tag, sense_buffer, sense_len);
0352 }
0353 
0354 /*
0355  * Print normalized SCSI sense header with a prefix.
0356  */
0357 void
0358 scsi_print_sense_hdr(const struct scsi_device *sdev, const char *name,
0359              const struct scsi_sense_hdr *sshdr)
0360 {
0361     scsi_log_print_sense_hdr(sdev, name, -1, sshdr);
0362 }
0363 EXPORT_SYMBOL(scsi_print_sense_hdr);
0364 
0365 /* Normalize and print sense buffer with name prefix */
0366 void __scsi_print_sense(const struct scsi_device *sdev, const char *name,
0367             const unsigned char *sense_buffer, int sense_len)
0368 {
0369     scsi_log_print_sense(sdev, name, -1, sense_buffer, sense_len);
0370 }
0371 EXPORT_SYMBOL(__scsi_print_sense);
0372 
0373 /* Normalize and print sense buffer in SCSI command */
0374 void scsi_print_sense(const struct scsi_cmnd *cmd)
0375 {
0376     scsi_log_print_sense(cmd->device, scmd_name(cmd),
0377                  scsi_cmd_to_rq((struct scsi_cmnd *)cmd)->tag,
0378                  cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
0379 }
0380 EXPORT_SYMBOL(scsi_print_sense);
0381 
0382 void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg,
0383                int disposition)
0384 {
0385     char *logbuf;
0386     size_t off, logbuf_len;
0387     const char *mlret_string = scsi_mlreturn_string(disposition);
0388     const char *hb_string = scsi_hostbyte_string(cmd->result);
0389     unsigned long cmd_age = (jiffies - cmd->jiffies_at_alloc) / HZ;
0390 
0391     logbuf = scsi_log_reserve_buffer(&logbuf_len);
0392     if (!logbuf)
0393         return;
0394 
0395     off = sdev_format_header(logbuf, logbuf_len, scmd_name(cmd),
0396                  scsi_cmd_to_rq((struct scsi_cmnd *)cmd)->tag);
0397 
0398     if (off >= logbuf_len)
0399         goto out_printk;
0400 
0401     if (msg) {
0402         off += scnprintf(logbuf + off, logbuf_len - off,
0403                  "%s: ", msg);
0404         if (WARN_ON(off >= logbuf_len))
0405             goto out_printk;
0406     }
0407     if (mlret_string)
0408         off += scnprintf(logbuf + off, logbuf_len - off,
0409                  "%s ", mlret_string);
0410     else
0411         off += scnprintf(logbuf + off, logbuf_len - off,
0412                  "UNKNOWN(0x%02x) ", disposition);
0413     if (WARN_ON(off >= logbuf_len))
0414         goto out_printk;
0415 
0416     off += scnprintf(logbuf + off, logbuf_len - off, "Result: ");
0417     if (WARN_ON(off >= logbuf_len))
0418         goto out_printk;
0419 
0420     if (hb_string)
0421         off += scnprintf(logbuf + off, logbuf_len - off,
0422                  "hostbyte=%s ", hb_string);
0423     else
0424         off += scnprintf(logbuf + off, logbuf_len - off,
0425                  "hostbyte=0x%02x ", host_byte(cmd->result));
0426     if (WARN_ON(off >= logbuf_len))
0427         goto out_printk;
0428 
0429     off += scnprintf(logbuf + off, logbuf_len - off,
0430              "driverbyte=DRIVER_OK ");
0431 
0432     off += scnprintf(logbuf + off, logbuf_len - off,
0433              "cmd_age=%lus", cmd_age);
0434 
0435 out_printk:
0436     dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
0437     scsi_log_release_buffer(logbuf);
0438 }
0439 EXPORT_SYMBOL(scsi_print_result);