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