0001
0002
0003
0004
0005
0006
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
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
0204 if (cmd->cmd_len > 16) {
0205
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
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
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
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);