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