Skip to content

Adding a Dtrace provider to the kernel

July 31, 2009

Since writing scsi.d I have been pondering if there should really be a scsi dtrace provider that allows you to do all that scsi.d does and more. Since the push of 6797025 that both removed the main reason for not doing this and also gave impetus to do it as scsi.d needed incompatible changes to use the new return function as the return “probe”.

This work is very much work in progress and may or may not see the light of day due to some other issues around scsi addressing, however I thought I would document how I added a kernel dtrace provider so if you want to you don’t have to do so much searching1.

Adding the probes themselves is simplicity itself using the DTRACE_PROBEN() macros. Following the convention I added this macro:

#define	DTRACE_SCSI_2(name, type1, arg1, type2, arg2)			\ 	DTRACE_PROBE2(__scsi_##name, type1, arg1, type2, arg2); 

to usr/src/uts/common/sys/sdt.h. Then after including <sys/sdt.h> in each file I put this macro in each of the places I wanted my probes:

 	DTRACE_SCSI_2(transport, struct scsi_pkt *, pkt,  	    struct scsi_address *, P_TO_ADDR(pkt)) 

The bit that took a while to find was how to turn these into a provider. To do that edit the file “usr/src/uts/common/dtrace/sdt_subr.c” and create the attribute structure2:


and add it to the sdt_providers array:

	{ "scsi", "__scsi_", &scsi_attr, 0 },

than add the probes to the sdt_args array:

 	{ "scsi", "transport", 0, 0, "struct scsi_pkt *", "scsi_pktinfo_t *"}, 	{ "scsi", "transport", 1, 1, "struct scsi_address *", "scsi_addrinfo_t *"}, 	{ "scsi", "complete", 0, 0, "struct scsi_pkt *", "scsi_pktinfo_t *"}, 	{ "scsi", "complete", 1, 1, "struct scsi_address *", "scsi_addrinfo_t *"},

Finally you need to create a file containing the definitions of the output structures, scsi_pktinfo_t and scsi_addrinfo_t and define translators for them. That goes into /usr/lib/dtrace and I called mine scsa.d (there is already one called scsi.d).

/*  * CDDL HEADER START  *  * The contents of this file are subject to the terms of the  * Common Development and Distribution License (the "License").  * You may not use this file except in compliance with the License.  *  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE  * or  * See the License for the specific language governing permissions  * and limitations under the License.  *  * When distributing Covered Code, include this CDDL HEADER in each  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.  * If applicable, add the following below this CDDL HEADER, with the  * fields enclosed by brackets "[]" replaced with your own identifying  * information: Portions Copyright [yyyy] [name of copyright owner]  *  * CDDL HEADER END  */ /*  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.  * Use is subject to license terms.  */  #pragma D depends_on module scsi #pragma D depends_on provider scsi  inline char TEST_UNIT_READY = 0x0; #pragma D binding "1.0" TEST_UNIT_READY inline char REZERO_UNIT_or_REWIND = 0x0001; #pragma D binding "1.0" REZERO_UNIT_or_REWIND  inline char SCSI_HBA_ADDR_COMPLEX = 0x0040; #pragma D binding "1.0" SCSI_HBA_ADDR_COMPLEX  typedef struct scsi_pktinfo { 	caddr_t pkt_ha_private; 	uint_t	pkt_flags; 	int	pkt_time; 	uchar_t *pkt_scbp; 	uchar_t *pkt_cdbp; 	ssize_t pkt_resid; 	uint_t	pkt_state; 	uint_t 	pkt_statistics; 	uchar_t pkt_reason; 	uint_t	pkt_cdblen; 	uint_t	pkt_tgtlen; 	uint_t	pkt_scblen; } scsi_pktinfo_t;  #pragma D binding "1.0" translator translator scsi_pktinfo_t  < struct scsi_pkt *P > { 	pkt_ha_private = P->pkt_ha_private; 	pkt_flags = P->pkt_flags; 	pkt_time = P->pkt_time; 	pkt_scbp = P->pkt_scbp; 	pkt_cdbp = P->pkt_cdbp; 	pkt_resid = P->pkt_resid; 	pkt_state = P->pkt_state; 	pkt_statistics = P->pkt_statistics; 	pkt_reason = P->pkt_reason; 	pkt_cdblen = P->pkt_cdblen; 	pkt_tgtlen = P->pkt_tgtlen; 	pkt_scblen = P->pkt_scblen; };  typedef struct scsi_addrinfo { 	struct scsi_hba_tran	*a_hba_tran; 	ushort_t a_target;	/* ua target */ 	uchar_t	 a_lun;		/* ua lun on target */ 	struct scsi_device *a_sd; } scsi_addrinfo_t;  #pragma D binding "1.0" translator translator scsi_addrinfo_t  < struct scsi_address *A > { 	a_hba_tran = A->a_hba_tran; 	a_target = !(A->a_hba_tran->tran_hba_flags & SCSI_HBA_ADDR_COMPLEX) ? 		0 : A->a.spi.a_target; 	a_lun = !(A->a_hba_tran->tran_hba_flags & SCSI_HBA_ADDR_COMPLEX) ? 		0 : A->a.spi.a_lun; 	a_sd = (A->a_hba_tran->tran_hba_flags & SCSI_HBA_ADDR_COMPLEX) ? 		A->a.a_sd : 0; };

again this is just enough to get going so I can see and use the probes:

jack@v4u-2500b-gmp03:~$ pfexec dtrace -P scsi -l    ID   PROVIDER            MODULE                          FUNCTION NAME  1303       scsi              scsi                    scsi_transport transport  1313       scsi              scsi                 scsi_hba_pkt_comp complete jack@v4u-2500b-gmp03:~$ 

While this all works well for parallel scsi getting the address of devices on fibre is not clear to me. If you have any suggestions I’m all ears.

1If there is such a document already in existence then please add a comment. I will just wish I could have found it.

2These may not be the right attributes but gets me to the point it compiles and can be used in a PoC.


From → Solaris

One Comment
  1. Chad Mynhier permalink

    Just a note: It’s best to get the D version correct in the "pragma D binding" lines in the translator file. The root cause for 6779011 ("libdtrace sometimes dumps core when running tst.1.0.d") was specifying an incorrect D version in a translator.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: