1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2010 FUJITSU LIMITED 4 * 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 14 static const char * 15 scsi_trace_misc(struct trace_seq *, unsigned char *, int); 16 17 static const char * 18 scsi_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 256 26 * 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 36 static const char * 37 scsi_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 56 static const char * 57 scsi_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 72 static const char * 73 scsi_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 93 static const char * 94 scsi_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 128 out: 129 trace_seq_putc(p, 0); 130 131 return ret; 132 } 133 134 static const char * 135 scsi_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 146 static const char * 147 scsi_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 170 out: 171 trace_seq_putc(p, 0); 172 173 return ret; 174 } 175 176 static const char * 177 scsi_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 216 out: 217 trace_seq_putc(p, 0); 218 219 return ret; 220 } 221 222 static const char * 223 scsi_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 256 out: 257 trace_seq_putc(p, 0); 258 259 return ret; 260 } 261 262 static const char * 263 scsi_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 287 out: 288 trace_seq_putc(p, 0); 289 290 return ret; 291 } 292 293 static const char * 294 scsi_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 322 out: 323 trace_seq_putc(p, 0); 324 325 return ret; 326 } 327 328 static const char * 329 scsi_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 348 static const char * 349 scsi_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 362 static const char * 363 scsi_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 373 const char * 374 scsi_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