scsi_logging.c 11 KB

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