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