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/types.h>
32 #include <sys/cmn_err.h>
33 #include <sys/debug.h>
34 #include <sys/errno.h>
35 #include <sys/dditypes.h>
37 #include <sys/sunddi.h>
38 #include <sys/sunndi.h>
39 #include <sys/ndi_impldefs.h>
41 #include <sys/promif.h>
42 #include <sys/sysmacros.h>
43 #include <sys/archsystm.h>
44 #include <sys/machsystm.h>
47 #include <sys/dr_util.h>
48 #include <sys/drmach.h>
51 dr_init_io_unit(dr_io_unit_t
*ip
)
55 if (DR_DEV_IS_ATTACHED(&ip
->sbi_cm
)) {
56 new_state
= DR_STATE_CONFIGURED
;
57 ip
->sbi_cm
.sbdev_cond
= SBD_COND_OK
;
58 } else if (DR_DEV_IS_PRESENT(&ip
->sbi_cm
)) {
59 new_state
= DR_STATE_CONNECTED
;
60 ip
->sbi_cm
.sbdev_cond
= SBD_COND_OK
;
62 new_state
= DR_STATE_EMPTY
;
64 dr_device_transition(&ip
->sbi_cm
, new_state
);
69 dr_attach_io(dr_handle_t
*hp
, dr_common_unit_t
*cp
)
73 dr_lock_status(hp
->h_bd
);
74 err
= drmach_configure(cp
->sbdev_id
, 0);
75 dr_unlock_status(hp
->h_bd
);
78 err
= drmach_io_post_attach(cp
->sbdev_id
);
81 DRERR_SET_C(&cp
->sbdev_error
, &err
);
85 * remove device nodes for the branch indicated by cp
89 dr_detach_io(dr_handle_t
*hp
, dr_common_unit_t
*cp
)
93 err
= drmach_unconfigure(cp
->sbdev_id
, 0);
96 err
= drmach_unconfigure(cp
->sbdev_id
, DEVI_BRANCH_DESTROY
);
99 err
= drmach_io_post_release(cp
->sbdev_id
);
102 dr_device_transition(cp
, DR_STATE_CONFIGURED
);
103 DRERR_SET_C(&cp
->sbdev_error
, &err
);
109 dr_disconnect_io(dr_io_unit_t
*ip
)
116 dr_pre_attach_io(dr_handle_t
*hp
,
117 dr_common_unit_t
**devlist
, int devnum
)
121 for (d
= 0; d
< devnum
; d
++) {
122 dr_common_unit_t
*cp
= devlist
[d
];
124 cmn_err(CE_CONT
, "OS configure %s", cp
->sbdev_path
);
132 dr_post_attach_io(dr_handle_t
*hp
,
133 dr_common_unit_t
**devlist
, int devnum
)
139 dr_check_io_refs(dr_handle_t
*hp
, dr_common_unit_t
**devlist
, int devnum
)
141 register int i
, reftotal
= 0;
142 static fn_t f
= "dr_check_io_refs";
144 for (i
= 0; i
< devnum
; i
++) {
145 dr_io_unit_t
*ip
= (dr_io_unit_t
*)devlist
[i
];
148 int refcount_non_gldv3
;
151 err
= drmach_get_dip(ip
->sbi_cm
.sbdev_id
, &dip
);
153 DRERR_SET_C(&ip
->sbi_cm
.sbdev_error
, &err
);
154 else if (dip
!= NULL
) {
156 refcount_non_gldv3
= 0;
157 ASSERT(e_ddi_branch_held(dip
));
158 dr_check_devices(dip
, &ref
, hp
, NULL
, NULL
,
159 0, &refcount_non_gldv3
);
160 ASSERT(refcount_non_gldv3
>= 0);
161 ASSERT(ref
>= refcount_non_gldv3
);
163 * Ignore reference counts of non-gldv3 network devices
164 * as Crossbow creates reference counts for non-active
165 * (unplumbed) instances. Reference count check in
166 * detach() known to prevent device from detaching
169 ref
-= refcount_non_gldv3
;
172 dr_dev_err(CE_WARN
, &ip
->sbi_cm
, ESBD_BUSY
);
174 PR_IO("%s: dip(%s) ref = %d\n",
175 f
, ddi_get_name(dip
), ref
);
178 PR_IO("%s: NO dip for id (0x%x)\n",
179 f
, (uint_t
)(uintptr_t)ip
->sbi_cm
.sbdev_id
);
187 dr_pre_release_io(dr_handle_t
*hp
,
188 dr_common_unit_t
**devlist
, int devnum
)
190 static fn_t f
= "dr_pre_release_io";
195 /* fail if any I/O device pre-release fails */
196 for (d
= 0; d
< devnum
; d
++) {
197 dr_io_unit_t
*ip
= (dr_io_unit_t
*)devlist
[d
];
199 if ((hp
->h_err
= drmach_io_pre_release(
200 ip
->sbi_cm
.sbdev_id
)) != 0) {
205 for (d
= 0; d
< devnum
; d
++) {
206 dr_io_unit_t
*ip
= (dr_io_unit_t
*)devlist
[d
];
209 err
= drmach_release(ip
->sbi_cm
.sbdev_id
);
211 DRERR_SET_C(&ip
->sbi_cm
.sbdev_error
,
217 /* fail if any I/O devices are still referenced */
218 if (dr_check_io_refs(hp
, devlist
, devnum
) > 0) {
219 PR_IO("%s: failed - I/O devices ref'd\n", f
);
221 /* recover before return error */
222 for (d
= 0; d
< devnum
; d
++) {
223 dr_io_unit_t
*ip
= (dr_io_unit_t
*)devlist
[d
];
225 err
= drmach_io_unrelease(ip
->sbi_cm
.sbdev_id
);
227 DRERR_SET_C(&ip
->sbi_cm
.sbdev_error
, &err
);
238 dr_pre_detach_io(dr_handle_t
*hp
,
239 dr_common_unit_t
**devlist
, int devnum
)
245 for (d
= 0; d
< devnum
; d
++) {
246 dr_common_unit_t
*cp
= devlist
[d
];
248 cmn_err(CE_CONT
, "OS unconfigure %s", cp
->sbdev_path
);
256 dr_post_detach_io(dr_handle_t
*hp
, dr_common_unit_t
**devlist
, int devnum
)
260 static fn_t f
= "dr_post_detach_io";
263 for (i
= 0; i
< devnum
; i
++) {
264 dr_common_unit_t
*cp
= devlist
[i
];
265 if (cp
->sbdev_error
!= NULL
) {
266 PR_IO("%s: Failed\n", f
);
275 dr_get_comp_cond(dr_io_unit_t
*ip
, dev_info_t
*dip
)
278 ip
->sbi_cm
.sbdev_cond
= SBD_COND_UNKNOWN
;
282 if (DEVI(dip
)->devi_flags
& DEVI_RETIRED
) {
283 ip
->sbi_cm
.sbdev_cond
= SBD_COND_FAILED
;
287 if (DR_DEV_IS_ATTACHED(&ip
->sbi_cm
)) {
288 ip
->sbi_cm
.sbdev_cond
= SBD_COND_OK
;
289 } else if (DR_DEV_IS_PRESENT(&ip
->sbi_cm
)) {
290 ip
->sbi_cm
.sbdev_cond
= SBD_COND_OK
;
295 dr_io_status(dr_handle_t
*hp
, dr_devset_t devset
, sbd_dev_stat_t
*dsp
)
305 * Only look for requested devices that are actually present.
307 devset
&= DR_DEVS_PRESENT(bp
);
309 for (i
= ix
= 0; i
< MAX_IO_UNITS_PER_BOARD
; i
++) {
313 drmach_status_t pstat
;
315 if (DEVSET_IN_SET(devset
, SBD_COMP_IO
, i
) == 0)
318 ip
= dr_get_io_unit(bp
, i
);
320 if (ip
->sbi_cm
.sbdev_state
== DR_STATE_EMPTY
) {
321 /* present, but not fully initialized */
325 id
= ip
->sbi_cm
.sbdev_id
;
326 if (id
== (drmachid_t
)0)
329 err
= drmach_status(ip
->sbi_cm
.sbdev_id
, &pstat
);
331 DRERR_SET_C(&ip
->sbi_cm
.sbdev_error
, &err
);
336 err
= drmach_get_dip(id
, &dip
);
338 /* catch this in debug kernels */
346 bzero((caddr_t
)isp
, sizeof (*isp
));
348 isp
->is_cm
.c_id
.c_type
= ip
->sbi_cm
.sbdev_type
;
349 isp
->is_cm
.c_id
.c_unit
= ip
->sbi_cm
.sbdev_unum
;
350 (void) strlcpy(isp
->is_cm
.c_id
.c_name
, pstat
.type
,
351 sizeof (isp
->is_cm
.c_id
.c_name
));
353 dr_get_comp_cond(ip
, dip
);
354 isp
->is_cm
.c_cond
= ip
->sbi_cm
.sbdev_cond
;
355 isp
->is_cm
.c_busy
= ip
->sbi_cm
.sbdev_busy
| pstat
.busy
;
356 isp
->is_cm
.c_time
= ip
->sbi_cm
.sbdev_time
;
357 isp
->is_cm
.c_ostate
= ip
->sbi_cm
.sbdev_ostate
;
358 isp
->is_cm
.c_sflags
= 0;
361 isp
->is_pathname
[0] = '\0';
362 isp
->is_referenced
= 0;
363 isp
->is_unsafe_count
= 0;
365 int refcount
= 0, idx
= 0;
366 uint64_t unsafe_devs
[SBD_MAX_UNSAFE
];
368 ASSERT(e_ddi_branch_held(dip
));
369 (void) ddi_pathname(dip
, isp
->is_pathname
);
371 /* check reference and unsafe counts on devices */
372 isp
->is_unsafe_count
= 0;
373 dr_check_devices(dip
, &refcount
, hp
, unsafe_devs
,
374 &idx
, SBD_MAX_UNSAFE
, NULL
);
376 isp
->is_unsafe_list
[idx
-1] = unsafe_devs
[idx
-1];
380 isp
->is_referenced
= (refcount
== 0) ? 0 : 1;