1*11304SJanie.Lu@Sun.COM /*
2*11304SJanie.Lu@Sun.COM * CDDL HEADER START
3*11304SJanie.Lu@Sun.COM *
4*11304SJanie.Lu@Sun.COM * The contents of this file are subject to the terms of the
5*11304SJanie.Lu@Sun.COM * Common Development and Distribution License (the "License").
6*11304SJanie.Lu@Sun.COM * You may not use this file except in compliance with the License.
7*11304SJanie.Lu@Sun.COM *
8*11304SJanie.Lu@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*11304SJanie.Lu@Sun.COM * or http://www.opensolaris.org/os/licensing.
10*11304SJanie.Lu@Sun.COM * See the License for the specific language governing permissions
11*11304SJanie.Lu@Sun.COM * and limitations under the License.
12*11304SJanie.Lu@Sun.COM *
13*11304SJanie.Lu@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
14*11304SJanie.Lu@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*11304SJanie.Lu@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
16*11304SJanie.Lu@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
17*11304SJanie.Lu@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
18*11304SJanie.Lu@Sun.COM *
19*11304SJanie.Lu@Sun.COM * CDDL HEADER END
20*11304SJanie.Lu@Sun.COM */
21*11304SJanie.Lu@Sun.COM
22*11304SJanie.Lu@Sun.COM /*
23*11304SJanie.Lu@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24*11304SJanie.Lu@Sun.COM * Use is subject to license terms.
25*11304SJanie.Lu@Sun.COM */
26*11304SJanie.Lu@Sun.COM
27*11304SJanie.Lu@Sun.COM /*
28*11304SJanie.Lu@Sun.COM * IO Performance Counter Driver
29*11304SJanie.Lu@Sun.COM */
30*11304SJanie.Lu@Sun.COM
31*11304SJanie.Lu@Sun.COM #include <sys/types.h>
32*11304SJanie.Lu@Sun.COM #include <sys/ddi.h>
33*11304SJanie.Lu@Sun.COM #include <sys/modctl.h>
34*11304SJanie.Lu@Sun.COM #include "iospc.h"
35*11304SJanie.Lu@Sun.COM
36*11304SJanie.Lu@Sun.COM /* Debugging level. */
37*11304SJanie.Lu@Sun.COM #ifdef DEBUG
38*11304SJanie.Lu@Sun.COM int iospc_debug = 0;
39*11304SJanie.Lu@Sun.COM #endif /* DEBUG */
40*11304SJanie.Lu@Sun.COM
41*11304SJanie.Lu@Sun.COM /* State structure anchor. */
42*11304SJanie.Lu@Sun.COM void *iospc_state_p;
43*11304SJanie.Lu@Sun.COM
44*11304SJanie.Lu@Sun.COM static int iospc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
45*11304SJanie.Lu@Sun.COM static int iospc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
46*11304SJanie.Lu@Sun.COM static int iospc_create_name_kstat(iospc_grp_t *grp);
47*11304SJanie.Lu@Sun.COM static void iospc_delete_name_kstats(kstat_t **name_kstats_pp,
48*11304SJanie.Lu@Sun.COM int num_kstats);
49*11304SJanie.Lu@Sun.COM static kstat_t *iospc_create_cntr_kstat(char *name, int dev_inst,
50*11304SJanie.Lu@Sun.COM int (*update)(kstat_t *, int), iospc_ksinfo_t *ksinfop, int num_pics);
51*11304SJanie.Lu@Sun.COM static int iospc_kstat_update(kstat_t *ksp, int rw);
52*11304SJanie.Lu@Sun.COM static kstat_t *iospc_create_picN_kstat(char *mod_name, int pic,
53*11304SJanie.Lu@Sun.COM uint64_t mask, int num_ev, iospc_event_t *ev_array);
54*11304SJanie.Lu@Sun.COM
55*11304SJanie.Lu@Sun.COM iospc_grp_t **iospc_leaf_grps = NULL;
56*11304SJanie.Lu@Sun.COM int iospc_kstat_inited = 0;
57*11304SJanie.Lu@Sun.COM kmutex_t iospc_mutex;
58*11304SJanie.Lu@Sun.COM
59*11304SJanie.Lu@Sun.COM static struct dev_ops iospc_ops = {
60*11304SJanie.Lu@Sun.COM DEVO_REV,
61*11304SJanie.Lu@Sun.COM 0,
62*11304SJanie.Lu@Sun.COM nulldev,
63*11304SJanie.Lu@Sun.COM nulldev,
64*11304SJanie.Lu@Sun.COM nulldev,
65*11304SJanie.Lu@Sun.COM iospc_attach,
66*11304SJanie.Lu@Sun.COM iospc_detach,
67*11304SJanie.Lu@Sun.COM nodev,
68*11304SJanie.Lu@Sun.COM NULL,
69*11304SJanie.Lu@Sun.COM NULL,
70*11304SJanie.Lu@Sun.COM nodev
71*11304SJanie.Lu@Sun.COM };
72*11304SJanie.Lu@Sun.COM
73*11304SJanie.Lu@Sun.COM extern struct mod_ops mod_driverops;
74*11304SJanie.Lu@Sun.COM
75*11304SJanie.Lu@Sun.COM static struct modldrv md = {
76*11304SJanie.Lu@Sun.COM &mod_driverops,
77*11304SJanie.Lu@Sun.COM "IO Perf Counter Driver",
78*11304SJanie.Lu@Sun.COM &iospc_ops,
79*11304SJanie.Lu@Sun.COM };
80*11304SJanie.Lu@Sun.COM
81*11304SJanie.Lu@Sun.COM static struct modlinkage ml = {
82*11304SJanie.Lu@Sun.COM MODREV_1,
83*11304SJanie.Lu@Sun.COM (void *)&md,
84*11304SJanie.Lu@Sun.COM NULL
85*11304SJanie.Lu@Sun.COM };
86*11304SJanie.Lu@Sun.COM
87*11304SJanie.Lu@Sun.COM /*
88*11304SJanie.Lu@Sun.COM * One-time module-wide initialization.
89*11304SJanie.Lu@Sun.COM */
90*11304SJanie.Lu@Sun.COM int
_init(void)91*11304SJanie.Lu@Sun.COM _init(void)
92*11304SJanie.Lu@Sun.COM {
93*11304SJanie.Lu@Sun.COM int rval;
94*11304SJanie.Lu@Sun.COM
95*11304SJanie.Lu@Sun.COM /* Initialize per-leaf soft state pointer. */
96*11304SJanie.Lu@Sun.COM if ((rval = ddi_soft_state_init(&iospc_state_p,
97*11304SJanie.Lu@Sun.COM sizeof (iospc_t), 1)) != DDI_SUCCESS)
98*11304SJanie.Lu@Sun.COM return (rval);
99*11304SJanie.Lu@Sun.COM
100*11304SJanie.Lu@Sun.COM /* If all checks out, install the module. */
101*11304SJanie.Lu@Sun.COM if ((rval = mod_install(&ml)) != DDI_SUCCESS) {
102*11304SJanie.Lu@Sun.COM ddi_soft_state_fini(&iospc_state_p);
103*11304SJanie.Lu@Sun.COM return (rval);
104*11304SJanie.Lu@Sun.COM }
105*11304SJanie.Lu@Sun.COM mutex_init(&iospc_mutex, NULL, MUTEX_DRIVER, NULL);
106*11304SJanie.Lu@Sun.COM return (DDI_SUCCESS);
107*11304SJanie.Lu@Sun.COM }
108*11304SJanie.Lu@Sun.COM
109*11304SJanie.Lu@Sun.COM /*
110*11304SJanie.Lu@Sun.COM * One-time module-wide cleanup, after last detach is done.
111*11304SJanie.Lu@Sun.COM */
112*11304SJanie.Lu@Sun.COM int
_fini(void)113*11304SJanie.Lu@Sun.COM _fini(void)
114*11304SJanie.Lu@Sun.COM {
115*11304SJanie.Lu@Sun.COM int rval;
116*11304SJanie.Lu@Sun.COM
117*11304SJanie.Lu@Sun.COM /*
118*11304SJanie.Lu@Sun.COM * Remove the module first as this operation is the only thing here
119*11304SJanie.Lu@Sun.COM * which can fail.
120*11304SJanie.Lu@Sun.COM */
121*11304SJanie.Lu@Sun.COM rval = mod_remove(&ml);
122*11304SJanie.Lu@Sun.COM if (rval != DDI_SUCCESS)
123*11304SJanie.Lu@Sun.COM return (rval);
124*11304SJanie.Lu@Sun.COM
125*11304SJanie.Lu@Sun.COM if (iospc_leaf_grps != NULL) {
126*11304SJanie.Lu@Sun.COM iospc_kstat_fini();
127*11304SJanie.Lu@Sun.COM mutex_enter(&iospc_mutex);
128*11304SJanie.Lu@Sun.COM iospc_kstat_inited = 0;
129*11304SJanie.Lu@Sun.COM (void) rfios_unbind_group();
130*11304SJanie.Lu@Sun.COM iospc_leaf_grps = NULL;
131*11304SJanie.Lu@Sun.COM mutex_exit(&iospc_mutex);
132*11304SJanie.Lu@Sun.COM }
133*11304SJanie.Lu@Sun.COM
134*11304SJanie.Lu@Sun.COM mutex_destroy(&iospc_mutex);
135*11304SJanie.Lu@Sun.COM
136*11304SJanie.Lu@Sun.COM /* Free px soft state */
137*11304SJanie.Lu@Sun.COM ddi_soft_state_fini(&iospc_state_p);
138*11304SJanie.Lu@Sun.COM
139*11304SJanie.Lu@Sun.COM return (DDI_SUCCESS);
140*11304SJanie.Lu@Sun.COM }
141*11304SJanie.Lu@Sun.COM
142*11304SJanie.Lu@Sun.COM int
_info(struct modinfo * modinfop)143*11304SJanie.Lu@Sun.COM _info(struct modinfo *modinfop)
144*11304SJanie.Lu@Sun.COM {
145*11304SJanie.Lu@Sun.COM return (mod_info(&ml, modinfop));
146*11304SJanie.Lu@Sun.COM }
147*11304SJanie.Lu@Sun.COM
148*11304SJanie.Lu@Sun.COM /*
149*11304SJanie.Lu@Sun.COM * Per-instance initialization. Suspend/resume not supported.
150*11304SJanie.Lu@Sun.COM */
151*11304SJanie.Lu@Sun.COM static int
iospc_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)152*11304SJanie.Lu@Sun.COM iospc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
153*11304SJanie.Lu@Sun.COM {
154*11304SJanie.Lu@Sun.COM iospc_t *iospc_p;
155*11304SJanie.Lu@Sun.COM int instance = ddi_get_instance(dip);
156*11304SJanie.Lu@Sun.COM char *ptr;
157*11304SJanie.Lu@Sun.COM
158*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc: iospc_attach: enter\n");
159*11304SJanie.Lu@Sun.COM switch (cmd) {
160*11304SJanie.Lu@Sun.COM case DDI_RESUME:
161*11304SJanie.Lu@Sun.COM case DDI_ATTACH:
162*11304SJanie.Lu@Sun.COM /* Initialize one-time kstat structures. */
163*11304SJanie.Lu@Sun.COM mutex_enter(&iospc_mutex);
164*11304SJanie.Lu@Sun.COM if (!iospc_kstat_inited) {
165*11304SJanie.Lu@Sun.COM if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
166*11304SJanie.Lu@Sun.COM 0, "compatible", &ptr)) != DDI_PROP_SUCCESS)
167*11304SJanie.Lu@Sun.COM goto bad_property;
168*11304SJanie.Lu@Sun.COM
169*11304SJanie.Lu@Sun.COM if ((strcmp(ptr, "SUNW,ktios-pr") == 0) ||
170*11304SJanie.Lu@Sun.COM (strcmp(ptr, "SUNW,rfios-pr") == 0)) {
171*11304SJanie.Lu@Sun.COM iospc_leaf_grps = rfios_bind_group();
172*11304SJanie.Lu@Sun.COM } else {
173*11304SJanie.Lu@Sun.COM ddi_prop_free(ptr);
174*11304SJanie.Lu@Sun.COM goto bad_property;
175*11304SJanie.Lu@Sun.COM }
176*11304SJanie.Lu@Sun.COM
177*11304SJanie.Lu@Sun.COM ddi_prop_free(ptr);
178*11304SJanie.Lu@Sun.COM
179*11304SJanie.Lu@Sun.COM if (iospc_kstat_init() != DDI_SUCCESS)
180*11304SJanie.Lu@Sun.COM goto bad_kstat_init;
181*11304SJanie.Lu@Sun.COM
182*11304SJanie.Lu@Sun.COM iospc_kstat_inited++;
183*11304SJanie.Lu@Sun.COM }
184*11304SJanie.Lu@Sun.COM mutex_exit(&iospc_mutex);
185*11304SJanie.Lu@Sun.COM
186*11304SJanie.Lu@Sun.COM if (ddi_soft_state_zalloc(iospc_state_p, instance) !=
187*11304SJanie.Lu@Sun.COM DDI_SUCCESS) {
188*11304SJanie.Lu@Sun.COM goto bad_softstate;
189*11304SJanie.Lu@Sun.COM }
190*11304SJanie.Lu@Sun.COM
191*11304SJanie.Lu@Sun.COM iospc_p = (iospc_t *)ddi_get_soft_state(iospc_state_p,
192*11304SJanie.Lu@Sun.COM instance);
193*11304SJanie.Lu@Sun.COM
194*11304SJanie.Lu@Sun.COM iospc_p->iospc_dip = dip;
195*11304SJanie.Lu@Sun.COM
196*11304SJanie.Lu@Sun.COM /* Set up kstats. */
197*11304SJanie.Lu@Sun.COM
198*11304SJanie.Lu@Sun.COM if (iospc_kstat_attach(iospc_p) != DDI_SUCCESS)
199*11304SJanie.Lu@Sun.COM goto bad_kstat_attach;
200*11304SJanie.Lu@Sun.COM
201*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc: iospc_attach: exit SUCCESS\n");
202*11304SJanie.Lu@Sun.COM
203*11304SJanie.Lu@Sun.COM return (DDI_SUCCESS);
204*11304SJanie.Lu@Sun.COM
205*11304SJanie.Lu@Sun.COM bad_kstat_attach:
206*11304SJanie.Lu@Sun.COM (void) ddi_soft_state_free(iospc_state_p, instance);
207*11304SJanie.Lu@Sun.COM bad_softstate:
208*11304SJanie.Lu@Sun.COM iospc_kstat_fini();
209*11304SJanie.Lu@Sun.COM bad_kstat_init:
210*11304SJanie.Lu@Sun.COM bad_property:
211*11304SJanie.Lu@Sun.COM mutex_enter(&iospc_mutex);
212*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc: iospc_attach: exit FAILURE\n");
213*11304SJanie.Lu@Sun.COM return (DDI_FAILURE);
214*11304SJanie.Lu@Sun.COM
215*11304SJanie.Lu@Sun.COM default:
216*11304SJanie.Lu@Sun.COM return (DDI_FAILURE);
217*11304SJanie.Lu@Sun.COM }
218*11304SJanie.Lu@Sun.COM }
219*11304SJanie.Lu@Sun.COM
220*11304SJanie.Lu@Sun.COM /*
221*11304SJanie.Lu@Sun.COM * Per-instance cleanup. Suspend/resume not supported.
222*11304SJanie.Lu@Sun.COM */
223*11304SJanie.Lu@Sun.COM static int
iospc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)224*11304SJanie.Lu@Sun.COM iospc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
225*11304SJanie.Lu@Sun.COM {
226*11304SJanie.Lu@Sun.COM int instance = ddi_get_instance(dip);
227*11304SJanie.Lu@Sun.COM
228*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc: iospc_detach: enter\n");
229*11304SJanie.Lu@Sun.COM iospc_t *iospc_p = (iospc_t *)ddi_get_soft_state(
230*11304SJanie.Lu@Sun.COM iospc_state_p, instance);
231*11304SJanie.Lu@Sun.COM
232*11304SJanie.Lu@Sun.COM switch (cmd) {
233*11304SJanie.Lu@Sun.COM case DDI_SUSPEND:
234*11304SJanie.Lu@Sun.COM case DDI_DETACH:
235*11304SJanie.Lu@Sun.COM iospc_kstat_detach(iospc_p);
236*11304SJanie.Lu@Sun.COM (void) ddi_soft_state_free(iospc_state_p, instance);
237*11304SJanie.Lu@Sun.COM
238*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc: iospc_detach: exit - SUCCESS\n");
239*11304SJanie.Lu@Sun.COM return (DDI_SUCCESS);
240*11304SJanie.Lu@Sun.COM
241*11304SJanie.Lu@Sun.COM default:
242*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc: iospc_detach: exit - FAILURE\n");
243*11304SJanie.Lu@Sun.COM return (DDI_FAILURE);
244*11304SJanie.Lu@Sun.COM }
245*11304SJanie.Lu@Sun.COM }
246*11304SJanie.Lu@Sun.COM
247*11304SJanie.Lu@Sun.COM #define PIC_STR_LEN 5 /* Size of a PICx name string. */
248*11304SJanie.Lu@Sun.COM
249*11304SJanie.Lu@Sun.COM /*
250*11304SJanie.Lu@Sun.COM * One-time initialization for this module.
251*11304SJanie.Lu@Sun.COM */
252*11304SJanie.Lu@Sun.COM int
iospc_kstat_init()253*11304SJanie.Lu@Sun.COM iospc_kstat_init()
254*11304SJanie.Lu@Sun.COM {
255*11304SJanie.Lu@Sun.COM iospc_grp_t **grp_pp;
256*11304SJanie.Lu@Sun.COM iospc_grp_t *grp_p;
257*11304SJanie.Lu@Sun.COM
258*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc: kstat_init: enter\n");
259*11304SJanie.Lu@Sun.COM
260*11304SJanie.Lu@Sun.COM /*
261*11304SJanie.Lu@Sun.COM * Initialize the name kstats for each group, drawing upon the table
262*11304SJanie.Lu@Sun.COM * for values.
263*11304SJanie.Lu@Sun.COM */
264*11304SJanie.Lu@Sun.COM for (grp_pp = iospc_leaf_grps; *grp_pp != NULL; grp_pp++) {
265*11304SJanie.Lu@Sun.COM
266*11304SJanie.Lu@Sun.COM grp_p = *grp_pp;
267*11304SJanie.Lu@Sun.COM
268*11304SJanie.Lu@Sun.COM IOSPC_DBG2("Setting up group for %s\n", grp_p->grp_name);
269*11304SJanie.Lu@Sun.COM
270*11304SJanie.Lu@Sun.COM /* Create basic pic event-type pair. */
271*11304SJanie.Lu@Sun.COM grp_p->name_kstats_pp = kmem_zalloc((grp_p->num_counters *
272*11304SJanie.Lu@Sun.COM sizeof (kstat_t)), KM_SLEEP);
273*11304SJanie.Lu@Sun.COM if (iospc_create_name_kstat(grp_p) != DDI_SUCCESS) {
274*11304SJanie.Lu@Sun.COM iospc_kstat_fini();
275*11304SJanie.Lu@Sun.COM IOSPC_DBG1("iospc: init: failure exit\n");
276*11304SJanie.Lu@Sun.COM return (DDI_FAILURE);
277*11304SJanie.Lu@Sun.COM }
278*11304SJanie.Lu@Sun.COM }
279*11304SJanie.Lu@Sun.COM
280*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc: kstat_init: success exit\n");
281*11304SJanie.Lu@Sun.COM
282*11304SJanie.Lu@Sun.COM return (DDI_SUCCESS);
283*11304SJanie.Lu@Sun.COM }
284*11304SJanie.Lu@Sun.COM
285*11304SJanie.Lu@Sun.COM /*
286*11304SJanie.Lu@Sun.COM * Per-instance initialization for this module.
287*11304SJanie.Lu@Sun.COM */
288*11304SJanie.Lu@Sun.COM int
iospc_kstat_attach(iospc_t * iospc_p)289*11304SJanie.Lu@Sun.COM iospc_kstat_attach(iospc_t *iospc_p)
290*11304SJanie.Lu@Sun.COM {
291*11304SJanie.Lu@Sun.COM iospc_grp_t **grp_pp;
292*11304SJanie.Lu@Sun.COM iospc_grp_t *grp_p;
293*11304SJanie.Lu@Sun.COM iospc_ksinfo_t *ksinfo_p;
294*11304SJanie.Lu@Sun.COM
295*11304SJanie.Lu@Sun.COM int i;
296*11304SJanie.Lu@Sun.COM
297*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc: kstat_attach %d: enter\n",
298*11304SJanie.Lu@Sun.COM ddi_get_instance(iospc_p->iospc_dip));
299*11304SJanie.Lu@Sun.COM
300*11304SJanie.Lu@Sun.COM /* Set up kstats for each group. */
301*11304SJanie.Lu@Sun.COM for (i = 0, grp_pp = iospc_leaf_grps; *grp_pp != NULL; i++, grp_pp++) {
302*11304SJanie.Lu@Sun.COM
303*11304SJanie.Lu@Sun.COM if (i >= IOSPC_MAX_NUM_GRPS)
304*11304SJanie.Lu@Sun.COM goto err;
305*11304SJanie.Lu@Sun.COM
306*11304SJanie.Lu@Sun.COM grp_p = *grp_pp;
307*11304SJanie.Lu@Sun.COM
308*11304SJanie.Lu@Sun.COM /*
309*11304SJanie.Lu@Sun.COM * ksinfo_p keeps all info needed by iospc_kstat_update,
310*11304SJanie.Lu@Sun.COM * which is fired off asynchronously on demand by the kstat
311*11304SJanie.Lu@Sun.COM * framework.
312*11304SJanie.Lu@Sun.COM */
313*11304SJanie.Lu@Sun.COM ksinfo_p = (iospc_ksinfo_t *)kmem_zalloc(
314*11304SJanie.Lu@Sun.COM sizeof (iospc_ksinfo_t), KM_SLEEP);
315*11304SJanie.Lu@Sun.COM
316*11304SJanie.Lu@Sun.COM ksinfo_p->iospc_p = iospc_p;
317*11304SJanie.Lu@Sun.COM ksinfo_p->grp_p = grp_p;
318*11304SJanie.Lu@Sun.COM
319*11304SJanie.Lu@Sun.COM /* Also save in state structure, for later cleanup. */
320*11304SJanie.Lu@Sun.COM iospc_p->iospc_ksinfo_p[i] = ksinfo_p;
321*11304SJanie.Lu@Sun.COM
322*11304SJanie.Lu@Sun.COM /* Create counter kstats */
323*11304SJanie.Lu@Sun.COM ksinfo_p->cntr_ksp = iospc_create_cntr_kstat(grp_p->grp_name,
324*11304SJanie.Lu@Sun.COM ddi_get_instance(iospc_p->iospc_dip),
325*11304SJanie.Lu@Sun.COM iospc_kstat_update, ksinfo_p, grp_p->num_counters);
326*11304SJanie.Lu@Sun.COM
327*11304SJanie.Lu@Sun.COM if (ksinfo_p->cntr_ksp == NULL)
328*11304SJanie.Lu@Sun.COM goto err;
329*11304SJanie.Lu@Sun.COM
330*11304SJanie.Lu@Sun.COM if (grp_p->access_init(iospc_p, ksinfo_p) != SUCCESS)
331*11304SJanie.Lu@Sun.COM goto err;
332*11304SJanie.Lu@Sun.COM }
333*11304SJanie.Lu@Sun.COM
334*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc: kstat_attach: success exit\n");
335*11304SJanie.Lu@Sun.COM return (DDI_SUCCESS);
336*11304SJanie.Lu@Sun.COM err:
337*11304SJanie.Lu@Sun.COM iospc_kstat_detach(iospc_p);
338*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc: kstat_attach: failure exit\n");
339*11304SJanie.Lu@Sun.COM return (DDI_FAILURE);
340*11304SJanie.Lu@Sun.COM }
341*11304SJanie.Lu@Sun.COM
342*11304SJanie.Lu@Sun.COM /*
343*11304SJanie.Lu@Sun.COM * Create the name kstats for each group.
344*11304SJanie.Lu@Sun.COM */
345*11304SJanie.Lu@Sun.COM static int
iospc_create_name_kstat(iospc_grp_t * grp_p)346*11304SJanie.Lu@Sun.COM iospc_create_name_kstat(iospc_grp_t *grp_p)
347*11304SJanie.Lu@Sun.COM {
348*11304SJanie.Lu@Sun.COM int i;
349*11304SJanie.Lu@Sun.COM
350*11304SJanie.Lu@Sun.COM for (i = 0; i < grp_p->num_counters; i++) {
351*11304SJanie.Lu@Sun.COM grp_p->name_kstats_pp[i] = iospc_create_picN_kstat(
352*11304SJanie.Lu@Sun.COM grp_p->grp_name, i,
353*11304SJanie.Lu@Sun.COM grp_p->regsel_p->fields_p[i].event_offset,
354*11304SJanie.Lu@Sun.COM grp_p->regsel_p->fields_p[i].num_events,
355*11304SJanie.Lu@Sun.COM grp_p->regsel_p->fields_p[i].events_p);
356*11304SJanie.Lu@Sun.COM
357*11304SJanie.Lu@Sun.COM if (grp_p->name_kstats_pp[i] == NULL)
358*11304SJanie.Lu@Sun.COM return (DDI_FAILURE);
359*11304SJanie.Lu@Sun.COM }
360*11304SJanie.Lu@Sun.COM return (DDI_SUCCESS);
361*11304SJanie.Lu@Sun.COM }
362*11304SJanie.Lu@Sun.COM
363*11304SJanie.Lu@Sun.COM /*
364*11304SJanie.Lu@Sun.COM * Create the picN kstat. Returns a pointer to the
365*11304SJanie.Lu@Sun.COM * kstat which the driver must store to allow it
366*11304SJanie.Lu@Sun.COM * to be deleted when necessary.
367*11304SJanie.Lu@Sun.COM */
368*11304SJanie.Lu@Sun.COM static kstat_t *
iospc_create_picN_kstat(char * mod_name,int pic,uint64_t ev_offset,int num_ev,iospc_event_t * ev_array)369*11304SJanie.Lu@Sun.COM iospc_create_picN_kstat(char *mod_name, int pic, uint64_t ev_offset,
370*11304SJanie.Lu@Sun.COM int num_ev, iospc_event_t *ev_array)
371*11304SJanie.Lu@Sun.COM {
372*11304SJanie.Lu@Sun.COM int event;
373*11304SJanie.Lu@Sun.COM char pic_name[PIC_STR_LEN];
374*11304SJanie.Lu@Sun.COM kstat_t *picN_ksp = NULL;
375*11304SJanie.Lu@Sun.COM struct kstat_named *pic_named_data;
376*11304SJanie.Lu@Sun.COM
377*11304SJanie.Lu@Sun.COM (void) snprintf(pic_name, PIC_STR_LEN, "pic%1d", pic);
378*11304SJanie.Lu@Sun.COM
379*11304SJanie.Lu@Sun.COM if ((picN_ksp = kstat_create(mod_name, 0, pic_name,
380*11304SJanie.Lu@Sun.COM "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) {
381*11304SJanie.Lu@Sun.COM return (NULL);
382*11304SJanie.Lu@Sun.COM }
383*11304SJanie.Lu@Sun.COM
384*11304SJanie.Lu@Sun.COM /* NOTE: Number of events is assumed to always be non-zero. */
385*11304SJanie.Lu@Sun.COM
386*11304SJanie.Lu@Sun.COM pic_named_data = (struct kstat_named *)picN_ksp->ks_data;
387*11304SJanie.Lu@Sun.COM
388*11304SJanie.Lu@Sun.COM /*
389*11304SJanie.Lu@Sun.COM * Fill up data section of the kstat
390*11304SJanie.Lu@Sun.COM * Write event names and their associated pcr masks.
391*11304SJanie.Lu@Sun.COM * num_ev - 1 is because CLEAR_PIC is added separately.
392*11304SJanie.Lu@Sun.COM */
393*11304SJanie.Lu@Sun.COM for (event = 0; event < num_ev - 1; event++) {
394*11304SJanie.Lu@Sun.COM pic_named_data[event].value.ui64 =
395*11304SJanie.Lu@Sun.COM ev_array[event].value << ev_offset;
396*11304SJanie.Lu@Sun.COM
397*11304SJanie.Lu@Sun.COM kstat_named_init(&pic_named_data[event],
398*11304SJanie.Lu@Sun.COM ev_array[event].name, KSTAT_DATA_UINT64);
399*11304SJanie.Lu@Sun.COM }
400*11304SJanie.Lu@Sun.COM
401*11304SJanie.Lu@Sun.COM /*
402*11304SJanie.Lu@Sun.COM * add the clear_pic entry
403*11304SJanie.Lu@Sun.COM */
404*11304SJanie.Lu@Sun.COM pic_named_data[event].value.ui64 =
405*11304SJanie.Lu@Sun.COM (uint64_t)~(ev_array[event].value << ev_offset);
406*11304SJanie.Lu@Sun.COM
407*11304SJanie.Lu@Sun.COM kstat_named_init(&pic_named_data[event], ev_array[event].name,
408*11304SJanie.Lu@Sun.COM KSTAT_DATA_UINT64);
409*11304SJanie.Lu@Sun.COM
410*11304SJanie.Lu@Sun.COM kstat_install(picN_ksp);
411*11304SJanie.Lu@Sun.COM
412*11304SJanie.Lu@Sun.COM return (picN_ksp);
413*11304SJanie.Lu@Sun.COM }
414*11304SJanie.Lu@Sun.COM
415*11304SJanie.Lu@Sun.COM /*
416*11304SJanie.Lu@Sun.COM * Create the "counters" kstat.
417*11304SJanie.Lu@Sun.COM */
418*11304SJanie.Lu@Sun.COM static kstat_t *
iospc_create_cntr_kstat(char * name,int dev_inst,int (* update)(kstat_t *,int),iospc_ksinfo_t * ksinfop,int num_pics)419*11304SJanie.Lu@Sun.COM iospc_create_cntr_kstat(char *name, int dev_inst,
420*11304SJanie.Lu@Sun.COM int (*update)(kstat_t *, int), iospc_ksinfo_t *ksinfop, int num_pics)
421*11304SJanie.Lu@Sun.COM {
422*11304SJanie.Lu@Sun.COM int i;
423*11304SJanie.Lu@Sun.COM char pic_str[PIC_STR_LEN];
424*11304SJanie.Lu@Sun.COM struct kstat *counters_ksp;
425*11304SJanie.Lu@Sun.COM struct kstat_named *counters_named_data;
426*11304SJanie.Lu@Sun.COM
427*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc_create_cntr_kstat: name: %s instance: %d\n",
428*11304SJanie.Lu@Sun.COM name, dev_inst);
429*11304SJanie.Lu@Sun.COM
430*11304SJanie.Lu@Sun.COM /*
431*11304SJanie.Lu@Sun.COM * Size of kstat is num_pics + 1. extra one for pcr.
432*11304SJanie.Lu@Sun.COM */
433*11304SJanie.Lu@Sun.COM
434*11304SJanie.Lu@Sun.COM if ((counters_ksp = kstat_create(name, dev_inst, "counters", "bus",
435*11304SJanie.Lu@Sun.COM KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) {
436*11304SJanie.Lu@Sun.COM return (NULL);
437*11304SJanie.Lu@Sun.COM }
438*11304SJanie.Lu@Sun.COM
439*11304SJanie.Lu@Sun.COM counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
440*11304SJanie.Lu@Sun.COM kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
441*11304SJanie.Lu@Sun.COM
442*11304SJanie.Lu@Sun.COM for (i = 0; i < num_pics; i++) {
443*11304SJanie.Lu@Sun.COM (void) snprintf(pic_str, PIC_STR_LEN, "pic%1d", i);
444*11304SJanie.Lu@Sun.COM
445*11304SJanie.Lu@Sun.COM kstat_named_init(&counters_named_data[i+1], pic_str,
446*11304SJanie.Lu@Sun.COM KSTAT_DATA_UINT64);
447*11304SJanie.Lu@Sun.COM }
448*11304SJanie.Lu@Sun.COM
449*11304SJanie.Lu@Sun.COM /*
450*11304SJanie.Lu@Sun.COM * Store the reg type and other info. in the kstat's private field
451*11304SJanie.Lu@Sun.COM * so that they are available to the update function.
452*11304SJanie.Lu@Sun.COM */
453*11304SJanie.Lu@Sun.COM counters_ksp->ks_private = (void *)ksinfop;
454*11304SJanie.Lu@Sun.COM counters_ksp->ks_update = update;
455*11304SJanie.Lu@Sun.COM
456*11304SJanie.Lu@Sun.COM kstat_install(counters_ksp);
457*11304SJanie.Lu@Sun.COM
458*11304SJanie.Lu@Sun.COM return (counters_ksp);
459*11304SJanie.Lu@Sun.COM }
460*11304SJanie.Lu@Sun.COM
461*11304SJanie.Lu@Sun.COM /*
462*11304SJanie.Lu@Sun.COM * Program a performance counter.
463*11304SJanie.Lu@Sun.COM *
464*11304SJanie.Lu@Sun.COM * reggroup is which type of counter.
465*11304SJanie.Lu@Sun.COM * counter is the counter number.
466*11304SJanie.Lu@Sun.COM * event is the event to program for that counter.
467*11304SJanie.Lu@Sun.COM */
468*11304SJanie.Lu@Sun.COM static int
iospc_perfcnt_program(iospc_t * iospc_p,iospc_grp_t * grp_p,iospc_ksinfo_t * ksinfo_p,uint64_t new_events)469*11304SJanie.Lu@Sun.COM iospc_perfcnt_program(iospc_t *iospc_p, iospc_grp_t *grp_p,
470*11304SJanie.Lu@Sun.COM iospc_ksinfo_t *ksinfo_p, uint64_t new_events)
471*11304SJanie.Lu@Sun.COM {
472*11304SJanie.Lu@Sun.COM uint64_t old_events;
473*11304SJanie.Lu@Sun.COM int rval = SUCCESS;
474*11304SJanie.Lu@Sun.COM uint64_t event_mask;
475*11304SJanie.Lu@Sun.COM int counter;
476*11304SJanie.Lu@Sun.COM
477*11304SJanie.Lu@Sun.COM IOSPC_DBG1(
478*11304SJanie.Lu@Sun.COM "iospc_perfcnt_program enter: new_events:0x%" PRIx64 "\n",
479*11304SJanie.Lu@Sun.COM new_events);
480*11304SJanie.Lu@Sun.COM
481*11304SJanie.Lu@Sun.COM if ((rval = grp_p->access(iospc_p, ksinfo_p->arg, IOSPC_REG_READ,
482*11304SJanie.Lu@Sun.COM grp_p->regsel_p->regoff, &old_events)) != SUCCESS)
483*11304SJanie.Lu@Sun.COM goto done_pgm;
484*11304SJanie.Lu@Sun.COM
485*11304SJanie.Lu@Sun.COM IOSPC_DBG1(" old_events:0x%" PRIx64 "\n", old_events);
486*11304SJanie.Lu@Sun.COM
487*11304SJanie.Lu@Sun.COM for (counter = 0; counter < grp_p->num_counters; counter++) {
488*11304SJanie.Lu@Sun.COM
489*11304SJanie.Lu@Sun.COM if (grp_p->counters_p[counter].zero_regoff == NO_REGISTER)
490*11304SJanie.Lu@Sun.COM continue;
491*11304SJanie.Lu@Sun.COM
492*11304SJanie.Lu@Sun.COM event_mask = grp_p->regsel_p->fields_p[counter].event_mask <<
493*11304SJanie.Lu@Sun.COM grp_p->regsel_p->fields_p[counter].event_offset;
494*11304SJanie.Lu@Sun.COM
495*11304SJanie.Lu@Sun.COM IOSPC_DBG1(
496*11304SJanie.Lu@Sun.COM "grp:%s, counter:%d, zero_regoff:0x%lx, "
497*11304SJanie.Lu@Sun.COM "event_mask:0x%" PRIx64 ", old&mask:0x%lx, "
498*11304SJanie.Lu@Sun.COM "new&mask:0x%lx\n",
499*11304SJanie.Lu@Sun.COM grp_p->grp_name, counter,
500*11304SJanie.Lu@Sun.COM grp_p->counters_p[counter].zero_regoff,
501*11304SJanie.Lu@Sun.COM event_mask, old_events & event_mask,
502*11304SJanie.Lu@Sun.COM new_events & event_mask);
503*11304SJanie.Lu@Sun.COM
504*11304SJanie.Lu@Sun.COM if ((old_events & event_mask) ==
505*11304SJanie.Lu@Sun.COM (new_events & event_mask))
506*11304SJanie.Lu@Sun.COM continue;
507*11304SJanie.Lu@Sun.COM
508*11304SJanie.Lu@Sun.COM IOSPC_DBG1("Zeroing counter %d\n", counter);
509*11304SJanie.Lu@Sun.COM
510*11304SJanie.Lu@Sun.COM if ((rval = grp_p->access(iospc_p, ksinfo_p->arg,
511*11304SJanie.Lu@Sun.COM IOSPC_REG_WRITE, grp_p->counters_p[counter].zero_regoff,
512*11304SJanie.Lu@Sun.COM &grp_p->counters_p[counter].zero_value)) != SUCCESS)
513*11304SJanie.Lu@Sun.COM goto done_pgm;
514*11304SJanie.Lu@Sun.COM }
515*11304SJanie.Lu@Sun.COM
516*11304SJanie.Lu@Sun.COM if (old_events != new_events) {
517*11304SJanie.Lu@Sun.COM
518*11304SJanie.Lu@Sun.COM IOSPC_DBG1("old != new, setting event reg %ld to 0x%lx\n",
519*11304SJanie.Lu@Sun.COM grp_p->regsel_p->regoff, new_events);
520*11304SJanie.Lu@Sun.COM
521*11304SJanie.Lu@Sun.COM if ((rval = grp_p->access(iospc_p, ksinfo_p->arg,
522*11304SJanie.Lu@Sun.COM IOSPC_REG_WRITE, grp_p->regsel_p->regoff, &new_events))
523*11304SJanie.Lu@Sun.COM != SUCCESS) {
524*11304SJanie.Lu@Sun.COM IOSPC_DBG1(
525*11304SJanie.Lu@Sun.COM "Write of new event data failed, "
526*11304SJanie.Lu@Sun.COM "select reg offset: %ld\n",
527*11304SJanie.Lu@Sun.COM grp_p->regsel_p->regoff);
528*11304SJanie.Lu@Sun.COM goto done_pgm;
529*11304SJanie.Lu@Sun.COM }
530*11304SJanie.Lu@Sun.COM }
531*11304SJanie.Lu@Sun.COM done_pgm:
532*11304SJanie.Lu@Sun.COM IOSPC_DBG1("iospc_perfcnt_program: returning status %d.\n", rval);
533*11304SJanie.Lu@Sun.COM return (rval);
534*11304SJanie.Lu@Sun.COM }
535*11304SJanie.Lu@Sun.COM
536*11304SJanie.Lu@Sun.COM /*
537*11304SJanie.Lu@Sun.COM * kstat update function. Handles reads/writes
538*11304SJanie.Lu@Sun.COM * from/to kstat.
539*11304SJanie.Lu@Sun.COM */
540*11304SJanie.Lu@Sun.COM static int
iospc_kstat_update(kstat_t * ksp,int rw)541*11304SJanie.Lu@Sun.COM iospc_kstat_update(kstat_t *ksp, int rw)
542*11304SJanie.Lu@Sun.COM {
543*11304SJanie.Lu@Sun.COM struct kstat_named *data_p;
544*11304SJanie.Lu@Sun.COM int counter;
545*11304SJanie.Lu@Sun.COM iospc_ksinfo_t *ksinfop = ksp->ks_private;
546*11304SJanie.Lu@Sun.COM iospc_grp_t *grp_p = ksinfop->grp_p;
547*11304SJanie.Lu@Sun.COM iospc_t *iospc_p = ksinfop->iospc_p;
548*11304SJanie.Lu@Sun.COM
549*11304SJanie.Lu@Sun.COM data_p = (struct kstat_named *)ksp->ks_data;
550*11304SJanie.Lu@Sun.COM
551*11304SJanie.Lu@Sun.COM if (rw == KSTAT_WRITE) {
552*11304SJanie.Lu@Sun.COM
553*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc_kstat_update: wr %ld\n",
554*11304SJanie.Lu@Sun.COM data_p[0].value.ui64);
555*11304SJanie.Lu@Sun.COM
556*11304SJanie.Lu@Sun.COM /*
557*11304SJanie.Lu@Sun.COM * Fields without programmable events won't be zeroed as
558*11304SJanie.Lu@Sun.COM * iospc_perfcnt_program is what zeros them.
559*11304SJanie.Lu@Sun.COM */
560*11304SJanie.Lu@Sun.COM
561*11304SJanie.Lu@Sun.COM /* This group has programmable events. */
562*11304SJanie.Lu@Sun.COM if (grp_p->regsel_p->regoff != NO_REGISTER) {
563*11304SJanie.Lu@Sun.COM
564*11304SJanie.Lu@Sun.COM IOSPC_DBG2("write: regoff has valid register\n");
565*11304SJanie.Lu@Sun.COM if (iospc_perfcnt_program(iospc_p, grp_p, ksinfop,
566*11304SJanie.Lu@Sun.COM data_p[0].value.ui64) != SUCCESS)
567*11304SJanie.Lu@Sun.COM return (EIO);
568*11304SJanie.Lu@Sun.COM }
569*11304SJanie.Lu@Sun.COM
570*11304SJanie.Lu@Sun.COM } else { /* Read the event register and all of the counters. */
571*11304SJanie.Lu@Sun.COM
572*11304SJanie.Lu@Sun.COM /* This group has programmable events. */
573*11304SJanie.Lu@Sun.COM if (grp_p->regsel_p->regoff != NO_REGISTER) {
574*11304SJanie.Lu@Sun.COM
575*11304SJanie.Lu@Sun.COM IOSPC_DBG2("read: regoff has valid register\n");
576*11304SJanie.Lu@Sun.COM
577*11304SJanie.Lu@Sun.COM if (grp_p->access(iospc_p, ksinfop->arg, IOSPC_REG_READ,
578*11304SJanie.Lu@Sun.COM grp_p->regsel_p->regoff, &data_p[0].value.ui64)
579*11304SJanie.Lu@Sun.COM != SUCCESS)
580*11304SJanie.Lu@Sun.COM return (EIO);
581*11304SJanie.Lu@Sun.COM } else
582*11304SJanie.Lu@Sun.COM data_p[0].value.ui64 = 0ull;
583*11304SJanie.Lu@Sun.COM
584*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc_kstat_update: rd event %lx\n",
585*11304SJanie.Lu@Sun.COM data_p[0].value.ui64);
586*11304SJanie.Lu@Sun.COM
587*11304SJanie.Lu@Sun.COM for (counter = 0; counter < grp_p->num_counters; counter++) {
588*11304SJanie.Lu@Sun.COM
589*11304SJanie.Lu@Sun.COM if (grp_p->access(iospc_p, ksinfop->arg, IOSPC_REG_READ,
590*11304SJanie.Lu@Sun.COM grp_p->counters_p[counter].regoff,
591*11304SJanie.Lu@Sun.COM &data_p[counter + 1].value.ui64) != SUCCESS)
592*11304SJanie.Lu@Sun.COM return (EIO);
593*11304SJanie.Lu@Sun.COM
594*11304SJanie.Lu@Sun.COM IOSPC_DBG2("cntr%d, off:0x%lx, val:0x%lx\n", counter,
595*11304SJanie.Lu@Sun.COM grp_p->counters_p[counter].regoff,
596*11304SJanie.Lu@Sun.COM data_p[counter + 1].value.ui64);
597*11304SJanie.Lu@Sun.COM }
598*11304SJanie.Lu@Sun.COM }
599*11304SJanie.Lu@Sun.COM return (SUCCESS);
600*11304SJanie.Lu@Sun.COM }
601*11304SJanie.Lu@Sun.COM
602*11304SJanie.Lu@Sun.COM void
iospc_kstat_fini()603*11304SJanie.Lu@Sun.COM iospc_kstat_fini()
604*11304SJanie.Lu@Sun.COM {
605*11304SJanie.Lu@Sun.COM iospc_grp_t **grp_pp;
606*11304SJanie.Lu@Sun.COM iospc_grp_t *grp_p;
607*11304SJanie.Lu@Sun.COM int j;
608*11304SJanie.Lu@Sun.COM
609*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc_kstat_fini called\n");
610*11304SJanie.Lu@Sun.COM
611*11304SJanie.Lu@Sun.COM for (j = 0, grp_pp = iospc_leaf_grps; *grp_pp != NULL; j++, grp_pp++) {
612*11304SJanie.Lu@Sun.COM grp_p = *grp_pp;
613*11304SJanie.Lu@Sun.COM if (grp_p->name_kstats_pp != NULL) {
614*11304SJanie.Lu@Sun.COM iospc_delete_name_kstats(grp_p->name_kstats_pp,
615*11304SJanie.Lu@Sun.COM grp_p->num_counters);
616*11304SJanie.Lu@Sun.COM kmem_free(grp_p->name_kstats_pp,
617*11304SJanie.Lu@Sun.COM grp_p->num_counters * sizeof (kstat_t));
618*11304SJanie.Lu@Sun.COM grp_p->name_kstats_pp = NULL;
619*11304SJanie.Lu@Sun.COM }
620*11304SJanie.Lu@Sun.COM }
621*11304SJanie.Lu@Sun.COM }
622*11304SJanie.Lu@Sun.COM
623*11304SJanie.Lu@Sun.COM static void
iospc_delete_name_kstats(kstat_t ** name_kstats_pp,int num_kstats)624*11304SJanie.Lu@Sun.COM iospc_delete_name_kstats(kstat_t **name_kstats_pp, int num_kstats)
625*11304SJanie.Lu@Sun.COM {
626*11304SJanie.Lu@Sun.COM int i;
627*11304SJanie.Lu@Sun.COM
628*11304SJanie.Lu@Sun.COM if (name_kstats_pp != NULL) {
629*11304SJanie.Lu@Sun.COM for (i = 0; i < num_kstats; i++) {
630*11304SJanie.Lu@Sun.COM if (name_kstats_pp[i] != NULL)
631*11304SJanie.Lu@Sun.COM kstat_delete(name_kstats_pp[i]);
632*11304SJanie.Lu@Sun.COM }
633*11304SJanie.Lu@Sun.COM }
634*11304SJanie.Lu@Sun.COM }
635*11304SJanie.Lu@Sun.COM
636*11304SJanie.Lu@Sun.COM void
iospc_kstat_detach(iospc_t * iospc_p)637*11304SJanie.Lu@Sun.COM iospc_kstat_detach(iospc_t *iospc_p)
638*11304SJanie.Lu@Sun.COM {
639*11304SJanie.Lu@Sun.COM iospc_grp_t **grp_pp;
640*11304SJanie.Lu@Sun.COM iospc_grp_t *grp_p;
641*11304SJanie.Lu@Sun.COM int i;
642*11304SJanie.Lu@Sun.COM
643*11304SJanie.Lu@Sun.COM IOSPC_DBG2("iospc_kstat_detach called\n");
644*11304SJanie.Lu@Sun.COM
645*11304SJanie.Lu@Sun.COM for (i = 0, grp_pp = iospc_leaf_grps; *grp_pp != NULL; i++, grp_pp++) {
646*11304SJanie.Lu@Sun.COM
647*11304SJanie.Lu@Sun.COM if (i >= IOSPC_MAX_NUM_GRPS)
648*11304SJanie.Lu@Sun.COM return;
649*11304SJanie.Lu@Sun.COM
650*11304SJanie.Lu@Sun.COM grp_p = *grp_pp;
651*11304SJanie.Lu@Sun.COM if (iospc_p->iospc_ksinfo_p[i] != NULL) {
652*11304SJanie.Lu@Sun.COM
653*11304SJanie.Lu@Sun.COM grp_p->access_fini(iospc_p, iospc_p->iospc_ksinfo_p[i]);
654*11304SJanie.Lu@Sun.COM
655*11304SJanie.Lu@Sun.COM if (iospc_p->iospc_ksinfo_p[i]->cntr_ksp != NULL)
656*11304SJanie.Lu@Sun.COM kstat_delete(
657*11304SJanie.Lu@Sun.COM iospc_p->iospc_ksinfo_p[i]->cntr_ksp);
658*11304SJanie.Lu@Sun.COM kmem_free(iospc_p->iospc_ksinfo_p[i],
659*11304SJanie.Lu@Sun.COM sizeof (iospc_ksinfo_t));
660*11304SJanie.Lu@Sun.COM }
661*11304SJanie.Lu@Sun.COM
662*11304SJanie.Lu@Sun.COM }
663*11304SJanie.Lu@Sun.COM }
664