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