scsi_logging.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  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 <[email protected]>
  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. struct request *rq = scsi_cmd_to_rq((struct scsi_cmnd *)scmd);
  27. if (!rq->q || !rq->q->disk)
  28. return NULL;
  29. return rq->q->disk->disk_name;
  30. }
  31. static size_t sdev_format_header(char *logbuf, size_t logbuf_len,
  32. const char *name, int tag)
  33. {
  34. size_t off = 0;
  35. if (name)
  36. off += scnprintf(logbuf + off, logbuf_len - off,
  37. "[%s] ", name);
  38. if (WARN_ON(off >= logbuf_len))
  39. return off;
  40. if (tag >= 0)
  41. off += scnprintf(logbuf + off, logbuf_len - off,
  42. "tag#%d ", tag);
  43. return off;
  44. }
  45. void sdev_prefix_printk(const char *level, const struct scsi_device *sdev,
  46. const char *name, const char *fmt, ...)
  47. {
  48. va_list args;
  49. char *logbuf;
  50. size_t off = 0, logbuf_len;
  51. if (!sdev)
  52. return;
  53. logbuf = scsi_log_reserve_buffer(&logbuf_len);
  54. if (!logbuf)
  55. return;
  56. if (name)
  57. off += scnprintf(logbuf + off, logbuf_len - off,
  58. "[%s] ", name);
  59. if (!WARN_ON(off >= logbuf_len)) {
  60. va_start(args, fmt);
  61. off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args);
  62. va_end(args);
  63. }
  64. dev_printk(level, &sdev->sdev_gendev, "%s", logbuf);
  65. scsi_log_release_buffer(logbuf);
  66. }
  67. EXPORT_SYMBOL(sdev_prefix_printk);
  68. void scmd_printk(const char *level, const struct scsi_cmnd *scmd,
  69. const char *fmt, ...)
  70. {
  71. va_list args;
  72. char *logbuf;
  73. size_t off = 0, logbuf_len;
  74. if (!scmd)
  75. return;
  76. logbuf = scsi_log_reserve_buffer(&logbuf_len);
  77. if (!logbuf)
  78. return;
  79. off = sdev_format_header(logbuf, logbuf_len, scmd_name(scmd),
  80. scsi_cmd_to_rq((struct scsi_cmnd *)scmd)->tag);
  81. if (off < logbuf_len) {
  82. va_start(args, fmt);
  83. off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args);
  84. va_end(args);
  85. }
  86. dev_printk(level, &scmd->device->sdev_gendev, "%s", logbuf);
  87. scsi_log_release_buffer(logbuf);
  88. }
  89. EXPORT_SYMBOL(scmd_printk);
  90. static size_t scsi_format_opcode_name(char *buffer, size_t buf_len,
  91. const unsigned char *cdbp)
  92. {
  93. int sa, cdb0;
  94. const char *cdb_name = NULL, *sa_name = NULL;
  95. size_t off;
  96. cdb0 = cdbp[0];
  97. if (cdb0 == VARIABLE_LENGTH_CMD) {
  98. int len = scsi_varlen_cdb_length(cdbp);
  99. if (len < 10) {
  100. off = scnprintf(buffer, buf_len,
  101. "short variable length command, len=%d",
  102. len);
  103. return off;
  104. }
  105. sa = (cdbp[8] << 8) + cdbp[9];
  106. } else
  107. sa = cdbp[1] & 0x1f;
  108. if (!scsi_opcode_sa_name(cdb0, sa, &cdb_name, &sa_name)) {
  109. if (cdb_name)
  110. off = scnprintf(buffer, buf_len, "%s", cdb_name);
  111. else {
  112. off = scnprintf(buffer, buf_len, "opcode=0x%x", cdb0);
  113. if (WARN_ON(off >= buf_len))
  114. return off;
  115. if (cdb0 >= VENDOR_SPECIFIC_CDB)
  116. off += scnprintf(buffer + off, buf_len - off,
  117. " (vendor)");
  118. else if (cdb0 >= 0x60 && cdb0 < 0x7e)
  119. off += scnprintf(buffer + off, buf_len - off,
  120. " (reserved)");
  121. }
  122. } else {
  123. if (sa_name)
  124. off = scnprintf(buffer, buf_len, "%s", sa_name);
  125. else if (cdb_name)
  126. off = scnprintf(buffer, buf_len, "%s, sa=0x%x",
  127. cdb_name, sa);
  128. else
  129. off = scnprintf(buffer, buf_len,
  130. "opcode=0x%x, sa=0x%x", cdb0, sa);
  131. }
  132. WARN_ON(off >= buf_len);
  133. return off;
  134. }
  135. size_t __scsi_format_command(char *logbuf, size_t logbuf_len,
  136. const unsigned char *cdb, size_t cdb_len)
  137. {
  138. int len, k;
  139. size_t off;
  140. off = scsi_format_opcode_name(logbuf, logbuf_len, cdb);
  141. if (off >= logbuf_len)
  142. return off;
  143. len = scsi_command_size(cdb);
  144. if (cdb_len < len)
  145. len = cdb_len;
  146. /* print out all bytes in cdb */
  147. for (k = 0; k < len; ++k) {
  148. if (off > logbuf_len - 3)
  149. break;
  150. off += scnprintf(logbuf + off, logbuf_len - off,
  151. " %02x", cdb[k]);
  152. }
  153. return off;
  154. }
  155. EXPORT_SYMBOL(__scsi_format_command);
  156. void scsi_print_command(struct scsi_cmnd *cmd)
  157. {
  158. int k;
  159. char *logbuf;
  160. size_t off, logbuf_len;
  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), scsi_cmd_to_rq(cmd)->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. scsi_cmd_to_rq(cmd)->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),
  331. scsi_cmd_to_rq((struct scsi_cmnd *)cmd)->tag,
  332. cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
  333. }
  334. EXPORT_SYMBOL(scsi_print_sense);
  335. void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg,
  336. int disposition)
  337. {
  338. char *logbuf;
  339. size_t off, logbuf_len;
  340. const char *mlret_string = scsi_mlreturn_string(disposition);
  341. const char *hb_string = scsi_hostbyte_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, scmd_name(cmd),
  347. scsi_cmd_to_rq((struct scsi_cmnd *)cmd)->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. off += scnprintf(logbuf + off, logbuf_len - off,
  376. "driverbyte=DRIVER_OK ");
  377. off += scnprintf(logbuf + off, logbuf_len - off,
  378. "cmd_age=%lus", cmd_age);
  379. out_printk:
  380. dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
  381. scsi_log_release_buffer(logbuf);
  382. }
  383. EXPORT_SYMBOL(scsi_print_result);