4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * I/O support routines for DR
31 #include <sys/debug.h>
32 #include <sys/types.h>
33 #include <sys/errno.h>
35 #include <sys/dditypes.h>
36 #include <sys/devops.h>
37 #include <sys/modctl.h>
41 #include <sys/sunddi.h>
42 #include <sys/sunndi.h>
43 #include <sys/ndi_impldefs.h>
46 #include <sys/processor.h>
47 #include <sys/cpuvar.h>
48 #include <sys/mem_config.h>
49 #include <sys/promif.h>
50 #include <sys/x_call.h>
51 #include <sys/cpu_sgnblk_defs.h>
52 #include <sys/membar.h>
53 #include <sys/stack.h>
54 #include <sys/sysmacros.h>
55 #include <sys/machsystm.h>
56 #include <sys/spitregs.h>
57 #include <sys/cpupart.h>
59 #include <sys/archsystm.h>
60 #include <vm/hat_sfmmu.h>
63 #include <sys/x_call.h>
64 #include <sys/cpu_module.h>
66 #include <sys/cmn_err.h>
69 #include <sys/dr_util.h>
70 #include <sys/drmach.h>
73 dr_init_io_unit(dr_io_unit_t
*ip
)
77 if (DR_DEV_IS_ATTACHED(&ip
->sbi_cm
)) {
78 new_state
= DR_STATE_CONFIGURED
;
79 ip
->sbi_cm
.sbdev_cond
= SBD_COND_OK
;
80 } else if (DR_DEV_IS_PRESENT(&ip
->sbi_cm
)) {
81 new_state
= DR_STATE_CONNECTED
;
82 ip
->sbi_cm
.sbdev_cond
= SBD_COND_OK
;
84 new_state
= DR_STATE_EMPTY
;
86 dr_device_transition(&ip
->sbi_cm
, new_state
);
91 dr_attach_io(dr_handle_t
*hp
, dr_common_unit_t
*cp
)
95 dr_lock_status(hp
->h_bd
);
96 err
= drmach_configure(cp
->sbdev_id
, 0);
97 dr_unlock_status(hp
->h_bd
);
100 err
= drmach_io_post_attach(cp
->sbdev_id
);
103 DRERR_SET_C(&cp
->sbdev_error
, &err
);
107 * remove device nodes for the branch indicated by cp
111 dr_detach_io(dr_handle_t
*hp
, dr_common_unit_t
*cp
)
115 err
= drmach_unconfigure(cp
->sbdev_id
, 0);
118 err
= drmach_unconfigure(cp
->sbdev_id
, DEVI_BRANCH_DESTROY
);
121 err
= drmach_io_post_release(cp
->sbdev_id
);
124 dr_device_transition(cp
, DR_STATE_CONFIGURED
);
125 DRERR_SET_C(&cp
->sbdev_error
, &err
);
131 dr_disconnect_io(dr_io_unit_t
*ip
)
138 dr_pre_attach_io(dr_handle_t
*hp
,
139 dr_common_unit_t
**devlist
, int devnum
)
143 for (d
= 0; d
< devnum
; d
++) {
144 dr_common_unit_t
*cp
= devlist
[d
];
146 cmn_err(CE_CONT
, "OS configure %s", cp
->sbdev_path
);
154 dr_post_attach_io(dr_handle_t
*hp
,
155 dr_common_unit_t
**devlist
, int devnum
)
161 dr_check_io_refs(dr_handle_t
*hp
, dr_common_unit_t
**devlist
, int devnum
)
163 register int i
, reftotal
= 0;
164 static fn_t f
= "dr_check_io_refs";
166 for (i
= 0; i
< devnum
; i
++) {
167 dr_io_unit_t
*ip
= (dr_io_unit_t
*)devlist
[i
];
170 int refcount_non_gldv3
;
173 err
= drmach_get_dip(ip
->sbi_cm
.sbdev_id
, &dip
);
175 DRERR_SET_C(&ip
->sbi_cm
.sbdev_error
, &err
);
176 else if (dip
!= NULL
) {
178 refcount_non_gldv3
= 0;
179 ASSERT(e_ddi_branch_held(dip
));
180 dr_check_devices(dip
, &ref
, hp
, NULL
, NULL
,
181 0, &refcount_non_gldv3
);
182 ASSERT(refcount_non_gldv3
>= 0);
183 ASSERT(ref
>= refcount_non_gldv3
);
185 * Ignore reference counts of non-gldv3 network devices
186 * as Crossbow creates reference counts for non-active
187 * (unplumbed) instances. Reference count check in
188 * detach() known to prevent device from detaching
191 ref
-= refcount_non_gldv3
;
194 dr_dev_err(CE_WARN
, &ip
->sbi_cm
, ESBD_BUSY
);
196 PR_IO("%s: dip(%s) ref = %d\n",
197 f
, ddi_get_name(dip
), ref
);
200 PR_IO("%s: NO dip for id (0x%x)\n",
201 f
, (uint_t
)(uintptr_t)ip
->sbi_cm
.sbdev_id
);
209 dr_pre_release_io(dr_handle_t
*hp
,
210 dr_common_unit_t
**devlist
, int devnum
)
212 static fn_t f
= "dr_pre_release_io";
217 /* fail if any I/O device pre-release fails */
218 for (d
= 0; d
< devnum
; d
++) {
219 dr_io_unit_t
*ip
= (dr_io_unit_t
*)devlist
[d
];
221 if ((hp
->h_err
= drmach_io_pre_release(
222 ip
->sbi_cm
.sbdev_id
)) != 0) {
227 for (d
= 0; d
< devnum
; d
++) {
228 dr_io_unit_t
*ip
= (dr_io_unit_t
*)devlist
[d
];
231 err
= drmach_release(ip
->sbi_cm
.sbdev_id
);
233 DRERR_SET_C(&ip
->sbi_cm
.sbdev_error
,
239 /* fail if any I/O devices are still referenced */
240 if (dr_check_io_refs(hp
, devlist
, devnum
) > 0) {
241 PR_IO("%s: failed - I/O devices ref'd\n", f
);
243 /* recover before return error */
244 for (d
= 0; d
< devnum
; d
++) {
245 dr_io_unit_t
*ip
= (dr_io_unit_t
*)devlist
[d
];
247 err
= drmach_io_unrelease(ip
->sbi_cm
.sbdev_id
);
249 DRERR_SET_C(&ip
->sbi_cm
.sbdev_error
, &err
);
260 dr_pre_detach_io(dr_handle_t
*hp
,
261 dr_common_unit_t
**devlist
, int devnum
)
267 for (d
= 0; d
< devnum
; d
++) {
268 dr_common_unit_t
*cp
= devlist
[d
];
270 cmn_err(CE_CONT
, "OS unconfigure %s", cp
->sbdev_path
);
278 dr_post_detach_io(dr_handle_t
*hp
, dr_common_unit_t
**devlist
, int devnum
)
282 static fn_t f
= "dr_post_detach_io";
285 for (i
= 0; i
< devnum
; i
++) {
286 dr_common_unit_t
*cp
= devlist
[i
];
287 if (cp
->sbdev_error
!= NULL
) {
288 PR_IO("%s: Failed\n", f
);
297 dr_get_comp_cond(dr_io_unit_t
*ip
, dev_info_t
*dip
)
300 ip
->sbi_cm
.sbdev_cond
= SBD_COND_UNKNOWN
;
304 if (DEVI(dip
)->devi_flags
& DEVI_RETIRED
) {
305 ip
->sbi_cm
.sbdev_cond
= SBD_COND_FAILED
;
309 if (DR_DEV_IS_ATTACHED(&ip
->sbi_cm
)) {
310 ip
->sbi_cm
.sbdev_cond
= SBD_COND_OK
;
311 } else if (DR_DEV_IS_PRESENT(&ip
->sbi_cm
)) {
312 ip
->sbi_cm
.sbdev_cond
= SBD_COND_OK
;
317 dr_io_status(dr_handle_t
*hp
, dr_devset_t devset
, sbd_dev_stat_t
*dsp
)
327 * Only look for requested devices that are actually present.
329 devset
&= DR_DEVS_PRESENT(bp
);
331 for (i
= ix
= 0; i
< MAX_IO_UNITS_PER_BOARD
; i
++) {
335 drmach_status_t pstat
;
337 if (DEVSET_IN_SET(devset
, SBD_COMP_IO
, i
) == 0)
340 ip
= dr_get_io_unit(bp
, i
);
342 if (ip
->sbi_cm
.sbdev_state
== DR_STATE_EMPTY
) {
343 /* present, but not fully initialized */
347 id
= ip
->sbi_cm
.sbdev_id
;
348 if (id
== (drmachid_t
)0)
351 err
= drmach_status(ip
->sbi_cm
.sbdev_id
, &pstat
);
353 DRERR_SET_C(&ip
->sbi_cm
.sbdev_error
, &err
);
358 err
= drmach_get_dip(id
, &dip
);
360 /* catch this in debug kernels */
368 bzero((caddr_t
)isp
, sizeof (*isp
));
370 isp
->is_cm
.c_id
.c_type
= ip
->sbi_cm
.sbdev_type
;
371 isp
->is_cm
.c_id
.c_unit
= ip
->sbi_cm
.sbdev_unum
;
372 (void) strncpy(isp
->is_cm
.c_id
.c_name
, pstat
.type
,
373 sizeof (isp
->is_cm
.c_id
.c_name
));
375 dr_get_comp_cond(ip
, dip
);
376 isp
->is_cm
.c_cond
= ip
->sbi_cm
.sbdev_cond
;
377 isp
->is_cm
.c_busy
= ip
->sbi_cm
.sbdev_busy
| pstat
.busy
;
378 isp
->is_cm
.c_time
= ip
->sbi_cm
.sbdev_time
;
379 isp
->is_cm
.c_ostate
= ip
->sbi_cm
.sbdev_ostate
;
380 isp
->is_cm
.c_sflags
= 0;
383 isp
->is_pathname
[0] = '\0';
384 isp
->is_referenced
= 0;
385 isp
->is_unsafe_count
= 0;
387 int refcount
= 0, idx
= 0;
388 uint64_t unsafe_devs
[SBD_MAX_UNSAFE
];
390 ASSERT(e_ddi_branch_held(dip
));
391 (void) ddi_pathname(dip
, isp
->is_pathname
);
393 /* check reference and unsafe counts on devices */
394 isp
->is_unsafe_count
= 0;
395 dr_check_devices(dip
, &refcount
, hp
, unsafe_devs
,
396 &idx
, SBD_MAX_UNSAFE
, NULL
);
398 isp
->is_unsafe_list
[idx
-1] = unsafe_devs
[idx
-1];
402 isp
->is_referenced
= (refcount
== 0) ? 0 : 1;