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 25 static const char * 26 scsi_trace_misc(struct trace_seq *, unsigned char *, int); 27 28 static const char * 29 scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len) 30 { 31 const char *ret = p->buffer + p->len; 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 46 static const char * 47 scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len) 48 { 49 const char *ret = p->buffer + p->len; 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 71 static const char * 72 scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len) 73 { 74 const char *ret = p->buffer + p->len; 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 94 static const char * 95 scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) 96 { 97 const char *ret = p->buffer + p->len; 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 125 static const char * 126 scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) 127 { 128 const char *ret = p->buffer + p->len, *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_printf(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 174 out: 175 trace_seq_putc(p, 0); 176 177 return ret; 178 } 179 180 static const char * 181 scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len) 182 { 183 const char *ret = p->buffer + p->len; 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 192 static const char * 193 scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) 194 { 195 const char *ret = p->buffer + p->len, *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_printf(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 227 out: 228 trace_seq_putc(p, 0); 229 230 return ret; 231 } 232 233 static const char * 234 scsi_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 247 static const char * 248 scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len) 249 { 250 const char *ret = p->buffer + p->len; 251 252 trace_seq_printf(p, "-"); 253 trace_seq_putc(p, 0); 254 255 return ret; 256 } 257 258 const char * 259 scsi_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: 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