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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * s1394_asynch.c
28 * 1394 Services Layer Asynchronous Communications Routines
29 * These routines handle all of the tasks relating to asynch commands
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 #include <sys/disp.h>
39 #include <sys/1394/t1394.h>
40 #include <sys/1394/s1394.h>
41 #include <sys/1394/h1394.h>
42 #include <sys/1394/ieee1394.h>
43 #include <sys/1394/ieee1212.h>
44
45 static void s1394_handle_lock(cmd1394_cmd_t *cmd);
46
47 static cmd1394_cmd_t *s1394_pending_q_remove(s1394_hal_t *hal);
48
49 static boolean_t s1394_process_pending_q(s1394_hal_t *hal);
50
51 static boolean_t s1394_pending_q_helper(s1394_hal_t *hal, cmd1394_cmd_t *cmd);
52
53 static int s1394_process_split_lock(cmd1394_cmd_t *cmd,
54 cmd1394_cmd_t *target_cmd);
55
56 static int s1394_finish_split_lock(cmd1394_cmd_t *cmd,
57 cmd1394_cmd_t *target_cmd);
58
59 /*
60 * s1394_alloc_cmd()
61 * is used to allocate a command for a target or for a HAL.
62 */
63 int
s1394_alloc_cmd(s1394_hal_t * hal,uint_t flags,cmd1394_cmd_t ** cmdp)64 s1394_alloc_cmd(s1394_hal_t *hal, uint_t flags, cmd1394_cmd_t **cmdp)
65 {
66 s1394_cmd_priv_t *s_priv;
67 void *hal_overhead;
68 uint_t cmd_size;
69 int alloc_sleep;
70
71 alloc_sleep = (flags & T1394_ALLOC_CMD_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP;
72
73 if ((alloc_sleep == KM_SLEEP) &&
74 (servicing_interrupt())) {
75 ASSERT(alloc_sleep != KM_SLEEP); /* fail */
76 return (DDI_FAILURE);
77 }
78
79 /* either FCP command or response, but not both */
80 if ((flags &
81 (T1394_ALLOC_CMD_FCP_COMMAND | T1394_ALLOC_CMD_FCP_RESPONSE)) ==
82 (T1394_ALLOC_CMD_FCP_COMMAND | T1394_ALLOC_CMD_FCP_RESPONSE)) {
83 return (DDI_FAILURE);
84 }
85
86 *cmdp = kmem_cache_alloc(hal->hal_kmem_cachep, alloc_sleep);
87 if (*cmdp == NULL) {
88 return (DDI_FAILURE);
89 }
90 cmd_size = sizeof (cmd1394_cmd_t) +
91 sizeof (s1394_cmd_priv_t) + hal->halinfo.hal_overhead;
92 bzero((void *)*cmdp, cmd_size);
93
94 (*cmdp)->cmd_version = T1394_VERSION_V1;
95 (*cmdp)->cmd_result = CMD1394_NOSTATUS;
96
97 /* Get the Services Layer private area */
98 s_priv = S1394_GET_CMD_PRIV(*cmdp);
99
100 /* Set extension type */
101 if (flags & T1394_ALLOC_CMD_FCP_COMMAND) {
102 s1394_fa_init_cmd(s_priv, S1394_FA_TYPE_FCP_CTL);
103 } else if (flags & T1394_ALLOC_CMD_FCP_RESPONSE) {
104 s1394_fa_init_cmd(s_priv, S1394_FA_TYPE_FCP_TGT);
105 }
106
107 /* Set up the hal_overhead ptr in the hal_cmd_private */
108 hal_overhead = (uchar_t *)s_priv + sizeof (s1394_cmd_priv_t);
109 s_priv->hal_cmd_private.hal_overhead = (void *)hal_overhead;
110
111 /* kstats - number of cmd allocs */
112 hal->hal_kstats->cmd_alloc++;
113
114 return (DDI_SUCCESS);
115 }
116
117 /*
118 * s1394_free_cmd()
119 * is used to free a command that had been previously allocated by
120 * s1394_alloc_cmd().
121 */
122 int
s1394_free_cmd(s1394_hal_t * hal,cmd1394_cmd_t ** cmdp)123 s1394_free_cmd(s1394_hal_t *hal, cmd1394_cmd_t **cmdp)
124 {
125 s1394_cmd_priv_t *s_priv;
126
127 /* Get the Services Layer private area */
128 s_priv = S1394_GET_CMD_PRIV(*cmdp);
129
130 /* Check that command isn't in use */
131 if (s_priv->cmd_in_use == B_TRUE) {
132 ASSERT(s_priv->cmd_in_use == B_FALSE);
133 return (DDI_FAILURE);
134 }
135
136 /* kstats - number of cmd allocs */
137 kmem_cache_free(hal->hal_kmem_cachep, *cmdp);
138
139 /* Command pointer is set to NULL before returning */
140 *cmdp = NULL;
141
142 /* kstats - number of cmd frees */
143 hal->hal_kstats->cmd_free++;
144
145 return (DDI_SUCCESS);
146 }
147
148 /*
149 * s1394_xfer_asynch_command()
150 * is used to send an asynch command down to the HAL. Based upon the type
151 * of command that is being sent, the appropriate HAL function is called.
152 * Command failures are handled be returning an error and/or shutting down
153 * the HAL, depending on the severity of the error.
154 */
155 int
s1394_xfer_asynch_command(s1394_hal_t * hal,cmd1394_cmd_t * cmd,int * err)156 s1394_xfer_asynch_command(s1394_hal_t *hal, cmd1394_cmd_t *cmd, int *err)
157 {
158 s1394_cmd_priv_t *s_priv;
159 h1394_cmd_priv_t *h_priv;
160 s1394_hal_state_t state;
161 dev_info_t *dip;
162 int result_from_hal;
163 int ret;
164
165 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
166
167 mutex_enter(&hal->topology_tree_mutex);
168 state = hal->hal_state;
169 if (((state != S1394_HAL_NORMAL) && (state != S1394_HAL_RESET)) ||
170 (hal->disable_requests_bit == 1)) {
171 *err = s1394_HAL_asynch_error(hal, cmd, state);
172 mutex_exit(&hal->topology_tree_mutex);
173 return (DDI_FAILURE);
174 }
175 mutex_exit(&hal->topology_tree_mutex);
176
177 /* Get the Services Layer private area */
178 s_priv = S1394_GET_CMD_PRIV(cmd);
179
180 /* Get a pointer to the HAL private struct */
181 h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
182
183 /* kstats - number of AT requests sent */
184 switch (cmd->cmd_type) {
185 case CMD1394_ASYNCH_RD_QUAD:
186 hal->hal_kstats->atreq_quad_rd++;
187 break;
188
189 case CMD1394_ASYNCH_RD_BLOCK:
190 hal->hal_kstats->atreq_blk_rd++;
191 break;
192
193 case CMD1394_ASYNCH_WR_QUAD:
194 hal->hal_kstats->atreq_quad_wr++;
195 break;
196
197 case CMD1394_ASYNCH_WR_BLOCK:
198 hal->hal_kstats->atreq_blk_wr++;
199 hal->hal_kstats->atreq_blk_wr_size += h_priv->mblk.length;
200 break;
201
202 case CMD1394_ASYNCH_LOCK_32:
203 hal->hal_kstats->atreq_lock32++;
204 break;
205
206 case CMD1394_ASYNCH_LOCK_64:
207 hal->hal_kstats->atreq_lock64++;
208 break;
209 }
210
211 switch (s_priv->cmd_priv_xfer_type) {
212 /* Call the HAL's read entry point */
213 case S1394_CMD_READ:
214 ret = HAL_CALL(hal).read(hal->halinfo.hal_private,
215 (cmd1394_cmd_t *)cmd,
216 (h1394_cmd_priv_t *)&s_priv->hal_cmd_private,
217 &result_from_hal);
218 break;
219
220 /* Call the HAL's write entry point */
221 case S1394_CMD_WRITE:
222 ret = HAL_CALL(hal).write(hal->halinfo.hal_private,
223 (cmd1394_cmd_t *)cmd,
224 (h1394_cmd_priv_t *)&s_priv->hal_cmd_private,
225 &result_from_hal);
226 break;
227
228 /* Call the HAL's lock entry point */
229 case S1394_CMD_LOCK:
230 ret = HAL_CALL(hal).lock(hal->halinfo.hal_private,
231 (cmd1394_cmd_t *)cmd,
232 (h1394_cmd_priv_t *)&s_priv->hal_cmd_private,
233 &result_from_hal);
234 break;
235
236 default:
237 *err = CMD1394_EUNKNOWN_ERROR;
238
239 return (DDI_FAILURE);
240 }
241
242 if (ret == DDI_FAILURE) {
243 switch (result_from_hal) {
244 case H1394_STATUS_EMPTY_TLABEL:
245 /* Out of TLABELs - Unable to send AT req */
246 *err = CMD1394_ENO_ATREQ;
247 break;
248
249 case H1394_STATUS_INVALID_BUSGEN:
250 /* Out of TLABELs - Unable to send AT req */
251 *err = CMD1394_ESTALE_GENERATION;
252 break;
253
254 case H1394_STATUS_NOMORE_SPACE:
255 /* No more space on HAL's HW queue */
256 *err = CMD1394_ENO_ATREQ;
257 break;
258
259 case H1394_STATUS_INTERNAL_ERROR:
260 dip = hal->halinfo.dip;
261
262 /* An unexpected error in the HAL */
263 cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
264 ddi_node_name(dip), ddi_get_instance(dip));
265
266 /* Disable the HAL */
267 s1394_hal_shutdown(hal, B_TRUE);
268
269 *err = CMD1394_EFATAL_ERROR;
270 break;
271
272 default:
273 dip = hal->halinfo.dip;
274
275 /* An unexpected error in the HAL */
276 cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
277 ddi_node_name(dip), ddi_get_instance(dip));
278
279 /* Disable the HAL */
280 s1394_hal_shutdown(hal, B_TRUE);
281
282 *err = CMD1394_EFATAL_ERROR;
283 break;
284 }
285
286 return (DDI_FAILURE);
287 }
288
289 /* No errors, return success */
290 *err = CMD1394_NOSTATUS;
291
292 return (DDI_SUCCESS);
293 }
294
295 /*
296 * s1394_setup_asynch_command()
297 * is used to setup an asynch command to be sent down to the HAL and out
298 * onto the bus. This function handles setting up the destination address
299 * (if necessary), speed, max_payload, putting the command onto the
300 * outstanding Q list, and any other things that must be done prior to
301 * calling the HAL.
302 */
303 int
s1394_setup_asynch_command(s1394_hal_t * hal,s1394_target_t * target,cmd1394_cmd_t * cmd,uint32_t xfer_type,int * err)304 s1394_setup_asynch_command(s1394_hal_t *hal, s1394_target_t *target,
305 cmd1394_cmd_t *cmd, uint32_t xfer_type, int *err)
306 {
307 s1394_cmd_priv_t *s_priv;
308 h1394_cmd_priv_t *h_priv;
309 uint64_t node;
310 uint32_t from_node;
311 uint32_t to_node;
312 uint32_t bus_capabilities;
313 uint_t current_max_payload;
314 uint_t max_rec;
315 uint_t max_blk;
316
317 ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
318
319 switch (cmd->cmd_type) {
320 case CMD1394_ASYNCH_RD_QUAD:
321 case CMD1394_ASYNCH_WR_QUAD:
322 case CMD1394_ASYNCH_RD_BLOCK:
323 case CMD1394_ASYNCH_WR_BLOCK:
324 case CMD1394_ASYNCH_LOCK_32:
325 case CMD1394_ASYNCH_LOCK_64:
326 break;
327
328 default:
329 *err = CMD1394_EINVALID_COMMAND;
330 return (DDI_FAILURE);
331 }
332
333 /* Check for potential address roll-over */
334 if (s1394_address_rollover(cmd) != B_FALSE) {
335 *err = CMD1394_EADDRESS_ERROR;
336 return (DDI_FAILURE);
337 }
338
339 /* Get the Services Layer private area */
340 s_priv = S1394_GET_CMD_PRIV(cmd);
341
342 /* Set up who sent command on which hal */
343 s_priv->sent_by_target = (s1394_target_t *)target;
344 s_priv->sent_on_hal = (s1394_hal_t *)hal;
345
346 /* Set up command transfer type */
347 s_priv->cmd_priv_xfer_type = xfer_type;
348
349 if (cmd->cmd_options & CMD1394_OVERRIDE_ADDR) {
350 /* Compare the current generation from the HAL struct */
351 /* to the one given by the target */
352
353 /* Speed is to be filled in from speed map */
354 from_node = IEEE1394_NODE_NUM(hal->node_id);
355 to_node = IEEE1394_ADDR_PHY_ID(cmd->cmd_addr);
356
357 if (cmd->bus_generation != hal->generation_count) {
358 *err = CMD1394_ESTALE_GENERATION;
359 return (DDI_FAILURE);
360 }
361
362 } else {
363 /* Set the generation */
364 cmd->bus_generation = hal->generation_count;
365
366 /* If not OVERRIDE_ADDR, then target may not be NULL */
367 ASSERT(target != NULL);
368
369 rw_enter(&hal->target_list_rwlock, RW_READER);
370
371 if ((target->target_state & S1394_TARG_GONE) != 0 ||
372 target->on_node == NULL) {
373 rw_exit(&hal->target_list_rwlock);
374 *err = CMD1394_EDEVICE_REMOVED;
375 return (DDI_FAILURE);
376 }
377
378 ASSERT((target->target_state & S1394_TARG_GONE) == 0);
379 node = target->on_node->node_num;
380 rw_exit(&hal->target_list_rwlock);
381
382 /* Mask in the top 16-bits */
383 cmd->cmd_addr = (cmd->cmd_addr & IEEE1394_ADDR_OFFSET_MASK);
384 cmd->cmd_addr = (cmd->cmd_addr |
385 (node << IEEE1394_ADDR_PHY_ID_SHIFT));
386 cmd->cmd_addr = (cmd->cmd_addr | IEEE1394_ADDR_BUS_ID_MASK);
387
388 /* Speed is to be filled in from speed map */
389 from_node = IEEE1394_NODE_NUM(hal->node_id);
390 to_node = (uint32_t)node;
391 }
392
393 /* Get a pointer to the HAL private struct */
394 h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
395
396 /* Copy the generation into the HAL's private field */
397 h_priv->bus_generation = cmd->bus_generation;
398
399 /* Fill in the nodeID */
400 cmd->nodeID = (cmd->cmd_addr & IEEE1394_ADDR_NODE_ID_MASK) >>
401 IEEE1394_ADDR_NODE_ID_SHIFT;
402
403 if (cmd->cmd_options & CMD1394_OVERRIDE_SPEED) {
404 if (cmd->cmd_speed > IEEE1394_S400) {
405 *err = CMD1394_EINVALID_COMMAND;
406 return (DDI_FAILURE);
407
408 } else {
409 s_priv->hal_cmd_private.speed = (int)cmd->cmd_speed;
410 }
411
412 } else {
413 /* Speed is to be filled in from speed map */
414 s_priv->hal_cmd_private.speed = (int)s1394_speed_map_get(hal,
415 from_node, to_node);
416 }
417
418 /* Is it a block request? */
419 if ((cmd->cmd_type == CMD1394_ASYNCH_RD_BLOCK) ||
420 (cmd->cmd_type == CMD1394_ASYNCH_WR_BLOCK)) {
421
422 if (cmd->cmd_u.b.data_block == NULL) {
423 *err = CMD1394_ENULL_MBLK;
424 return (DDI_FAILURE);
425 }
426
427 /* Also need to check for MBLK_TOO_SMALL */
428 if (s1394_mblk_too_small(cmd) != B_FALSE) {
429 *err = CMD1394_EMBLK_TOO_SMALL;
430 return (DDI_FAILURE);
431 }
432
433 /* Initialize bytes_transferred to zero */
434 cmd->cmd_u.b.bytes_transferred = 0;
435
436 /* Handle the MAX_PAYLOAD size */
437 if (cmd->cmd_options & CMD1394_OVERRIDE_ADDR) {
438
439 current_max_payload = 512 <<
440 (s_priv->hal_cmd_private.speed);
441 if (hal->topology_tree[to_node].cfgrom) {
442 bus_capabilities =
443 hal->topology_tree[to_node].cfgrom[
444 IEEE1212_NODE_CAP_QUAD];
445 max_rec = (bus_capabilities &
446 IEEE1394_BIB_MAXREC_MASK) >>
447 IEEE1394_BIB_MAXREC_SHIFT;
448 } else {
449 max_rec = 0;
450 }
451
452 if ((max_rec > 0) && (max_rec < 14)) {
453 max_blk = 1 << (max_rec + 1);
454
455 } else {
456 /* These are either unspecified or reserved */
457 max_blk = 4;
458 }
459 if (max_blk < current_max_payload)
460 current_max_payload = max_blk;
461
462 } else {
463 rw_enter(&hal->target_list_rwlock, RW_READER);
464 current_max_payload = target->current_max_payload;
465 rw_exit(&hal->target_list_rwlock);
466 }
467
468 if (cmd->cmd_options & CMD1394_OVERRIDE_MAX_PAYLOAD) {
469 if (current_max_payload > cmd->cmd_u.b.max_payload)
470 current_max_payload = cmd->cmd_u.b.max_payload;
471 }
472
473 h_priv->mblk.curr_mblk = cmd->cmd_u.b.data_block;
474
475 if (cmd->cmd_type == CMD1394_ASYNCH_WR_BLOCK) {
476 h_priv->mblk.curr_offset =
477 cmd->cmd_u.b.data_block->b_rptr;
478 } else {
479 h_priv->mblk.curr_offset =
480 cmd->cmd_u.b.data_block->b_wptr;
481 }
482
483 if (cmd->cmd_u.b.blk_length > current_max_payload) {
484 h_priv->mblk.length = current_max_payload;
485 s_priv->data_remaining = cmd->cmd_u.b.blk_length;
486
487 } else {
488 h_priv->mblk.length = cmd->cmd_u.b.blk_length;
489 s_priv->data_remaining = cmd->cmd_u.b.blk_length;
490 }
491 }
492
493 /* Mark command as being used */
494 s_priv->cmd_in_use = B_TRUE;
495
496 /* Put command on the HAL's outstanding request Q */
497 s1394_insert_q_asynch_cmd(hal, cmd);
498
499 return (DDI_SUCCESS);
500 }
501
502 /*
503 * s1394_insert_q_asynch_cmd()
504 * is used to insert a given command structure onto a HAL's outstanding
505 * asynch queue.
506 */
507 void
s1394_insert_q_asynch_cmd(s1394_hal_t * hal,cmd1394_cmd_t * cmd)508 s1394_insert_q_asynch_cmd(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
509 {
510 s1394_cmd_priv_t *s_priv;
511 s1394_cmd_priv_t *c_priv;
512 cmd1394_cmd_t *temp_cmd;
513
514 mutex_enter(&hal->outstanding_q_mutex);
515
516 /* Get the Services Layer private area */
517 s_priv = S1394_GET_CMD_PRIV(cmd);
518
519 /* Is the outstanding request queue empty? */
520 if ((hal->outstanding_q_head == NULL) &&
521 (hal->outstanding_q_tail == NULL)) {
522
523 hal->outstanding_q_head = (cmd1394_cmd_t *)cmd;
524 hal->outstanding_q_tail = (cmd1394_cmd_t *)cmd;
525 s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
526 s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
527
528 } else {
529 s_priv->cmd_priv_next = hal->outstanding_q_head;
530 s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
531
532 temp_cmd = (cmd1394_cmd_t *)hal->outstanding_q_head;
533 c_priv = (s1394_cmd_priv_t *)((uchar_t *)temp_cmd +
534 sizeof (cmd1394_cmd_t));
535 c_priv->cmd_priv_prev = (cmd1394_cmd_t *)cmd;
536
537 hal->outstanding_q_head = (cmd1394_cmd_t *)cmd;
538 }
539
540 mutex_exit(&hal->outstanding_q_mutex);
541 }
542
543 /*
544 * s1394_remove_q_asynch_cmd()
545 * is used to remove a given command structure from a HAL's outstanding
546 * asynch queue.
547 */
548 void
s1394_remove_q_asynch_cmd(s1394_hal_t * hal,cmd1394_cmd_t * cmd)549 s1394_remove_q_asynch_cmd(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
550 {
551 s1394_cmd_priv_t *s_priv;
552 s1394_cmd_priv_t *c_priv;
553 cmd1394_cmd_t *prev_cmd;
554 cmd1394_cmd_t *next_cmd;
555
556 mutex_enter(&hal->outstanding_q_mutex);
557
558 /* Get the Services Layer private area */
559 s_priv = S1394_GET_CMD_PRIV(cmd);
560
561 prev_cmd = (cmd1394_cmd_t *)s_priv->cmd_priv_prev;
562 next_cmd = (cmd1394_cmd_t *)s_priv->cmd_priv_next;
563
564 s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
565 s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
566
567 if (prev_cmd != NULL) {
568 c_priv = (s1394_cmd_priv_t *)((uchar_t *)prev_cmd +
569 sizeof (cmd1394_cmd_t));
570 c_priv->cmd_priv_next = (cmd1394_cmd_t *)next_cmd;
571
572 } else {
573 if (hal->outstanding_q_head == (cmd1394_cmd_t *)cmd)
574 hal->outstanding_q_head = (cmd1394_cmd_t *)next_cmd;
575 }
576
577 if (next_cmd != NULL) {
578 c_priv = (s1394_cmd_priv_t *)((uchar_t *)next_cmd +
579 sizeof (cmd1394_cmd_t));
580 c_priv->cmd_priv_prev = (cmd1394_cmd_t *)prev_cmd;
581
582 } else {
583 if (hal->outstanding_q_tail == (cmd1394_cmd_t *)cmd)
584 hal->outstanding_q_tail = (cmd1394_cmd_t *)prev_cmd;
585 }
586
587 mutex_exit(&hal->outstanding_q_mutex);
588 }
589
590 /*
591 * s1394_atreq_cmd_complete()
592 * is called by h1394_cmd_is_complete() when an AT request has completed.
593 * Based upon a command's completion status, s1394_atreq_cmd_complete()
594 * determines whether to call the target (or unblock), put the command onto
595 * the pending Q to be sent out later, or to resend the command
596 * (multi-part command).
597 */
598 void
s1394_atreq_cmd_complete(s1394_hal_t * hal,cmd1394_cmd_t * req,int status)599 s1394_atreq_cmd_complete(s1394_hal_t *hal, cmd1394_cmd_t *req, int status)
600 {
601 s1394_cmd_priv_t *s_priv;
602 h1394_cmd_priv_t *h_priv;
603 dev_info_t *dip;
604 int ret;
605 int cmd_result;
606 int err;
607
608 /* Get the Services Layer private area */
609 s_priv = S1394_GET_CMD_PRIV(req);
610
611 /* If not an ack_complete... */
612 if (status != H1394_CMD_SUCCESS) {
613 /* kstats - number of failure AT responses */
614 switch (req->cmd_type) {
615 case CMD1394_ASYNCH_RD_QUAD:
616 hal->hal_kstats->atresp_quad_rd_fail++;
617 break;
618
619 case CMD1394_ASYNCH_RD_BLOCK:
620 hal->hal_kstats->atresp_blk_rd_fail++;
621 break;
622
623 case CMD1394_ASYNCH_WR_QUAD:
624 hal->hal_kstats->atresp_quad_wr_fail++;
625 break;
626
627 case CMD1394_ASYNCH_WR_BLOCK:
628 hal->hal_kstats->atresp_blk_wr_fail++;
629 break;
630
631 case CMD1394_ASYNCH_LOCK_32:
632 hal->hal_kstats->atresp_lock32_fail++;
633 break;
634
635 case CMD1394_ASYNCH_LOCK_64:
636 hal->hal_kstats->atresp_lock64_fail++;
637 break;
638 }
639
640
641 switch (status) {
642 /* evt_missing_ack */
643 case H1394_CMD_ETIMEOUT:
644 cmd_result = CMD1394_ETIMEOUT;
645 break;
646
647 /* evt_flushed */
648 case H1394_CMD_EBUSRESET:
649 /* Move request to pending Q if cancel on */
650 /* reset is not set */
651 if (req->cmd_options & CMD1394_CANCEL_ON_BUS_RESET) {
652 cmd_result = CMD1394_EBUSRESET;
653 break;
654 }
655 s1394_remove_q_asynch_cmd(hal, req);
656 s1394_pending_q_insert(hal, req, S1394_PENDING_Q_REAR);
657 return;
658
659 /* ack_busy_X */
660 /* ack_busy_A */
661 /* ack_busy_B */
662 case H1394_CMD_EDEVICE_BUSY:
663 cmd_result = CMD1394_EDEVICE_BUSY;
664 break;
665
666 /* ack_data_error */
667 case H1394_CMD_EDATA_ERROR:
668 cmd_result = CMD1394_EDATA_ERROR;
669 break;
670
671 /* ack_type_error */
672 case H1394_CMD_ETYPE_ERROR:
673 cmd_result = CMD1394_ETYPE_ERROR;
674 break;
675
676 /* resp_address_error */
677 /* ack_address_error */
678 case H1394_CMD_EADDR_ERROR:
679 cmd_result = CMD1394_EADDRESS_ERROR;
680 break;
681
682 /* resp_conflict_error */
683 /* ack_conflict_error */
684 case H1394_CMD_ERSRC_CONFLICT:
685 cmd_result = CMD1394_ERSRC_CONFLICT;
686 break;
687
688 /* ack_tardy */
689 case H1394_CMD_EDEVICE_POWERUP:
690 cmd_result = CMD1394_EDEVICE_BUSY;
691 break;
692
693 /* device errors (bad tcodes, ACKs, etc...) */
694 case H1394_CMD_EDEVICE_ERROR:
695 cmd_result = CMD1394_EDEVICE_ERROR;
696 break;
697
698 /* Unknown error type */
699 case H1394_CMD_EUNKNOWN_ERROR:
700 cmd_result = CMD1394_EUNKNOWN_ERROR;
701 break;
702
703 /* Unrecognized error */
704 default:
705 dip = hal->halinfo.dip;
706
707 /* An unexpected error in the HAL */
708 cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
709 ddi_node_name(dip), ddi_get_instance(dip));
710
711 /* Disable the HAL */
712 s1394_hal_shutdown(hal, B_TRUE);
713
714 return;
715 }
716
717 /* Remove command from the HAL's outstanding request Q */
718 s1394_remove_q_asynch_cmd(hal, req);
719
720 s_priv->cmd_in_use = B_FALSE;
721
722 req->cmd_result = cmd_result;
723
724 /* Is this a blocking command? */
725 if (req->cmd_options & CMD1394_BLOCKING) {
726 /* Unblock the waiting command */
727 mutex_enter(&s_priv->blocking_mutex);
728 s_priv->blocking_flag = B_TRUE;
729 cv_signal(&s_priv->blocking_cv);
730 mutex_exit(&s_priv->blocking_mutex);
731
732 return;
733 }
734
735 /* Call the target's completion_callback() */
736 if (req->completion_callback != NULL) {
737 req->completion_callback(req);
738 }
739
740 return;
741 }
742
743 /* Successful unless otherwise modified */
744 err = CMD1394_CMDSUCCESS;
745
746 if ((req->cmd_type == CMD1394_ASYNCH_RD_BLOCK) ||
747 (req->cmd_type == CMD1394_ASYNCH_WR_BLOCK)) {
748
749 /* Get a pointer to the HAL private struct */
750 h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
751
752 /* Update data_remaining */
753 s_priv->data_remaining -= h_priv->mblk.length;
754
755 /* Increment bytes_transferred */
756 req->cmd_u.b.bytes_transferred += h_priv->mblk.length;
757
758 if (req->cmd_type == CMD1394_ASYNCH_RD_BLOCK)
759 hal->hal_kstats->atreq_blk_rd_size +=
760 h_priv->mblk.length;
761
762 /* Is there still more to send? */
763 if (s_priv->data_remaining > 0) {
764
765 /* Setup the new mblk and offset */
766 h_priv->mblk.curr_mblk = h_priv->mblk.next_mblk;
767 h_priv->mblk.curr_offset = h_priv->mblk.next_offset;
768
769 /* Update destination address */
770 if (!(req->cmd_options &
771 CMD1394_DISABLE_ADDR_INCREMENT)) {
772 req->cmd_addr += h_priv->mblk.length;
773 }
774
775 /*
776 * Use the current MAX_PAYLOAD size. This value
777 * doesn't need to be recalculated because we must
778 * be in the same generation on the bus, else we
779 * would have seen a bus reset error.
780 */
781 if (s_priv->data_remaining < h_priv->mblk.length) {
782 h_priv->mblk.length = s_priv->data_remaining;
783 }
784
785 /* Send command out again */
786 ret = s1394_xfer_asynch_command(hal, req, &err);
787
788 if (ret == DDI_SUCCESS) {
789 return;
790
791 } else if (err == CMD1394_ESTALE_GENERATION) {
792 /* Remove cmd from outstanding request Q */
793 s1394_remove_q_asynch_cmd(hal, req);
794 s1394_pending_q_insert(hal, req,
795 S1394_PENDING_Q_REAR);
796
797 return;
798 }
799 }
800 }
801
802 /* Remove command from the HAL's outstanding request Q */
803 s1394_remove_q_asynch_cmd(hal, req);
804
805 s_priv->cmd_in_use = B_FALSE;
806
807 /* Set status */
808 req->cmd_result = err;
809
810 /* Is this a blocking command? */
811 if (req->cmd_options & CMD1394_BLOCKING) {
812 /* Unblock the waiting command */
813 mutex_enter(&s_priv->blocking_mutex);
814 s_priv->blocking_flag = B_TRUE;
815 cv_signal(&s_priv->blocking_cv);
816 mutex_exit(&s_priv->blocking_mutex);
817
818 return;
819 }
820
821 /* Set status and call completion_callback() */
822 if (req->completion_callback != NULL) {
823
824 req->completion_callback(req);
825
826 return;
827 }
828 }
829
830 /*
831 * s1394_atresp_cmd_complete()
832 * is similar to s1394_atreq_cmd_complete(). It is also called by
833 * h1394_cmd_is_complete(), but when an AT response has completed.
834 * Again, based upon the command's completion status,
835 * s1394_atresp_cmd_complete() determines whether to call the target or
836 * to simply cleanup the command and return.
837 */
838 void
s1394_atresp_cmd_complete(s1394_hal_t * hal,cmd1394_cmd_t * resp,int status)839 s1394_atresp_cmd_complete(s1394_hal_t *hal, cmd1394_cmd_t *resp, int status)
840 {
841 s1394_cmd_priv_t *s_priv;
842 h1394_cmd_priv_t *h_priv;
843 dev_info_t *dip;
844 boolean_t valid_addr_blk;
845 int target_status;
846
847 target_status = CMD1394_CMDSUCCESS;
848
849 /* If not an ack_complete */
850 if (status != H1394_CMD_SUCCESS) {
851 switch (status) {
852 /* evt_missing_ack */
853 case H1394_CMD_ETIMEOUT:
854 target_status = CMD1394_ETIMEOUT;
855 break;
856
857 /* evt_flushed */
858 case H1394_CMD_EBUSRESET:
859 target_status = CMD1394_EBUSRESET;
860 break;
861
862 /* ack_busy_X */
863 /* ack_busy_A */
864 /* ack_busy_B */
865 case H1394_CMD_EDEVICE_BUSY:
866 target_status = CMD1394_EDEVICE_BUSY;
867 break;
868
869 /* ack_data_error */
870 case H1394_CMD_EDATA_ERROR:
871 target_status = CMD1394_EDATA_ERROR;
872 break;
873
874 /* ack_type_error */
875 case H1394_CMD_ETYPE_ERROR:
876 target_status = CMD1394_ETYPE_ERROR;
877 break;
878
879 /* ack_address_error */
880 case H1394_CMD_EADDR_ERROR:
881 target_status = CMD1394_EADDRESS_ERROR;
882 break;
883
884 /* ack_conflict_error */
885 case H1394_CMD_ERSRC_CONFLICT:
886 target_status = CMD1394_ERSRC_CONFLICT;
887 break;
888
889 /* ack_tardy */
890 case H1394_CMD_EDEVICE_POWERUP:
891 target_status = CMD1394_EDEVICE_BUSY;
892 break;
893
894 /* device errors (bad tcodes, ACKs, etc...) */
895 case H1394_CMD_EDEVICE_ERROR:
896 target_status = CMD1394_EDEVICE_ERROR;
897 break;
898
899 /* Unknown error type */
900 case H1394_CMD_EUNKNOWN_ERROR:
901 target_status = CMD1394_EUNKNOWN_ERROR;
902 break;
903
904 /* Unrecognized error */
905 default:
906 dip = hal->halinfo.dip;
907
908 /* An unexpected error in the HAL */
909 cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
910 ddi_node_name(dip), ddi_get_instance(dip));
911
912 /* Disable the HAL */
913 s1394_hal_shutdown(hal, B_TRUE);
914
915 return;
916 }
917 }
918
919 /* Get the Services Layer private area */
920 s_priv = S1394_GET_CMD_PRIV(resp);
921
922 /* Get a pointer to the HAL private struct */
923 h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
924
925 valid_addr_blk = s_priv->arreq_valid_addr;
926
927 if (valid_addr_blk == B_TRUE) {
928 /* Set the command status */
929 resp->cmd_result = target_status;
930
931 switch (s_priv->cmd_priv_xfer_type) {
932 case S1394_CMD_READ:
933 case S1394_CMD_WRITE:
934 case S1394_CMD_LOCK:
935 if (resp->completion_callback != NULL) {
936 resp->completion_callback(resp);
937 }
938 break;
939
940 default:
941 dip = hal->halinfo.dip;
942
943 /* An unexpected error in the HAL */
944 cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
945 ddi_node_name(dip), ddi_get_instance(dip));
946
947 /* Disable the HAL */
948 s1394_hal_shutdown(hal, B_TRUE);
949
950 return;
951 }
952 }
953
954 /* Free the command - Pass it back to the HAL */
955 HAL_CALL(hal).response_complete(hal->halinfo.hal_private, resp, h_priv);
956 }
957
958 /*
959 * s1394_send_response()
960 * is used to send a response to an AR request. Depending on whether the
961 * request was a broadcast request, a write to posted write address space,
962 * or some other request, either a response packet is sent, or the command
963 * is returned to the HAL. A return value of DDI_SUCCESS means that the
964 * command has been handled correctly. It was either successfully sent to
965 * the HAL, or, if it was posted_write of broadcast, it was freed up. A
966 * return value of DDI_FAILURE indicates either a serious error, in which
967 * case the HAL is shutdown, or a failure returned by the HAL, in which
968 * case the command is freed up and notice of the failure is returned.
969 */
970 int
s1394_send_response(s1394_hal_t * hal,cmd1394_cmd_t * resp)971 s1394_send_response(s1394_hal_t *hal, cmd1394_cmd_t *resp)
972 {
973 s1394_cmd_priv_t *s_priv;
974 h1394_cmd_priv_t *h_priv;
975 dev_info_t *dip;
976 int ret;
977 int result;
978
979 /* Get the Services Layer private area */
980 s_priv = S1394_GET_CMD_PRIV(resp);
981
982 /* Get a pointer to the HAL private struct */
983 h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
984
985 /*
986 * If request was broadcast or a write request to a posted write
987 * address, don't send a response
988 */
989 if ((resp->broadcast == 1) || ((s_priv->posted_write == B_TRUE) &&
990 ((resp->cmd_result == CMD1394_ASYNCH_WR_QUAD) ||
991 (resp->cmd_result == CMD1394_ASYNCH_WR_BLOCK)))) {
992
993 /* Free the command - Pass it back to the HAL */
994 HAL_CALL(hal).response_complete(hal->halinfo.hal_private,
995 resp, h_priv);
996
997 return (DDI_SUCCESS);
998 }
999
1000 /* kstats - number of failure responses sent */
1001 if (resp->cmd_result != IEEE1394_RESP_COMPLETE) {
1002 switch (resp->cmd_type) {
1003 case CMD1394_ASYNCH_RD_QUAD:
1004 hal->hal_kstats->arresp_quad_rd_fail++;
1005 break;
1006
1007 case CMD1394_ASYNCH_RD_BLOCK:
1008 hal->hal_kstats->arresp_blk_rd_fail++;
1009 break;
1010
1011 case CMD1394_ASYNCH_WR_QUAD:
1012 hal->hal_kstats->arresp_quad_wr_fail++;
1013 break;
1014
1015 case CMD1394_ASYNCH_WR_BLOCK:
1016 hal->hal_kstats->arresp_blk_wr_fail++;
1017 break;
1018
1019 case CMD1394_ASYNCH_LOCK_32:
1020 hal->hal_kstats->arresp_lock32_fail++;
1021 break;
1022
1023 case CMD1394_ASYNCH_LOCK_64:
1024 hal->hal_kstats->arresp_lock64_fail++;
1025 break;
1026 }
1027 } else {
1028 if (resp->cmd_type == CMD1394_ASYNCH_RD_BLOCK)
1029 hal->hal_kstats->arreq_blk_rd_size +=
1030 resp->cmd_u.b.blk_length;
1031 }
1032
1033 if (resp->cmd_type == CMD1394_ASYNCH_RD_BLOCK) {
1034 h_priv->mblk.curr_mblk = resp->cmd_u.b.data_block;
1035 h_priv->mblk.curr_offset = resp->cmd_u.b.data_block->b_rptr;
1036 h_priv->mblk.length = resp->cmd_u.b.blk_length;
1037 }
1038
1039 switch (s_priv->cmd_priv_xfer_type) {
1040 case S1394_CMD_READ:
1041 ret = HAL_CALL(hal).read_response(hal->halinfo.hal_private,
1042 resp, h_priv, &result);
1043 break;
1044
1045 case S1394_CMD_WRITE:
1046 ret = HAL_CALL(hal).write_response(hal->halinfo.hal_private,
1047 resp, h_priv, &result);
1048 break;
1049
1050 case S1394_CMD_LOCK:
1051 ret = HAL_CALL(hal).lock_response(hal->halinfo.hal_private,
1052 resp, h_priv, &result);
1053 break;
1054
1055 default:
1056 dip = hal->halinfo.dip;
1057
1058 /* An unexpected error in the HAL */
1059 cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
1060 ddi_node_name(dip), ddi_get_instance(dip));
1061
1062 /* Disable the HAL */
1063 s1394_hal_shutdown(hal, B_TRUE);
1064
1065 return (DDI_FAILURE);
1066 }
1067
1068 /* Unable to send a response */
1069 if (ret != DDI_SUCCESS) {
1070 /* Free the command - Pass it back to the HAL */
1071 HAL_CALL(hal).response_complete(hal->halinfo.hal_private,
1072 resp, h_priv);
1073
1074 return (DDI_FAILURE);
1075 }
1076
1077 return (DDI_SUCCESS);
1078 }
1079
1080 /*
1081 * s1394_compare_swap()
1082 * is used by t1394_lock() to send a lock request. Any of the lock
1083 * requests specified explicitly by the 1394 spec will pass thru here,
1084 * i.e compare-swap, mask-swap, etc.
1085 */
1086 int
s1394_compare_swap(s1394_hal_t * hal,s1394_target_t * target,cmd1394_cmd_t * cmd)1087 s1394_compare_swap(s1394_hal_t *hal, s1394_target_t *target, cmd1394_cmd_t *cmd)
1088 {
1089 s1394_cmd_priv_t *s_priv;
1090 s1394_hal_state_t state;
1091 int err;
1092 int ret;
1093
1094 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1095
1096 /* Lock the topology tree - protect from bus reset */
1097 mutex_enter(&hal->topology_tree_mutex);
1098
1099 ret = s1394_setup_asynch_command(hal, target, cmd, S1394_CMD_LOCK,
1100 &err);
1101
1102 /* Unlock the topology tree */
1103 mutex_exit(&hal->topology_tree_mutex);
1104
1105 /* Get the Services Layer private area */
1106 s_priv = S1394_GET_CMD_PRIV(cmd);
1107
1108 /* Command has now been put onto the queue! */
1109 if (ret != DDI_SUCCESS) {
1110 /* Copy error code into result */
1111 cmd->cmd_result = err;
1112
1113 return (DDI_FAILURE);
1114 }
1115
1116 mutex_enter(&hal->topology_tree_mutex);
1117 state = hal->hal_state;
1118 /* If this command was sent during a bus reset, */
1119 /* then put it onto the pending Q. */
1120 if (state == S1394_HAL_RESET) {
1121 /* Remove cmd from outstanding request Q */
1122 s1394_remove_q_asynch_cmd(hal, cmd);
1123
1124 /* Are we on the bus reset event stack? */
1125 if (s1394_on_br_thread(hal) == B_TRUE) {
1126 /* Blocking commands are not allowed */
1127 if (cmd->cmd_options & CMD1394_BLOCKING) {
1128 mutex_exit(&hal->topology_tree_mutex);
1129
1130 s_priv->cmd_in_use = B_FALSE;
1131
1132 cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
1133
1134 return (DDI_FAILURE);
1135 }
1136 }
1137
1138 s1394_pending_q_insert(hal, cmd, S1394_PENDING_Q_FRONT);
1139 mutex_exit(&hal->topology_tree_mutex);
1140
1141 /* Block (if necessary) */
1142 s1394_block_on_asynch_cmd(cmd);
1143
1144 return (DDI_SUCCESS);
1145 }
1146 mutex_exit(&hal->topology_tree_mutex);
1147
1148 /* Send the command out */
1149 ret = s1394_xfer_asynch_command(hal, cmd, &err);
1150
1151 if (ret != DDI_SUCCESS) {
1152 if (err == CMD1394_ESTALE_GENERATION) {
1153 /* Remove cmd from outstanding request Q */
1154 s1394_remove_q_asynch_cmd(hal, cmd);
1155 s1394_pending_q_insert(hal, cmd, S1394_PENDING_Q_FRONT);
1156
1157 /* Block (if necessary) */
1158 s1394_block_on_asynch_cmd(cmd);
1159
1160 return (DDI_SUCCESS);
1161
1162 } else {
1163 /* Remove cmd from outstanding request Q */
1164 s1394_remove_q_asynch_cmd(hal, cmd);
1165
1166 s_priv->cmd_in_use = B_FALSE;
1167
1168 /* Copy error code into result */
1169 cmd->cmd_result = err;
1170
1171 return (DDI_FAILURE);
1172 }
1173 } else {
1174 /* Block (if necessary) */
1175 s1394_block_on_asynch_cmd(cmd);
1176
1177 return (DDI_SUCCESS);
1178 }
1179 }
1180
1181 /*
1182 * s1394_split_lock_req()
1183 * is also used by t1394_lock() to send a lock request. The difference
1184 * is that s1394_split_lock_req() is used to send the software supported
1185 * lock types, i.e. bit_and, bit_or, etc. These lock requests require
1186 * more than one transaction, typically compare-swap's.
1187 */
1188 int
s1394_split_lock_req(s1394_hal_t * hal,s1394_target_t * target,cmd1394_cmd_t * cmd)1189 s1394_split_lock_req(s1394_hal_t *hal, s1394_target_t *target,
1190 cmd1394_cmd_t *cmd)
1191 {
1192 s1394_cmd_priv_t *s_priv;
1193 cmd1394_cmd_t *tmp_cmd;
1194
1195 /* Allocate a temporary command */
1196 if (s1394_alloc_cmd(hal, T1394_ALLOC_CMD_NOSLEEP, &tmp_cmd) !=
1197 DDI_SUCCESS) {
1198 cmd->cmd_result = CMD1394_EUNKNOWN_ERROR;
1199
1200 return (DDI_FAILURE);
1201 }
1202
1203 /* Get the Services Layer private area */
1204 s_priv = S1394_GET_CMD_PRIV(tmp_cmd);
1205
1206 tmp_cmd->completion_callback = s1394_handle_lock;
1207 tmp_cmd->cmd_callback_arg = (opaque_t)cmd;
1208 tmp_cmd->cmd_type = cmd->cmd_type;
1209 tmp_cmd->cmd_addr = cmd->cmd_addr;
1210 tmp_cmd->cmd_options = cmd->cmd_options;
1211 tmp_cmd->bus_generation = cmd->bus_generation;
1212
1213 /* The temporary command can not block */
1214 tmp_cmd->cmd_options = tmp_cmd->cmd_options & ~CMD1394_BLOCKING;
1215
1216 /* Setup compare-swap with data_value == arg_value (read) */
1217 if (tmp_cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
1218 tmp_cmd->cmd_u.l32.data_value = 0;
1219 tmp_cmd->cmd_u.l32.arg_value = 0;
1220 tmp_cmd->cmd_u.l32.lock_type = CMD1394_LOCK_COMPARE_SWAP;
1221 s_priv->temp_num_retries = cmd->cmd_u.l32.num_retries;
1222 } else {
1223 tmp_cmd->cmd_u.l64.data_value = 0;
1224 tmp_cmd->cmd_u.l64.arg_value = 0;
1225 tmp_cmd->cmd_u.l64.lock_type = CMD1394_LOCK_COMPARE_SWAP;
1226 s_priv->temp_num_retries = cmd->cmd_u.l64.num_retries;
1227 }
1228
1229 /* Initialize lock_req_step */
1230 s_priv->lock_req_step = 0;
1231
1232 /* Get the Services Layer private area for the target cmd */
1233 s_priv = S1394_GET_CMD_PRIV(cmd);
1234
1235 s_priv->cmd_in_use = B_TRUE;
1236
1237 /* Send the request */
1238 if (s1394_compare_swap(hal, target, tmp_cmd) != DDI_SUCCESS) {
1239 s_priv->cmd_in_use = B_FALSE;
1240
1241 /* Free the temporary command */
1242 if (s1394_free_cmd(hal, &tmp_cmd) != DDI_SUCCESS)
1243 cmd->cmd_result = CMD1394_EUNKNOWN_ERROR;
1244
1245 return (DDI_FAILURE);
1246 }
1247
1248 /* Block (if necessary) */
1249 s1394_block_on_asynch_cmd(cmd);
1250
1251 return (DDI_SUCCESS);
1252 }
1253
1254 /*
1255 * s1394_handle_lock()
1256 * is the callback for s1394_split_lock_req(). It does all of the real
1257 * work. Based on the specific lock type all necessary manipulation is
1258 * performed and another compare swap is sent out. If the transaction
1259 * is unsuccessful, it is retried.
1260 */
1261 static void
s1394_handle_lock(cmd1394_cmd_t * cmd)1262 s1394_handle_lock(cmd1394_cmd_t *cmd)
1263 {
1264 s1394_hal_t *to_hal;
1265 s1394_target_t *target;
1266 s1394_cmd_priv_t *s_priv;
1267 cmd1394_cmd_t *target_cmd;
1268 uint32_t lock_req_step;
1269 int tcmd_result;
1270 int ret;
1271
1272 /* Get the Services Layer private area */
1273 s_priv = S1394_GET_CMD_PRIV(cmd);
1274
1275 lock_req_step = s_priv->lock_req_step;
1276
1277 /* Get the target's command */
1278 target_cmd = (cmd1394_cmd_t *)cmd->cmd_callback_arg;
1279
1280 /* Get the destination of the command */
1281 to_hal = s_priv->sent_on_hal;
1282
1283 lock_req_step_0:
1284 /* Is this step 0 completing? */
1285 if (lock_req_step == 0) {
1286 /* Was the request successful? */
1287 if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
1288 /* Do any math, bit ops, or byte-swapping necessary */
1289 ret = s1394_process_split_lock(cmd, target_cmd);
1290
1291 if (ret != DDI_SUCCESS) {
1292 tcmd_result = target_cmd->cmd_result;
1293 goto lock_req_done;
1294 }
1295
1296 s_priv->lock_req_step = 1;
1297
1298 target = s_priv->sent_by_target;
1299
1300 if (s1394_compare_swap(to_hal, target, cmd) !=
1301 DDI_SUCCESS) {
1302 tcmd_result = cmd->cmd_result;
1303 goto lock_req_done;
1304 } else {
1305 return;
1306 }
1307 } else {
1308 /* Command failed for some reason */
1309 tcmd_result = cmd->cmd_result;
1310 goto lock_req_done;
1311 }
1312 } else { /* lock_req_step == 1 */
1313 /* Was the request successful? */
1314 if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
1315 /* Do whatever's necessary to finish up the lock */
1316 ret = s1394_finish_split_lock(cmd, target_cmd);
1317
1318 if (ret != DDI_SUCCESS) {
1319 lock_req_step = 0;
1320 goto lock_req_step_0;
1321 } else {
1322 tcmd_result = cmd->cmd_result;
1323 goto lock_req_done;
1324 }
1325 } else {
1326 /* Command failed for some reason */
1327 tcmd_result = cmd->cmd_result;
1328 goto lock_req_done;
1329 }
1330 }
1331
1332 lock_req_done:
1333 (void) s1394_free_cmd(to_hal, &cmd);
1334
1335 /* Get the Services Layer private area */
1336 s_priv = S1394_GET_CMD_PRIV(target_cmd);
1337
1338 s_priv->cmd_in_use = B_FALSE;
1339
1340 target_cmd->cmd_result = tcmd_result;
1341
1342 /* Is this a blocking command? */
1343 if (target_cmd->cmd_options & CMD1394_BLOCKING) {
1344 /* Unblock the waiting command */
1345 mutex_enter(&s_priv->blocking_mutex);
1346 s_priv->blocking_flag = B_TRUE;
1347 cv_signal(&s_priv->blocking_cv);
1348 mutex_exit(&s_priv->blocking_mutex);
1349
1350 return;
1351 }
1352
1353 /* Call the target's completion_callback() */
1354 if (target_cmd->completion_callback != NULL)
1355 target_cmd->completion_callback(target_cmd);
1356 }
1357
1358 /*
1359 * s1394_pending_q_insert()
1360 * is used to insert a given command structure onto a HAL's pending queue
1361 * for later processing (after the bus reset). All commands returned by
1362 * the HAL, are inserted onto the rear of the list (first priority), and
1363 * all other commands (from targets during bus reset) are put onto the front.
1364 */
1365 void
s1394_pending_q_insert(s1394_hal_t * hal,cmd1394_cmd_t * cmd,uint_t flags)1366 s1394_pending_q_insert(s1394_hal_t *hal, cmd1394_cmd_t *cmd, uint_t flags)
1367 {
1368 cmd1394_cmd_t *temp_cmd;
1369 s1394_cmd_priv_t *s_priv;
1370 s1394_cmd_priv_t *c_priv;
1371
1372 mutex_enter(&hal->pending_q_mutex);
1373
1374 /* Get the Services Layer private area */
1375 s_priv = S1394_GET_CMD_PRIV(cmd);
1376
1377 /* Is the outstanding request queue empty? */
1378 if ((hal->pending_q_head == NULL) && (hal->pending_q_tail == NULL)) {
1379
1380 hal->pending_q_head = (cmd1394_cmd_t *)cmd;
1381 hal->pending_q_tail = (cmd1394_cmd_t *)cmd;
1382 s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
1383 s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
1384
1385 } else if (flags == S1394_PENDING_Q_FRONT) {
1386 s_priv->cmd_priv_next = hal->pending_q_head;
1387 s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
1388
1389 temp_cmd = (cmd1394_cmd_t *)hal->pending_q_head;
1390 c_priv = (s1394_cmd_priv_t *)((uchar_t *)temp_cmd +
1391 sizeof (cmd1394_cmd_t));
1392 c_priv->cmd_priv_prev = (cmd1394_cmd_t *)cmd;
1393
1394 hal->pending_q_head = (cmd1394_cmd_t *)cmd;
1395
1396 } else {
1397 s_priv->cmd_priv_prev = hal->pending_q_tail;
1398 s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
1399
1400 temp_cmd = (cmd1394_cmd_t *)hal->pending_q_tail;
1401 c_priv = (s1394_cmd_priv_t *)((uchar_t *)temp_cmd +
1402 sizeof (cmd1394_cmd_t));
1403 c_priv->cmd_priv_next = (cmd1394_cmd_t *)cmd;
1404
1405 hal->pending_q_tail = (cmd1394_cmd_t *)cmd;
1406 }
1407
1408 mutex_exit(&hal->pending_q_mutex);
1409
1410 /* kstats - number of pending Q insertions */
1411 hal->hal_kstats->pending_q_insert++;
1412 }
1413
1414 /*
1415 * s1394_pending_q_remove()
1416 * is used to remove a command structure from a HAL's pending queue for
1417 * processing.
1418 */
1419 static cmd1394_cmd_t *
s1394_pending_q_remove(s1394_hal_t * hal)1420 s1394_pending_q_remove(s1394_hal_t *hal)
1421 {
1422 s1394_cmd_priv_t *s_priv;
1423 s1394_cmd_priv_t *c_priv;
1424 cmd1394_cmd_t *cmd;
1425 cmd1394_cmd_t *prev_cmd;
1426
1427 mutex_enter(&hal->pending_q_mutex);
1428
1429 cmd = (cmd1394_cmd_t *)hal->pending_q_tail;
1430 if (cmd == NULL) {
1431 mutex_exit(&hal->pending_q_mutex);
1432 return (NULL);
1433 }
1434
1435 /* Get the Services Layer private area */
1436 s_priv = S1394_GET_CMD_PRIV(cmd);
1437
1438 prev_cmd = (cmd1394_cmd_t *)s_priv->cmd_priv_prev;
1439
1440 s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
1441 s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
1442
1443 if (prev_cmd != NULL) {
1444 c_priv = (s1394_cmd_priv_t *)((uchar_t *)prev_cmd +
1445 sizeof (cmd1394_cmd_t));
1446 c_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
1447
1448 } else {
1449 hal->pending_q_head = (cmd1394_cmd_t *)NULL;
1450 }
1451 hal->pending_q_tail = (cmd1394_cmd_t *)prev_cmd;
1452
1453 mutex_exit(&hal->pending_q_mutex);
1454
1455 return (cmd);
1456 }
1457
1458 /*
1459 * s1394_resend_pending_cmds()
1460 * is called when the pending queue is to be flushed. After most of the
1461 * bus reset processing is completed, the pending commands are sent/resent.
1462 */
1463 void
s1394_resend_pending_cmds(s1394_hal_t * hal)1464 s1394_resend_pending_cmds(s1394_hal_t *hal)
1465 {
1466 int done;
1467
1468 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1469
1470 do {
1471 done = s1394_process_pending_q(hal);
1472 } while (done == B_FALSE);
1473
1474 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1475 }
1476
1477 /*
1478 * s1394_process_pending_q()
1479 * is called to send/resend the commands on the pending queue. All command
1480 * handling can be done here, including notifying the target of failed
1481 * commands, etc. If it is necessary to recompute the address, speed,
1482 * or max_payload for a command, that can be done here too. And if there
1483 * is no reason not to continue sending commands from the pending queue,
1484 * then a B_FALSE is returned, else B_TRUE is returned.
1485 */
1486 static boolean_t
s1394_process_pending_q(s1394_hal_t * hal)1487 s1394_process_pending_q(s1394_hal_t *hal)
1488 {
1489 s1394_cmd_priv_t *s_priv;
1490 h1394_cmd_priv_t *h_priv;
1491 s1394_target_t *target;
1492 cmd1394_cmd_t *cmd;
1493 uint64_t node;
1494 uint32_t from_node;
1495 uint32_t to_node;
1496 uint_t current_max_payload;
1497 int ret;
1498
1499 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1500
1501 /* Pull a command from the Pending Q */
1502 cmd = s1394_pending_q_remove(hal);
1503
1504 if (cmd == NULL) {
1505 return (B_TRUE);
1506 }
1507
1508 /* Get the Services Layer private area */
1509 s_priv = S1394_GET_CMD_PRIV(cmd);
1510
1511 /* Get a pointer to the HAL private struct */
1512 h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
1513
1514 if ((cmd->cmd_options & CMD1394_OVERRIDE_ADDR) ||
1515 (cmd->cmd_options & CMD1394_CANCEL_ON_BUS_RESET)) {
1516 if (h_priv->bus_generation == hal->generation_count) {
1517 ret = s1394_pending_q_helper(hal, cmd);
1518 return (ret);
1519 } else {
1520
1521 s_priv->cmd_in_use = B_FALSE;
1522
1523 cmd->cmd_result = CMD1394_EBUSRESET;
1524
1525 /* Is this a blocking command? */
1526 if (cmd->cmd_options & CMD1394_BLOCKING) {
1527 /* Unblock the waiting command */
1528 mutex_enter(&s_priv->blocking_mutex);
1529 s_priv->blocking_flag = B_TRUE;
1530 cv_signal(&s_priv->blocking_cv);
1531 mutex_exit(&s_priv->blocking_mutex);
1532
1533 return (B_FALSE);
1534 }
1535
1536 /* Call the target's completion_callback() */
1537 if (cmd->completion_callback != NULL) {
1538 cmd->completion_callback(cmd);
1539 }
1540
1541 return (B_FALSE);
1542 }
1543 } else {
1544 if (h_priv->bus_generation == hal->generation_count) {
1545 ret = s1394_pending_q_helper(hal, cmd);
1546 return (ret);
1547 } else {
1548 /* Make sure we can get the topology_tree_mutex */
1549 if (s1394_lock_tree(hal) != DDI_SUCCESS)
1550 return (B_TRUE);
1551
1552 /* Set the generation */
1553 cmd->bus_generation = hal->generation_count;
1554
1555 /* Copy the generation into the HAL's private field */
1556 h_priv->bus_generation = cmd->bus_generation;
1557
1558 target = s_priv->sent_by_target;
1559
1560 /* If not OVERRIDE_ADDR, then target may not be NULL */
1561 ASSERT(target != NULL);
1562
1563 rw_enter(&hal->target_list_rwlock, RW_READER);
1564
1565 if (((target->target_state & S1394_TARG_GONE) == 0) &&
1566 (target->on_node != NULL)) {
1567 node = target->on_node->node_num;
1568 rw_exit(&hal->target_list_rwlock);
1569 } else {
1570 rw_exit(&hal->target_list_rwlock);
1571
1572 s_priv->cmd_in_use = B_FALSE;
1573
1574 cmd->cmd_result = CMD1394_EDEVICE_REMOVED;
1575
1576 /* Is this a blocking command? */
1577 if (cmd->cmd_options & CMD1394_BLOCKING) {
1578 s1394_unlock_tree(hal);
1579
1580 /* Unblock the waiting command */
1581 mutex_enter(&s_priv->blocking_mutex);
1582 s_priv->blocking_flag = B_TRUE;
1583 cv_signal(&s_priv->blocking_cv);
1584 mutex_exit(&s_priv->blocking_mutex);
1585
1586 return (B_FALSE);
1587 }
1588
1589 /* Call the target's completion_callback() */
1590 if (cmd->completion_callback != NULL) {
1591 s1394_unlock_tree(hal);
1592 cmd->completion_callback(cmd);
1593 return (B_FALSE);
1594 } else {
1595 s1394_unlock_tree(hal);
1596 return (B_FALSE);
1597 }
1598 }
1599
1600 /* Mask in the top 16-bits */
1601 cmd->cmd_addr = cmd->cmd_addr &
1602 IEEE1394_ADDR_OFFSET_MASK;
1603 cmd->cmd_addr = cmd->cmd_addr |
1604 (node << IEEE1394_ADDR_PHY_ID_SHIFT);
1605 cmd->cmd_addr = cmd->cmd_addr |
1606 IEEE1394_ADDR_BUS_ID_MASK;
1607
1608 /* Speed is to be filled in from speed map */
1609 from_node = IEEE1394_NODE_NUM(hal->node_id);
1610 to_node = (uint32_t)node;
1611
1612 /* Fill in the nodeID */
1613 cmd->nodeID =
1614 (cmd->cmd_addr & IEEE1394_ADDR_NODE_ID_MASK) >>
1615 IEEE1394_ADDR_NODE_ID_SHIFT;
1616
1617 if (cmd->cmd_options & CMD1394_OVERRIDE_SPEED) {
1618 s_priv->hal_cmd_private.speed =
1619 (int)cmd->cmd_speed;
1620 } else {
1621 /* Speed is to be filled in from speed map */
1622 s_priv->hal_cmd_private.speed =
1623 (int)s1394_speed_map_get(hal, from_node,
1624 to_node);
1625 }
1626
1627 /* Is it a block request? */
1628 if ((cmd->cmd_type == CMD1394_ASYNCH_RD_BLOCK) ||
1629 (cmd->cmd_type == CMD1394_ASYNCH_WR_BLOCK)) {
1630
1631 /* Get a pointer to the HAL private struct */
1632 h_priv = (h1394_cmd_priv_t *)&s_priv->
1633 hal_cmd_private;
1634
1635 /* Handle the MAX_PAYLOAD size */
1636 if (s_priv->sent_by_target != NULL) {
1637 current_max_payload =
1638 s_priv->sent_by_target->
1639 current_max_payload;
1640 } else {
1641 current_max_payload = 4;
1642 }
1643 if (cmd->cmd_options &
1644 CMD1394_OVERRIDE_MAX_PAYLOAD) {
1645 if (current_max_payload >
1646 cmd->cmd_u.b.max_payload)
1647 current_max_payload =
1648 cmd->cmd_u.b.max_payload;
1649 }
1650 if (s_priv->data_remaining <
1651 current_max_payload) {
1652 h_priv->mblk.length =
1653 s_priv->data_remaining;
1654 } else {
1655 h_priv->mblk.length =
1656 current_max_payload;
1657 }
1658 }
1659 s1394_unlock_tree(hal);
1660 ret = s1394_pending_q_helper(hal, cmd);
1661 return (ret);
1662 }
1663 }
1664 }
1665
1666 /*
1667 * s1394_pending_q_helper()
1668 * is a "helper" function for s1394_process_pending_q(). It attempts to
1669 * resend commands, handling error conditions whenever necessary.
1670 */
1671 static boolean_t
s1394_pending_q_helper(s1394_hal_t * hal,cmd1394_cmd_t * cmd)1672 s1394_pending_q_helper(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
1673 {
1674 s1394_cmd_priv_t *s_priv;
1675 int err;
1676 int ret;
1677
1678 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1679
1680 /* Get the Services Layer private area */
1681 s_priv = S1394_GET_CMD_PRIV(cmd);
1682
1683 /* Put cmd on outstanding request Q */
1684 s1394_insert_q_asynch_cmd(hal, cmd);
1685
1686 /* Send command out again */
1687 ret = s1394_xfer_asynch_command(hal, cmd, &err);
1688
1689 if (ret != DDI_SUCCESS) {
1690 if (err == CMD1394_ESTALE_GENERATION) {
1691 /* Remove cmd outstanding req Q */
1692 s1394_remove_q_asynch_cmd(hal, cmd);
1693 s1394_pending_q_insert(hal, cmd, S1394_PENDING_Q_FRONT);
1694
1695 return (B_TRUE);
1696 } else {
1697 /* Remove cmd from outstanding request Q */
1698 s1394_remove_q_asynch_cmd(hal, cmd);
1699
1700 s_priv->cmd_in_use = B_FALSE;
1701
1702 cmd->cmd_result = err;
1703
1704 /* Is this a blocking command? */
1705 if (cmd->cmd_options & CMD1394_BLOCKING) {
1706 /* Unblock waiting command */
1707 mutex_enter(&s_priv->blocking_mutex);
1708 s_priv->blocking_flag = B_TRUE;
1709 cv_signal(&s_priv->blocking_cv);
1710 mutex_exit(&s_priv->blocking_mutex);
1711
1712 return (B_FALSE);
1713 }
1714
1715 /* Call target completion_callback() */
1716 if (cmd->completion_callback != NULL) {
1717 cmd->completion_callback(cmd);
1718 return (B_FALSE);
1719 } else {
1720 return (B_FALSE);
1721 }
1722 }
1723 }
1724
1725 return (B_FALSE);
1726 }
1727
1728 /*
1729 * s1394_process_split_lock()
1730 * is a "helper" function for the s1394_handle_lock() callback. Its
1731 * job is to perform whatever manipulation is required for the given
1732 * request.
1733 */
1734 static int
s1394_process_split_lock(cmd1394_cmd_t * cmd,cmd1394_cmd_t * target_cmd)1735 s1394_process_split_lock(cmd1394_cmd_t *cmd, cmd1394_cmd_t *target_cmd)
1736 {
1737 uint64_t new_value64;
1738 uint64_t data_value64;
1739 uint64_t arg_value64;
1740 uint64_t old_value64;
1741 uint64_t temp_value64;
1742 uint32_t new_value32;
1743 uint32_t data_value32;
1744 uint32_t arg_value32;
1745 uint32_t old_value32;
1746 uint32_t temp_value32;
1747
1748 if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
1749 old_value32 = cmd->cmd_u.l32.old_value;
1750 data_value32 = target_cmd->cmd_u.l32.data_value;
1751 arg_value32 = target_cmd->cmd_u.l32.arg_value;
1752
1753 /* Lock type specific */
1754 switch (target_cmd->cmd_u.l32.lock_type) {
1755 case CMD1394_LOCK_BIT_AND:
1756 new_value32 = old_value32 & data_value32;
1757 break;
1758
1759 case CMD1394_LOCK_BIT_OR:
1760 new_value32 = old_value32 | data_value32;
1761 break;
1762
1763 case CMD1394_LOCK_BIT_XOR:
1764 new_value32 = old_value32 ^ data_value32;
1765 break;
1766
1767 case CMD1394_LOCK_INCREMENT:
1768 old_value32 = T1394_DATA32(old_value32);
1769 new_value32 = old_value32 + 1;
1770 new_value32 = T1394_DATA32(new_value32);
1771 old_value32 = T1394_DATA32(old_value32);
1772 break;
1773
1774 case CMD1394_LOCK_DECREMENT:
1775 old_value32 = T1394_DATA32(old_value32);
1776 new_value32 = old_value32 - 1;
1777 new_value32 = T1394_DATA32(new_value32);
1778 old_value32 = T1394_DATA32(old_value32);
1779 break;
1780
1781 case CMD1394_LOCK_ADD:
1782 old_value32 = T1394_DATA32(old_value32);
1783 new_value32 = old_value32 + data_value32;
1784 new_value32 = T1394_DATA32(new_value32);
1785 old_value32 = T1394_DATA32(old_value32);
1786 break;
1787
1788 case CMD1394_LOCK_SUBTRACT:
1789 old_value32 = T1394_DATA32(old_value32);
1790 new_value32 = old_value32 - data_value32;
1791 new_value32 = T1394_DATA32(new_value32);
1792 old_value32 = T1394_DATA32(old_value32);
1793 break;
1794
1795 case CMD1394_LOCK_THRESH_ADD:
1796 old_value32 = T1394_DATA32(old_value32);
1797 temp_value32 = (old_value32 + data_value32);
1798 if ((temp_value32 >= old_value32) &&
1799 (temp_value32 <= arg_value32)) {
1800 new_value32 = T1394_DATA32(temp_value32);
1801 old_value32 = T1394_DATA32(old_value32);
1802 } else {
1803 /* Failed threshold add */
1804 target_cmd->cmd_u.l32.old_value =
1805 T1394_DATA32(cmd->cmd_u.l32.old_value);
1806 target_cmd->cmd_result = CMD1394_CMDSUCCESS;
1807 return (DDI_FAILURE);
1808 }
1809 break;
1810
1811 case CMD1394_LOCK_THRESH_SUBTRACT:
1812 old_value32 = T1394_DATA32(old_value32);
1813 temp_value32 = (old_value32 - data_value32);
1814 if ((old_value32 >= data_value32) &&
1815 (temp_value32 >= arg_value32)) {
1816 new_value32 = T1394_DATA32(temp_value32);
1817 old_value32 = T1394_DATA32(old_value32);
1818 } else {
1819 /* Failed threshold subtract */
1820 target_cmd->cmd_u.l32.old_value =
1821 T1394_DATA32(cmd->cmd_u.l32.old_value);
1822 target_cmd->cmd_result = CMD1394_CMDSUCCESS;
1823 return (DDI_FAILURE);
1824 }
1825 break;
1826
1827 case CMD1394_LOCK_CLIP_ADD:
1828 old_value32 = T1394_DATA32(old_value32);
1829 temp_value32 = (old_value32 + data_value32);
1830 if ((temp_value32 < old_value32) ||
1831 (temp_value32 > arg_value32))
1832 new_value32 = T1394_DATA32(arg_value32);
1833 else
1834 new_value32 = T1394_DATA32(temp_value32);
1835 old_value32 = T1394_DATA32(old_value32);
1836 break;
1837
1838 case CMD1394_LOCK_CLIP_SUBTRACT:
1839 old_value32 = T1394_DATA32(old_value32);
1840 temp_value32 = (old_value32 - data_value32);
1841 if ((data_value32 > old_value32) ||
1842 (temp_value32 < arg_value32))
1843 new_value32 = T1394_DATA32(arg_value32);
1844 else
1845 new_value32 = T1394_DATA32(temp_value32);
1846 old_value32 = T1394_DATA32(old_value32);
1847 break;
1848 }
1849
1850 /* Send compare-swap lock request */
1851 cmd->cmd_u.l32.arg_value = old_value32;
1852 cmd->cmd_u.l32.data_value = new_value32;
1853 } else {
1854 old_value64 = cmd->cmd_u.l64.old_value;
1855 data_value64 = target_cmd->cmd_u.l64.data_value;
1856 arg_value64 = target_cmd->cmd_u.l64.arg_value;
1857
1858 /* Lock type specific */
1859 switch (target_cmd->cmd_u.l64.lock_type) {
1860 case CMD1394_LOCK_BIT_AND:
1861 new_value64 = old_value64 & data_value64;
1862 break;
1863
1864 case CMD1394_LOCK_BIT_OR:
1865 new_value64 = old_value64 | data_value64;
1866 break;
1867
1868 case CMD1394_LOCK_BIT_XOR:
1869 new_value64 = old_value64 ^ data_value64;
1870 break;
1871
1872 case CMD1394_LOCK_INCREMENT:
1873 old_value64 = T1394_DATA64(old_value64);
1874 new_value64 = old_value64 + 1;
1875 new_value64 = T1394_DATA64(new_value64);
1876 old_value64 = T1394_DATA64(old_value64);
1877 break;
1878
1879 case CMD1394_LOCK_DECREMENT:
1880 old_value64 = T1394_DATA64(old_value64);
1881 new_value64 = old_value64 - 1;
1882 new_value64 = T1394_DATA64(new_value64);
1883 old_value64 = T1394_DATA64(old_value64);
1884 break;
1885
1886 case CMD1394_LOCK_ADD:
1887 old_value64 = T1394_DATA64(old_value64);
1888 new_value64 = old_value64 + data_value64;
1889 new_value64 = T1394_DATA64(new_value64);
1890 old_value64 = T1394_DATA64(old_value64);
1891 break;
1892
1893 case CMD1394_LOCK_SUBTRACT:
1894 old_value64 = T1394_DATA64(old_value64);
1895 new_value64 = old_value64 - data_value64;
1896 new_value64 = T1394_DATA64(new_value64);
1897 old_value64 = T1394_DATA64(old_value64);
1898 break;
1899
1900 case CMD1394_LOCK_THRESH_ADD:
1901 old_value64 = T1394_DATA64(old_value64);
1902 temp_value64 = (old_value64 + data_value64);
1903 if ((temp_value64 >= old_value64) &&
1904 (temp_value64 <= arg_value64)) {
1905 new_value64 = T1394_DATA64(temp_value64);
1906 old_value64 = T1394_DATA64(old_value64);
1907 } else {
1908 /* Failed threshold add */
1909 target_cmd->cmd_u.l64.old_value =
1910 T1394_DATA64(cmd->cmd_u.l64.old_value);
1911 target_cmd->cmd_result = CMD1394_CMDSUCCESS;
1912 return (DDI_FAILURE);
1913 }
1914 break;
1915
1916 case CMD1394_LOCK_THRESH_SUBTRACT:
1917 old_value64 = T1394_DATA64(old_value64);
1918 temp_value64 = (old_value64 - data_value64);
1919 if ((old_value64 >= data_value64) &&
1920 (temp_value64 >= arg_value64)) {
1921 new_value64 = T1394_DATA64(temp_value64);
1922 old_value64 = T1394_DATA64(old_value64);
1923 } else {
1924 /* Failed threshold subtract */
1925 target_cmd->cmd_u.l64.old_value =
1926 T1394_DATA64(cmd->cmd_u.l64.old_value);
1927 target_cmd->cmd_result = CMD1394_CMDSUCCESS;
1928 return (DDI_FAILURE);
1929 }
1930 break;
1931
1932 case CMD1394_LOCK_CLIP_ADD:
1933 old_value64 = T1394_DATA64(old_value64);
1934 temp_value64 = (old_value64 + data_value64);
1935 if ((temp_value64 < old_value64) ||
1936 (temp_value64 > arg_value64))
1937 new_value64 = T1394_DATA64(arg_value64);
1938 else
1939 new_value64 = T1394_DATA64(temp_value64);
1940 old_value64 = T1394_DATA64(old_value64);
1941 break;
1942
1943 case CMD1394_LOCK_CLIP_SUBTRACT:
1944 old_value64 = T1394_DATA64(old_value64);
1945 temp_value64 = (old_value64 - data_value64);
1946 if ((data_value64 > old_value64) ||
1947 (temp_value64 < arg_value64))
1948 new_value64 = T1394_DATA64(arg_value64);
1949 else
1950 new_value64 = T1394_DATA64(temp_value64);
1951 old_value64 = T1394_DATA64(old_value64);
1952 break;
1953 }
1954
1955 /* Send compare-swap lock request */
1956 cmd->cmd_u.l64.arg_value = old_value64;
1957 cmd->cmd_u.l64.data_value = new_value64;
1958 }
1959
1960 return (DDI_SUCCESS);
1961 }
1962
1963 /*
1964 * s1394_finish_split_lock()
1965 * is another "helper" function for the s1394_handle_lock() callback.
1966 * Its job is to finish up whatever lock request procesing is necessary.
1967 */
1968 static int
s1394_finish_split_lock(cmd1394_cmd_t * cmd,cmd1394_cmd_t * target_cmd)1969 s1394_finish_split_lock(cmd1394_cmd_t *cmd, cmd1394_cmd_t *target_cmd)
1970 {
1971 s1394_cmd_priv_t *s_priv;
1972 uint64_t tmp_value64;
1973 uint32_t tmp_value32;
1974
1975 /* Get the Services Layer private area */
1976 s_priv = S1394_GET_CMD_PRIV(cmd);
1977
1978 if (((cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) &&
1979 (cmd->cmd_u.l32.old_value == cmd->cmd_u.l32.arg_value)) ||
1980 ((cmd->cmd_type == CMD1394_ASYNCH_LOCK_64) &&
1981 (cmd->cmd_u.l64.old_value == cmd->cmd_u.l64.arg_value))) {
1982
1983 if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
1984 switch (cmd->cmd_u.l32.lock_type) {
1985 case CMD1394_LOCK_INCREMENT:
1986 case CMD1394_LOCK_DECREMENT:
1987 case CMD1394_LOCK_ADD:
1988 case CMD1394_LOCK_SUBTRACT:
1989 case CMD1394_LOCK_THRESH_ADD:
1990 case CMD1394_LOCK_THRESH_SUBTRACT:
1991 case CMD1394_LOCK_CLIP_ADD:
1992 case CMD1394_LOCK_CLIP_SUBTRACT:
1993 tmp_value32 = cmd->cmd_u.l32.old_value;
1994 tmp_value32 = T1394_DATA32(tmp_value32);
1995 target_cmd->cmd_u.l32.old_value = tmp_value32;
1996 break;
1997 default:
1998 tmp_value32 = cmd->cmd_u.l32.old_value;
1999 target_cmd->cmd_u.l32.old_value = tmp_value32;
2000 break;
2001 }
2002 } else {
2003 switch (cmd->cmd_u.l64.lock_type) {
2004 case CMD1394_LOCK_INCREMENT:
2005 case CMD1394_LOCK_DECREMENT:
2006 case CMD1394_LOCK_ADD:
2007 case CMD1394_LOCK_SUBTRACT:
2008 case CMD1394_LOCK_THRESH_ADD:
2009 case CMD1394_LOCK_THRESH_SUBTRACT:
2010 case CMD1394_LOCK_CLIP_ADD:
2011 case CMD1394_LOCK_CLIP_SUBTRACT:
2012 tmp_value64 = cmd->cmd_u.l64.old_value;
2013 tmp_value64 = T1394_DATA64(tmp_value64);
2014 target_cmd->cmd_u.l64.old_value = tmp_value64;
2015 break;
2016 default:
2017 tmp_value64 = cmd->cmd_u.l64.old_value;
2018 target_cmd->cmd_u.l64.old_value = tmp_value64;
2019 break;
2020 }
2021 }
2022 /* Set status */
2023 target_cmd->cmd_result = CMD1394_CMDSUCCESS;
2024 return (DDI_SUCCESS);
2025 } else {
2026 if (s_priv->temp_num_retries > 0) {
2027 /* Decrement retry count */
2028 s_priv->temp_num_retries--;
2029
2030 /* Reset lock_req_step */
2031 s_priv->lock_req_step = 0;
2032
2033 /* Resend... start at step 0 again */
2034 return (DDI_FAILURE);
2035 } else {
2036 /* Failed... RETRIES_EXCEEDED */
2037 target_cmd->cmd_result = CMD1394_ERETRIES_EXCEEDED;
2038 return (DDI_SUCCESS);
2039 }
2040 }
2041 }
2042