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 searching.
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 structure:
static dtrace_pattr_t scsi_attr = {
{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
};
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 http://www.opensolaris.org/os/licensing.
* 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.