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 <trace/events/scsi.h> 21 22#define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f) 23#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9]) 24 25static const char * 26scsi_trace_misc(struct trace_seq *, unsigned char *, int); 27 28static const char * 29scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len) 30{ 31 const char *ret = trace_seq_buffer_ptr(p); 32 sector_t lba = 0, txlen = 0; 33 34 lba |= ((cdb[1] & 0x1F) << 16); 35 lba |= (cdb[2] << 8); 36 lba |= cdb[3]; 37 txlen = cdb[4]; 38 39 trace_seq_printf(p, "lba=%llu txlen=%llu", 40 (unsigned long long)lba, (unsigned long long)txlen); 41 trace_seq_putc(p, 0); 42 43 return ret; 44} 45 46static const char * 47scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len) 48{ 49 const char *ret = trace_seq_buffer_ptr(p); 50 sector_t lba = 0, txlen = 0; 51 52 lba |= (cdb[2] << 24); 53 lba |= (cdb[3] << 16); 54 lba |= (cdb[4] << 8); 55 lba |= cdb[5]; 56 txlen |= (cdb[7] << 8); 57 txlen |= cdb[8]; 58 59 trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", 60 (unsigned long long)lba, (unsigned long long)txlen, 61 cdb[1] >> 5); 62 63 if (cdb[0] == WRITE_SAME) 64 trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); 65 66 trace_seq_putc(p, 0); 67 68 return ret; 69} 70 71static const char * 72scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len) 73{ 74 const char *ret = trace_seq_buffer_ptr(p); 75 sector_t lba = 0, txlen = 0; 76 77 lba |= (cdb[2] << 24); 78 lba |= (cdb[3] << 16); 79 lba |= (cdb[4] << 8); 80 lba |= cdb[5]; 81 txlen |= (cdb[6] << 24); 82 txlen |= (cdb[7] << 16); 83 txlen |= (cdb[8] << 8); 84 txlen |= cdb[9]; 85 86 trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", 87 (unsigned long long)lba, (unsigned long long)txlen, 88 cdb[1] >> 5); 89 trace_seq_putc(p, 0); 90 91 return ret; 92} 93 94static const char * 95scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) 96{ 97 const char *ret = trace_seq_buffer_ptr(p); 98 sector_t lba = 0, txlen = 0; 99 100 lba |= ((u64)cdb[2] << 56); 101 lba |= ((u64)cdb[3] << 48); 102 lba |= ((u64)cdb[4] << 40); 103 lba |= ((u64)cdb[5] << 32); 104 lba |= (cdb[6] << 24); 105 lba |= (cdb[7] << 16); 106 lba |= (cdb[8] << 8); 107 lba |= cdb[9]; 108 txlen |= (cdb[10] << 24); 109 txlen |= (cdb[11] << 16); 110 txlen |= (cdb[12] << 8); 111 txlen |= cdb[13]; 112 113 trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", 114 (unsigned long long)lba, (unsigned long long)txlen, 115 cdb[1] >> 5); 116 117 if (cdb[0] == WRITE_SAME_16) 118 trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); 119 120 trace_seq_putc(p, 0); 121 122 return ret; 123} 124 125static const char * 126scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) 127{ 128 const char *ret = trace_seq_buffer_ptr(p), *cmd; 129 sector_t lba = 0, txlen = 0; 130 u32 ei_lbrt = 0; 131 132 switch (SERVICE_ACTION32(cdb)) { 133 case READ_32: 134 cmd = "READ"; 135 break; 136 case VERIFY_32: 137 cmd = "VERIFY"; 138 break; 139 case WRITE_32: 140 cmd = "WRITE"; 141 break; 142 case WRITE_SAME_32: 143 cmd = "WRITE_SAME"; 144 break; 145 default: 146 trace_seq_puts(p, "UNKNOWN"); 147 goto out; 148 } 149 150 lba |= ((u64)cdb[12] << 56); 151 lba |= ((u64)cdb[13] << 48); 152 lba |= ((u64)cdb[14] << 40); 153 lba |= ((u64)cdb[15] << 32); 154 lba |= (cdb[16] << 24); 155 lba |= (cdb[17] << 16); 156 lba |= (cdb[18] << 8); 157 lba |= cdb[19]; 158 ei_lbrt |= (cdb[20] << 24); 159 ei_lbrt |= (cdb[21] << 16); 160 ei_lbrt |= (cdb[22] << 8); 161 ei_lbrt |= cdb[23]; 162 txlen |= (cdb[28] << 24); 163 txlen |= (cdb[29] << 16); 164 txlen |= (cdb[30] << 8); 165 txlen |= cdb[31]; 166 167 trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u", 168 cmd, (unsigned long long)lba, 169 (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt); 170 171 if (SERVICE_ACTION32(cdb) == WRITE_SAME_32) 172 trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1); 173 174out: 175 trace_seq_putc(p, 0); 176 177 return ret; 178} 179 180static const char * 181scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len) 182{ 183 const char *ret = trace_seq_buffer_ptr(p); 184 unsigned int regions = cdb[7] << 8 | cdb[8]; 185 186 trace_seq_printf(p, "regions=%u", (regions - 8) / 16); 187 trace_seq_putc(p, 0); 188 189 return ret; 190} 191 192static const char * 193scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) 194{ 195 const char *ret = trace_seq_buffer_ptr(p), *cmd; 196 sector_t lba = 0; 197 u32 alloc_len = 0; 198 199 switch (SERVICE_ACTION16(cdb)) { 200 case SAI_READ_CAPACITY_16: 201 cmd = "READ_CAPACITY_16"; 202 break; 203 case SAI_GET_LBA_STATUS: 204 cmd = "GET_LBA_STATUS"; 205 break; 206 default: 207 trace_seq_puts(p, "UNKNOWN"); 208 goto out; 209 } 210 211 lba |= ((u64)cdb[2] << 56); 212 lba |= ((u64)cdb[3] << 48); 213 lba |= ((u64)cdb[4] << 40); 214 lba |= ((u64)cdb[5] << 32); 215 lba |= (cdb[6] << 24); 216 lba |= (cdb[7] << 16); 217 lba |= (cdb[8] << 8); 218 lba |= cdb[9]; 219 alloc_len |= (cdb[10] << 24); 220 alloc_len |= (cdb[11] << 16); 221 alloc_len |= (cdb[12] << 8); 222 alloc_len |= cdb[13]; 223 224 trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, 225 (unsigned long long)lba, alloc_len); 226 227out: 228 trace_seq_putc(p, 0); 229 230 return ret; 231} 232 233static const char * 234scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len) 235{ 236 switch (SERVICE_ACTION32(cdb)) { 237 case READ_32: 238 case VERIFY_32: 239 case WRITE_32: 240 case WRITE_SAME_32: 241 return scsi_trace_rw32(p, cdb, len); 242 default: 243 return scsi_trace_misc(p, cdb, len); 244 } 245} 246 247static const char * 248scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len) 249{ 250 const char *ret = trace_seq_buffer_ptr(p); 251 252 trace_seq_putc(p, '-'); 253 trace_seq_putc(p, 0); 254 255 return ret; 256} 257 258const char * 259scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len) 260{ 261 switch (cdb[0]) { 262 case READ_6: 263 case WRITE_6: 264 return scsi_trace_rw6(p, cdb, len); 265 case READ_10: 266 case VERIFY: 267 case WRITE_10: 268 case WRITE_SAME: 269 return scsi_trace_rw10(p, cdb, len); 270 case READ_12: 271 case VERIFY_12: 272 case WRITE_12: 273 return scsi_trace_rw12(p, cdb, len); 274 case READ_16: 275 case VERIFY_16: 276 case WRITE_16: 277 case WRITE_SAME_16: 278 return scsi_trace_rw16(p, cdb, len); 279 case UNMAP: 280 return scsi_trace_unmap(p, cdb, len); 281 case SERVICE_ACTION_IN_16: 282 return scsi_trace_service_action_in(p, cdb, len); 283 case VARIABLE_LENGTH_CMD: 284 return scsi_trace_varlen(p, cdb, len); 285 default: 286 return scsi_trace_misc(p, cdb, len); 287 } 288} 289