5255 uts shouldn't open-code ISP2
[illumos-gate.git] / usr / src / uts / common / io / 1394 / s1394_cmp.c
blob05944d737903f5027d630d58bc00fa2a2c4536ef
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * s1394_cmp.c
31 * 1394 Services Layer Connection Management Procedures Support Routines
34 #include <sys/conf.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/cmn_err.h>
38 #include <sys/types.h>
39 #include <sys/kmem.h>
40 #include <sys/tnf_probe.h>
42 #include <sys/1394/t1394.h>
43 #include <sys/1394/s1394.h>
44 #include <sys/1394/h1394.h>
46 static void s1394_cmp_init(s1394_hal_t *hal);
47 static void s1394_cmp_fini(s1394_hal_t *hal);
48 static void s1394_cmp_ompr_recv_read_request(cmd1394_cmd_t *req);
49 static void s1394_cmp_impr_recv_read_request(cmd1394_cmd_t *req);
50 static void s1394_cmp_ompr_recv_lock_request(cmd1394_cmd_t *req);
51 static void s1394_cmp_impr_recv_lock_request(cmd1394_cmd_t *req);
52 static void s1394_cmp_notify_reg_change(s1394_hal_t *hal, t1394_cmp_reg_t reg,
53 s1394_target_t *self);
57 * number of retries to notify registered targets in case target list
58 * changes while the list rwlock is dropped for the time of callback
60 uint_t s1394_cmp_notify_retry_cnt = 3;
62 s1394_fa_descr_t s1394_cmp_ompr_descr = {
63 IEC61883_CMP_OMPR_ADDR,
65 T1394_ADDR_RDENBL | T1394_ADDR_LKENBL,
67 s1394_cmp_ompr_recv_read_request,
68 NULL,
69 s1394_cmp_ompr_recv_lock_request
74 s1394_fa_descr_t s1394_cmp_impr_descr = {
75 IEC61883_CMP_IMPR_ADDR,
77 T1394_ADDR_RDENBL | T1394_ADDR_LKENBL,
79 s1394_cmp_impr_recv_read_request,
80 NULL,
81 s1394_cmp_impr_recv_lock_request
87 int
88 s1394_cmp_register(s1394_target_t *target, t1394_cmp_evts_t *evts)
90 s1394_hal_t *hal = target->on_hal;
91 static t1394_cmp_evts_t default_evts = { NULL, NULL };
93 TNF_PROBE_0_DEBUG(s1394_cmp_register_enter, S1394_TNF_SL_CMP_STACK, "");
95 rw_enter(&hal->target_list_rwlock, RW_WRITER);
97 * if registering the first target, claim and initialize addresses
99 if (s1394_fa_list_is_empty(hal, S1394_FA_TYPE_CMP)) {
100 if (s1394_fa_claim_addr(hal, S1394_FA_TYPE_CMP_OMPR,
101 &s1394_cmp_ompr_descr) != DDI_SUCCESS) {
102 rw_exit(&hal->target_list_rwlock);
103 return (DDI_FAILURE);
106 if (s1394_fa_claim_addr(hal, S1394_FA_TYPE_CMP_IMPR,
107 &s1394_cmp_impr_descr) != DDI_SUCCESS) {
108 s1394_fa_free_addr(hal, S1394_FA_TYPE_CMP_OMPR);
109 rw_exit(&hal->target_list_rwlock);
110 return (DDI_FAILURE);
113 s1394_cmp_init(hal);
116 /* Add on the target list (we only use one list) */
117 s1394_fa_list_add(hal, target, S1394_FA_TYPE_CMP);
119 if (evts == NULL) {
120 evts = &default_evts;
122 target->target_fa[S1394_FA_TYPE_CMP].fat_u.cmp.cm_evts = *evts;
124 rw_exit(&hal->target_list_rwlock);
126 TNF_PROBE_0_DEBUG(s1394_cmp_register_exit, S1394_TNF_SL_CMP_STACK, "");
127 return (DDI_SUCCESS);
131 s1394_cmp_unregister(s1394_target_t *target)
133 s1394_hal_t *hal = target->on_hal;
135 TNF_PROBE_0_DEBUG(s1394_cmp_unregister_enter, S1394_TNF_SL_CMP_STACK,
136 "");
138 rw_enter(&hal->target_list_rwlock, RW_WRITER);
140 if (s1394_fa_list_remove(hal, target,
141 S1394_FA_TYPE_CMP) == DDI_SUCCESS) {
142 if (s1394_fa_list_is_empty(hal, S1394_FA_TYPE_CMP)) {
143 s1394_fa_free_addr(hal, S1394_FA_TYPE_CMP_OMPR);
144 s1394_fa_free_addr(hal, S1394_FA_TYPE_CMP_IMPR);
145 s1394_cmp_fini(hal);
147 } else {
148 TNF_PROBE_0(s1394_cmp_unregister_common_error_list,
149 S1394_TNF_SL_CMP_ERROR, "");
152 rw_exit(&hal->target_list_rwlock);
154 TNF_PROBE_0_DEBUG(s1394_cmp_unregister_exit, S1394_TNF_SL_CMP_STACK,
155 "");
156 return (DDI_SUCCESS);
160 s1394_cmp_read(s1394_target_t *target, t1394_cmp_reg_t reg, uint32_t *valp)
162 s1394_hal_t *hal = target->on_hal;
163 s1394_cmp_hal_t *cmp = &hal->hal_cmp;
164 int ret = DDI_FAILURE;
166 TNF_PROBE_0_DEBUG(s1394_cmp_read_enter, S1394_TNF_SL_CMP_STACK, "");
168 if (reg == T1394_CMP_OMPR) {
169 rw_enter(&cmp->cmp_ompr_rwlock, RW_READER);
170 *valp = cmp->cmp_ompr_val;
171 rw_exit(&cmp->cmp_ompr_rwlock);
172 ret = DDI_SUCCESS;
173 } else if (reg == T1394_CMP_IMPR) {
174 rw_enter(&cmp->cmp_impr_rwlock, RW_READER);
175 *valp = cmp->cmp_impr_val;
176 rw_exit(&cmp->cmp_impr_rwlock);
177 ret = DDI_SUCCESS;
180 TNF_PROBE_0_DEBUG(s1394_cmp_read_exit, S1394_TNF_SL_CMP_STACK, "");
181 return (ret);
185 s1394_cmp_cas(s1394_target_t *target, t1394_cmp_reg_t reg, uint32_t arg_val,
186 uint32_t new_val, uint32_t *old_valp)
188 s1394_hal_t *hal = target->on_hal;
189 s1394_cmp_hal_t *cmp = &hal->hal_cmp;
190 int ret = DDI_SUCCESS;
192 TNF_PROBE_0_DEBUG(s1394_cmp_cas_enter, S1394_TNF_SL_CMP_STACK, "");
194 if (reg == T1394_CMP_OMPR) {
195 rw_enter(&cmp->cmp_ompr_rwlock, RW_WRITER);
196 *old_valp = cmp->cmp_ompr_val;
197 if (cmp->cmp_ompr_val == arg_val) {
198 cmp->cmp_ompr_val = new_val;
200 rw_exit(&cmp->cmp_ompr_rwlock);
201 } else if (reg == T1394_CMP_IMPR) {
202 rw_enter(&cmp->cmp_impr_rwlock, RW_WRITER);
203 *old_valp = cmp->cmp_impr_val;
204 if (cmp->cmp_impr_val == arg_val) {
205 cmp->cmp_impr_val = new_val;
207 rw_exit(&cmp->cmp_impr_rwlock);
208 } else {
209 ret = DDI_FAILURE;
212 /* notify other targets */
213 if (ret == DDI_SUCCESS) {
214 s1394_cmp_notify_reg_change(hal, reg, target);
217 TNF_PROBE_0_DEBUG(s1394_cmp_cas_exit, S1394_TNF_SL_CMP_STACK, "");
218 return (ret);
221 static void
222 s1394_cmp_init(s1394_hal_t *hal)
224 s1394_cmp_hal_t *cmp = &hal->hal_cmp;
226 rw_init(&cmp->cmp_ompr_rwlock, NULL, RW_DRIVER, NULL);
227 rw_init(&cmp->cmp_impr_rwlock, NULL, RW_DRIVER, NULL);
229 cmp->cmp_ompr_val = IEC61883_CMP_OMPR_INIT_VAL;
230 cmp->cmp_impr_val = IEC61883_CMP_IMPR_INIT_VAL;
233 static void
234 s1394_cmp_fini(s1394_hal_t *hal)
236 s1394_cmp_hal_t *cmp = &hal->hal_cmp;
238 rw_destroy(&cmp->cmp_ompr_rwlock);
239 rw_destroy(&cmp->cmp_impr_rwlock);
243 * iMPR/oMPR read/lock requests
245 static void
246 s1394_cmp_ompr_recv_read_request(cmd1394_cmd_t *req)
248 s1394_hal_t *hal = req->cmd_callback_arg;
249 s1394_cmp_hal_t *cmp = &hal->hal_cmp;
251 TNF_PROBE_0_DEBUG(s1394_cmp_ompr_recv_read_request_enter,
252 S1394_TNF_SL_CMP_STACK, "");
254 if (req->cmd_type != CMD1394_ASYNCH_RD_QUAD) {
255 req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
256 } else {
257 rw_enter(&cmp->cmp_ompr_rwlock, RW_READER);
258 req->cmd_u.q.quadlet_data = cmp->cmp_ompr_val;
259 rw_exit(&cmp->cmp_ompr_rwlock);
260 req->cmd_result = IEEE1394_RESP_COMPLETE;
263 (void) s1394_send_response(hal, req);
265 TNF_PROBE_0_DEBUG(s1394_cmp_ompr_recv_read_request_exit,
266 S1394_TNF_SL_CMP_STACK, "");
269 static void
270 s1394_cmp_impr_recv_read_request(cmd1394_cmd_t *req)
272 s1394_hal_t *hal = req->cmd_callback_arg;
273 s1394_cmp_hal_t *cmp = &hal->hal_cmp;
275 TNF_PROBE_0_DEBUG(s1394_cmp_impr_recv_read_request_enter,
276 S1394_TNF_SL_CMP_STACK, "");
278 if (req->cmd_type != CMD1394_ASYNCH_RD_QUAD) {
279 req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
280 } else {
281 rw_enter(&cmp->cmp_impr_rwlock, RW_READER);
282 req->cmd_u.q.quadlet_data = cmp->cmp_impr_val;
283 rw_exit(&cmp->cmp_impr_rwlock);
284 req->cmd_result = IEEE1394_RESP_COMPLETE;
287 (void) s1394_send_response(hal, req);
289 TNF_PROBE_0_DEBUG(s1394_cmp_impr_recv_read_request_exit,
290 S1394_TNF_SL_CMP_STACK, "");
293 static void
294 s1394_cmp_ompr_recv_lock_request(cmd1394_cmd_t *req)
296 s1394_hal_t *hal = req->cmd_callback_arg;
297 s1394_cmp_hal_t *cmp = &hal->hal_cmp;
298 boolean_t notify = B_TRUE;
300 TNF_PROBE_0_DEBUG(s1394_cmp_ompr_recv_lock_request_enter,
301 S1394_TNF_SL_CMP_STACK, "");
303 if ((req->cmd_type != CMD1394_ASYNCH_LOCK_32) ||
304 (req->cmd_u.l32.lock_type != CMD1394_LOCK_COMPARE_SWAP)) {
305 req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
306 notify = B_FALSE;
307 } else {
308 rw_enter(&cmp->cmp_ompr_rwlock, RW_WRITER);
309 req->cmd_u.l32.old_value = cmp->cmp_ompr_val;
310 if (cmp->cmp_ompr_val == req->cmd_u.l32.arg_value) {
311 /* write only allowed bits */
312 cmp->cmp_ompr_val = (req->cmd_u.l32.data_value &
313 IEC61883_CMP_OMPR_LOCK_MASK) |
314 (cmp->cmp_ompr_val & ~IEC61883_CMP_OMPR_LOCK_MASK);
316 rw_exit(&cmp->cmp_ompr_rwlock);
317 req->cmd_result = IEEE1394_RESP_COMPLETE;
320 (void) s1394_send_response(hal, req);
322 /* notify all targets */
323 if (notify) {
324 s1394_cmp_notify_reg_change(hal, T1394_CMP_OMPR, NULL);
327 TNF_PROBE_0_DEBUG(s1394_cmp_ompr_recv_lock_request_exit,
328 S1394_TNF_SL_CMP_STACK, "");
331 static void
332 s1394_cmp_impr_recv_lock_request(cmd1394_cmd_t *req)
334 s1394_hal_t *hal = req->cmd_callback_arg;
335 s1394_cmp_hal_t *cmp = &hal->hal_cmp;
336 boolean_t notify = B_TRUE;
338 TNF_PROBE_0_DEBUG(s1394_cmp_impr_recv_lock_request_enter,
339 S1394_TNF_SL_CMP_STACK, "");
341 if ((req->cmd_type != CMD1394_ASYNCH_LOCK_32) ||
342 (req->cmd_u.l32.lock_type != CMD1394_LOCK_COMPARE_SWAP)) {
343 req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
344 notify = B_FALSE;
345 } else {
346 rw_enter(&cmp->cmp_impr_rwlock, RW_WRITER);
347 req->cmd_u.l32.old_value = cmp->cmp_impr_val;
348 if (cmp->cmp_impr_val == req->cmd_u.l32.arg_value) {
349 /* write only allowed bits */
350 cmp->cmp_impr_val = (req->cmd_u.l32.data_value &
351 IEC61883_CMP_IMPR_LOCK_MASK) |
352 (cmp->cmp_impr_val & ~IEC61883_CMP_IMPR_LOCK_MASK);
354 rw_exit(&cmp->cmp_impr_rwlock);
355 req->cmd_result = IEEE1394_RESP_COMPLETE;
358 (void) s1394_send_response(hal, req);
360 /* notify all targets */
361 if (notify) {
362 s1394_cmp_notify_reg_change(hal, T1394_CMP_IMPR, NULL);
365 TNF_PROBE_0_DEBUG(s1394_cmp_impr_recv_lock_request_exit,
366 S1394_TNF_SL_CMP_STACK, "");
370 * Notify registered targets except 'self' about register value change
372 static void
373 s1394_cmp_notify_reg_change(s1394_hal_t *hal, t1394_cmp_reg_t reg,
374 s1394_target_t *self)
376 s1394_target_t *target;
377 s1394_fa_target_t *fat;
378 uint_t saved_gen;
379 int num_retries = 0;
380 void (*cb)(opaque_t, t1394_cmp_reg_t);
381 opaque_t arg;
383 TNF_PROBE_0_DEBUG(s1394_cmp_notify_reg_change_enter,
384 S1394_TNF_SL_CMP_STACK, "");
386 rw_enter(&hal->target_list_rwlock, RW_READER);
388 start:
389 target = hal->hal_fa[S1394_FA_TYPE_CMP].fal_head;
391 for (; target; target = fat->fat_next) {
392 fat = &target->target_fa[S1394_FA_TYPE_CMP];
395 * even if the target list changes when the lock is dropped,
396 * comparing with self is safe because the target should
397 * not unregister until all CMP operations are completed
399 if (target == self) {
400 continue;
403 cb = fat->fat_u.cmp.cm_evts.cmp_reg_change;
404 if (cb == NULL) {
405 continue;
407 arg = fat->fat_u.cmp.cm_evts.cmp_arg;
409 saved_gen = s1394_fa_list_gen(hal, S1394_FA_TYPE_CMP);
411 rw_exit(&hal->target_list_rwlock);
412 cb(arg, reg);
413 rw_enter(&hal->target_list_rwlock, RW_READER);
416 * List could change while we dropped the lock. In such
417 * case, start all over again, because missing a register
418 * change can have more serious consequences for a
419 * target than receiving same notification more than once
421 if (saved_gen != s1394_fa_list_gen(hal, S1394_FA_TYPE_CMP)) {
422 TNF_PROBE_2(s1394_cmp_notify_reg_change_error,
423 S1394_TNF_SL_CMP_ERROR, "",
424 tnf_string, msg, "list gen changed",
425 tnf_opaque, num_retries, num_retries);
426 if (++num_retries <= s1394_cmp_notify_retry_cnt) {
427 goto start;
428 } else {
429 break;
434 rw_exit(&hal->target_list_rwlock);
436 TNF_PROBE_0_DEBUG(s1394_cmp_notify_reg_change_exit,
437 S1394_TNF_SL_CMP_STACK, "");