scsi_logging.c 11 KB

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