5255 uts shouldn't open-code ISP2
[illumos-gate.git] / usr / src / uts / common / io / 1394 / s1394_asynch.c
blob66e3a6cc13073e684f739a15128f853012bb91d5
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * s1394_asynch.c
30 * 1394 Services Layer Asynchronous Communications Routines
31 * These routines handle all of the tasks relating to asynch commands
34 #include <sys/conf.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/cmn_err.h>
38 #include <sys/types.h>
39 #include <sys/kmem.h>
40 #include <sys/disp.h>
41 #include <sys/tnf_probe.h>
43 #include <sys/1394/t1394.h>
44 #include <sys/1394/s1394.h>
45 #include <sys/1394/h1394.h>
46 #include <sys/1394/ieee1394.h>
47 #include <sys/1394/ieee1212.h>
49 static void s1394_handle_lock(cmd1394_cmd_t *cmd);
51 static cmd1394_cmd_t *s1394_pending_q_remove(s1394_hal_t *hal);
53 static boolean_t s1394_process_pending_q(s1394_hal_t *hal);
55 static boolean_t s1394_pending_q_helper(s1394_hal_t *hal, cmd1394_cmd_t *cmd);
57 static int s1394_process_split_lock(cmd1394_cmd_t *cmd,
58 cmd1394_cmd_t *target_cmd);
60 static int s1394_finish_split_lock(cmd1394_cmd_t *cmd,
61 cmd1394_cmd_t *target_cmd);
64 * s1394_alloc_cmd()
65 * is used to allocate a command for a target or for a HAL.
67 int
68 s1394_alloc_cmd(s1394_hal_t *hal, uint_t flags, cmd1394_cmd_t **cmdp)
70 s1394_cmd_priv_t *s_priv;
71 void *hal_overhead;
72 uint_t cmd_size;
73 int alloc_sleep;
75 TNF_PROBE_0_DEBUG(s1394_alloc_cmd_enter, S1394_TNF_SL_STACK, "");
77 alloc_sleep = (flags & T1394_ALLOC_CMD_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP;
79 if ((alloc_sleep == KM_SLEEP) &&
80 (servicing_interrupt())) {
81 TNF_PROBE_1(s1394_alloc_cmd_error, S1394_TNF_SL_ATREQ_ERROR,
82 "", tnf_string, msg, "Tried to sleep in intr context");
83 TNF_PROBE_0_DEBUG(s1394_alloc_cmd_exit,
84 S1394_TNF_SL_ATREQ_STACK, "");
85 ASSERT(alloc_sleep != KM_SLEEP); /* fail */
86 return (DDI_FAILURE);
89 /* either FCP command or response, but not both */
90 if ((flags &
91 (T1394_ALLOC_CMD_FCP_COMMAND | T1394_ALLOC_CMD_FCP_RESPONSE)) ==
92 (T1394_ALLOC_CMD_FCP_COMMAND | T1394_ALLOC_CMD_FCP_RESPONSE)) {
93 TNF_PROBE_1(s1394_alloc_cmd_error, S1394_TNF_SL_ATREQ_ERROR,
94 "", tnf_string, msg, "Both FCP cmd and resp flags");
95 TNF_PROBE_0_DEBUG(s1394_alloc_cmd_exit,
96 S1394_TNF_SL_ATREQ_STACK, "");
97 return (DDI_FAILURE);
100 *cmdp = kmem_cache_alloc(hal->hal_kmem_cachep, alloc_sleep);
101 if (*cmdp == NULL) {
102 TNF_PROBE_0_DEBUG(s1394_alloc_cmd_exit,
103 S1394_TNF_SL_STACK, "");
104 return (DDI_FAILURE);
106 cmd_size = sizeof (cmd1394_cmd_t) +
107 sizeof (s1394_cmd_priv_t) + hal->halinfo.hal_overhead;
108 bzero((void *)*cmdp, cmd_size);
110 (*cmdp)->cmd_version = T1394_VERSION_V1;
111 (*cmdp)->cmd_result = CMD1394_NOSTATUS;
113 /* Get the Services Layer private area */
114 s_priv = S1394_GET_CMD_PRIV(*cmdp);
116 /* Set extension type */
117 if (flags & T1394_ALLOC_CMD_FCP_COMMAND) {
118 s1394_fa_init_cmd(s_priv, S1394_FA_TYPE_FCP_CTL);
119 } else if (flags & T1394_ALLOC_CMD_FCP_RESPONSE) {
120 s1394_fa_init_cmd(s_priv, S1394_FA_TYPE_FCP_TGT);
123 /* Set up the hal_overhead ptr in the hal_cmd_private */
124 hal_overhead = (uchar_t *)s_priv + sizeof (s1394_cmd_priv_t);
125 s_priv->hal_cmd_private.hal_overhead = (void *)hal_overhead;
127 TNF_PROBE_1_DEBUG(s1394_alloc_cmd, S1394_TNF_SL_STACK, "",
128 tnf_opaque, cmd, *cmdp);
130 /* kstats - number of cmd allocs */
131 hal->hal_kstats->cmd_alloc++;
133 TNF_PROBE_0_DEBUG(s1394_alloc_cmd_exit, S1394_TNF_SL_STACK, "");
134 return (DDI_SUCCESS);
138 * s1394_free_cmd()
139 * is used to free a command that had been previously allocated by
140 * s1394_alloc_cmd().
143 s1394_free_cmd(s1394_hal_t *hal, cmd1394_cmd_t **cmdp)
145 s1394_cmd_priv_t *s_priv;
147 TNF_PROBE_0_DEBUG(s1394_free_cmd_enter, S1394_TNF_SL_STACK, "");
149 /* Get the Services Layer private area */
150 s_priv = S1394_GET_CMD_PRIV(*cmdp);
152 /* Check that command isn't in use */
153 if (s_priv->cmd_in_use == B_TRUE) {
154 TNF_PROBE_1(s1394_free_cmd_error, S1394_TNF_SL_ERROR, "",
155 tnf_string, msg, "Attempted to free an in-use command");
156 TNF_PROBE_0_DEBUG(s1394_free_cmd_exit, S1394_TNF_SL_STACK, "");
157 ASSERT(s_priv->cmd_in_use == B_FALSE);
158 return (DDI_FAILURE);
160 TNF_PROBE_1_DEBUG(s1394_free_cmd, S1394_TNF_SL_STACK, "",
161 tnf_opaque, cmd, *cmdp);
163 /* kstats - number of cmd allocs */
164 kmem_cache_free(hal->hal_kmem_cachep, *cmdp);
166 /* Command pointer is set to NULL before returning */
167 *cmdp = NULL;
169 /* kstats - number of cmd frees */
170 hal->hal_kstats->cmd_free++;
172 TNF_PROBE_0_DEBUG(s1394_free_cmd_exit, S1394_TNF_SL_STACK, "");
173 return (DDI_SUCCESS);
177 * s1394_xfer_asynch_command()
178 * is used to send an asynch command down to the HAL. Based upon the type
179 * of command that is being sent, the appropriate HAL function is called.
180 * Command failures are handled be returning an error and/or shutting down
181 * the HAL, depending on the severity of the error.
184 s1394_xfer_asynch_command(s1394_hal_t *hal, cmd1394_cmd_t *cmd, int *err)
186 s1394_cmd_priv_t *s_priv;
187 h1394_cmd_priv_t *h_priv;
188 s1394_hal_state_t state;
189 dev_info_t *dip;
190 int result_from_hal;
191 int ret;
193 TNF_PROBE_0_DEBUG(s1394_xfer_asynch_command_enter,
194 S1394_TNF_SL_ATREQ_STACK, "");
196 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
198 mutex_enter(&hal->topology_tree_mutex);
199 state = hal->hal_state;
200 if (((state != S1394_HAL_NORMAL) && (state != S1394_HAL_RESET)) ||
201 (hal->disable_requests_bit == 1)) {
202 *err = s1394_HAL_asynch_error(hal, cmd, state);
203 mutex_exit(&hal->topology_tree_mutex);
204 TNF_PROBE_0_DEBUG(s1394_xfer_asynch_command_exit,
205 S1394_TNF_SL_ATREQ_STACK, "");
206 return (DDI_FAILURE);
208 mutex_exit(&hal->topology_tree_mutex);
210 /* Get the Services Layer private area */
211 s_priv = S1394_GET_CMD_PRIV(cmd);
213 /* Get a pointer to the HAL private struct */
214 h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
216 /* kstats - number of AT requests sent */
217 switch (cmd->cmd_type) {
218 case CMD1394_ASYNCH_RD_QUAD:
219 hal->hal_kstats->atreq_quad_rd++;
220 break;
222 case CMD1394_ASYNCH_RD_BLOCK:
223 hal->hal_kstats->atreq_blk_rd++;
224 break;
226 case CMD1394_ASYNCH_WR_QUAD:
227 hal->hal_kstats->atreq_quad_wr++;
228 break;
230 case CMD1394_ASYNCH_WR_BLOCK:
231 hal->hal_kstats->atreq_blk_wr++;
232 hal->hal_kstats->atreq_blk_wr_size += h_priv->mblk.length;
233 break;
235 case CMD1394_ASYNCH_LOCK_32:
236 hal->hal_kstats->atreq_lock32++;
237 break;
239 case CMD1394_ASYNCH_LOCK_64:
240 hal->hal_kstats->atreq_lock64++;
241 break;
244 switch (s_priv->cmd_priv_xfer_type) {
245 /* Call the HAL's read entry point */
246 case S1394_CMD_READ:
247 ret = HAL_CALL(hal).read(hal->halinfo.hal_private,
248 (cmd1394_cmd_t *)cmd,
249 (h1394_cmd_priv_t *)&s_priv->hal_cmd_private,
250 &result_from_hal);
251 break;
253 /* Call the HAL's write entry point */
254 case S1394_CMD_WRITE:
255 ret = HAL_CALL(hal).write(hal->halinfo.hal_private,
256 (cmd1394_cmd_t *)cmd,
257 (h1394_cmd_priv_t *)&s_priv->hal_cmd_private,
258 &result_from_hal);
259 break;
261 /* Call the HAL's lock entry point */
262 case S1394_CMD_LOCK:
263 ret = HAL_CALL(hal).lock(hal->halinfo.hal_private,
264 (cmd1394_cmd_t *)cmd,
265 (h1394_cmd_priv_t *)&s_priv->hal_cmd_private,
266 &result_from_hal);
267 break;
269 default:
270 *err = CMD1394_EUNKNOWN_ERROR;
272 TNF_PROBE_1(s1394_xfer_asynch_command_error,
273 S1394_TNF_SL_ATREQ_ERROR, "", tnf_string, msg,
274 "Invalid command type specified");
275 TNF_PROBE_0_DEBUG(s1394_xfer_asynch_command_exit,
276 S1394_TNF_SL_ATREQ_STACK, "");
277 return (DDI_FAILURE);
280 TNF_PROBE_0_DEBUG(s1394_xfer_asynch_command_return_from_HAL,
281 S1394_TNF_SL_ATREQ_STACK, "");
283 if (ret == DDI_FAILURE) {
284 switch (result_from_hal) {
285 case H1394_STATUS_EMPTY_TLABEL:
286 /* Out of TLABELs - Unable to send AT req */
287 *err = CMD1394_ENO_ATREQ;
288 break;
290 case H1394_STATUS_INVALID_BUSGEN:
291 /* Out of TLABELs - Unable to send AT req */
292 *err = CMD1394_ESTALE_GENERATION;
293 break;
295 case H1394_STATUS_NOMORE_SPACE:
296 /* No more space on HAL's HW queue */
297 *err = CMD1394_ENO_ATREQ;
298 break;
300 case H1394_STATUS_INTERNAL_ERROR:
301 dip = hal->halinfo.dip;
303 /* An unexpected error in the HAL */
304 cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
305 ddi_node_name(dip), ddi_get_instance(dip));
307 /* Disable the HAL */
308 s1394_hal_shutdown(hal, B_TRUE);
310 *err = CMD1394_EFATAL_ERROR;
311 break;
313 default:
314 dip = hal->halinfo.dip;
316 /* An unexpected error in the HAL */
317 cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
318 ddi_node_name(dip), ddi_get_instance(dip));
320 /* Disable the HAL */
321 s1394_hal_shutdown(hal, B_TRUE);
323 *err = CMD1394_EFATAL_ERROR;
324 break;
327 TNF_PROBE_2_DEBUG(s1394_xfer_asynch_command_exit,
328 S1394_TNF_SL_ATREQ_STACK, "",
329 tnf_int, result_from_hal, result_from_hal,
330 tnf_int, err, *err);
331 return (DDI_FAILURE);
334 /* No errors, return success */
335 *err = CMD1394_NOSTATUS;
337 TNF_PROBE_0_DEBUG(s1394_xfer_asynch_command_exit,
338 S1394_TNF_SL_ATREQ_STACK, "");
339 return (DDI_SUCCESS);
343 * s1394_setup_asynch_command()
344 * is used to setup an asynch command to be sent down to the HAL and out
345 * onto the bus. This function handles setting up the destination address
346 * (if necessary), speed, max_payload, putting the command onto the
347 * outstanding Q list, and any other things that must be done prior to
348 * calling the HAL.
351 s1394_setup_asynch_command(s1394_hal_t *hal, s1394_target_t *target,
352 cmd1394_cmd_t *cmd, uint32_t xfer_type, int *err)
354 s1394_cmd_priv_t *s_priv;
355 h1394_cmd_priv_t *h_priv;
356 uint64_t node;
357 uint32_t from_node;
358 uint32_t to_node;
359 uint32_t bus_capabilities;
360 uint_t current_max_payload;
361 uint_t max_rec;
362 uint_t max_blk;
364 TNF_PROBE_0_DEBUG(s1394_setup_asynch_command_enter,
365 S1394_TNF_SL_ATREQ_STACK, "");
367 ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
369 switch (cmd->cmd_type) {
370 case CMD1394_ASYNCH_RD_QUAD:
371 case CMD1394_ASYNCH_WR_QUAD:
372 case CMD1394_ASYNCH_RD_BLOCK:
373 case CMD1394_ASYNCH_WR_BLOCK:
374 case CMD1394_ASYNCH_LOCK_32:
375 case CMD1394_ASYNCH_LOCK_64:
376 break;
378 default:
379 *err = CMD1394_EINVALID_COMMAND;
380 TNF_PROBE_1(s1394_setup_asynch_command_error,
381 S1394_TNF_SL_ATREQ_ERROR, "", tnf_string, msg,
382 "Invalid command type specified");
383 TNF_PROBE_0_DEBUG(s1394_setup_asynch_command_exit,
384 S1394_TNF_SL_ATREQ_STACK, "");
385 return (DDI_FAILURE);
388 /* Check for potential address roll-over */
389 if (s1394_address_rollover(cmd) != B_FALSE) {
390 *err = CMD1394_EADDRESS_ERROR;
391 TNF_PROBE_0_DEBUG(s1394_setup_asynch_command_exit,
392 S1394_TNF_SL_ATREQ_STACK, "");
393 return (DDI_FAILURE);
396 /* Get the Services Layer private area */
397 s_priv = S1394_GET_CMD_PRIV(cmd);
399 /* Set up who sent command on which hal */
400 s_priv->sent_by_target = (s1394_target_t *)target;
401 s_priv->sent_on_hal = (s1394_hal_t *)hal;
403 /* Set up command transfer type */
404 s_priv->cmd_priv_xfer_type = xfer_type;
406 if (cmd->cmd_options & CMD1394_OVERRIDE_ADDR) {
407 /* Compare the current generation from the HAL struct */
408 /* to the one given by the target */
410 /* Speed is to be filled in from speed map */
411 from_node = IEEE1394_NODE_NUM(hal->node_id);
412 to_node = IEEE1394_ADDR_PHY_ID(cmd->cmd_addr);
414 if (cmd->bus_generation != hal->generation_count) {
415 *err = CMD1394_ESTALE_GENERATION;
416 TNF_PROBE_0_DEBUG(s1394_setup_asynch_command_exit,
417 S1394_TNF_SL_ATREQ_STACK, "");
418 return (DDI_FAILURE);
421 } else {
422 /* Set the generation */
423 cmd->bus_generation = hal->generation_count;
425 /* If not OVERRIDE_ADDR, then target may not be NULL */
426 ASSERT(target != NULL);
428 rw_enter(&hal->target_list_rwlock, RW_READER);
430 if ((target->target_state & S1394_TARG_GONE) != 0 ||
431 target->on_node == NULL) {
432 rw_exit(&hal->target_list_rwlock);
433 *err = CMD1394_EDEVICE_REMOVED;
434 TNF_PROBE_0_DEBUG(s1394_setup_asynch_command_exit,
435 S1394_TNF_SL_ATREQ_STACK, "");
436 return (DDI_FAILURE);
439 ASSERT((target->target_state & S1394_TARG_GONE) == 0);
440 node = target->on_node->node_num;
441 rw_exit(&hal->target_list_rwlock);
443 /* Mask in the top 16-bits */
444 cmd->cmd_addr = (cmd->cmd_addr & IEEE1394_ADDR_OFFSET_MASK);
445 cmd->cmd_addr = (cmd->cmd_addr |
446 (node << IEEE1394_ADDR_PHY_ID_SHIFT));
447 cmd->cmd_addr = (cmd->cmd_addr | IEEE1394_ADDR_BUS_ID_MASK);
449 /* Speed is to be filled in from speed map */
450 from_node = IEEE1394_NODE_NUM(hal->node_id);
451 to_node = (uint32_t)node;
454 /* Get a pointer to the HAL private struct */
455 h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
457 /* Copy the generation into the HAL's private field */
458 h_priv->bus_generation = cmd->bus_generation;
460 /* Fill in the nodeID */
461 cmd->nodeID = (cmd->cmd_addr & IEEE1394_ADDR_NODE_ID_MASK) >>
462 IEEE1394_ADDR_NODE_ID_SHIFT;
464 if (cmd->cmd_options & CMD1394_OVERRIDE_SPEED) {
465 if (cmd->cmd_speed > IEEE1394_S400) {
466 *err = CMD1394_EINVALID_COMMAND;
467 TNF_PROBE_0_DEBUG(s1394_setup_asynch_command_exit,
468 S1394_TNF_SL_ATREQ_STACK, "");
469 return (DDI_FAILURE);
471 } else {
472 s_priv->hal_cmd_private.speed = (int)cmd->cmd_speed;
475 } else {
476 /* Speed is to be filled in from speed map */
477 s_priv->hal_cmd_private.speed = (int)s1394_speed_map_get(hal,
478 from_node, to_node);
481 /* Is it a block request? */
482 if ((cmd->cmd_type == CMD1394_ASYNCH_RD_BLOCK) ||
483 (cmd->cmd_type == CMD1394_ASYNCH_WR_BLOCK)) {
485 if (cmd->cmd_u.b.data_block == NULL) {
486 *err = CMD1394_ENULL_MBLK;
487 TNF_PROBE_0_DEBUG(s1394_setup_asynch_command_exit,
488 S1394_TNF_SL_ATREQ_STACK, "");
489 return (DDI_FAILURE);
492 /* Also need to check for MBLK_TOO_SMALL */
493 if (s1394_mblk_too_small(cmd) != B_FALSE) {
494 *err = CMD1394_EMBLK_TOO_SMALL;
495 TNF_PROBE_0_DEBUG(s1394_setup_asynch_command_exit,
496 S1394_TNF_SL_ATREQ_STACK, "");
497 return (DDI_FAILURE);
500 /* Initialize bytes_transferred to zero */
501 cmd->cmd_u.b.bytes_transferred = 0;
503 /* Handle the MAX_PAYLOAD size */
504 if (cmd->cmd_options & CMD1394_OVERRIDE_ADDR) {
506 current_max_payload = 512 <<
507 (s_priv->hal_cmd_private.speed);
508 if (hal->topology_tree[to_node].cfgrom) {
509 bus_capabilities =
510 hal->topology_tree[to_node].cfgrom[
511 IEEE1212_NODE_CAP_QUAD];
512 max_rec = (bus_capabilities &
513 IEEE1394_BIB_MAXREC_MASK) >>
514 IEEE1394_BIB_MAXREC_SHIFT;
515 } else {
516 max_rec = 0;
519 if ((max_rec > 0) && (max_rec < 14)) {
520 max_blk = 1 << (max_rec + 1);
522 } else {
523 /* These are either unspecified or reserved */
524 max_blk = 4;
526 if (max_blk < current_max_payload)
527 current_max_payload = max_blk;
529 } else {
530 rw_enter(&hal->target_list_rwlock, RW_READER);
531 current_max_payload = target->current_max_payload;
532 rw_exit(&hal->target_list_rwlock);
535 if (cmd->cmd_options & CMD1394_OVERRIDE_MAX_PAYLOAD) {
536 if (current_max_payload > cmd->cmd_u.b.max_payload)
537 current_max_payload = cmd->cmd_u.b.max_payload;
540 h_priv->mblk.curr_mblk = cmd->cmd_u.b.data_block;
542 if (cmd->cmd_type == CMD1394_ASYNCH_WR_BLOCK) {
543 h_priv->mblk.curr_offset =
544 cmd->cmd_u.b.data_block->b_rptr;
545 } else {
546 h_priv->mblk.curr_offset =
547 cmd->cmd_u.b.data_block->b_wptr;
550 if (cmd->cmd_u.b.blk_length > current_max_payload) {
551 h_priv->mblk.length = current_max_payload;
552 s_priv->data_remaining = cmd->cmd_u.b.blk_length;
554 } else {
555 h_priv->mblk.length = cmd->cmd_u.b.blk_length;
556 s_priv->data_remaining = cmd->cmd_u.b.blk_length;
560 /* Mark command as being used */
561 s_priv->cmd_in_use = B_TRUE;
563 /* Put command on the HAL's outstanding request Q */
564 s1394_insert_q_asynch_cmd(hal, cmd);
566 TNF_PROBE_0_DEBUG(s1394_setup_asynch_command_exit,
567 S1394_TNF_SL_ATREQ_STACK, "");
568 return (DDI_SUCCESS);
572 * s1394_insert_q_asynch_cmd()
573 * is used to insert a given command structure onto a HAL's outstanding
574 * asynch queue.
576 void
577 s1394_insert_q_asynch_cmd(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
579 s1394_cmd_priv_t *s_priv;
580 s1394_cmd_priv_t *c_priv;
581 cmd1394_cmd_t *temp_cmd;
583 TNF_PROBE_0_DEBUG(s1394_insert_q_asynch_cmd_enter,
584 S1394_TNF_SL_ATREQ_STACK, "");
586 mutex_enter(&hal->outstanding_q_mutex);
588 /* Get the Services Layer private area */
589 s_priv = S1394_GET_CMD_PRIV(cmd);
591 /* Is the outstanding request queue empty? */
592 if ((hal->outstanding_q_head == NULL) &&
593 (hal->outstanding_q_tail == NULL)) {
595 hal->outstanding_q_head = (cmd1394_cmd_t *)cmd;
596 hal->outstanding_q_tail = (cmd1394_cmd_t *)cmd;
597 s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
598 s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
600 } else {
601 s_priv->cmd_priv_next = hal->outstanding_q_head;
602 s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
604 temp_cmd = (cmd1394_cmd_t *)hal->outstanding_q_head;
605 c_priv = (s1394_cmd_priv_t *)((uchar_t *)temp_cmd +
606 sizeof (cmd1394_cmd_t));
607 c_priv->cmd_priv_prev = (cmd1394_cmd_t *)cmd;
609 hal->outstanding_q_head = (cmd1394_cmd_t *)cmd;
612 mutex_exit(&hal->outstanding_q_mutex);
614 TNF_PROBE_0_DEBUG(s1394_insert_q_asynch_cmd_exit,
615 S1394_TNF_SL_ATREQ_STACK, "");
619 * s1394_remove_q_asynch_cmd()
620 * is used to remove a given command structure from a HAL's outstanding
621 * asynch queue.
623 void
624 s1394_remove_q_asynch_cmd(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
626 s1394_cmd_priv_t *s_priv;
627 s1394_cmd_priv_t *c_priv;
628 cmd1394_cmd_t *prev_cmd;
629 cmd1394_cmd_t *next_cmd;
631 TNF_PROBE_0_DEBUG(s1394_remove_q_asynch_cmd_enter,
632 S1394_TNF_SL_ATREQ_STACK, "");
634 mutex_enter(&hal->outstanding_q_mutex);
636 /* Get the Services Layer private area */
637 s_priv = S1394_GET_CMD_PRIV(cmd);
639 prev_cmd = (cmd1394_cmd_t *)s_priv->cmd_priv_prev;
640 next_cmd = (cmd1394_cmd_t *)s_priv->cmd_priv_next;
642 s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
643 s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
645 if (prev_cmd != NULL) {
646 c_priv = (s1394_cmd_priv_t *)((uchar_t *)prev_cmd +
647 sizeof (cmd1394_cmd_t));
648 c_priv->cmd_priv_next = (cmd1394_cmd_t *)next_cmd;
650 } else {
651 if (hal->outstanding_q_head == (cmd1394_cmd_t *)cmd)
652 hal->outstanding_q_head = (cmd1394_cmd_t *)next_cmd;
655 if (next_cmd != NULL) {
656 c_priv = (s1394_cmd_priv_t *)((uchar_t *)next_cmd +
657 sizeof (cmd1394_cmd_t));
658 c_priv->cmd_priv_prev = (cmd1394_cmd_t *)prev_cmd;
660 } else {
661 if (hal->outstanding_q_tail == (cmd1394_cmd_t *)cmd)
662 hal->outstanding_q_tail = (cmd1394_cmd_t *)prev_cmd;
665 mutex_exit(&hal->outstanding_q_mutex);
667 TNF_PROBE_0_DEBUG(s1394_remove_q_asynch_cmd_exit,
668 S1394_TNF_SL_ATREQ_STACK, "");
672 * s1394_atreq_cmd_complete()
673 * is called by h1394_cmd_is_complete() when an AT request has completed.
674 * Based upon a command's completion status, s1394_atreq_cmd_complete()
675 * determines whether to call the target (or unblock), put the command onto
676 * the pending Q to be sent out later, or to resend the command
677 * (multi-part command).
679 void
680 s1394_atreq_cmd_complete(s1394_hal_t *hal, cmd1394_cmd_t *req, int status)
682 s1394_cmd_priv_t *s_priv;
683 h1394_cmd_priv_t *h_priv;
684 dev_info_t *dip;
685 int ret;
686 int cmd_result;
687 int err;
689 TNF_PROBE_0_DEBUG(s1394_atreq_cmd_complete_enter,
690 S1394_TNF_SL_ATREQ_STACK, "");
692 /* Get the Services Layer private area */
693 s_priv = S1394_GET_CMD_PRIV(req);
695 /* If not an ack_complete... */
696 if (status != H1394_CMD_SUCCESS) {
697 /* kstats - number of failure AT responses */
698 switch (req->cmd_type) {
699 case CMD1394_ASYNCH_RD_QUAD:
700 hal->hal_kstats->atresp_quad_rd_fail++;
701 break;
703 case CMD1394_ASYNCH_RD_BLOCK:
704 hal->hal_kstats->atresp_blk_rd_fail++;
705 break;
707 case CMD1394_ASYNCH_WR_QUAD:
708 hal->hal_kstats->atresp_quad_wr_fail++;
709 break;
711 case CMD1394_ASYNCH_WR_BLOCK:
712 hal->hal_kstats->atresp_blk_wr_fail++;
713 break;
715 case CMD1394_ASYNCH_LOCK_32:
716 hal->hal_kstats->atresp_lock32_fail++;
717 break;
719 case CMD1394_ASYNCH_LOCK_64:
720 hal->hal_kstats->atresp_lock64_fail++;
721 break;
725 switch (status) {
726 /* evt_missing_ack */
727 case H1394_CMD_ETIMEOUT:
728 cmd_result = CMD1394_ETIMEOUT;
729 break;
731 /* evt_flushed */
732 case H1394_CMD_EBUSRESET:
733 /* Move request to pending Q if cancel on */
734 /* reset is not set */
735 if (req->cmd_options & CMD1394_CANCEL_ON_BUS_RESET) {
736 cmd_result = CMD1394_EBUSRESET;
737 break;
739 s1394_remove_q_asynch_cmd(hal, req);
740 s1394_pending_q_insert(hal, req, S1394_PENDING_Q_REAR);
741 TNF_PROBE_0_DEBUG(s1394_atreq_cmd_complete_exit,
742 S1394_TNF_SL_ATREQ_STACK, "");
743 return;
745 /* ack_busy_X */
746 /* ack_busy_A */
747 /* ack_busy_B */
748 case H1394_CMD_EDEVICE_BUSY:
749 cmd_result = CMD1394_EDEVICE_BUSY;
750 break;
752 /* ack_data_error */
753 case H1394_CMD_EDATA_ERROR:
754 cmd_result = CMD1394_EDATA_ERROR;
755 break;
757 /* ack_type_error */
758 case H1394_CMD_ETYPE_ERROR:
759 cmd_result = CMD1394_ETYPE_ERROR;
760 break;
762 /* resp_address_error */
763 /* ack_address_error */
764 case H1394_CMD_EADDR_ERROR:
765 cmd_result = CMD1394_EADDRESS_ERROR;
766 break;
768 /* resp_conflict_error */
769 /* ack_conflict_error */
770 case H1394_CMD_ERSRC_CONFLICT:
771 cmd_result = CMD1394_ERSRC_CONFLICT;
772 break;
774 /* ack_tardy */
775 case H1394_CMD_EDEVICE_POWERUP:
776 cmd_result = CMD1394_EDEVICE_BUSY;
777 break;
779 /* device errors (bad tcodes, ACKs, etc...) */
780 case H1394_CMD_EDEVICE_ERROR:
781 cmd_result = CMD1394_EDEVICE_ERROR;
782 break;
784 /* Unknown error type */
785 case H1394_CMD_EUNKNOWN_ERROR:
786 cmd_result = CMD1394_EUNKNOWN_ERROR;
787 break;
789 /* Unrecognized error */
790 default:
791 dip = hal->halinfo.dip;
793 /* An unexpected error in the HAL */
794 cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
795 ddi_node_name(dip), ddi_get_instance(dip));
797 /* Disable the HAL */
798 s1394_hal_shutdown(hal, B_TRUE);
800 TNF_PROBE_2(s1394_atreq_cmd_complete_error,
801 S1394_TNF_SL_ATREQ_ERROR, "", tnf_string, msg,
802 "Unrecognized cmd status code",
803 tnf_int, status, status);
804 TNF_PROBE_0_DEBUG(s1394_atreq_cmd_complete_exit,
805 S1394_TNF_SL_ATREQ_STACK, "");
806 return;
809 /* Remove command from the HAL's outstanding request Q */
810 s1394_remove_q_asynch_cmd(hal, req);
812 s_priv->cmd_in_use = B_FALSE;
814 req->cmd_result = cmd_result;
816 /* Is this a blocking command? */
817 if (req->cmd_options & CMD1394_BLOCKING) {
818 /* Unblock the waiting command */
819 mutex_enter(&s_priv->blocking_mutex);
820 s_priv->blocking_flag = B_TRUE;
821 cv_signal(&s_priv->blocking_cv);
822 mutex_exit(&s_priv->blocking_mutex);
824 TNF_PROBE_0_DEBUG(s1394_atreq_cmd_complete_exit,
825 S1394_TNF_SL_ATREQ_STACK, "");
826 return;
829 /* Call the target's completion_callback() */
830 if (req->completion_callback != NULL) {
831 TNF_PROBE_0_DEBUG(s1394_atreq_cmd_complete_do_callback,
832 S1394_TNF_SL_ATREQ_STACK, "");
833 req->completion_callback(req);
836 TNF_PROBE_0_DEBUG(s1394_atreq_cmd_complete_exit,
837 S1394_TNF_SL_ATREQ_STACK, "");
838 return;
841 /* Successful unless otherwise modified */
842 err = CMD1394_CMDSUCCESS;
844 if ((req->cmd_type == CMD1394_ASYNCH_RD_BLOCK) ||
845 (req->cmd_type == CMD1394_ASYNCH_WR_BLOCK)) {
847 /* Get a pointer to the HAL private struct */
848 h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
850 /* Update data_remaining */
851 s_priv->data_remaining -= h_priv->mblk.length;
853 /* Increment bytes_transferred */
854 req->cmd_u.b.bytes_transferred += h_priv->mblk.length;
856 if (req->cmd_type == CMD1394_ASYNCH_RD_BLOCK)
857 hal->hal_kstats->atreq_blk_rd_size +=
858 h_priv->mblk.length;
860 /* Is there still more to send? */
861 if (s_priv->data_remaining > 0) {
863 /* Setup the new mblk and offset */
864 h_priv->mblk.curr_mblk = h_priv->mblk.next_mblk;
865 h_priv->mblk.curr_offset = h_priv->mblk.next_offset;
867 /* Update destination address */
868 if (!(req->cmd_options &
869 CMD1394_DISABLE_ADDR_INCREMENT)) {
870 req->cmd_addr += h_priv->mblk.length;
874 * Use the current MAX_PAYLOAD size. This value
875 * doesn't need to be recalculated because we must
876 * be in the same generation on the bus, else we
877 * would have seen a bus reset error.
879 if (s_priv->data_remaining < h_priv->mblk.length) {
880 h_priv->mblk.length = s_priv->data_remaining;
883 /* Send command out again */
884 ret = s1394_xfer_asynch_command(hal, req, &err);
886 if (ret == DDI_SUCCESS) {
887 TNF_PROBE_0_DEBUG(s1394_atreq_cmd_complete_exit,
888 S1394_TNF_SL_ATREQ_STACK, "");
889 return;
891 } else if (err == CMD1394_ESTALE_GENERATION) {
892 /* Remove cmd from outstanding request Q */
893 s1394_remove_q_asynch_cmd(hal, req);
894 s1394_pending_q_insert(hal, req,
895 S1394_PENDING_Q_REAR);
897 TNF_PROBE_0_DEBUG(s1394_atreq_cmd_complete_exit,
898 S1394_TNF_SL_ATREQ_STACK, "");
899 return;
904 /* Remove command from the HAL's outstanding request Q */
905 s1394_remove_q_asynch_cmd(hal, req);
907 s_priv->cmd_in_use = B_FALSE;
909 /* Set status */
910 req->cmd_result = err;
912 /* Is this a blocking command? */
913 if (req->cmd_options & CMD1394_BLOCKING) {
914 /* Unblock the waiting command */
915 mutex_enter(&s_priv->blocking_mutex);
916 s_priv->blocking_flag = B_TRUE;
917 cv_signal(&s_priv->blocking_cv);
918 mutex_exit(&s_priv->blocking_mutex);
920 TNF_PROBE_0_DEBUG(s1394_atreq_cmd_complete_exit,
921 S1394_TNF_SL_ATREQ_STACK, "");
922 return;
925 /* Set status and call completion_callback() */
926 if (req->completion_callback != NULL) {
928 TNF_PROBE_0_DEBUG(s1394_atreq_cmd_complete_do_callback,
929 S1394_TNF_SL_ATREQ_STACK, "");
931 req->completion_callback(req);
933 TNF_PROBE_0_DEBUG(s1394_atreq_cmd_complete_exit,
934 S1394_TNF_SL_ATREQ_STACK, "");
935 return;
938 TNF_PROBE_0_DEBUG(s1394_atreq_cmd_complete_exit,
939 S1394_TNF_SL_ATREQ_STACK, "");
943 * s1394_atresp_cmd_complete()
944 * is similar to s1394_atreq_cmd_complete(). It is also called by
945 * h1394_cmd_is_complete(), but when an AT response has completed.
946 * Again, based upon the command's completion status,
947 * s1394_atresp_cmd_complete() determines whether to call the target or
948 * to simply cleanup the command and return.
950 void
951 s1394_atresp_cmd_complete(s1394_hal_t *hal, cmd1394_cmd_t *resp, int status)
953 s1394_cmd_priv_t *s_priv;
954 h1394_cmd_priv_t *h_priv;
955 dev_info_t *dip;
956 boolean_t valid_addr_blk;
957 int target_status;
959 TNF_PROBE_0_DEBUG(s1394_atresp_cmd_complete_enter,
960 S1394_TNF_SL_ATRESP_STACK, "");
962 target_status = CMD1394_CMDSUCCESS;
964 /* If not an ack_complete */
965 if (status != H1394_CMD_SUCCESS) {
966 switch (status) {
967 /* evt_missing_ack */
968 case H1394_CMD_ETIMEOUT:
969 target_status = CMD1394_ETIMEOUT;
970 break;
972 /* evt_flushed */
973 case H1394_CMD_EBUSRESET:
974 target_status = CMD1394_EBUSRESET;
975 break;
977 /* ack_busy_X */
978 /* ack_busy_A */
979 /* ack_busy_B */
980 case H1394_CMD_EDEVICE_BUSY:
981 target_status = CMD1394_EDEVICE_BUSY;
982 break;
984 /* ack_data_error */
985 case H1394_CMD_EDATA_ERROR:
986 target_status = CMD1394_EDATA_ERROR;
987 break;
989 /* ack_type_error */
990 case H1394_CMD_ETYPE_ERROR:
991 target_status = CMD1394_ETYPE_ERROR;
992 break;
994 /* ack_address_error */
995 case H1394_CMD_EADDR_ERROR:
996 target_status = CMD1394_EADDRESS_ERROR;
997 break;
999 /* ack_conflict_error */
1000 case H1394_CMD_ERSRC_CONFLICT:
1001 target_status = CMD1394_ERSRC_CONFLICT;
1002 break;
1004 /* ack_tardy */
1005 case H1394_CMD_EDEVICE_POWERUP:
1006 target_status = CMD1394_EDEVICE_BUSY;
1007 break;
1009 /* device errors (bad tcodes, ACKs, etc...) */
1010 case H1394_CMD_EDEVICE_ERROR:
1011 target_status = CMD1394_EDEVICE_ERROR;
1012 break;
1014 /* Unknown error type */
1015 case H1394_CMD_EUNKNOWN_ERROR:
1016 target_status = CMD1394_EUNKNOWN_ERROR;
1017 break;
1019 /* Unrecognized error */
1020 default:
1021 dip = hal->halinfo.dip;
1023 /* An unexpected error in the HAL */
1024 cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
1025 ddi_node_name(dip), ddi_get_instance(dip));
1027 /* Disable the HAL */
1028 s1394_hal_shutdown(hal, B_TRUE);
1030 TNF_PROBE_2(s1394_atresp_cmd_complete_error,
1031 S1394_TNF_SL_ATRESP_ERROR, "", tnf_string, msg,
1032 "Unrecognized cmd status code",
1033 tnf_int, status, status);
1034 TNF_PROBE_0_DEBUG(s1394_atresp_cmd_complete_exit,
1035 S1394_TNF_SL_ATRESP_STACK, "");
1036 return;
1040 /* Get the Services Layer private area */
1041 s_priv = S1394_GET_CMD_PRIV(resp);
1043 /* Get a pointer to the HAL private struct */
1044 h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
1046 valid_addr_blk = s_priv->arreq_valid_addr;
1048 if (valid_addr_blk == B_TRUE) {
1049 /* Set the command status */
1050 resp->cmd_result = target_status;
1052 switch (s_priv->cmd_priv_xfer_type) {
1053 case S1394_CMD_READ:
1054 case S1394_CMD_WRITE:
1055 case S1394_CMD_LOCK:
1056 if (resp->completion_callback != NULL) {
1057 TNF_PROBE_0_DEBUG(
1058 s1394_atresp_cmd_complete_do_callback,
1059 S1394_TNF_SL_ATRESP_STACK, "");
1060 resp->completion_callback(resp);
1062 break;
1064 default:
1065 dip = hal->halinfo.dip;
1067 /* An unexpected error in the HAL */
1068 cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
1069 ddi_node_name(dip), ddi_get_instance(dip));
1071 /* Disable the HAL */
1072 s1394_hal_shutdown(hal, B_TRUE);
1074 TNF_PROBE_1(s1394_atresp_cmd_complete_error,
1075 S1394_TNF_SL_ATRESP_ERROR, "", tnf_string, msg,
1076 "Unrecognized transfer type");
1077 TNF_PROBE_0_DEBUG(s1394_atresp_cmd_complete_exit,
1078 S1394_TNF_SL_ATRESP_STACK, "");
1079 return;
1083 TNF_PROBE_0_DEBUG(s1394_atresp_cmd_complete_call_hal_cmplt,
1084 S1394_TNF_SL_ATRESP_STACK, "");
1086 /* Free the command - Pass it back to the HAL */
1087 HAL_CALL(hal).response_complete(hal->halinfo.hal_private, resp, h_priv);
1089 TNF_PROBE_1_DEBUG(s1394_atresp_cmd_complete_exit,
1090 S1394_TNF_SL_ATRESP_STACK, "", tnf_int, status, target_status);
1094 * s1394_send_response()
1095 * is used to send a response to an AR request. Depending on whether the
1096 * request was a broadcast request, a write to posted write address space,
1097 * or some other request, either a response packet is sent, or the command
1098 * is returned to the HAL. A return value of DDI_SUCCESS means that the
1099 * command has been handled correctly. It was either successfully sent to
1100 * the HAL, or, if it was posted_write of broadcast, it was freed up. A
1101 * return value of DDI_FAILURE indicates either a serious error, in which
1102 * case the HAL is shutdown, or a failure returned by the HAL, in which
1103 * case the command is freed up and notice of the failure is returned.
1106 s1394_send_response(s1394_hal_t *hal, cmd1394_cmd_t *resp)
1108 s1394_cmd_priv_t *s_priv;
1109 h1394_cmd_priv_t *h_priv;
1110 dev_info_t *dip;
1111 int ret;
1112 int result;
1114 TNF_PROBE_0_DEBUG(s1394_send_response_enter, S1394_TNF_SL_ATRESP_STACK,
1115 "");
1117 /* Get the Services Layer private area */
1118 s_priv = S1394_GET_CMD_PRIV(resp);
1120 /* Get a pointer to the HAL private struct */
1121 h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
1124 * If request was broadcast or a write request to a posted write
1125 * address, don't send a response
1127 if ((resp->broadcast == 1) || ((s_priv->posted_write == B_TRUE) &&
1128 ((resp->cmd_result == CMD1394_ASYNCH_WR_QUAD) ||
1129 (resp->cmd_result == CMD1394_ASYNCH_WR_BLOCK)))) {
1131 TNF_PROBE_0_DEBUG(s1394_send_response_call_hal_cmplt,
1132 S1394_TNF_SL_ATRESP_STACK, "");
1134 /* Free the command - Pass it back to the HAL */
1135 HAL_CALL(hal).response_complete(hal->halinfo.hal_private,
1136 resp, h_priv);
1138 TNF_PROBE_0_DEBUG(s1394_send_response_exit,
1139 S1394_TNF_SL_ATRESP_STACK, "");
1140 return (DDI_SUCCESS);
1143 TNF_PROBE_0_DEBUG(s1394_send_response_call_hal_resp,
1144 S1394_TNF_SL_ATRESP_STACK, "");
1146 /* kstats - number of failure responses sent */
1147 if (resp->cmd_result != IEEE1394_RESP_COMPLETE) {
1148 switch (resp->cmd_type) {
1149 case CMD1394_ASYNCH_RD_QUAD:
1150 hal->hal_kstats->arresp_quad_rd_fail++;
1151 break;
1153 case CMD1394_ASYNCH_RD_BLOCK:
1154 hal->hal_kstats->arresp_blk_rd_fail++;
1155 break;
1157 case CMD1394_ASYNCH_WR_QUAD:
1158 hal->hal_kstats->arresp_quad_wr_fail++;
1159 break;
1161 case CMD1394_ASYNCH_WR_BLOCK:
1162 hal->hal_kstats->arresp_blk_wr_fail++;
1163 break;
1165 case CMD1394_ASYNCH_LOCK_32:
1166 hal->hal_kstats->arresp_lock32_fail++;
1167 break;
1169 case CMD1394_ASYNCH_LOCK_64:
1170 hal->hal_kstats->arresp_lock64_fail++;
1171 break;
1173 } else {
1174 if (resp->cmd_type == CMD1394_ASYNCH_RD_BLOCK)
1175 hal->hal_kstats->arreq_blk_rd_size +=
1176 resp->cmd_u.b.blk_length;
1179 if (resp->cmd_type == CMD1394_ASYNCH_RD_BLOCK) {
1180 h_priv->mblk.curr_mblk = resp->cmd_u.b.data_block;
1181 h_priv->mblk.curr_offset = resp->cmd_u.b.data_block->b_rptr;
1182 h_priv->mblk.length = resp->cmd_u.b.blk_length;
1185 switch (s_priv->cmd_priv_xfer_type) {
1186 case S1394_CMD_READ:
1187 ret = HAL_CALL(hal).read_response(hal->halinfo.hal_private,
1188 resp, h_priv, &result);
1189 break;
1191 case S1394_CMD_WRITE:
1192 ret = HAL_CALL(hal).write_response(hal->halinfo.hal_private,
1193 resp, h_priv, &result);
1194 break;
1196 case S1394_CMD_LOCK:
1197 ret = HAL_CALL(hal).lock_response(hal->halinfo.hal_private,
1198 resp, h_priv, &result);
1199 break;
1201 default:
1202 dip = hal->halinfo.dip;
1204 /* An unexpected error in the HAL */
1205 cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
1206 ddi_node_name(dip), ddi_get_instance(dip));
1208 /* Disable the HAL */
1209 s1394_hal_shutdown(hal, B_TRUE);
1211 TNF_PROBE_1(s1394_send_response_error,
1212 S1394_TNF_SL_ATRESP_ERROR, "", tnf_string, msg,
1213 "Unrecognized transfer type");
1214 TNF_PROBE_0_DEBUG(s1394_send_response_exit,
1215 S1394_TNF_SL_ATRESP_STACK, "");
1216 return (DDI_FAILURE);
1219 /* Unable to send a response */
1220 if (ret != DDI_SUCCESS) {
1221 if (result == H1394_STATUS_INVALID_BUSGEN) {
1222 TNF_PROBE_1(s1394_send_response_error,
1223 S1394_TNF_SL_ATRESP_ERROR, "", tnf_string, msg,
1224 "Invalid generation in response");
1225 } else if (result == H1394_STATUS_NOMORE_SPACE) {
1226 TNF_PROBE_1(s1394_send_response_error,
1227 S1394_TNF_SL_ATRESP_ERROR, "", tnf_string, msg,
1228 "No more space on AT response queue");
1229 } else {
1230 TNF_PROBE_1(s1394_send_response_error,
1231 S1394_TNF_SL_ATRESP_ERROR, "", tnf_string, msg,
1232 "Unknown problem in s1394_send_response");
1234 TNF_PROBE_0_DEBUG(s1394_send_response_call_hal_cmplt,
1235 S1394_TNF_SL_ATRESP_STACK, "");
1237 /* Free the command - Pass it back to the HAL */
1238 HAL_CALL(hal).response_complete(hal->halinfo.hal_private,
1239 resp, h_priv);
1241 TNF_PROBE_0_DEBUG(s1394_send_response_exit,
1242 S1394_TNF_SL_ATRESP_STACK, "");
1243 return (DDI_FAILURE);
1246 TNF_PROBE_0_DEBUG(s1394_send_response_exit, S1394_TNF_SL_ATRESP_STACK,
1247 "");
1248 return (DDI_SUCCESS);
1252 * s1394_compare_swap()
1253 * is used by t1394_lock() to send a lock request. Any of the lock
1254 * requests specified explicitly by the 1394 spec will pass thru here,
1255 * i.e compare-swap, mask-swap, etc.
1258 s1394_compare_swap(s1394_hal_t *hal, s1394_target_t *target, cmd1394_cmd_t *cmd)
1260 s1394_cmd_priv_t *s_priv;
1261 s1394_hal_state_t state;
1262 int err;
1263 int ret;
1265 TNF_PROBE_0_DEBUG(s1394_compare_swap_enter, S1394_TNF_SL_ATREQ_STACK,
1266 "");
1268 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1270 /* Lock the topology tree - protect from bus reset */
1271 mutex_enter(&hal->topology_tree_mutex);
1273 ret = s1394_setup_asynch_command(hal, target, cmd, S1394_CMD_LOCK,
1274 &err);
1276 /* Unlock the topology tree */
1277 mutex_exit(&hal->topology_tree_mutex);
1279 /* Get the Services Layer private area */
1280 s_priv = S1394_GET_CMD_PRIV(cmd);
1282 /* Command has now been put onto the queue! */
1283 if (ret != DDI_SUCCESS) {
1284 /* Copy error code into result */
1285 cmd->cmd_result = err;
1287 TNF_PROBE_0(s1394_compare_swap_error_in_setup_asynch,
1288 S1394_TNF_SL_ATREQ_ERROR, "");
1289 TNF_PROBE_0_DEBUG(s1394_compare_swap_exit,
1290 S1394_TNF_SL_ATREQ_STACK, "");
1291 return (DDI_FAILURE);
1294 mutex_enter(&hal->topology_tree_mutex);
1295 state = hal->hal_state;
1296 /* If this command was sent during a bus reset, */
1297 /* then put it onto the pending Q. */
1298 if (state == S1394_HAL_RESET) {
1299 /* Remove cmd from outstanding request Q */
1300 s1394_remove_q_asynch_cmd(hal, cmd);
1302 /* Are we on the bus reset event stack? */
1303 if (s1394_on_br_thread(hal) == B_TRUE) {
1304 /* Blocking commands are not allowed */
1305 if (cmd->cmd_options & CMD1394_BLOCKING) {
1306 mutex_exit(&hal->topology_tree_mutex);
1308 s_priv->cmd_in_use = B_FALSE;
1310 cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
1312 TNF_PROBE_1(s1394_compare_swap_error,
1313 S1394_TNF_SL_ATREQ_ERROR, "", tnf_string,
1314 msg, "CMD1394_BLOCKING in bus reset ctxt");
1315 TNF_PROBE_0_DEBUG(s1394_compare_swap_exit,
1316 S1394_TNF_SL_ATREQ_STACK, "");
1317 return (DDI_FAILURE);
1321 s1394_pending_q_insert(hal, cmd, S1394_PENDING_Q_FRONT);
1322 mutex_exit(&hal->topology_tree_mutex);
1324 /* Block (if necessary) */
1325 s1394_block_on_asynch_cmd(cmd);
1327 TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
1328 "");
1329 return (DDI_SUCCESS);
1331 mutex_exit(&hal->topology_tree_mutex);
1333 /* Send the command out */
1334 ret = s1394_xfer_asynch_command(hal, cmd, &err);
1336 if (ret != DDI_SUCCESS) {
1337 if (err == CMD1394_ESTALE_GENERATION) {
1338 /* Remove cmd from outstanding request Q */
1339 s1394_remove_q_asynch_cmd(hal, cmd);
1340 s1394_pending_q_insert(hal, cmd, S1394_PENDING_Q_FRONT);
1342 /* Block (if necessary) */
1343 s1394_block_on_asynch_cmd(cmd);
1345 TNF_PROBE_0_DEBUG(s1394_compare_swap_exit,
1346 S1394_TNF_SL_ATREQ_STACK, "");
1347 return (DDI_SUCCESS);
1349 } else {
1350 /* Remove cmd from outstanding request Q */
1351 s1394_remove_q_asynch_cmd(hal, cmd);
1353 s_priv->cmd_in_use = B_FALSE;
1355 /* Copy error code into result */
1356 cmd->cmd_result = err;
1358 TNF_PROBE_0(s1394_compare_swap_error_in_xfer,
1359 S1394_TNF_SL_ATREQ_ERROR, "");
1360 TNF_PROBE_0_DEBUG(s1394_compare_swap_exit,
1361 S1394_TNF_SL_ATREQ_STACK, "");
1362 return (DDI_FAILURE);
1364 } else {
1365 /* Block (if necessary) */
1366 s1394_block_on_asynch_cmd(cmd);
1368 TNF_PROBE_0_DEBUG(s1394_compare_swap_exit,
1369 S1394_TNF_SL_ATREQ_STACK, "");
1370 return (DDI_SUCCESS);
1375 * s1394_split_lock_req()
1376 * is also used by t1394_lock() to send a lock request. The difference
1377 * is that s1394_split_lock_req() is used to send the software supported
1378 * lock types, i.e. bit_and, bit_or, etc. These lock requests require
1379 * more than one transaction, typically compare-swap's.
1382 s1394_split_lock_req(s1394_hal_t *hal, s1394_target_t *target,
1383 cmd1394_cmd_t *cmd)
1385 s1394_cmd_priv_t *s_priv;
1386 cmd1394_cmd_t *tmp_cmd;
1388 TNF_PROBE_0_DEBUG(s1394_split_lock_req_enter,
1389 S1394_TNF_SL_ATREQ_STACK, "");
1391 /* Allocate a temporary command */
1392 if (s1394_alloc_cmd(hal, T1394_ALLOC_CMD_NOSLEEP, &tmp_cmd) !=
1393 DDI_SUCCESS) {
1394 cmd->cmd_result = CMD1394_EUNKNOWN_ERROR;
1396 TNF_PROBE_0(s1394_split_lock_req_error_alloc_cmd,
1397 S1394_TNF_SL_ATREQ_ERROR, "");
1398 TNF_PROBE_0_DEBUG(s1394_split_lock_req_exit,
1399 S1394_TNF_SL_ATREQ_STACK, "");
1400 return (DDI_FAILURE);
1403 /* Get the Services Layer private area */
1404 s_priv = S1394_GET_CMD_PRIV(tmp_cmd);
1406 tmp_cmd->completion_callback = s1394_handle_lock;
1407 tmp_cmd->cmd_callback_arg = (opaque_t)cmd;
1408 tmp_cmd->cmd_type = cmd->cmd_type;
1409 tmp_cmd->cmd_addr = cmd->cmd_addr;
1410 tmp_cmd->cmd_options = cmd->cmd_options;
1411 tmp_cmd->bus_generation = cmd->bus_generation;
1413 /* The temporary command can not block */
1414 tmp_cmd->cmd_options = tmp_cmd->cmd_options & ~CMD1394_BLOCKING;
1416 /* Setup compare-swap with data_value == arg_value (read) */
1417 if (tmp_cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
1418 tmp_cmd->cmd_u.l32.data_value = 0;
1419 tmp_cmd->cmd_u.l32.arg_value = 0;
1420 tmp_cmd->cmd_u.l32.lock_type = CMD1394_LOCK_COMPARE_SWAP;
1421 s_priv->temp_num_retries = cmd->cmd_u.l32.num_retries;
1422 } else {
1423 tmp_cmd->cmd_u.l64.data_value = 0;
1424 tmp_cmd->cmd_u.l64.arg_value = 0;
1425 tmp_cmd->cmd_u.l64.lock_type = CMD1394_LOCK_COMPARE_SWAP;
1426 s_priv->temp_num_retries = cmd->cmd_u.l64.num_retries;
1429 /* Initialize lock_req_step */
1430 s_priv->lock_req_step = 0;
1432 /* Get the Services Layer private area for the target cmd */
1433 s_priv = S1394_GET_CMD_PRIV(cmd);
1435 s_priv->cmd_in_use = B_TRUE;
1437 /* Send the request */
1438 if (s1394_compare_swap(hal, target, tmp_cmd) != DDI_SUCCESS) {
1439 s_priv->cmd_in_use = B_FALSE;
1441 /* Free the temporary command */
1442 if (s1394_free_cmd(hal, &tmp_cmd) != DDI_SUCCESS)
1443 cmd->cmd_result = CMD1394_EUNKNOWN_ERROR;
1445 TNF_PROBE_0_DEBUG(s1394_split_lock_req_exit,
1446 S1394_TNF_SL_ATREQ_STACK, "");
1447 return (DDI_FAILURE);
1450 /* Block (if necessary) */
1451 s1394_block_on_asynch_cmd(cmd);
1453 TNF_PROBE_0_DEBUG(s1394_split_lock_req_exit,
1454 S1394_TNF_SL_ATREQ_STACK, "");
1455 return (DDI_SUCCESS);
1459 * s1394_handle_lock()
1460 * is the callback for s1394_split_lock_req(). It does all of the real
1461 * work. Based on the specific lock type all necessary manipulation is
1462 * performed and another compare swap is sent out. If the transaction
1463 * is unsuccessful, it is retried.
1465 static void
1466 s1394_handle_lock(cmd1394_cmd_t *cmd)
1468 s1394_hal_t *to_hal;
1469 s1394_target_t *target;
1470 s1394_cmd_priv_t *s_priv;
1471 cmd1394_cmd_t *target_cmd;
1472 uint32_t lock_req_step;
1473 int tcmd_result;
1474 int ret;
1477 TNF_PROBE_0_DEBUG(s1394_handle_lock_enter, S1394_TNF_SL_ATREQ_STACK,
1478 "");
1480 /* Get the Services Layer private area */
1481 s_priv = S1394_GET_CMD_PRIV(cmd);
1483 lock_req_step = s_priv->lock_req_step;
1485 /* Get the target's command */
1486 target_cmd = (cmd1394_cmd_t *)cmd->cmd_callback_arg;
1488 /* Get the destination of the command */
1489 to_hal = s_priv->sent_on_hal;
1491 lock_req_step_0:
1492 /* Is this step 0 completing? */
1493 if (lock_req_step == 0) {
1494 /* Was the request successful? */
1495 if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
1496 /* Do any math, bit ops, or byte-swapping necessary */
1497 ret = s1394_process_split_lock(cmd, target_cmd);
1499 if (ret != DDI_SUCCESS) {
1500 tcmd_result = target_cmd->cmd_result;
1501 goto lock_req_done;
1504 s_priv->lock_req_step = 1;
1506 target = s_priv->sent_by_target;
1508 if (s1394_compare_swap(to_hal, target, cmd) !=
1509 DDI_SUCCESS) {
1510 tcmd_result = cmd->cmd_result;
1511 goto lock_req_done;
1512 } else {
1513 TNF_PROBE_0_DEBUG(s1394_handle_lock_exit,
1514 S1394_TNF_SL_ATREQ_STACK, "");
1515 return;
1517 } else {
1518 /* Command failed for some reason */
1519 tcmd_result = cmd->cmd_result;
1520 goto lock_req_done;
1522 } else { /* lock_req_step == 1 */
1523 /* Was the request successful? */
1524 if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
1525 /* Do whatever's necessary to finish up the lock */
1526 ret = s1394_finish_split_lock(cmd, target_cmd);
1528 if (ret != DDI_SUCCESS) {
1529 lock_req_step = 0;
1530 goto lock_req_step_0;
1531 } else {
1532 tcmd_result = cmd->cmd_result;
1533 goto lock_req_done;
1535 } else {
1536 /* Command failed for some reason */
1537 tcmd_result = cmd->cmd_result;
1538 goto lock_req_done;
1542 lock_req_done:
1543 if (s1394_free_cmd(to_hal, &cmd) != DDI_SUCCESS) {
1544 TNF_PROBE_0(s1394_handle_lock_error_in_freecmd,
1545 S1394_TNF_SL_ATREQ_ERROR, "");
1548 /* Get the Services Layer private area */
1549 s_priv = S1394_GET_CMD_PRIV(target_cmd);
1551 s_priv->cmd_in_use = B_FALSE;
1553 target_cmd->cmd_result = tcmd_result;
1555 /* Is this a blocking command? */
1556 if (target_cmd->cmd_options & CMD1394_BLOCKING) {
1557 /* Unblock the waiting command */
1558 mutex_enter(&s_priv->blocking_mutex);
1559 s_priv->blocking_flag = B_TRUE;
1560 cv_signal(&s_priv->blocking_cv);
1561 mutex_exit(&s_priv->blocking_mutex);
1563 TNF_PROBE_0_DEBUG(s1394_handle_lock_exit,
1564 S1394_TNF_SL_ATREQ_STACK, "");
1565 return;
1568 /* Call the target's completion_callback() */
1569 if (target_cmd->completion_callback != NULL)
1570 target_cmd->completion_callback(target_cmd);
1572 TNF_PROBE_0_DEBUG(s1394_handle_lock_exit,
1573 S1394_TNF_SL_ATREQ_STACK, "");
1577 * s1394_pending_q_insert()
1578 * is used to insert a given command structure onto a HAL's pending queue
1579 * for later processing (after the bus reset). All commands returned by
1580 * the HAL, are inserted onto the rear of the list (first priority), and
1581 * all other commands (from targets during bus reset) are put onto the front.
1583 void
1584 s1394_pending_q_insert(s1394_hal_t *hal, cmd1394_cmd_t *cmd, uint_t flags)
1586 cmd1394_cmd_t *temp_cmd;
1587 s1394_cmd_priv_t *s_priv;
1588 s1394_cmd_priv_t *c_priv;
1590 TNF_PROBE_0_DEBUG(s1394_pending_q_insert_enter,
1591 S1394_TNF_SL_ATREQ_STACK, "");
1593 mutex_enter(&hal->pending_q_mutex);
1595 /* Get the Services Layer private area */
1596 s_priv = S1394_GET_CMD_PRIV(cmd);
1598 /* Is the outstanding request queue empty? */
1599 if ((hal->pending_q_head == NULL) && (hal->pending_q_tail == NULL)) {
1601 hal->pending_q_head = (cmd1394_cmd_t *)cmd;
1602 hal->pending_q_tail = (cmd1394_cmd_t *)cmd;
1603 s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
1604 s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
1606 } else if (flags == S1394_PENDING_Q_FRONT) {
1607 s_priv->cmd_priv_next = hal->pending_q_head;
1608 s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
1610 temp_cmd = (cmd1394_cmd_t *)hal->pending_q_head;
1611 c_priv = (s1394_cmd_priv_t *)((uchar_t *)temp_cmd +
1612 sizeof (cmd1394_cmd_t));
1613 c_priv->cmd_priv_prev = (cmd1394_cmd_t *)cmd;
1615 hal->pending_q_head = (cmd1394_cmd_t *)cmd;
1617 } else {
1618 s_priv->cmd_priv_prev = hal->pending_q_tail;
1619 s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
1621 temp_cmd = (cmd1394_cmd_t *)hal->pending_q_tail;
1622 c_priv = (s1394_cmd_priv_t *)((uchar_t *)temp_cmd +
1623 sizeof (cmd1394_cmd_t));
1624 c_priv->cmd_priv_next = (cmd1394_cmd_t *)cmd;
1626 hal->pending_q_tail = (cmd1394_cmd_t *)cmd;
1629 mutex_exit(&hal->pending_q_mutex);
1631 /* kstats - number of pending Q insertions */
1632 hal->hal_kstats->pending_q_insert++;
1634 TNF_PROBE_0_DEBUG(s1394_pending_q_insert_exit,
1635 S1394_TNF_SL_ATREQ_STACK, "");
1639 * s1394_pending_q_remove()
1640 * is used to remove a command structure from a HAL's pending queue for
1641 * processing.
1643 static cmd1394_cmd_t *
1644 s1394_pending_q_remove(s1394_hal_t *hal)
1646 s1394_cmd_priv_t *s_priv;
1647 s1394_cmd_priv_t *c_priv;
1648 cmd1394_cmd_t *cmd;
1649 cmd1394_cmd_t *prev_cmd;
1651 TNF_PROBE_0_DEBUG(s1394_pending_q_remove_enter,
1652 S1394_TNF_SL_ATREQ_STACK, "");
1654 mutex_enter(&hal->pending_q_mutex);
1656 cmd = (cmd1394_cmd_t *)hal->pending_q_tail;
1657 if (cmd == NULL) {
1658 mutex_exit(&hal->pending_q_mutex);
1659 TNF_PROBE_0_DEBUG(s1394_pending_q_remove_exit,
1660 S1394_TNF_SL_ATREQ_STACK, "");
1661 return (NULL);
1664 /* Get the Services Layer private area */
1665 s_priv = S1394_GET_CMD_PRIV(cmd);
1667 prev_cmd = (cmd1394_cmd_t *)s_priv->cmd_priv_prev;
1669 s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
1670 s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
1672 if (prev_cmd != NULL) {
1673 c_priv = (s1394_cmd_priv_t *)((uchar_t *)prev_cmd +
1674 sizeof (cmd1394_cmd_t));
1675 c_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
1677 } else {
1678 hal->pending_q_head = (cmd1394_cmd_t *)NULL;
1680 hal->pending_q_tail = (cmd1394_cmd_t *)prev_cmd;
1682 mutex_exit(&hal->pending_q_mutex);
1684 TNF_PROBE_0_DEBUG(s1394_pending_q_remove_exit,
1685 S1394_TNF_SL_ATREQ_STACK, "");
1686 return (cmd);
1690 * s1394_resend_pending_cmds()
1691 * is called when the pending queue is to be flushed. After most of the
1692 * bus reset processing is completed, the pending commands are sent/resent.
1694 void
1695 s1394_resend_pending_cmds(s1394_hal_t *hal)
1697 int done;
1699 TNF_PROBE_0_DEBUG(s1394_resend_pending_cmds_enter,
1700 S1394_TNF_SL_BR_STACK, "");
1702 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1704 do {
1705 done = s1394_process_pending_q(hal);
1706 } while (done == B_FALSE);
1708 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1710 TNF_PROBE_0_DEBUG(s1394_resend_pending_cmds_exit,
1711 S1394_TNF_SL_BR_STACK, "");
1715 * s1394_process_pending_q()
1716 * is called to send/resend the commands on the pending queue. All command
1717 * handling can be done here, including notifying the target of failed
1718 * commands, etc. If it is necessary to recompute the address, speed,
1719 * or max_payload for a command, that can be done here too. And if there
1720 * is no reason not to continue sending commands from the pending queue,
1721 * then a B_FALSE is returned, else B_TRUE is returned.
1723 static boolean_t
1724 s1394_process_pending_q(s1394_hal_t *hal)
1726 s1394_cmd_priv_t *s_priv;
1727 h1394_cmd_priv_t *h_priv;
1728 s1394_target_t *target;
1729 cmd1394_cmd_t *cmd;
1730 uint64_t node;
1731 uint32_t from_node;
1732 uint32_t to_node;
1733 uint_t current_max_payload;
1734 int ret;
1736 TNF_PROBE_0_DEBUG(s1394_process_pending_q_enter,
1737 S1394_TNF_SL_BR_STACK, "");
1739 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1741 /* Pull a command from the Pending Q */
1742 cmd = s1394_pending_q_remove(hal);
1744 if (cmd == NULL) {
1745 TNF_PROBE_0_DEBUG(s1394_process_pending_q_exit,
1746 S1394_TNF_SL_BR_STACK, "");
1747 return (B_TRUE);
1750 /* Get the Services Layer private area */
1751 s_priv = S1394_GET_CMD_PRIV(cmd);
1753 /* Get a pointer to the HAL private struct */
1754 h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
1756 if ((cmd->cmd_options & CMD1394_OVERRIDE_ADDR) ||
1757 (cmd->cmd_options & CMD1394_CANCEL_ON_BUS_RESET)) {
1758 if (h_priv->bus_generation == hal->generation_count) {
1759 ret = s1394_pending_q_helper(hal, cmd);
1760 return (ret);
1761 } else {
1763 s_priv->cmd_in_use = B_FALSE;
1765 cmd->cmd_result = CMD1394_EBUSRESET;
1767 /* Is this a blocking command? */
1768 if (cmd->cmd_options & CMD1394_BLOCKING) {
1769 /* Unblock the waiting command */
1770 mutex_enter(&s_priv->blocking_mutex);
1771 s_priv->blocking_flag = B_TRUE;
1772 cv_signal(&s_priv->blocking_cv);
1773 mutex_exit(&s_priv->blocking_mutex);
1775 TNF_PROBE_0_DEBUG(s1394_process_pending_q_exit,
1776 S1394_TNF_SL_BR_STACK, "");
1777 return (B_FALSE);
1780 /* Call the target's completion_callback() */
1781 if (cmd->completion_callback != NULL) {
1782 cmd->completion_callback(cmd);
1785 TNF_PROBE_0_DEBUG(s1394_process_pending_q_exit,
1786 S1394_TNF_SL_BR_STACK, "");
1787 return (B_FALSE);
1789 } else {
1790 if (h_priv->bus_generation == hal->generation_count) {
1791 ret = s1394_pending_q_helper(hal, cmd);
1792 return (ret);
1793 } else {
1794 /* Make sure we can get the topology_tree_mutex */
1795 if (s1394_lock_tree(hal) != DDI_SUCCESS)
1796 return (B_TRUE);
1798 /* Set the generation */
1799 cmd->bus_generation = hal->generation_count;
1801 /* Copy the generation into the HAL's private field */
1802 h_priv->bus_generation = cmd->bus_generation;
1804 target = s_priv->sent_by_target;
1806 /* If not OVERRIDE_ADDR, then target may not be NULL */
1807 ASSERT(target != NULL);
1809 rw_enter(&hal->target_list_rwlock, RW_READER);
1811 if (((target->target_state & S1394_TARG_GONE) == 0) &&
1812 (target->on_node != NULL)) {
1813 node = target->on_node->node_num;
1814 rw_exit(&hal->target_list_rwlock);
1815 } else {
1816 rw_exit(&hal->target_list_rwlock);
1818 s_priv->cmd_in_use = B_FALSE;
1820 cmd->cmd_result = CMD1394_EDEVICE_REMOVED;
1822 /* Is this a blocking command? */
1823 if (cmd->cmd_options & CMD1394_BLOCKING) {
1824 s1394_unlock_tree(hal);
1826 /* Unblock the waiting command */
1827 mutex_enter(&s_priv->blocking_mutex);
1828 s_priv->blocking_flag = B_TRUE;
1829 cv_signal(&s_priv->blocking_cv);
1830 mutex_exit(&s_priv->blocking_mutex);
1832 TNF_PROBE_0_DEBUG(
1833 s1394_process_pending_q_exit,
1834 S1394_TNF_SL_BR_STACK,
1835 "");
1836 return (B_FALSE);
1839 /* Call the target's completion_callback() */
1840 if (cmd->completion_callback != NULL) {
1841 s1394_unlock_tree(hal);
1842 cmd->completion_callback(cmd);
1843 TNF_PROBE_0_DEBUG(
1844 s1394_process_pending_q_exit,
1845 S1394_TNF_SL_BR_STACK, "");
1846 return (B_FALSE);
1847 } else {
1848 s1394_unlock_tree(hal);
1849 TNF_PROBE_0_DEBUG(
1850 s1394_process_pending_q_exit,
1851 S1394_TNF_SL_BR_STACK, "");
1852 return (B_FALSE);
1856 /* Mask in the top 16-bits */
1857 cmd->cmd_addr = cmd->cmd_addr &
1858 IEEE1394_ADDR_OFFSET_MASK;
1859 cmd->cmd_addr = cmd->cmd_addr |
1860 (node << IEEE1394_ADDR_PHY_ID_SHIFT);
1861 cmd->cmd_addr = cmd->cmd_addr |
1862 IEEE1394_ADDR_BUS_ID_MASK;
1864 /* Speed is to be filled in from speed map */
1865 from_node = IEEE1394_NODE_NUM(hal->node_id);
1866 to_node = (uint32_t)node;
1868 /* Fill in the nodeID */
1869 cmd->nodeID =
1870 (cmd->cmd_addr & IEEE1394_ADDR_NODE_ID_MASK) >>
1871 IEEE1394_ADDR_NODE_ID_SHIFT;
1873 if (cmd->cmd_options & CMD1394_OVERRIDE_SPEED) {
1874 s_priv->hal_cmd_private.speed =
1875 (int)cmd->cmd_speed;
1876 } else {
1877 /* Speed is to be filled in from speed map */
1878 s_priv->hal_cmd_private.speed =
1879 (int)s1394_speed_map_get(hal, from_node,
1880 to_node);
1883 /* Is it a block request? */
1884 if ((cmd->cmd_type == CMD1394_ASYNCH_RD_BLOCK) ||
1885 (cmd->cmd_type == CMD1394_ASYNCH_WR_BLOCK)) {
1887 /* Get a pointer to the HAL private struct */
1888 h_priv = (h1394_cmd_priv_t *)&s_priv->
1889 hal_cmd_private;
1891 /* Handle the MAX_PAYLOAD size */
1892 if (s_priv->sent_by_target != NULL) {
1893 current_max_payload =
1894 s_priv->sent_by_target->
1895 current_max_payload;
1896 } else {
1897 current_max_payload = 4;
1899 if (cmd->cmd_options &
1900 CMD1394_OVERRIDE_MAX_PAYLOAD) {
1901 if (current_max_payload >
1902 cmd->cmd_u.b.max_payload)
1903 current_max_payload =
1904 cmd->cmd_u.b.max_payload;
1906 if (s_priv->data_remaining <
1907 current_max_payload) {
1908 h_priv->mblk.length =
1909 s_priv->data_remaining;
1910 } else {
1911 h_priv->mblk.length =
1912 current_max_payload;
1915 s1394_unlock_tree(hal);
1916 ret = s1394_pending_q_helper(hal, cmd);
1917 TNF_PROBE_0_DEBUG(s1394_process_pending_q_exit,
1918 S1394_TNF_SL_BR_STACK, "");
1919 return (ret);
1925 * s1394_pending_q_helper()
1926 * is a "helper" function for s1394_process_pending_q(). It attempts to
1927 * resend commands, handling error conditions whenever necessary.
1929 static boolean_t
1930 s1394_pending_q_helper(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
1932 s1394_cmd_priv_t *s_priv;
1933 int err;
1934 int ret;
1936 TNF_PROBE_0_DEBUG(s1394_pending_q_helper_enter,
1937 S1394_TNF_SL_BR_STACK, "");
1939 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1941 /* Get the Services Layer private area */
1942 s_priv = S1394_GET_CMD_PRIV(cmd);
1944 /* Put cmd on outstanding request Q */
1945 s1394_insert_q_asynch_cmd(hal, cmd);
1947 /* Send command out again */
1948 ret = s1394_xfer_asynch_command(hal, cmd, &err);
1950 if (ret != DDI_SUCCESS) {
1951 if (err == CMD1394_ESTALE_GENERATION) {
1952 /* Remove cmd outstanding req Q */
1953 s1394_remove_q_asynch_cmd(hal, cmd);
1954 s1394_pending_q_insert(hal, cmd, S1394_PENDING_Q_FRONT);
1956 TNF_PROBE_0_DEBUG(s1394_pending_q_helper_exit,
1957 S1394_TNF_SL_BR_STACK, "");
1958 return (B_TRUE);
1959 } else {
1960 /* Remove cmd from outstanding request Q */
1961 s1394_remove_q_asynch_cmd(hal, cmd);
1963 s_priv->cmd_in_use = B_FALSE;
1965 cmd->cmd_result = err;
1967 /* Is this a blocking command? */
1968 if (cmd->cmd_options & CMD1394_BLOCKING) {
1969 /* Unblock waiting command */
1970 mutex_enter(&s_priv->blocking_mutex);
1971 s_priv->blocking_flag = B_TRUE;
1972 cv_signal(&s_priv->blocking_cv);
1973 mutex_exit(&s_priv->blocking_mutex);
1975 TNF_PROBE_0_DEBUG(s1394_pending_q_helper_exit,
1976 S1394_TNF_SL_BR_STACK, "");
1977 return (B_FALSE);
1980 /* Call target completion_callback() */
1981 if (cmd->completion_callback != NULL) {
1982 cmd->completion_callback(cmd);
1983 TNF_PROBE_0_DEBUG(s1394_pending_q_helper_exit,
1984 S1394_TNF_SL_BR_STACK, "");
1985 return (B_FALSE);
1986 } else {
1987 TNF_PROBE_0_DEBUG(s1394_pending_q_helper_exit,
1988 S1394_TNF_SL_BR_STACK, "");
1989 return (B_FALSE);
1994 TNF_PROBE_0_DEBUG(s1394_pending_q_helper_exit,
1995 S1394_TNF_SL_BR_STACK, "");
1996 return (B_FALSE);
2000 * s1394_process_split_lock()
2001 * is a "helper" function for the s1394_handle_lock() callback. Its
2002 * job is to perform whatever manipulation is required for the given
2003 * request.
2005 static int
2006 s1394_process_split_lock(cmd1394_cmd_t *cmd, cmd1394_cmd_t *target_cmd)
2008 uint64_t new_value64;
2009 uint64_t data_value64;
2010 uint64_t arg_value64;
2011 uint64_t old_value64;
2012 uint64_t temp_value64;
2013 uint32_t new_value32;
2014 uint32_t data_value32;
2015 uint32_t arg_value32;
2016 uint32_t old_value32;
2017 uint32_t temp_value32;
2019 TNF_PROBE_0_DEBUG(s1394_process_split_lock_enter,
2020 S1394_TNF_SL_ATREQ_STACK, "");
2022 if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
2023 old_value32 = cmd->cmd_u.l32.old_value;
2024 data_value32 = target_cmd->cmd_u.l32.data_value;
2025 arg_value32 = target_cmd->cmd_u.l32.arg_value;
2027 /* Lock type specific */
2028 switch (target_cmd->cmd_u.l32.lock_type) {
2029 case CMD1394_LOCK_BIT_AND:
2030 new_value32 = old_value32 & data_value32;
2031 break;
2033 case CMD1394_LOCK_BIT_OR:
2034 new_value32 = old_value32 | data_value32;
2035 break;
2037 case CMD1394_LOCK_BIT_XOR:
2038 new_value32 = old_value32 ^ data_value32;
2039 break;
2041 case CMD1394_LOCK_INCREMENT:
2042 old_value32 = T1394_DATA32(old_value32);
2043 new_value32 = old_value32 + 1;
2044 new_value32 = T1394_DATA32(new_value32);
2045 old_value32 = T1394_DATA32(old_value32);
2046 break;
2048 case CMD1394_LOCK_DECREMENT:
2049 old_value32 = T1394_DATA32(old_value32);
2050 new_value32 = old_value32 - 1;
2051 new_value32 = T1394_DATA32(new_value32);
2052 old_value32 = T1394_DATA32(old_value32);
2053 break;
2055 case CMD1394_LOCK_ADD:
2056 old_value32 = T1394_DATA32(old_value32);
2057 new_value32 = old_value32 + data_value32;
2058 new_value32 = T1394_DATA32(new_value32);
2059 old_value32 = T1394_DATA32(old_value32);
2060 break;
2062 case CMD1394_LOCK_SUBTRACT:
2063 old_value32 = T1394_DATA32(old_value32);
2064 new_value32 = old_value32 - data_value32;
2065 new_value32 = T1394_DATA32(new_value32);
2066 old_value32 = T1394_DATA32(old_value32);
2067 break;
2069 case CMD1394_LOCK_THRESH_ADD:
2070 old_value32 = T1394_DATA32(old_value32);
2071 temp_value32 = (old_value32 + data_value32);
2072 if ((temp_value32 >= old_value32) &&
2073 (temp_value32 <= arg_value32)) {
2074 new_value32 = T1394_DATA32(temp_value32);
2075 old_value32 = T1394_DATA32(old_value32);
2076 } else {
2077 /* Failed threshold add */
2078 target_cmd->cmd_u.l32.old_value =
2079 T1394_DATA32(cmd->cmd_u.l32.old_value);
2080 target_cmd->cmd_result = CMD1394_CMDSUCCESS;
2081 TNF_PROBE_0_DEBUG(
2082 s1394_process_split_lock_exit,
2083 S1394_TNF_SL_ATREQ_STACK, "");
2084 return (DDI_FAILURE);
2086 break;
2088 case CMD1394_LOCK_THRESH_SUBTRACT:
2089 old_value32 = T1394_DATA32(old_value32);
2090 temp_value32 = (old_value32 - data_value32);
2091 if ((old_value32 >= data_value32) &&
2092 (temp_value32 >= arg_value32)) {
2093 new_value32 = T1394_DATA32(temp_value32);
2094 old_value32 = T1394_DATA32(old_value32);
2095 } else {
2096 /* Failed threshold subtract */
2097 target_cmd->cmd_u.l32.old_value =
2098 T1394_DATA32(cmd->cmd_u.l32.old_value);
2099 target_cmd->cmd_result = CMD1394_CMDSUCCESS;
2100 TNF_PROBE_0_DEBUG(
2101 s1394_process_split_lock_exit,
2102 S1394_TNF_SL_ATREQ_STACK, "");
2103 return (DDI_FAILURE);
2105 break;
2107 case CMD1394_LOCK_CLIP_ADD:
2108 old_value32 = T1394_DATA32(old_value32);
2109 temp_value32 = (old_value32 + data_value32);
2110 if ((temp_value32 < old_value32) ||
2111 (temp_value32 > arg_value32))
2112 new_value32 = T1394_DATA32(arg_value32);
2113 else
2114 new_value32 = T1394_DATA32(temp_value32);
2115 old_value32 = T1394_DATA32(old_value32);
2116 break;
2118 case CMD1394_LOCK_CLIP_SUBTRACT:
2119 old_value32 = T1394_DATA32(old_value32);
2120 temp_value32 = (old_value32 - data_value32);
2121 if ((data_value32 > old_value32) ||
2122 (temp_value32 < arg_value32))
2123 new_value32 = T1394_DATA32(arg_value32);
2124 else
2125 new_value32 = T1394_DATA32(temp_value32);
2126 old_value32 = T1394_DATA32(old_value32);
2127 break;
2130 /* Send compare-swap lock request */
2131 cmd->cmd_u.l32.arg_value = old_value32;
2132 cmd->cmd_u.l32.data_value = new_value32;
2133 } else {
2134 old_value64 = cmd->cmd_u.l64.old_value;
2135 data_value64 = target_cmd->cmd_u.l64.data_value;
2136 arg_value64 = target_cmd->cmd_u.l64.arg_value;
2138 /* Lock type specific */
2139 switch (target_cmd->cmd_u.l64.lock_type) {
2140 case CMD1394_LOCK_BIT_AND:
2141 new_value64 = old_value64 & data_value64;
2142 break;
2144 case CMD1394_LOCK_BIT_OR:
2145 new_value64 = old_value64 | data_value64;
2146 break;
2148 case CMD1394_LOCK_BIT_XOR:
2149 new_value64 = old_value64 ^ data_value64;
2150 break;
2152 case CMD1394_LOCK_INCREMENT:
2153 old_value64 = T1394_DATA64(old_value64);
2154 new_value64 = old_value64 + 1;
2155 new_value64 = T1394_DATA64(new_value64);
2156 old_value64 = T1394_DATA64(old_value64);
2157 break;
2159 case CMD1394_LOCK_DECREMENT:
2160 old_value64 = T1394_DATA64(old_value64);
2161 new_value64 = old_value64 - 1;
2162 new_value64 = T1394_DATA64(new_value64);
2163 old_value64 = T1394_DATA64(old_value64);
2164 break;
2166 case CMD1394_LOCK_ADD:
2167 old_value64 = T1394_DATA64(old_value64);
2168 new_value64 = old_value64 + data_value64;
2169 new_value64 = T1394_DATA64(new_value64);
2170 old_value64 = T1394_DATA64(old_value64);
2171 break;
2173 case CMD1394_LOCK_SUBTRACT:
2174 old_value64 = T1394_DATA64(old_value64);
2175 new_value64 = old_value64 - data_value64;
2176 new_value64 = T1394_DATA64(new_value64);
2177 old_value64 = T1394_DATA64(old_value64);
2178 break;
2180 case CMD1394_LOCK_THRESH_ADD:
2181 old_value64 = T1394_DATA64(old_value64);
2182 temp_value64 = (old_value64 + data_value64);
2183 if ((temp_value64 >= old_value64) &&
2184 (temp_value64 <= arg_value64)) {
2185 new_value64 = T1394_DATA64(temp_value64);
2186 old_value64 = T1394_DATA64(old_value64);
2187 } else {
2188 /* Failed threshold add */
2189 target_cmd->cmd_u.l64.old_value =
2190 T1394_DATA64(cmd->cmd_u.l64.old_value);
2191 target_cmd->cmd_result = CMD1394_CMDSUCCESS;
2192 TNF_PROBE_0_DEBUG(
2193 s1394_process_split_lock_exit,
2194 S1394_TNF_SL_ATREQ_STACK, "");
2195 return (DDI_FAILURE);
2197 break;
2199 case CMD1394_LOCK_THRESH_SUBTRACT:
2200 old_value64 = T1394_DATA64(old_value64);
2201 temp_value64 = (old_value64 - data_value64);
2202 if ((old_value64 >= data_value64) &&
2203 (temp_value64 >= arg_value64)) {
2204 new_value64 = T1394_DATA64(temp_value64);
2205 old_value64 = T1394_DATA64(old_value64);
2206 } else {
2207 /* Failed threshold subtract */
2208 target_cmd->cmd_u.l64.old_value =
2209 T1394_DATA64(cmd->cmd_u.l64.old_value);
2210 target_cmd->cmd_result = CMD1394_CMDSUCCESS;
2211 TNF_PROBE_0_DEBUG(
2212 s1394_process_split_lock_exit,
2213 S1394_TNF_SL_ATREQ_STACK, "");
2214 return (DDI_FAILURE);
2216 break;
2218 case CMD1394_LOCK_CLIP_ADD:
2219 old_value64 = T1394_DATA64(old_value64);
2220 temp_value64 = (old_value64 + data_value64);
2221 if ((temp_value64 < old_value64) ||
2222 (temp_value64 > arg_value64))
2223 new_value64 = T1394_DATA64(arg_value64);
2224 else
2225 new_value64 = T1394_DATA64(temp_value64);
2226 old_value64 = T1394_DATA64(old_value64);
2227 break;
2229 case CMD1394_LOCK_CLIP_SUBTRACT:
2230 old_value64 = T1394_DATA64(old_value64);
2231 temp_value64 = (old_value64 - data_value64);
2232 if ((data_value64 > old_value64) ||
2233 (temp_value64 < arg_value64))
2234 new_value64 = T1394_DATA64(arg_value64);
2235 else
2236 new_value64 = T1394_DATA64(temp_value64);
2237 old_value64 = T1394_DATA64(old_value64);
2238 break;
2241 /* Send compare-swap lock request */
2242 cmd->cmd_u.l64.arg_value = old_value64;
2243 cmd->cmd_u.l64.data_value = new_value64;
2246 TNF_PROBE_0_DEBUG(s1394_process_split_lock_exit,
2247 S1394_TNF_SL_ATREQ_STACK, "");
2248 return (DDI_SUCCESS);
2252 * s1394_finish_split_lock()
2253 * is another "helper" function for the s1394_handle_lock() callback.
2254 * Its job is to finish up whatever lock request procesing is necessary.
2256 static int
2257 s1394_finish_split_lock(cmd1394_cmd_t *cmd, cmd1394_cmd_t *target_cmd)
2259 s1394_cmd_priv_t *s_priv;
2260 uint64_t tmp_value64;
2261 uint32_t tmp_value32;
2263 TNF_PROBE_0_DEBUG(s1394_finish_split_lock_enter,
2264 S1394_TNF_SL_ATREQ_STACK, "");
2266 /* Get the Services Layer private area */
2267 s_priv = S1394_GET_CMD_PRIV(cmd);
2269 if (((cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) &&
2270 (cmd->cmd_u.l32.old_value == cmd->cmd_u.l32.arg_value)) ||
2271 ((cmd->cmd_type == CMD1394_ASYNCH_LOCK_64) &&
2272 (cmd->cmd_u.l64.old_value == cmd->cmd_u.l64.arg_value))) {
2274 if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
2275 switch (cmd->cmd_u.l32.lock_type) {
2276 case CMD1394_LOCK_INCREMENT:
2277 case CMD1394_LOCK_DECREMENT:
2278 case CMD1394_LOCK_ADD:
2279 case CMD1394_LOCK_SUBTRACT:
2280 case CMD1394_LOCK_THRESH_ADD:
2281 case CMD1394_LOCK_THRESH_SUBTRACT:
2282 case CMD1394_LOCK_CLIP_ADD:
2283 case CMD1394_LOCK_CLIP_SUBTRACT:
2284 tmp_value32 = cmd->cmd_u.l32.old_value;
2285 tmp_value32 = T1394_DATA32(tmp_value32);
2286 target_cmd->cmd_u.l32.old_value = tmp_value32;
2287 break;
2288 default:
2289 tmp_value32 = cmd->cmd_u.l32.old_value;
2290 target_cmd->cmd_u.l32.old_value = tmp_value32;
2291 break;
2293 } else {
2294 switch (cmd->cmd_u.l64.lock_type) {
2295 case CMD1394_LOCK_INCREMENT:
2296 case CMD1394_LOCK_DECREMENT:
2297 case CMD1394_LOCK_ADD:
2298 case CMD1394_LOCK_SUBTRACT:
2299 case CMD1394_LOCK_THRESH_ADD:
2300 case CMD1394_LOCK_THRESH_SUBTRACT:
2301 case CMD1394_LOCK_CLIP_ADD:
2302 case CMD1394_LOCK_CLIP_SUBTRACT:
2303 tmp_value64 = cmd->cmd_u.l64.old_value;
2304 tmp_value64 = T1394_DATA64(tmp_value64);
2305 target_cmd->cmd_u.l64.old_value = tmp_value64;
2306 break;
2307 default:
2308 tmp_value64 = cmd->cmd_u.l64.old_value;
2309 target_cmd->cmd_u.l64.old_value = tmp_value64;
2310 break;
2313 /* Set status */
2314 target_cmd->cmd_result = CMD1394_CMDSUCCESS;
2315 TNF_PROBE_0_DEBUG(s1394_finish_split_lock_exit,
2316 S1394_TNF_SL_ATREQ_STACK, "");
2317 return (DDI_SUCCESS);
2318 } else {
2319 if (s_priv->temp_num_retries > 0) {
2320 /* Decrement retry count */
2321 s_priv->temp_num_retries--;
2323 /* Reset lock_req_step */
2324 s_priv->lock_req_step = 0;
2326 TNF_PROBE_0_DEBUG(s1394_finish_split_lock_start_over,
2327 S1394_TNF_SL_ATREQ_STACK, "");
2328 /* Resend... start at step 0 again */
2329 TNF_PROBE_0_DEBUG(s1394_finish_split_lock_exit,
2330 S1394_TNF_SL_ATREQ_STACK, "");
2331 return (DDI_FAILURE);
2332 } else {
2333 /* Failed... RETRIES_EXCEEDED */
2334 target_cmd->cmd_result = CMD1394_ERETRIES_EXCEEDED;
2335 TNF_PROBE_0_DEBUG(s1394_finish_split_lock_exit,
2336 S1394_TNF_SL_ATREQ_STACK, "");
2337 return (DDI_SUCCESS);