Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[SCSI] scsi_trace: Enhance SCSI command tracing

Various SCSI trace enhancements:

- Display data and protection information scatterlist lengths in the
trace output

- Add support for VERIFY and WRITE SAME commands and decode the UNMAP
bit if applicable

- Add decoding of the PROTECT field for READ/VERIFY/WRITE/WRITE SAME
commands as well as the EXPECTED INITIAL REFERENCE TAG field for
their 32-byte variants

- Decode READ CAPACITY(16), GET LBA STATUS, and UNMAP

Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>

authored by

Martin K. Petersen and committed by
James Bottomley
c446c1f9 bf816235

+136 -20
+111 -12
drivers/scsi/scsi_trace.c
··· 19 19 #include <linux/trace_seq.h> 20 20 #include <trace/events/scsi.h> 21 21 22 - #define SERVICE_ACTION(cdb) ((cdb[8] << 8) | cdb[9]) 22 + #define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f) 23 + #define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9]) 23 24 24 25 static const char * 25 26 scsi_trace_misc(struct trace_seq *, unsigned char *, int); ··· 56 55 txlen |= (cdb[7] << 8); 57 56 txlen |= cdb[8]; 58 57 59 - trace_seq_printf(p, "lba=%llu txlen=%llu", 60 - (unsigned long long)lba, (unsigned long long)txlen); 58 + trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", 59 + (unsigned long long)lba, (unsigned long long)txlen, 60 + cdb[1] >> 5); 61 61 trace_seq_putc(p, 0); 62 62 63 63 return ret; ··· 79 77 txlen |= (cdb[8] << 8); 80 78 txlen |= cdb[9]; 81 79 82 - trace_seq_printf(p, "lba=%llu txlen=%llu", 83 - (unsigned long long)lba, (unsigned long long)txlen); 80 + trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", 81 + (unsigned long long)lba, (unsigned long long)txlen, 82 + cdb[1] >> 5); 84 83 trace_seq_putc(p, 0); 85 84 86 85 return ret; ··· 106 103 txlen |= (cdb[12] << 8); 107 104 txlen |= cdb[13]; 108 105 109 - trace_seq_printf(p, "lba=%llu txlen=%llu", 110 - (unsigned long long)lba, (unsigned long long)txlen); 106 + trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", 107 + (unsigned long long)lba, (unsigned long long)txlen, 108 + cdb[1] >> 5); 109 + 110 + if (cdb[0] == WRITE_SAME_16) 111 + trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); 112 + 111 113 trace_seq_putc(p, 0); 112 114 113 115 return ret; ··· 121 113 static const char * 122 114 scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) 123 115 { 124 - const char *ret = p->buffer + p->len; 116 + const char *ret = p->buffer + p->len, *cmd; 125 117 sector_t lba = 0, txlen = 0; 118 + u32 ei_lbrt = 0; 119 + 120 + switch (SERVICE_ACTION32(cdb)) { 121 + case READ_32: 122 + cmd = "READ"; 123 + break; 124 + case VERIFY_32: 125 + cmd = "VERIFY"; 126 + break; 127 + case WRITE_32: 128 + cmd = "WRITE"; 129 + break; 130 + case WRITE_SAME_32: 131 + cmd = "WRITE_SAME"; 132 + break; 133 + default: 134 + trace_seq_printf(p, "UNKNOWN"); 135 + goto out; 136 + } 126 137 127 138 lba |= ((u64)cdb[12] << 56); 128 139 lba |= ((u64)cdb[13] << 48); ··· 151 124 lba |= (cdb[17] << 16); 152 125 lba |= (cdb[18] << 8); 153 126 lba |= cdb[19]; 127 + ei_lbrt |= (cdb[20] << 24); 128 + ei_lbrt |= (cdb[21] << 16); 129 + ei_lbrt |= (cdb[22] << 8); 130 + ei_lbrt |= cdb[23]; 154 131 txlen |= (cdb[28] << 24); 155 132 txlen |= (cdb[29] << 16); 156 133 txlen |= (cdb[30] << 8); 157 134 txlen |= cdb[31]; 158 135 159 - trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu", 160 - (SERVICE_ACTION(cdb) == READ_32 ? "READ" : "WRITE"), 161 - (unsigned long long)lba, (unsigned long long)txlen); 136 + trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u", 137 + cmd, (unsigned long long)lba, 138 + (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt); 162 139 140 + if (SERVICE_ACTION32(cdb) == WRITE_SAME_32) 141 + trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1); 142 + 143 + out: 144 + trace_seq_putc(p, 0); 145 + 146 + return ret; 147 + } 148 + 149 + static const char * 150 + scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len) 151 + { 152 + const char *ret = p->buffer + p->len; 153 + unsigned int regions = cdb[7] << 8 | cdb[8]; 154 + 155 + trace_seq_printf(p, "regions=%u", (regions - 8) / 16); 156 + trace_seq_putc(p, 0); 157 + 158 + return ret; 159 + } 160 + 161 + static const char * 162 + scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) 163 + { 164 + const char *ret = p->buffer + p->len, *cmd; 165 + sector_t lba = 0; 166 + u32 alloc_len = 0; 167 + 168 + switch (SERVICE_ACTION16(cdb)) { 169 + case SAI_READ_CAPACITY_16: 170 + cmd = "READ_CAPACITY_16"; 171 + break; 172 + case SAI_GET_LBA_STATUS: 173 + cmd = "GET_LBA_STATUS"; 174 + break; 175 + default: 176 + trace_seq_printf(p, "UNKNOWN"); 177 + goto out; 178 + } 179 + 180 + lba |= ((u64)cdb[2] << 56); 181 + lba |= ((u64)cdb[3] << 48); 182 + lba |= ((u64)cdb[4] << 40); 183 + lba |= ((u64)cdb[5] << 32); 184 + lba |= (cdb[6] << 24); 185 + lba |= (cdb[7] << 16); 186 + lba |= (cdb[8] << 8); 187 + lba |= cdb[9]; 188 + alloc_len |= (cdb[10] << 24); 189 + alloc_len |= (cdb[11] << 16); 190 + alloc_len |= (cdb[12] << 8); 191 + alloc_len |= cdb[13]; 192 + 193 + trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, 194 + (unsigned long long)lba, alloc_len); 195 + 196 + out: 163 197 trace_seq_putc(p, 0); 164 198 165 199 return ret; ··· 229 141 static const char * 230 142 scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len) 231 143 { 232 - switch (SERVICE_ACTION(cdb)) { 144 + switch (SERVICE_ACTION32(cdb)) { 233 145 case READ_32: 146 + case VERIFY_32: 234 147 case WRITE_32: 148 + case WRITE_SAME_32: 235 149 return scsi_trace_rw32(p, cdb, len); 236 150 default: 237 151 return scsi_trace_misc(p, cdb, len); ··· 259 169 case WRITE_6: 260 170 return scsi_trace_rw6(p, cdb, len); 261 171 case READ_10: 172 + case VERIFY: 262 173 case WRITE_10: 174 + case WRITE_SAME: 263 175 return scsi_trace_rw10(p, cdb, len); 264 176 case READ_12: 177 + case VERIFY_12: 265 178 case WRITE_12: 266 179 return scsi_trace_rw12(p, cdb, len); 267 180 case READ_16: 181 + case VERIFY_16: 268 182 case WRITE_16: 183 + case WRITE_SAME_16: 269 184 return scsi_trace_rw16(p, cdb, len); 185 + case UNMAP: 186 + return scsi_trace_unmap(p, cdb, len); 187 + case SERVICE_ACTION_IN: 188 + return scsi_trace_service_action_in(p, cdb, len); 270 189 case VARIABLE_LENGTH_CMD: 271 190 return scsi_trace_varlen(p, cdb, len); 272 191 default:
+25 -8
include/trace/events/scsi.h
··· 200 200 __field( unsigned int, lun ) 201 201 __field( unsigned int, opcode ) 202 202 __field( unsigned int, cmd_len ) 203 + __field( unsigned int, data_sglen ) 204 + __field( unsigned int, prot_sglen ) 203 205 __dynamic_array(unsigned char, cmnd, cmd->cmd_len) 204 206 ), 205 207 ··· 212 210 __entry->lun = cmd->device->lun; 213 211 __entry->opcode = cmd->cmnd[0]; 214 212 __entry->cmd_len = cmd->cmd_len; 213 + __entry->data_sglen = scsi_sg_count(cmd); 214 + __entry->prot_sglen = scsi_prot_sg_count(cmd); 215 215 memcpy(__get_dynamic_array(cmnd), cmd->cmnd, cmd->cmd_len); 216 216 ), 217 217 218 - TP_printk("host_no=%u channel=%u id=%u lun=%u cmnd=(%s %s raw=%s)", 218 + TP_printk("host_no=%u channel=%u id=%u lun=%u data_sgl=%u prot_sgl=%u" \ 219 + " cmnd=(%s %s raw=%s)", 219 220 __entry->host_no, __entry->channel, __entry->id, 220 - __entry->lun, show_opcode_name(__entry->opcode), 221 + __entry->lun, __entry->data_sglen, __entry->prot_sglen, 222 + show_opcode_name(__entry->opcode), 221 223 __parse_cdb(__get_dynamic_array(cmnd), __entry->cmd_len), 222 224 __print_hex(__get_dynamic_array(cmnd), __entry->cmd_len)) 223 225 ); ··· 240 234 __field( int, rtn ) 241 235 __field( unsigned int, opcode ) 242 236 __field( unsigned int, cmd_len ) 237 + __field( unsigned int, data_sglen ) 238 + __field( unsigned int, prot_sglen ) 243 239 __dynamic_array(unsigned char, cmnd, cmd->cmd_len) 244 240 ), 245 241 ··· 253 245 __entry->rtn = rtn; 254 246 __entry->opcode = cmd->cmnd[0]; 255 247 __entry->cmd_len = cmd->cmd_len; 248 + __entry->data_sglen = scsi_sg_count(cmd); 249 + __entry->prot_sglen = scsi_prot_sg_count(cmd); 256 250 memcpy(__get_dynamic_array(cmnd), cmd->cmnd, cmd->cmd_len); 257 251 ), 258 252 259 - TP_printk("host_no=%u channel=%u id=%u lun=%u cmnd=(%s %s raw=%s)" 260 - " rtn=%d", 253 + TP_printk("host_no=%u channel=%u id=%u lun=%u data_sgl=%u prot_sgl=%u" \ 254 + " cmnd=(%s %s raw=%s) rtn=%d", 261 255 __entry->host_no, __entry->channel, __entry->id, 262 - __entry->lun, show_opcode_name(__entry->opcode), 256 + __entry->lun, __entry->data_sglen, __entry->prot_sglen, 257 + show_opcode_name(__entry->opcode), 263 258 __parse_cdb(__get_dynamic_array(cmnd), __entry->cmd_len), 264 259 __print_hex(__get_dynamic_array(cmnd), __entry->cmd_len), 265 260 __entry->rtn) ··· 282 271 __field( int, result ) 283 272 __field( unsigned int, opcode ) 284 273 __field( unsigned int, cmd_len ) 274 + __field( unsigned int, data_sglen ) 275 + __field( unsigned int, prot_sglen ) 285 276 __dynamic_array(unsigned char, cmnd, cmd->cmd_len) 286 277 ), 287 278 ··· 295 282 __entry->result = cmd->result; 296 283 __entry->opcode = cmd->cmnd[0]; 297 284 __entry->cmd_len = cmd->cmd_len; 285 + __entry->data_sglen = scsi_sg_count(cmd); 286 + __entry->prot_sglen = scsi_prot_sg_count(cmd); 298 287 memcpy(__get_dynamic_array(cmnd), cmd->cmnd, cmd->cmd_len); 299 288 ), 300 289 301 - TP_printk("host_no=%u channel=%u id=%u lun=%u cmnd=(%s %s raw=%s) " 302 - "result=(driver=%s host=%s message=%s status=%s)", 290 + TP_printk("host_no=%u channel=%u id=%u lun=%u data_sgl=%u " \ 291 + "prot_sgl=%u cmnd=(%s %s raw=%s) result=(driver=%s host=%s " \ 292 + "message=%s status=%s)", 303 293 __entry->host_no, __entry->channel, __entry->id, 304 - __entry->lun, show_opcode_name(__entry->opcode), 294 + __entry->lun, __entry->data_sglen, __entry->prot_sglen, 295 + show_opcode_name(__entry->opcode), 305 296 __parse_cdb(__get_dynamic_array(cmnd), __entry->cmd_len), 306 297 __print_hex(__get_dynamic_array(cmnd), __entry->cmd_len), 307 298 show_driverbyte_name(((__entry->result) >> 24) & 0xff),