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
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]
23 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
31 * 1394 Services Layer FCP Support Routines
36 #include <sys/sunddi.h>
37 #include <sys/cmn_err.h>
38 #include <sys/types.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 int s1394_fcp_register_common(s1394_target_t
*target
,
47 t1394_fcp_evts_t
*evts
, s1394_fa_type_t type
, s1394_fa_descr_t
*descr
);
48 static int s1394_fcp_unregister_common(s1394_target_t
*target
,
49 s1394_fa_type_t type
);
50 static void s1394_fcp_resp_recv_write_request(cmd1394_cmd_t
*req
);
51 static void s1394_fcp_cmd_recv_write_request(cmd1394_cmd_t
*req
);
52 static void s1394_fcp_recv_write_request(cmd1394_cmd_t
*req
,
53 s1394_fa_type_t type
);
54 static void s1394_fcp_recv_write_unclaimed(s1394_hal_t
*hal
,
59 * number of retries to notify registered targets in case target list
60 * changes while the list rwlock is dropped for the time of callback
62 uint_t s1394_fcp_notify_retry_cnt
= 3;
64 s1394_fa_descr_t s1394_fcp_ctl_descr
= {
65 IEC61883_FCP_RESP_ADDR
,
66 IEC61883_FCP_RESP_SIZE
,
68 { NULL
, s1394_fcp_resp_recv_write_request
, NULL
},
72 s1394_fa_descr_t s1394_fcp_tgt_descr
= {
73 IEC61883_FCP_CMD_ADDR
,
74 IEC61883_FCP_CMD_SIZE
,
76 { NULL
, s1394_fcp_cmd_recv_write_request
, NULL
},
77 IEC61883_FCP_RESP_ADDR
82 s1394_fcp_hal_init(s1394_hal_t
*hal
)
84 int ret
= DDI_SUCCESS
;
86 TNF_PROBE_0_DEBUG(s1394_fcp_hal_init_enter
, S1394_TNF_SL_FCP_STACK
, "");
88 if ((ddi_prop_exists(DDI_DEV_T_ANY
, hal
->halinfo
.dip
, DDI_PROP_DONTPASS
,
89 "h1394-fcp-claim-on-demand")) == 0) {
90 /* if not on-demand, claim addresses now */
91 ret
= s1394_fa_claim_addr(hal
, S1394_FA_TYPE_FCP_CTL
,
92 &s1394_fcp_ctl_descr
);
93 if (ret
== DDI_SUCCESS
) {
94 ret
= s1394_fa_claim_addr(hal
, S1394_FA_TYPE_FCP_TGT
,
95 &s1394_fcp_tgt_descr
);
96 if (ret
!= DDI_SUCCESS
) {
97 s1394_fa_free_addr(hal
, S1394_FA_TYPE_FCP_CTL
);
102 TNF_PROBE_0_DEBUG(s1394_fcp_hal_init_exit
, S1394_TNF_SL_FCP_STACK
, "");
107 s1394_fcp_register_ctl(s1394_target_t
*target
, t1394_fcp_evts_t
*evts
)
109 return (s1394_fcp_register_common(target
, evts
, S1394_FA_TYPE_FCP_CTL
,
110 &s1394_fcp_ctl_descr
));
114 s1394_fcp_register_tgt(s1394_target_t
*target
, t1394_fcp_evts_t
*evts
)
116 return (s1394_fcp_register_common(target
, evts
, S1394_FA_TYPE_FCP_TGT
,
117 &s1394_fcp_tgt_descr
));
121 s1394_fcp_unregister_ctl(s1394_target_t
*target
)
123 return (s1394_fcp_unregister_common(target
, S1394_FA_TYPE_FCP_CTL
));
127 s1394_fcp_unregister_tgt(s1394_target_t
*target
)
129 return (s1394_fcp_unregister_common(target
, S1394_FA_TYPE_FCP_TGT
));
134 s1394_fcp_register_common(s1394_target_t
*target
, t1394_fcp_evts_t
*evts
,
135 s1394_fa_type_t type
, s1394_fa_descr_t
*descr
)
137 s1394_hal_t
*hal
= target
->on_hal
;
138 s1394_fcp_target_t
*fcp
;
140 rw_enter(&hal
->target_list_rwlock
, RW_WRITER
);
142 if (s1394_fa_list_is_empty(hal
, type
)) {
143 if (s1394_fa_claim_addr(hal
, type
, descr
) != DDI_SUCCESS
) {
144 rw_exit(&hal
->target_list_rwlock
);
145 return (DDI_FAILURE
);
149 /* Add on the target list */
150 s1394_fa_list_add(hal
, target
, type
);
152 fcp
= &target
->target_fa
[type
].fat_u
.fcp
;
153 fcp
->fc_evts
= *evts
;
155 rw_exit(&hal
->target_list_rwlock
);
157 return (DDI_SUCCESS
);
161 s1394_fcp_unregister_common(s1394_target_t
*target
, s1394_fa_type_t type
)
163 s1394_hal_t
*hal
= target
->on_hal
;
166 rw_enter(&hal
->target_list_rwlock
, RW_WRITER
);
168 result
= s1394_fa_list_remove(hal
, target
, type
);
169 if (result
== DDI_SUCCESS
) {
170 if (s1394_fa_list_is_empty(hal
, type
)) {
171 s1394_fa_free_addr(hal
, type
);
174 TNF_PROBE_0(s1394_fcp_unregister_common_error_list
,
175 S1394_TNF_SL_FCP_ERROR
, "");
178 rw_exit(&hal
->target_list_rwlock
);
184 * s1394_fcp_write_check_cmd()
185 * Check if an FCP command is formed correctly;
186 * set cmd_result and return DDI_FAILURE if not.
189 s1394_fcp_write_check_cmd(cmd1394_cmd_t
*cmd
)
193 /* 4-byte writes must be quadlet writes */
194 if (cmd
->cmd_type
== CMD1394_ASYNCH_WR_BLOCK
) {
195 len
= cmd
->cmd_u
.b
.blk_length
;
197 cmd
->cmd_result
= CMD1394_ETYPE_ERROR
;
198 TNF_PROBE_0(t1394_write_error_type
,
199 S1394_TNF_SL_FCP_ERROR
, "");
200 return (DDI_FAILURE
);
207 * request must be within FCP range. we avoid extra checks by
208 * using the fact that command and response are of the same size
210 if ((cmd
->cmd_addr
& IEEE1394_ADDR_OFFSET_MASK
) + len
>
211 IEC61883_FCP_CMD_SIZE
) {
212 cmd
->cmd_result
= CMD1394_EADDRESS_ERROR
;
213 TNF_PROBE_0(t1394_write_error_addr
, S1394_TNF_SL_FCP_ERROR
, "");
214 return (DDI_FAILURE
);
217 /* some options don't make sense for FCP commands */
218 if (cmd
->cmd_options
& CMD1394_OVERRIDE_ADDR
) {
219 cmd
->cmd_result
= CMD1394_EINVALID_COMMAND
;
220 TNF_PROBE_0(t1394_write_error_opt
, S1394_TNF_SL_FCP_ERROR
, "");
221 return (DDI_FAILURE
);
224 return (DDI_SUCCESS
);
228 s1394_fcp_resp_recv_write_request(cmd1394_cmd_t
*req
)
230 s1394_fcp_recv_write_request(req
, S1394_FA_TYPE_FCP_CTL
);
234 s1394_fcp_cmd_recv_write_request(cmd1394_cmd_t
*req
)
236 s1394_fcp_recv_write_request(req
, S1394_FA_TYPE_FCP_TGT
);
240 * s1394_fcp_recv_write_request()
241 * Common write request handler
244 s1394_fcp_recv_write_request(cmd1394_cmd_t
*req
, s1394_fa_type_t type
)
246 s1394_hal_t
*hal
= (s1394_hal_t
*)req
->cmd_callback_arg
;
247 s1394_target_t
*target
;
248 s1394_fa_target_t
*fat
;
251 int (*cb
)(cmd1394_cmd_t
*req
);
252 boolean_t restored
= B_FALSE
;
253 int ret
= T1394_REQ_UNCLAIMED
;
255 TNF_PROBE_0_DEBUG(s1394_fcp_recv_write_request_enter
,
256 S1394_TNF_SL_FCP_STACK
, "");
258 rw_enter(&hal
->target_list_rwlock
, RW_READER
);
261 target
= hal
->hal_fa
[type
].fal_head
;
264 s1394_fa_restore_cmd(hal
, req
);
267 /* Find a target that claims the request */
269 fat
= &target
->target_fa
[type
];
271 cb
= fat
->fat_u
.fcp
.fc_evts
.fcp_write_request
;
275 req
->cmd_callback_arg
= fat
->fat_u
.fcp
.fc_evts
.fcp_arg
;
277 saved_gen
= s1394_fa_list_gen(hal
, type
);
279 rw_exit(&hal
->target_list_rwlock
);
281 rw_enter(&hal
->target_list_rwlock
, RW_READER
);
283 if (ret
== T1394_REQ_CLAIMED
) {
288 * List could change while we dropped the lock. In such
289 * case, start all over again, because missing a write
290 * request can have more serious consequences for a
291 * target than receiving same request more than once
293 if (saved_gen
!= s1394_fa_list_gen(hal
, type
)) {
294 TNF_PROBE_2(s1394_fcp_recv_write_request_error
,
295 S1394_TNF_SL_FCP_ERROR
, "",
296 tnf_string
, msg
, "list gen changed",
297 tnf_opaque
, num_retries
, num_retries
);
299 if (num_retries
<= s1394_fcp_notify_retry_cnt
) {
306 target
= fat
->fat_next
;
307 } while (target
!= NULL
);
310 rw_exit(&hal
->target_list_rwlock
);
312 if (ret
!= T1394_REQ_CLAIMED
) {
313 TNF_PROBE_0(s1394_fcp_recv_write_request_error_unclaimed
,
314 S1394_TNF_SL_FCP_ERROR
, "");
316 s1394_fa_convert_cmd(hal
, req
);
318 s1394_fcp_recv_write_unclaimed(hal
, req
);
321 TNF_PROBE_0_DEBUG(s1394_fcp_recv_write_request_exit
,
322 S1394_TNF_SL_FCP_STACK
, "");
326 * none of the targets claimed the request - send an appropriate response
329 s1394_fcp_recv_write_unclaimed(s1394_hal_t
*hal
, cmd1394_cmd_t
*req
)
331 req
->cmd_result
= IEEE1394_RESP_ADDRESS_ERROR
;
332 (void) s1394_send_response(hal
, req
);