414 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2010 FUJITSU LIMITED4 * Copyright (C) 2010 Tomohiro Kusumi <kusumi.tomohiro@jp.fujitsu.com>5 */6#include <linux/kernel.h>7#include <linux/trace_seq.h>8#include <linux/unaligned.h>9#include <trace/events/scsi.h>10 11#define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f)12#define SERVICE_ACTION32(cdb) (get_unaligned_be16(&cdb[8]))13 14static const char *15scsi_trace_misc(struct trace_seq *, unsigned char *, int);16 17static const char *18scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len)19{20 const char *ret = trace_seq_buffer_ptr(p);21 u32 lba, txlen;22 23 lba = get_unaligned_be24(&cdb[1]) & 0x1fffff;24 /*25 * From SBC-2: a TRANSFER LENGTH field set to zero specifies that 25626 * logical blocks shall be read (READ(6)) or written (WRITE(6)).27 */28 txlen = cdb[4] ? cdb[4] : 256;29 30 trace_seq_printf(p, "lba=%u txlen=%u", lba, txlen);31 trace_seq_putc(p, 0);32 33 return ret;34}35 36static const char *37scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len)38{39 const char *ret = trace_seq_buffer_ptr(p);40 u32 lba, txlen;41 42 lba = get_unaligned_be32(&cdb[2]);43 txlen = get_unaligned_be16(&cdb[7]);44 45 trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen,46 cdb[1] >> 5);47 48 if (cdb[0] == WRITE_SAME)49 trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);50 51 trace_seq_putc(p, 0);52 53 return ret;54}55 56static const char *57scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len)58{59 const char *ret = trace_seq_buffer_ptr(p);60 u32 lba, txlen;61 62 lba = get_unaligned_be32(&cdb[2]);63 txlen = get_unaligned_be32(&cdb[6]);64 65 trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen,66 cdb[1] >> 5);67 trace_seq_putc(p, 0);68 69 return ret;70}71 72static const char *73scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len)74{75 const char *ret = trace_seq_buffer_ptr(p);76 u64 lba;77 u32 txlen;78 79 lba = get_unaligned_be64(&cdb[2]);80 txlen = get_unaligned_be32(&cdb[10]);81 82 trace_seq_printf(p, "lba=%llu txlen=%u protect=%u", lba, txlen,83 cdb[1] >> 5);84 85 if (cdb[0] == WRITE_SAME_16)86 trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);87 88 trace_seq_putc(p, 0);89 90 return ret;91}92 93static const char *94scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len)95{96 const char *ret = trace_seq_buffer_ptr(p), *cmd;97 u64 lba;98 u32 ei_lbrt, txlen;99 100 switch (SERVICE_ACTION32(cdb)) {101 case READ_32:102 cmd = "READ";103 break;104 case VERIFY_32:105 cmd = "VERIFY";106 break;107 case WRITE_32:108 cmd = "WRITE";109 break;110 case WRITE_SAME_32:111 cmd = "WRITE_SAME";112 break;113 default:114 trace_seq_puts(p, "UNKNOWN");115 goto out;116 }117 118 lba = get_unaligned_be64(&cdb[12]);119 ei_lbrt = get_unaligned_be32(&cdb[20]);120 txlen = get_unaligned_be32(&cdb[28]);121 122 trace_seq_printf(p, "%s_32 lba=%llu txlen=%u protect=%u ei_lbrt=%u",123 cmd, lba, txlen, cdb[10] >> 5, ei_lbrt);124 125 if (SERVICE_ACTION32(cdb) == WRITE_SAME_32)126 trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1);127 128out:129 trace_seq_putc(p, 0);130 131 return ret;132}133 134static const char *135scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len)136{137 const char *ret = trace_seq_buffer_ptr(p);138 unsigned int regions = get_unaligned_be16(&cdb[7]);139 140 trace_seq_printf(p, "regions=%u", (regions - 8) / 16);141 trace_seq_putc(p, 0);142 143 return ret;144}145 146static const char *147scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len)148{149 const char *ret = trace_seq_buffer_ptr(p), *cmd;150 u64 lba;151 u32 alloc_len;152 153 switch (SERVICE_ACTION16(cdb)) {154 case SAI_READ_CAPACITY_16:155 cmd = "READ_CAPACITY_16";156 break;157 case SAI_GET_LBA_STATUS:158 cmd = "GET_LBA_STATUS";159 break;160 default:161 trace_seq_puts(p, "UNKNOWN");162 goto out;163 }164 165 lba = get_unaligned_be64(&cdb[2]);166 alloc_len = get_unaligned_be32(&cdb[10]);167 168 trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, lba, alloc_len);169 170out:171 trace_seq_putc(p, 0);172 173 return ret;174}175 176static const char *177scsi_trace_maintenance_in(struct trace_seq *p, unsigned char *cdb, int len)178{179 const char *ret = trace_seq_buffer_ptr(p), *cmd;180 u32 alloc_len;181 182 switch (SERVICE_ACTION16(cdb)) {183 case MI_REPORT_IDENTIFYING_INFORMATION:184 cmd = "REPORT_IDENTIFYING_INFORMATION";185 break;186 case MI_REPORT_TARGET_PGS:187 cmd = "REPORT_TARGET_PORT_GROUPS";188 break;189 case MI_REPORT_ALIASES:190 cmd = "REPORT_ALIASES";191 break;192 case MI_REPORT_SUPPORTED_OPERATION_CODES:193 cmd = "REPORT_SUPPORTED_OPERATION_CODES";194 break;195 case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS:196 cmd = "REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS";197 break;198 case MI_REPORT_PRIORITY:199 cmd = "REPORT_PRIORITY";200 break;201 case MI_REPORT_TIMESTAMP:202 cmd = "REPORT_TIMESTAMP";203 break;204 case MI_MANAGEMENT_PROTOCOL_IN:205 cmd = "MANAGEMENT_PROTOCOL_IN";206 break;207 default:208 trace_seq_puts(p, "UNKNOWN");209 goto out;210 }211 212 alloc_len = get_unaligned_be32(&cdb[6]);213 214 trace_seq_printf(p, "%s alloc_len=%u", cmd, alloc_len);215 216out:217 trace_seq_putc(p, 0);218 219 return ret;220}221 222static const char *223scsi_trace_maintenance_out(struct trace_seq *p, unsigned char *cdb, int len)224{225 const char *ret = trace_seq_buffer_ptr(p), *cmd;226 u32 alloc_len;227 228 switch (SERVICE_ACTION16(cdb)) {229 case MO_SET_IDENTIFYING_INFORMATION:230 cmd = "SET_IDENTIFYING_INFORMATION";231 break;232 case MO_SET_TARGET_PGS:233 cmd = "SET_TARGET_PORT_GROUPS";234 break;235 case MO_CHANGE_ALIASES:236 cmd = "CHANGE_ALIASES";237 break;238 case MO_SET_PRIORITY:239 cmd = "SET_PRIORITY";240 break;241 case MO_SET_TIMESTAMP:242 cmd = "SET_TIMESTAMP";243 break;244 case MO_MANAGEMENT_PROTOCOL_OUT:245 cmd = "MANAGEMENT_PROTOCOL_OUT";246 break;247 default:248 trace_seq_puts(p, "UNKNOWN");249 goto out;250 }251 252 alloc_len = get_unaligned_be32(&cdb[6]);253 254 trace_seq_printf(p, "%s alloc_len=%u", cmd, alloc_len);255 256out:257 trace_seq_putc(p, 0);258 259 return ret;260}261 262static const char *263scsi_trace_zbc_in(struct trace_seq *p, unsigned char *cdb, int len)264{265 const char *ret = trace_seq_buffer_ptr(p), *cmd;266 u64 zone_id;267 u32 alloc_len;268 u8 options;269 270 switch (SERVICE_ACTION16(cdb)) {271 case ZI_REPORT_ZONES:272 cmd = "REPORT_ZONES";273 break;274 default:275 trace_seq_puts(p, "UNKNOWN");276 goto out;277 }278 279 zone_id = get_unaligned_be64(&cdb[2]);280 alloc_len = get_unaligned_be32(&cdb[10]);281 options = cdb[14] & 0x3f;282 283 trace_seq_printf(p, "%s zone=%llu alloc_len=%u options=%u partial=%u",284 cmd, (unsigned long long)zone_id, alloc_len,285 options, (cdb[14] >> 7) & 1);286 287out:288 trace_seq_putc(p, 0);289 290 return ret;291}292 293static const char *294scsi_trace_zbc_out(struct trace_seq *p, unsigned char *cdb, int len)295{296 const char *ret = trace_seq_buffer_ptr(p), *cmd;297 u64 zone_id;298 299 switch (SERVICE_ACTION16(cdb)) {300 case ZO_CLOSE_ZONE:301 cmd = "CLOSE_ZONE";302 break;303 case ZO_FINISH_ZONE:304 cmd = "FINISH_ZONE";305 break;306 case ZO_OPEN_ZONE:307 cmd = "OPEN_ZONE";308 break;309 case ZO_RESET_WRITE_POINTER:310 cmd = "RESET_WRITE_POINTER";311 break;312 default:313 trace_seq_puts(p, "UNKNOWN");314 goto out;315 }316 317 zone_id = get_unaligned_be64(&cdb[2]);318 319 trace_seq_printf(p, "%s zone=%llu all=%u", cmd,320 (unsigned long long)zone_id, cdb[14] & 1);321 322out:323 trace_seq_putc(p, 0);324 325 return ret;326}327 328static const char *329scsi_trace_atomic_write16_out(struct trace_seq *p, unsigned char *cdb, int len)330{331 const char *ret = trace_seq_buffer_ptr(p);332 unsigned int boundary_size;333 unsigned int nr_blocks;334 sector_t lba;335 336 lba = get_unaligned_be64(&cdb[2]);337 boundary_size = get_unaligned_be16(&cdb[10]);338 nr_blocks = get_unaligned_be16(&cdb[12]);339 340 trace_seq_printf(p, "lba=%llu txlen=%u boundary_size=%u",341 lba, nr_blocks, boundary_size);342 343 trace_seq_putc(p, 0);344 345 return ret;346}347 348static const char *349scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len)350{351 switch (SERVICE_ACTION32(cdb)) {352 case READ_32:353 case VERIFY_32:354 case WRITE_32:355 case WRITE_SAME_32:356 return scsi_trace_rw32(p, cdb, len);357 default:358 return scsi_trace_misc(p, cdb, len);359 }360}361 362static const char *363scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len)364{365 const char *ret = trace_seq_buffer_ptr(p);366 367 trace_seq_putc(p, '-');368 trace_seq_putc(p, 0);369 370 return ret;371}372 373const char *374scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len)375{376 switch (cdb[0]) {377 case READ_6:378 case WRITE_6:379 return scsi_trace_rw6(p, cdb, len);380 case READ_10:381 case VERIFY:382 case WRITE_10:383 case WRITE_SAME:384 return scsi_trace_rw10(p, cdb, len);385 case READ_12:386 case VERIFY_12:387 case WRITE_12:388 return scsi_trace_rw12(p, cdb, len);389 case READ_16:390 case VERIFY_16:391 case WRITE_16:392 case WRITE_SAME_16:393 return scsi_trace_rw16(p, cdb, len);394 case UNMAP:395 return scsi_trace_unmap(p, cdb, len);396 case SERVICE_ACTION_IN_16:397 return scsi_trace_service_action_in(p, cdb, len);398 case VARIABLE_LENGTH_CMD:399 return scsi_trace_varlen(p, cdb, len);400 case MAINTENANCE_IN:401 return scsi_trace_maintenance_in(p, cdb, len);402 case MAINTENANCE_OUT:403 return scsi_trace_maintenance_out(p, cdb, len);404 case ZBC_IN:405 return scsi_trace_zbc_in(p, cdb, len);406 case ZBC_OUT:407 return scsi_trace_zbc_out(p, cdb, len);408 case WRITE_ATOMIC_16:409 return scsi_trace_atomic_write16_out(p, cdb, len);410 default:411 return scsi_trace_misc(p, cdb, len);412 }413}414