xref: /illumos-gate/usr/src/uts/common/io/1394/s1394_fa.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
1 /*
2  * CDDL HEADER START
3  *
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.
8  *
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.
13  *
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]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * s1394_fa.c
31  *    1394 Services Layer Fixed Address Support Routines
32  *    Currently used for FCP support.
33  */
34 
35 #include <sys/conf.h>
36 #include <sys/ddi.h>
37 #include <sys/sunddi.h>
38 #include <sys/cmn_err.h>
39 #include <sys/types.h>
40 #include <sys/kmem.h>
41 #include <sys/tnf_probe.h>
42 
43 #include <sys/1394/t1394.h>
44 #include <sys/1394/s1394.h>
45 #include <sys/1394/h1394.h>
46 
47 static void s1394_fa_completion_cb(cmd1394_cmd_t *cmd);
48 
49 /*
50  * s1394_fa_claim_addr_blk()
51  *    Claim fixed address block.
52  */
53 int
54 s1394_fa_claim_addr(s1394_hal_t *hal, s1394_fa_type_t type,
55     s1394_fa_descr_t *descr)
56 {
57 	t1394_alloc_addr_t	addr;
58 	s1394_fa_hal_t		*falp = &hal->hal_fa[type];
59 	int			ret;
60 
61 	TNF_PROBE_0_DEBUG(s1394_fa_claim_addr_enter, S1394_TNF_SL_FA_STACK, "");
62 
63 	/* Might have been claimed already */
64 	if (falp->fal_addr_blk != NULL) {
65 		TNF_PROBE_0_DEBUG(s1394_fa_claim_addr_exit,
66 		    S1394_TNF_SL_FA_STACK, "");
67 		return (DDI_SUCCESS);
68 	}
69 
70 	falp->fal_descr = descr;
71 
72 	bzero(&addr, sizeof (addr));
73 	addr.aa_type = T1394_ADDR_FIXED;
74 	addr.aa_address = descr->fd_addr;
75 	addr.aa_length = descr->fd_size;
76 	addr.aa_enable = descr->fd_enable;
77 	addr.aa_evts = descr->fd_evts;
78 	addr.aa_arg = hal;
79 
80 	ret = s1394_claim_addr_blk(hal, &addr);
81 	if (ret != DDI_SUCCESS) {
82 		TNF_PROBE_2(s1394_fa_claim_addr_error, S1394_TNF_SL_FA_ERROR,
83 		    "", tnf_int, type, type, tnf_int, ret, ret);
84 	} else {
85 		falp->fal_addr_blk = (s1394_addr_space_blk_t *)addr.aa_hdl;
86 	}
87 
88 	TNF_PROBE_0_DEBUG(s1394_fa_claim_addr_exit, S1394_TNF_SL_FA_STACK, "");
89 	return (ret);
90 }
91 
92 /*
93  * s1394_fa_free_addr_blk()
94  *    Free fixed address block.
95  */
96 void
97 s1394_fa_free_addr(s1394_hal_t *hal, s1394_fa_type_t type)
98 {
99 	s1394_fa_hal_t		*falp = &hal->hal_fa[type];
100 	int			ret;
101 
102 	TNF_PROBE_0_DEBUG(s1394_fa_free_addr_enter, S1394_TNF_SL_FA_STACK, "");
103 
104 	/* Might have been freed already */
105 	if (falp->fal_addr_blk != NULL) {
106 		ret = s1394_free_addr_blk(hal, falp->fal_addr_blk);
107 		if (ret != DDI_SUCCESS) {
108 			TNF_PROBE_1(s1394_fa_free_addr_error,
109 			    S1394_TNF_SL_FA_STACK, "", tnf_int, ret, ret);
110 		}
111 		falp->fal_addr_blk = NULL;
112 	}
113 
114 	TNF_PROBE_0_DEBUG(s1394_fa_free_addr_exit, S1394_TNF_SL_FA_STACK, "");
115 }
116 
117 /*
118  * s1394_fa_list_add()
119  *    Add target to the list of FA clients.
120  *    target_list_rwlock should be writer-held.
121  */
122 void
123 s1394_fa_list_add(s1394_hal_t *hal, s1394_target_t *target,
124     s1394_fa_type_t type)
125 {
126 	s1394_fa_hal_t	*fal = &hal->hal_fa[type];
127 
128 	if (fal->fal_head == NULL) {
129 		ASSERT(fal->fal_tail == NULL);
130 		fal->fal_head = fal->fal_tail = target;
131 	} else {
132 		fal->fal_tail->target_fa[type].fat_next = target;
133 		fal->fal_tail = target;
134 	}
135 	fal->fal_gen++;
136 }
137 
138 /*
139  * s1394_fa_list_remove()
140  *    Remove target from the list of FA clients.
141  *    target_list_rwlock should be writer-held.
142  */
143 int
144 s1394_fa_list_remove(s1394_hal_t *hal, s1394_target_t *target,
145     s1394_fa_type_t type)
146 {
147 	s1394_fa_hal_t	*fal = &hal->hal_fa[type];
148 	s1394_target_t	*curp, **nextp, *prevp = NULL;
149 
150 	for (nextp = &fal->fal_head; (curp = *nextp) != NULL; ) {
151 		if (curp == target) {
152 			*nextp = target->target_fa[type].fat_next;
153 			if (target == fal->fal_tail) {
154 				fal->fal_tail = prevp;
155 			}
156 			fal->fal_gen++;
157 			return (DDI_SUCCESS);
158 		}
159 		nextp = &curp->target_fa[type].fat_next;
160 		prevp = curp;
161 	}
162 	return (DDI_FAILURE);
163 }
164 
165 /*
166  * s1394_fa_list_is_empty()
167  *    Returns B_TRUE if the target list is empty
168  *    target_list_rwlock should be at least reader-held.
169  */
170 boolean_t
171 s1394_fa_list_is_empty(s1394_hal_t *hal, s1394_fa_type_t type)
172 {
173 	s1394_fa_hal_t	*fal = &hal->hal_fa[type];
174 
175 	return (fal->fal_head == NULL);
176 }
177 
178 /*
179  * s1394_fa_list_gen()
180  *    Returns list generation number.
181  *    target_list_rwlock should be at least reader-held.
182  */
183 uint_t
184 s1394_fa_list_gen(s1394_hal_t *hal, s1394_fa_type_t type)
185 {
186 	s1394_fa_hal_t	*fal = &hal->hal_fa[type];
187 
188 	return (fal->fal_gen);
189 }
190 
191 /*
192  * s1394_fa_init_cmd()
193  *    initialize the FA specific part of the command
194  */
195 void
196 s1394_fa_init_cmd(s1394_cmd_priv_t *s_priv, s1394_fa_type_t type)
197 {
198 	s_priv->cmd_ext_type = S1394_CMD_EXT_FA;
199 	s_priv->cmd_ext.fa.type = type;
200 }
201 
202 /*
203  * s1394_fa_convert_cmd()
204  *    convert an FA command (with a relative address) to a regular 1394 command
205  */
206 void
207 s1394_fa_convert_cmd(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
208 {
209 	s1394_fa_cmd_priv_t *fa_priv = S1394_GET_FA_CMD_PRIV(cmd);
210 
211 	cmd->cmd_addr += hal->hal_fa[fa_priv->type].fal_descr->fd_conv_base;
212 	fa_priv->completion_callback = cmd->completion_callback;
213 	fa_priv->callback_arg = cmd->cmd_callback_arg;
214 	cmd->completion_callback = s1394_fa_completion_cb;
215 	cmd->cmd_callback_arg = hal;
216 }
217 
218 /*
219  * s1394_fa_restore_cmd()
220  *    opposite of s1394_fa_convert_cmd(): regular 1394 command to FA command
221  */
222 void
223 s1394_fa_restore_cmd(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
224 {
225 	s1394_fa_cmd_priv_t *fa_priv = S1394_GET_FA_CMD_PRIV(cmd);
226 
227 	ASSERT(fa_priv->type < S1394_FA_NTYPES);
228 
229 	cmd->cmd_addr -= hal->hal_fa[fa_priv->type].fal_descr->fd_conv_base;
230 	cmd->completion_callback = fa_priv->completion_callback;
231 	cmd->cmd_callback_arg = fa_priv->callback_arg;
232 }
233 
234 /*
235  * s1394_fa_check_restore_cmd()
236  *    if a command has FA extension, do s1394_fa_restore_cmd()
237  */
238 void
239 s1394_fa_check_restore_cmd(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
240 {
241 	s1394_cmd_priv_t *s_priv = S1394_GET_CMD_PRIV(cmd);
242 
243 	if (s_priv->cmd_ext_type == S1394_CMD_EXT_FA) {
244 		s1394_fa_restore_cmd(hal, cmd);
245 	}
246 }
247 
248 /*
249  * s1394_fa_completion_cb()
250  *    FA completion callback: restore command and call original callback
251  */
252 static void
253 s1394_fa_completion_cb(cmd1394_cmd_t *cmd)
254 {
255 	s1394_hal_t	*hal = cmd->cmd_callback_arg;
256 
257 	TNF_PROBE_0_DEBUG(s1394_fa_completion_cb_enter,
258 	    S1394_TNF_SL_FA_STACK, "");
259 
260 	s1394_fa_restore_cmd(hal, cmd);
261 
262 	if (cmd->completion_callback) {
263 		cmd->completion_callback(cmd);
264 	}
265 
266 	TNF_PROBE_0_DEBUG(s1394_fa_completion_cb_exit,
267 	    S1394_TNF_SL_FA_STACK, "");
268 }
269