scsi_logging.c 12 KB

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