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