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_fcp.c 29 * 1394 Services Layer FCP Support Routines 30 */ 31 32 #include <sys/conf.h> 33 #include <sys/ddi.h> 34 #include <sys/sunddi.h> 35 #include <sys/cmn_err.h> 36 #include <sys/types.h> 37 #include <sys/kmem.h> 38 39 #include <sys/1394/t1394.h> 40 #include <sys/1394/s1394.h> 41 #include <sys/1394/h1394.h> 42 43 static int s1394_fcp_register_common(s1394_target_t *target, 44 t1394_fcp_evts_t *evts, s1394_fa_type_t type, s1394_fa_descr_t *descr); 45 static int s1394_fcp_unregister_common(s1394_target_t *target, 46 s1394_fa_type_t type); 47 static void s1394_fcp_resp_recv_write_request(cmd1394_cmd_t *req); 48 static void s1394_fcp_cmd_recv_write_request(cmd1394_cmd_t *req); 49 static void s1394_fcp_recv_write_request(cmd1394_cmd_t *req, 50 s1394_fa_type_t type); 51 static void s1394_fcp_recv_write_unclaimed(s1394_hal_t *hal, 52 cmd1394_cmd_t *req); 53 54 55 /* 56 * number of retries to notify registered targets in case target list 57 * changes while the list rwlock is dropped for the time of callback 58 */ 59 uint_t s1394_fcp_notify_retry_cnt = 3; 60 61 s1394_fa_descr_t s1394_fcp_ctl_descr = { 62 IEC61883_FCP_RESP_ADDR, 63 IEC61883_FCP_RESP_SIZE, 64 T1394_ADDR_WRENBL, 65 { NULL, s1394_fcp_resp_recv_write_request, NULL }, 66 IEC61883_FCP_CMD_ADDR 67 }; 68 69 s1394_fa_descr_t s1394_fcp_tgt_descr = { 70 IEC61883_FCP_CMD_ADDR, 71 IEC61883_FCP_CMD_SIZE, 72 T1394_ADDR_WRENBL, 73 { NULL, s1394_fcp_cmd_recv_write_request, NULL }, 74 IEC61883_FCP_RESP_ADDR 75 }; 76 77 78 int 79 s1394_fcp_hal_init(s1394_hal_t *hal) 80 { 81 int ret = DDI_SUCCESS; 82 83 if ((ddi_prop_exists(DDI_DEV_T_ANY, hal->halinfo.dip, DDI_PROP_DONTPASS, 84 "h1394-fcp-claim-on-demand")) == 0) { 85 /* if not on-demand, claim addresses now */ 86 ret = s1394_fa_claim_addr(hal, S1394_FA_TYPE_FCP_CTL, 87 &s1394_fcp_ctl_descr); 88 if (ret == DDI_SUCCESS) { 89 ret = s1394_fa_claim_addr(hal, S1394_FA_TYPE_FCP_TGT, 90 &s1394_fcp_tgt_descr); 91 if (ret != DDI_SUCCESS) { 92 s1394_fa_free_addr(hal, S1394_FA_TYPE_FCP_CTL); 93 } 94 } 95 } 96 97 return (ret); 98 } 99 100 int 101 s1394_fcp_register_ctl(s1394_target_t *target, t1394_fcp_evts_t *evts) 102 { 103 return (s1394_fcp_register_common(target, evts, S1394_FA_TYPE_FCP_CTL, 104 &s1394_fcp_ctl_descr)); 105 } 106 107 int 108 s1394_fcp_register_tgt(s1394_target_t *target, t1394_fcp_evts_t *evts) 109 { 110 return (s1394_fcp_register_common(target, evts, S1394_FA_TYPE_FCP_TGT, 111 &s1394_fcp_tgt_descr)); 112 } 113 114 int 115 s1394_fcp_unregister_ctl(s1394_target_t *target) 116 { 117 return (s1394_fcp_unregister_common(target, S1394_FA_TYPE_FCP_CTL)); 118 } 119 120 int 121 s1394_fcp_unregister_tgt(s1394_target_t *target) 122 { 123 return (s1394_fcp_unregister_common(target, S1394_FA_TYPE_FCP_TGT)); 124 } 125 126 127 static int 128 s1394_fcp_register_common(s1394_target_t *target, t1394_fcp_evts_t *evts, 129 s1394_fa_type_t type, s1394_fa_descr_t *descr) 130 { 131 s1394_hal_t *hal = target->on_hal; 132 s1394_fcp_target_t *fcp; 133 134 rw_enter(&hal->target_list_rwlock, RW_WRITER); 135 136 if (s1394_fa_list_is_empty(hal, type)) { 137 if (s1394_fa_claim_addr(hal, type, descr) != DDI_SUCCESS) { 138 rw_exit(&hal->target_list_rwlock); 139 return (DDI_FAILURE); 140 } 141 } 142 143 /* Add on the target list */ 144 s1394_fa_list_add(hal, target, type); 145 146 fcp = &target->target_fa[type].fat_u.fcp; 147 fcp->fc_evts = *evts; 148 149 rw_exit(&hal->target_list_rwlock); 150 151 return (DDI_SUCCESS); 152 } 153 154 static int 155 s1394_fcp_unregister_common(s1394_target_t *target, s1394_fa_type_t type) 156 { 157 s1394_hal_t *hal = target->on_hal; 158 int result; 159 160 rw_enter(&hal->target_list_rwlock, RW_WRITER); 161 162 result = s1394_fa_list_remove(hal, target, type); 163 if (result == DDI_SUCCESS) { 164 if (s1394_fa_list_is_empty(hal, type)) { 165 s1394_fa_free_addr(hal, type); 166 } 167 } 168 169 rw_exit(&hal->target_list_rwlock); 170 171 return (result); 172 } 173 174 /* 175 * s1394_fcp_write_check_cmd() 176 * Check if an FCP command is formed correctly; 177 * set cmd_result and return DDI_FAILURE if not. 178 */ 179 int 180 s1394_fcp_write_check_cmd(cmd1394_cmd_t *cmd) 181 { 182 int len; 183 184 /* 4-byte writes must be quadlet writes */ 185 if (cmd->cmd_type == CMD1394_ASYNCH_WR_BLOCK) { 186 len = cmd->cmd_u.b.blk_length; 187 if (len == 4) { 188 cmd->cmd_result = CMD1394_ETYPE_ERROR; 189 return (DDI_FAILURE); 190 } 191 } else { 192 len = 4; 193 } 194 195 /* 196 * request must be within FCP range. we avoid extra checks by 197 * using the fact that command and response are of the same size 198 */ 199 if ((cmd->cmd_addr & IEEE1394_ADDR_OFFSET_MASK) + len > 200 IEC61883_FCP_CMD_SIZE) { 201 cmd->cmd_result = CMD1394_EADDRESS_ERROR; 202 return (DDI_FAILURE); 203 } 204 205 /* some options don't make sense for FCP commands */ 206 if (cmd->cmd_options & CMD1394_OVERRIDE_ADDR) { 207 cmd->cmd_result = CMD1394_EINVALID_COMMAND; 208 return (DDI_FAILURE); 209 } 210 211 return (DDI_SUCCESS); 212 } 213 214 static void 215 s1394_fcp_resp_recv_write_request(cmd1394_cmd_t *req) 216 { 217 s1394_fcp_recv_write_request(req, S1394_FA_TYPE_FCP_CTL); 218 } 219 220 static void 221 s1394_fcp_cmd_recv_write_request(cmd1394_cmd_t *req) 222 { 223 s1394_fcp_recv_write_request(req, S1394_FA_TYPE_FCP_TGT); 224 } 225 226 /* 227 * s1394_fcp_recv_write_request() 228 * Common write request handler 229 */ 230 static void 231 s1394_fcp_recv_write_request(cmd1394_cmd_t *req, s1394_fa_type_t type) 232 { 233 s1394_hal_t *hal = (s1394_hal_t *)req->cmd_callback_arg; 234 s1394_target_t *target; 235 s1394_fa_target_t *fat; 236 uint_t saved_gen; 237 int num_retries = 0; 238 int (*cb)(cmd1394_cmd_t *req); 239 boolean_t restored = B_FALSE; 240 int ret = T1394_REQ_UNCLAIMED; 241 242 rw_enter(&hal->target_list_rwlock, RW_READER); 243 244 start: 245 target = hal->hal_fa[type].fal_head; 246 247 if (target) { 248 s1394_fa_restore_cmd(hal, req); 249 restored = B_TRUE; 250 251 /* Find a target that claims the request */ 252 do { 253 fat = &target->target_fa[type]; 254 255 cb = fat->fat_u.fcp.fc_evts.fcp_write_request; 256 if (cb == NULL) { 257 continue; 258 } 259 req->cmd_callback_arg = fat->fat_u.fcp.fc_evts.fcp_arg; 260 261 saved_gen = s1394_fa_list_gen(hal, type); 262 263 rw_exit(&hal->target_list_rwlock); 264 ret = cb(req); 265 rw_enter(&hal->target_list_rwlock, RW_READER); 266 267 if (ret == T1394_REQ_CLAIMED) { 268 break; 269 } 270 271 /* 272 * List could change while we dropped the lock. In such 273 * case, start all over again, because missing a write 274 * request can have more serious consequences for a 275 * target than receiving same request more than once 276 */ 277 if (saved_gen != s1394_fa_list_gen(hal, type)) { 278 num_retries++; 279 if (num_retries <= s1394_fcp_notify_retry_cnt) { 280 goto start; 281 } else { 282 break; 283 } 284 } 285 286 target = fat->fat_next; 287 } while (target != NULL); 288 } 289 290 rw_exit(&hal->target_list_rwlock); 291 292 if (ret != T1394_REQ_CLAIMED) { 293 if (restored) { 294 s1394_fa_convert_cmd(hal, req); 295 } 296 s1394_fcp_recv_write_unclaimed(hal, req); 297 } 298 } 299 300 /* 301 * none of the targets claimed the request - send an appropriate response 302 */ 303 static void 304 s1394_fcp_recv_write_unclaimed(s1394_hal_t *hal, cmd1394_cmd_t *req) 305 { 306 req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR; 307 (void) s1394_send_response(hal, req); 308 } 309