ioat_chan.c revision 7656:2621e50fdf4a
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/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <sys/errno.h>
28#include <sys/types.h>
29#include <sys/conf.h>
30#include <sys/kmem.h>
31#include <sys/ddi.h>
32#include <sys/stat.h>
33#include <sys/sunddi.h>
34#include <sys/file.h>
35#include <sys/open.h>
36#include <sys/modctl.h>
37#include <sys/ddi_impldefs.h>
38#include <sys/sysmacros.h>
39#include <vm/hat.h>
40#include <vm/as.h>
41#include <sys/mach_mmu.h>
42#ifdef __xpv
43#include <sys/hypervisor.h>
44#endif
45
46#include <sys/ioat.h>
47
48
49extern ddi_device_acc_attr_t ioat_acc_attr;
50
51/* dma attr for the descriptor rings */
52ddi_dma_attr_t ioat_desc_dma_attr = {
53	DMA_ATTR_V0,		/* dma_attr_version */
54	0x0,			/* dma_attr_addr_lo */
55	0xffffffffffffffff,	/* dma_attr_addr_hi */
56	0xffffffff,		/* dma_attr_count_max */
57	0x1000,			/* dma_attr_align */
58	0x1,			/* dma_attr_burstsizes */
59	0x1,			/* dma_attr_minxfer */
60	0xffffffff,		/* dma_attr_maxxfer */
61	0xffffffff,		/* dma_attr_seg */
62	0x1,			/* dma_attr_sgllen */
63	0x1,			/* dma_attr_granular */
64	0x0,			/* dma_attr_flags */
65};
66
67/* dma attr for the completion buffers */
68ddi_dma_attr_t ioat_cmpl_dma_attr = {
69	DMA_ATTR_V0,		/* dma_attr_version */
70	0x0,			/* dma_attr_addr_lo */
71	0xffffffffffffffff,	/* dma_attr_addr_hi */
72	0xffffffff,		/* dma_attr_count_max */
73	0x40,			/* dma_attr_align */
74	0x1,			/* dma_attr_burstsizes */
75	0x1,			/* dma_attr_minxfer */
76	0xffffffff,		/* dma_attr_maxxfer */
77	0xffffffff,		/* dma_attr_seg */
78	0x1,			/* dma_attr_sgllen */
79	0x1,			/* dma_attr_granular */
80	0x0,			/* dma_attr_flags */
81};
82
83static int ioat_completion_alloc(ioat_channel_t channel);
84static void ioat_completion_free(ioat_channel_t channel);
85static void ioat_channel_start(ioat_channel_t channel);
86static void ioat_channel_reset(ioat_channel_t channel);
87
88int ioat_ring_alloc(ioat_channel_t channel, uint_t desc_cnt);
89void ioat_ring_free(ioat_channel_t channel);
90void ioat_ring_seed(ioat_channel_t channel, ioat_chan_dma_desc_t *desc);
91int ioat_ring_reserve(ioat_channel_t channel, ioat_channel_ring_t *ring,
92    dcopy_cmd_t cmd);
93
94static void ioat_cmd_post_copy(ioat_channel_ring_t *ring, uint64_t src_addr,
95    uint64_t dest_addr, uint32_t size, uint32_t ctrl);
96static void ioat_cmd_post_dca(ioat_channel_ring_t *ring, uint32_t dca_id);
97
98
99/*
100 * ioat_channel_init()
101 */
102int
103ioat_channel_init(ioat_state_t *state)
104{
105	int i;
106
107	/*
108	 * initialize each dma channel's state which doesn't change across
109	 * channel alloc/free.
110	 */
111	state->is_chansize = sizeof (struct ioat_channel_s) *
112	    state->is_num_channels;
113	state->is_channel = kmem_zalloc(state->is_chansize, KM_SLEEP);
114	for (i = 0; i < state->is_num_channels; i++) {
115		state->is_channel[i].ic_state = state;
116		state->is_channel[i].ic_regs = (uint8_t *)
117		    ((uintptr_t)state->is_genregs +
118		    (uintptr_t)(IOAT_CHANNELREG_OFFSET * (i + 1)));
119	}
120
121	/* initial the allocator (from 0 to state->is_num_channels) */
122	ioat_rs_init(state, 0, state->is_num_channels, &state->is_channel_rs);
123
124	return (DDI_SUCCESS);
125}
126
127
128/*
129 * ioat_channel_fini()
130 */
131void
132ioat_channel_fini(ioat_state_t *state)
133{
134	ioat_rs_fini(&state->is_channel_rs);
135	kmem_free(state->is_channel, state->is_chansize);
136}
137
138
139/*
140 * ioat_channel_alloc()
141 *   NOTE: We intentionaly don't handle DCOPY_SLEEP (if no channels are
142 *	available)
143 */
144/*ARGSUSED*/
145int
146ioat_channel_alloc(void *device_private, dcopy_handle_t handle, int flags,
147    uint_t size, dcopy_query_channel_t *info, void *channel_private)
148{
149#define	CHANSTRSIZE	20
150	struct ioat_channel_s *channel;
151	char chanstr[CHANSTRSIZE];
152	ioat_channel_t *chan;
153	ioat_state_t *state;
154	size_t cmd_size;
155	uint_t chan_num;
156	uint32_t estat;
157	int e;
158
159
160	state = (ioat_state_t *)device_private;
161	chan = (ioat_channel_t *)channel_private;
162
163	/* allocate a H/W channel */
164	e = ioat_rs_alloc(state->is_channel_rs, &chan_num);
165	if (e != DDI_SUCCESS) {
166		return (DCOPY_NORESOURCES);
167	}
168
169	channel = &state->is_channel[chan_num];
170	channel->ic_inuse = B_TRUE;
171	channel->ic_chan_num = chan_num;
172	channel->ic_ver = state->is_ver;
173	channel->ic_dca_active = B_FALSE;
174	channel->ic_channel_state = IOAT_CHANNEL_OK;
175	channel->ic_dcopy_handle = handle;
176
177#ifdef	DEBUG
178	{
179		/* if we're cbv2, verify that the V2 compatibility bit is set */
180		uint16_t reg;
181		if (channel->ic_ver == IOAT_CBv2) {
182			reg = ddi_get16(state->is_reg_handle,
183			    (uint16_t *)&channel->ic_regs[IOAT_CHAN_COMP]);
184			ASSERT(reg & 0x2);
185		}
186	}
187#endif
188
189	/*
190	 * Configure DMA channel
191	 *   Channel In Use
192	 *   Error Interrupt Enable
193	 *   Any Error Abort Enable
194	 *   Error Completion Enable
195	 */
196	ddi_put16(state->is_reg_handle,
197	    (uint16_t *)&channel->ic_regs[IOAT_CHAN_CTL], 0x011C);
198
199	/* check channel error register, clear any errors */
200	estat = ddi_get32(state->is_reg_handle,
201	    (uint32_t *)&channel->ic_regs[IOAT_CHAN_ERR]);
202	if (estat != 0) {
203#ifdef	DEBUG
204		cmn_err(CE_CONT, "cleared errors (0x%x) before channel (%d) "
205		    "enable\n", estat, channel->ic_chan_num);
206#endif
207		ddi_put32(state->is_reg_handle,
208		    (uint32_t *)&channel->ic_regs[IOAT_CHAN_ERR], estat);
209	}
210
211	/* allocate and initialize the descriptor buf */
212	e = ioat_ring_alloc(channel, size);
213	if (e != DDI_SUCCESS) {
214		goto chinitfail_desc_alloc;
215	}
216
217	/* allocate and initialize the completion space */
218	e = ioat_completion_alloc(channel);
219	if (e != DDI_SUCCESS) {
220		goto chinitfail_completion_alloc;
221	}
222
223	/* setup kmem_cache for commands */
224	cmd_size = sizeof (struct dcopy_cmd_s) +
225	    sizeof (struct dcopy_cmd_priv_s) +
226	    sizeof (struct ioat_cmd_private_s);
227	(void) snprintf(chanstr, CHANSTRSIZE, "ioat%dchan%dcmd",
228	    state->is_instance, channel->ic_chan_num);
229	channel->ic_cmd_cache = kmem_cache_create(chanstr, cmd_size, 64,
230	    NULL, NULL, NULL, NULL, NULL, 0);
231	if (channel->ic_cmd_cache == NULL) {
232		goto chinitfail_kmem_cache;
233	}
234
235	/* start-up the channel */
236	ioat_channel_start(channel);
237
238	/* fill in the channel info returned to dcopy */
239	info->qc_version = DCOPY_QUERY_CHANNEL_V0;
240	info->qc_id = state->is_deviceinfo.di_id;
241	info->qc_capabilities = (uint64_t)state->is_capabilities;
242	info->qc_channel_size = (uint64_t)size;
243	info->qc_chan_num = (uint64_t)channel->ic_chan_num;
244	if (channel->ic_ver == IOAT_CBv1) {
245		info->qc_dca_supported = B_FALSE;
246	} else {
247		if (info->qc_capabilities & IOAT_DMACAP_DCA) {
248			info->qc_dca_supported = B_TRUE;
249		} else {
250			info->qc_dca_supported = B_FALSE;
251		}
252	}
253
254	*chan = channel;
255
256	return (DCOPY_SUCCESS);
257
258chinitfail_kmem_cache:
259	ioat_completion_free(channel);
260chinitfail_completion_alloc:
261	ioat_ring_free(channel);
262chinitfail_desc_alloc:
263	return (DCOPY_FAILURE);
264}
265
266
267/*
268 * ioat_channel_suspend()
269 */
270/*ARGSUSED*/
271void
272ioat_channel_suspend(ioat_state_t *state)
273{
274	/*
275	 * normally you would disable interrupts and reset the H/W here. But
276	 * since the suspend framework doesn't know who is using us, it may
277	 * not suspend their I/O before us.  Since we won't actively be doing
278	 * any DMA or interrupts unless someone asks us to, it's safe to not
279	 * do anything here.
280	 */
281}
282
283
284/*
285 * ioat_channel_resume()
286 */
287int
288ioat_channel_resume(ioat_state_t *state)
289{
290	ioat_channel_ring_t *ring;
291	ioat_channel_t channel;
292	uint32_t estat;
293	int i;
294
295
296	for (i = 0; i < state->is_num_channels; i++) {
297		channel = &state->is_channel[i];
298		ring = channel->ic_ring;
299
300		if (!channel->ic_inuse) {
301			continue;
302		}
303
304		/*
305		 * Configure DMA channel
306		 *   Channel In Use
307		 *   Error Interrupt Enable
308		 *   Any Error Abort Enable
309		 *   Error Completion Enable
310		 */
311		ddi_put16(state->is_reg_handle,
312		    (uint16_t *)&channel->ic_regs[IOAT_CHAN_CTL], 0x011C);
313
314		/* check channel error register, clear any errors */
315		estat = ddi_get32(state->is_reg_handle,
316		    (uint32_t *)&channel->ic_regs[IOAT_CHAN_ERR]);
317		if (estat != 0) {
318#ifdef	DEBUG
319			cmn_err(CE_CONT, "cleared errors (0x%x) before channel"
320			    " (%d) enable\n", estat, channel->ic_chan_num);
321#endif
322			ddi_put32(state->is_reg_handle,
323			    (uint32_t *)&channel->ic_regs[IOAT_CHAN_ERR],
324			    estat);
325		}
326
327		/* Re-initialize the ring */
328		bzero(ring->cr_desc, channel->ic_desc_alloc_size);
329		/* write the physical address into the chain address register */
330		if (channel->ic_ver == IOAT_CBv1) {
331			ddi_put32(state->is_reg_handle,
332			    (uint32_t *)&channel->ic_regs[IOAT_V1_CHAN_ADDR_LO],
333			    (uint32_t)(ring->cr_phys_desc & 0xffffffff));
334			ddi_put32(state->is_reg_handle,
335			    (uint32_t *)&channel->ic_regs[IOAT_V1_CHAN_ADDR_HI],
336			    (uint32_t)(ring->cr_phys_desc >> 32));
337		} else {
338			ASSERT(channel->ic_ver == IOAT_CBv2);
339			ddi_put32(state->is_reg_handle,
340			    (uint32_t *)&channel->ic_regs[IOAT_V2_CHAN_ADDR_LO],
341			    (uint32_t)(ring->cr_phys_desc & 0xffffffff));
342			ddi_put32(state->is_reg_handle,
343			    (uint32_t *)&channel->ic_regs[IOAT_V2_CHAN_ADDR_HI],
344			    (uint32_t)(ring->cr_phys_desc >> 32));
345		}
346
347		/* re-initialize the completion buffer */
348		bzero((void *)channel->ic_cmpl, channel->ic_cmpl_alloc_size);
349		/* write the phys addr into the completion address register */
350		ddi_put32(state->is_reg_handle,
351		    (uint32_t *)&channel->ic_regs[IOAT_CHAN_CMPL_LO],
352		    (uint32_t)(channel->ic_phys_cmpl & 0xffffffff));
353		ddi_put32(state->is_reg_handle,
354		    (uint32_t *)&channel->ic_regs[IOAT_CHAN_CMPL_HI],
355		    (uint32_t)(channel->ic_phys_cmpl >> 32));
356
357		/* start-up the channel */
358		ioat_channel_start(channel);
359
360	}
361
362	return (DDI_SUCCESS);
363}
364
365/*
366 * quiesce(9E) entry point.
367 *
368 * This function is called when the system is single-threaded at high
369 * PIL with preemption disabled. Therefore, this function must not be
370 * blocked.
371 *
372 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
373 * DDI_FAILURE indicates an error condition and should almost never happen.
374 */
375void
376ioat_channel_quiesce(ioat_state_t *state)
377{
378	int i;
379
380	/*
381	 * Walk through all channels and quiesce
382	 */
383	for (i = 0; i < state->is_num_channels; i++) {
384
385		ioat_channel_t	channel = state->is_channel + i;
386
387		if (!channel->ic_inuse)
388			continue;
389
390		/* disable the interrupts */
391		ddi_put16(state->is_reg_handle,
392		    (uint16_t *)&channel->ic_regs[IOAT_CHAN_CTL],
393		    0x0);
394
395		ioat_channel_reset(channel);
396	}
397}
398
399
400/*
401 * ioat_channel_free()
402 */
403void
404ioat_channel_free(void *channel_private)
405{
406	struct ioat_channel_s *channel;
407	ioat_channel_t *chan;
408	ioat_state_t *state;
409	uint_t chan_num;
410
411
412	chan = (ioat_channel_t *)channel_private;
413	channel = *chan;
414
415	state = channel->ic_state;
416	chan_num = channel->ic_chan_num;
417
418	/* disable the interrupts */
419	ddi_put16(state->is_reg_handle,
420	    (uint16_t *)&channel->ic_regs[IOAT_CHAN_CTL], 0x0);
421
422	ioat_channel_reset(channel);
423
424	/* cleanup command cache */
425	kmem_cache_destroy(channel->ic_cmd_cache);
426
427	/* clean-up/free-up the completion space and descriptors */
428	ioat_completion_free(channel);
429	ioat_ring_free(channel);
430
431	channel->ic_inuse = B_FALSE;
432
433	/* free the H/W DMA engine */
434	ioat_rs_free(state->is_channel_rs, chan_num);
435
436	*chan = NULL;
437}
438
439
440/*
441 * ioat_channel_intr()
442 */
443void
444ioat_channel_intr(ioat_channel_t channel)
445{
446	ioat_state_t *state;
447	uint16_t chanctrl;
448	uint32_t chanerr;
449	uint32_t status;
450
451
452	state = channel->ic_state;
453
454	if (channel->ic_ver == IOAT_CBv1) {
455		status = ddi_get32(state->is_reg_handle,
456		    (uint32_t *)&channel->ic_regs[IOAT_V1_CHAN_STS_LO]);
457	} else {
458		ASSERT(channel->ic_ver == IOAT_CBv2);
459		status = ddi_get32(state->is_reg_handle,
460		    (uint32_t *)&channel->ic_regs[IOAT_V2_CHAN_STS_LO]);
461	}
462
463	/* if that status isn't ACTIVE or IDLE, the channel has failed */
464	if (status & IOAT_CHAN_STS_FAIL_MASK) {
465		chanerr = ddi_get32(state->is_reg_handle,
466		    (uint32_t *)&channel->ic_regs[IOAT_CHAN_ERR]);
467		cmn_err(CE_WARN, "channel(%d) fatal failure! "
468		    "chanstat_lo=0x%X; chanerr=0x%X\n",
469		    channel->ic_chan_num, status, chanerr);
470		channel->ic_channel_state = IOAT_CHANNEL_IN_FAILURE;
471		ioat_channel_reset(channel);
472
473		return;
474	}
475
476	/*
477	 * clear interrupt disable bit if set (it's a RW1C). Read it back to
478	 * ensure the write completes.
479	 */
480	chanctrl = ddi_get16(state->is_reg_handle,
481	    (uint16_t *)&channel->ic_regs[IOAT_CHAN_CTL]);
482	ddi_put16(state->is_reg_handle,
483	    (uint16_t *)&channel->ic_regs[IOAT_CHAN_CTL], chanctrl);
484	(void) ddi_get16(state->is_reg_handle,
485	    (uint16_t *)&channel->ic_regs[IOAT_CHAN_CTL]);
486
487	/* tell dcopy we have seen a completion on this channel */
488	dcopy_device_channel_notify(channel->ic_dcopy_handle, DCOPY_COMPLETION);
489}
490
491
492/*
493 * ioat_channel_start()
494 */
495void
496ioat_channel_start(ioat_channel_t channel)
497{
498	ioat_chan_dma_desc_t desc;
499
500	/* set the first descriptor up as a NULL descriptor */
501	bzero(&desc, sizeof (desc));
502	desc.dd_size = 0;
503	desc.dd_ctrl = IOAT_DESC_CTRL_OP_DMA | IOAT_DESC_DMACTRL_NULL |
504	    IOAT_DESC_CTRL_CMPL;
505	desc.dd_next_desc = 0x0;
506
507	/* setup the very first descriptor */
508	ioat_ring_seed(channel, &desc);
509}
510
511
512/*
513 * ioat_channel_reset()
514 */
515void
516ioat_channel_reset(ioat_channel_t channel)
517{
518	ioat_state_t *state;
519
520	state = channel->ic_state;
521
522	/* hit the reset bit */
523	if (channel->ic_ver == IOAT_CBv1) {
524		ddi_put8(state->is_reg_handle,
525		    &channel->ic_regs[IOAT_V1_CHAN_CMD], 0x20);
526	} else {
527		ASSERT(channel->ic_ver == IOAT_CBv2);
528		ddi_put8(state->is_reg_handle,
529		    &channel->ic_regs[IOAT_V2_CHAN_CMD], 0x20);
530	}
531}
532
533
534/*
535 * ioat_completion_alloc()
536 */
537int
538ioat_completion_alloc(ioat_channel_t channel)
539{
540	ioat_state_t *state;
541	size_t real_length;
542	uint_t cookie_cnt;
543	int e;
544
545
546	state = channel->ic_state;
547
548	/*
549	 * allocate memory for the completion status, zero it out, and get
550	 * the paddr. We'll allocate a physically contiguous cache line.
551	 */
552	e = ddi_dma_alloc_handle(state->is_dip, &ioat_cmpl_dma_attr,
553	    DDI_DMA_SLEEP, NULL, &channel->ic_cmpl_dma_handle);
554	if (e != DDI_SUCCESS) {
555		goto cmplallocfail_alloc_handle;
556	}
557	channel->ic_cmpl_alloc_size = 64;
558	e = ddi_dma_mem_alloc(channel->ic_cmpl_dma_handle,
559	    channel->ic_cmpl_alloc_size, &ioat_acc_attr,
560	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
561	    (caddr_t *)&channel->ic_cmpl, &real_length,
562	    &channel->ic_cmpl_handle);
563	if (e != DDI_SUCCESS) {
564		goto cmplallocfail_mem_alloc;
565	}
566	bzero((void *)channel->ic_cmpl, channel->ic_cmpl_alloc_size);
567	e = ddi_dma_addr_bind_handle(channel->ic_cmpl_dma_handle, NULL,
568	    (caddr_t)channel->ic_cmpl, channel->ic_cmpl_alloc_size,
569	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
570	    &channel->ic_cmpl_cookie, &cookie_cnt);
571	if (e != DDI_SUCCESS) {
572		goto cmplallocfail_addr_bind;
573	}
574	ASSERT(cookie_cnt == 1);
575	ASSERT(channel->ic_cmpl_cookie.dmac_size ==
576	    channel->ic_cmpl_alloc_size);
577	channel->ic_phys_cmpl = channel->ic_cmpl_cookie.dmac_laddress;
578
579	/* write the physical address into the completion address register */
580	ddi_put32(state->is_reg_handle,
581	    (uint32_t *)&channel->ic_regs[IOAT_CHAN_CMPL_LO],
582	    (uint32_t)(channel->ic_phys_cmpl & 0xffffffff));
583	ddi_put32(state->is_reg_handle,
584	    (uint32_t *)&channel->ic_regs[IOAT_CHAN_CMPL_HI],
585	    (uint32_t)(channel->ic_phys_cmpl >> 32));
586
587	return (DDI_SUCCESS);
588
589cmplallocfail_addr_bind:
590	ddi_dma_mem_free(&channel->ic_desc_handle);
591cmplallocfail_mem_alloc:
592	ddi_dma_free_handle(&channel->ic_desc_dma_handle);
593cmplallocfail_alloc_handle:
594	return (DDI_FAILURE);
595}
596
597
598/*
599 * ioat_completion_free()
600 */
601void
602ioat_completion_free(ioat_channel_t channel)
603{
604	ioat_state_t *state;
605
606	state = channel->ic_state;
607
608	/* reset the completion address register */
609	ddi_put32(state->is_reg_handle,
610	    (uint32_t *)&channel->ic_regs[IOAT_CHAN_CMPL_LO], 0x0);
611	ddi_put32(state->is_reg_handle,
612	    (uint32_t *)&channel->ic_regs[IOAT_CHAN_CMPL_HI], 0x0);
613
614	/* unbind, then free up the memory, dma handle */
615	(void) ddi_dma_unbind_handle(channel->ic_cmpl_dma_handle);
616	ddi_dma_mem_free(&channel->ic_cmpl_handle);
617	ddi_dma_free_handle(&channel->ic_cmpl_dma_handle);
618}
619
620/*
621 * ioat_ring_alloc()
622 */
623int
624ioat_ring_alloc(ioat_channel_t channel, uint_t desc_cnt)
625{
626	ioat_channel_ring_t *ring;
627	ioat_state_t *state;
628	size_t real_length;
629	uint_t cookie_cnt;
630	int e;
631
632
633	state = channel->ic_state;
634
635	ring = kmem_zalloc(sizeof (ioat_channel_ring_t), KM_SLEEP);
636	channel->ic_ring = ring;
637	ring->cr_chan = channel;
638	ring->cr_post_cnt = 0;
639
640	mutex_init(&ring->cr_cmpl_mutex, NULL, MUTEX_DRIVER,
641	    channel->ic_state->is_iblock_cookie);
642	mutex_init(&ring->cr_desc_mutex, NULL, MUTEX_DRIVER,
643	    channel->ic_state->is_iblock_cookie);
644
645	/*
646	 * allocate memory for the ring, zero it out, and get the paddr.
647	 * We'll allocate a physically contiguous chunck of memory  which
648	 * simplifies the completion logic.
649	 */
650	e = ddi_dma_alloc_handle(state->is_dip, &ioat_desc_dma_attr,
651	    DDI_DMA_SLEEP, NULL, &channel->ic_desc_dma_handle);
652	if (e != DDI_SUCCESS) {
653		goto ringallocfail_alloc_handle;
654	}
655	/*
656	 * allocate one extra descriptor so we can simplify the empty/full
657	 * logic. Then round that number up to a whole multiple of 4.
658	 */
659	channel->ic_chan_desc_cnt = ((desc_cnt + 1) + 3) & ~0x3;
660	ring->cr_desc_last = channel->ic_chan_desc_cnt - 1;
661	channel->ic_desc_alloc_size = channel->ic_chan_desc_cnt *
662	    sizeof (ioat_chan_desc_t);
663	e = ddi_dma_mem_alloc(channel->ic_desc_dma_handle,
664	    channel->ic_desc_alloc_size, &ioat_acc_attr,
665	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
666	    (caddr_t *)&ring->cr_desc, &real_length, &channel->ic_desc_handle);
667	if (e != DDI_SUCCESS) {
668		goto ringallocfail_mem_alloc;
669	}
670	bzero(ring->cr_desc, channel->ic_desc_alloc_size);
671	e = ddi_dma_addr_bind_handle(channel->ic_desc_dma_handle, NULL,
672	    (caddr_t)ring->cr_desc, channel->ic_desc_alloc_size,
673	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
674	    &channel->ic_desc_cookies, &cookie_cnt);
675	if (e != DDI_SUCCESS) {
676		goto ringallocfail_addr_bind;
677	}
678	ASSERT(cookie_cnt == 1);
679	ASSERT(channel->ic_desc_cookies.dmac_size ==
680	    channel->ic_desc_alloc_size);
681	ring->cr_phys_desc = channel->ic_desc_cookies.dmac_laddress;
682
683	/* write the physical address into the chain address register */
684	if (channel->ic_ver == IOAT_CBv1) {
685		ddi_put32(state->is_reg_handle,
686		    (uint32_t *)&channel->ic_regs[IOAT_V1_CHAN_ADDR_LO],
687		    (uint32_t)(ring->cr_phys_desc & 0xffffffff));
688		ddi_put32(state->is_reg_handle,
689		    (uint32_t *)&channel->ic_regs[IOAT_V1_CHAN_ADDR_HI],
690		    (uint32_t)(ring->cr_phys_desc >> 32));
691	} else {
692		ASSERT(channel->ic_ver == IOAT_CBv2);
693		ddi_put32(state->is_reg_handle,
694		    (uint32_t *)&channel->ic_regs[IOAT_V2_CHAN_ADDR_LO],
695		    (uint32_t)(ring->cr_phys_desc & 0xffffffff));
696		ddi_put32(state->is_reg_handle,
697		    (uint32_t *)&channel->ic_regs[IOAT_V2_CHAN_ADDR_HI],
698		    (uint32_t)(ring->cr_phys_desc >> 32));
699	}
700
701	return (DCOPY_SUCCESS);
702
703ringallocfail_addr_bind:
704	ddi_dma_mem_free(&channel->ic_desc_handle);
705ringallocfail_mem_alloc:
706	ddi_dma_free_handle(&channel->ic_desc_dma_handle);
707ringallocfail_alloc_handle:
708	mutex_destroy(&ring->cr_desc_mutex);
709	mutex_destroy(&ring->cr_cmpl_mutex);
710	kmem_free(channel->ic_ring, sizeof (ioat_channel_ring_t));
711
712	return (DCOPY_FAILURE);
713}
714
715
716/*
717 * ioat_ring_free()
718 */
719void
720ioat_ring_free(ioat_channel_t channel)
721{
722	ioat_state_t *state;
723
724
725	state = channel->ic_state;
726
727	/* reset the chain address register */
728	if (channel->ic_ver == IOAT_CBv1) {
729		ddi_put32(state->is_reg_handle,
730		    (uint32_t *)&channel->ic_regs[IOAT_V1_CHAN_ADDR_LO], 0x0);
731		ddi_put32(state->is_reg_handle,
732		    (uint32_t *)&channel->ic_regs[IOAT_V1_CHAN_ADDR_HI], 0x0);
733	} else {
734		ASSERT(channel->ic_ver == IOAT_CBv2);
735		ddi_put32(state->is_reg_handle,
736		    (uint32_t *)&channel->ic_regs[IOAT_V2_CHAN_ADDR_LO], 0x0);
737		ddi_put32(state->is_reg_handle,
738		    (uint32_t *)&channel->ic_regs[IOAT_V2_CHAN_ADDR_HI], 0x0);
739	}
740
741	/* unbind, then free up the memory, dma handle */
742	(void) ddi_dma_unbind_handle(channel->ic_desc_dma_handle);
743	ddi_dma_mem_free(&channel->ic_desc_handle);
744	ddi_dma_free_handle(&channel->ic_desc_dma_handle);
745
746	mutex_destroy(&channel->ic_ring->cr_desc_mutex);
747	mutex_destroy(&channel->ic_ring->cr_cmpl_mutex);
748	kmem_free(channel->ic_ring, sizeof (ioat_channel_ring_t));
749
750}
751
752
753/*
754 * ioat_ring_seed()
755 *    write the first descriptor in the ring.
756 */
757void
758ioat_ring_seed(ioat_channel_t channel, ioat_chan_dma_desc_t *in_desc)
759{
760	ioat_channel_ring_t *ring;
761	ioat_chan_dma_desc_t *desc;
762	ioat_chan_dma_desc_t *prev;
763	ioat_state_t *state;
764
765
766	state = channel->ic_state;
767	ring = channel->ic_ring;
768
769	/* init the completion state */
770	ring->cr_cmpl_gen = 0x0;
771	ring->cr_cmpl_last = 0x0;
772
773	/* write in the descriptor and init the descriptor state */
774	ring->cr_post_cnt++;
775	channel->ic_ring->cr_desc[0] = *(ioat_chan_desc_t *)in_desc;
776	ring->cr_desc_gen = 0;
777	ring->cr_desc_prev = 0;
778	ring->cr_desc_next = 1;
779
780	if (channel->ic_ver == IOAT_CBv1) {
781		/* hit the start bit */
782		ddi_put8(state->is_reg_handle,
783		    &channel->ic_regs[IOAT_V1_CHAN_CMD], 0x1);
784	} else {
785		/*
786		 * if this is CBv2, link the descriptor to an empty
787		 * descriptor
788		 */
789		ASSERT(ring->cr_chan->ic_ver == IOAT_CBv2);
790		desc = (ioat_chan_dma_desc_t *)
791		    &ring->cr_desc[ring->cr_desc_next];
792		prev = (ioat_chan_dma_desc_t *)
793		    &ring->cr_desc[ring->cr_desc_prev];
794
795		desc->dd_ctrl = 0;
796		desc->dd_next_desc = 0x0;
797
798		prev->dd_next_desc = ring->cr_phys_desc +
799		    (ring->cr_desc_next << 6);
800
801		ddi_put16(state->is_reg_handle,
802		    (uint16_t *)&channel->ic_regs[IOAT_V2_CHAN_CNT],
803		    (uint16_t)1);
804	}
805
806}
807
808
809/*
810 * ioat_cmd_alloc()
811 */
812int
813ioat_cmd_alloc(void *private, int flags, dcopy_cmd_t *cmd)
814{
815	ioat_cmd_private_t *priv;
816	ioat_channel_t channel;
817	dcopy_cmd_t oldcmd;
818	int kmflag;
819
820
821	channel = (ioat_channel_t)private;
822
823	if (flags & DCOPY_NOSLEEP) {
824		kmflag = KM_NOSLEEP;
825	} else {
826		kmflag = KM_SLEEP;
827	}
828
829	/* save the command passed incase DCOPY_ALLOC_LINK is set */
830	oldcmd = *cmd;
831
832	*cmd = kmem_cache_alloc(channel->ic_cmd_cache, kmflag);
833	if (*cmd == NULL) {
834		return (DCOPY_NORESOURCES);
835	}
836
837	/* setup the dcopy and ioat private state pointers */
838	(*cmd)->dp_version = DCOPY_CMD_V0;
839	(*cmd)->dp_cmd = 0;
840	(*cmd)->dp_private = (struct dcopy_cmd_priv_s *)
841	    ((uintptr_t)(*cmd) + sizeof (struct dcopy_cmd_s));
842	(*cmd)->dp_private->pr_device_cmd_private =
843	    (struct ioat_cmd_private_s *)((uintptr_t)(*cmd)->dp_private +
844	    sizeof (struct dcopy_cmd_priv_s));
845
846	/*
847	 * if DCOPY_ALLOC_LINK is set, link the old command to the new one
848	 * just allocated.
849	 */
850	priv = (*cmd)->dp_private->pr_device_cmd_private;
851	if (flags & DCOPY_ALLOC_LINK) {
852		priv->ip_next = oldcmd;
853	} else {
854		priv->ip_next = NULL;
855	}
856
857	return (DCOPY_SUCCESS);
858}
859
860
861/*
862 * ioat_cmd_free()
863 */
864void
865ioat_cmd_free(void *private, dcopy_cmd_t *cmdp)
866{
867	ioat_cmd_private_t *priv;
868	ioat_channel_t channel;
869	dcopy_cmd_t next;
870	dcopy_cmd_t cmd;
871
872
873	channel = (ioat_channel_t)private;
874	cmd = *(cmdp);
875
876	/*
877	 * free all the commands in the chain (see DCOPY_ALLOC_LINK in
878	 * ioat_cmd_alloc() for more info).
879	 */
880	while (cmd != NULL) {
881		priv = cmd->dp_private->pr_device_cmd_private;
882		next = priv->ip_next;
883		kmem_cache_free(channel->ic_cmd_cache, cmd);
884		cmd = next;
885	}
886	*cmdp = NULL;
887}
888
889
890/*
891 * ioat_cmd_post()
892 */
893int
894ioat_cmd_post(void *private, dcopy_cmd_t cmd)
895{
896	ioat_channel_ring_t *ring;
897	ioat_cmd_private_t *priv;
898	ioat_channel_t channel;
899	ioat_state_t *state;
900	uint64_t dest_paddr;
901	uint64_t src_paddr;
902	uint64_t dest_addr;
903	uint32_t dest_size;
904	uint64_t src_addr;
905	uint32_t src_size;
906	size_t xfer_size;
907	uint32_t ctrl;
908	size_t size;
909	int e;
910
911
912	channel = (ioat_channel_t)private;
913	priv = cmd->dp_private->pr_device_cmd_private;
914
915	state = channel->ic_state;
916	ring = channel->ic_ring;
917
918	mutex_enter(&ring->cr_desc_mutex);
919
920	/* if the channel has had a fatal failure, return failure */
921	if (channel->ic_channel_state == IOAT_CHANNEL_IN_FAILURE) {
922		mutex_exit(&ring->cr_cmpl_mutex);
923		return (DCOPY_FAILURE);
924	}
925
926	/* make sure we have space for the descriptors */
927	e = ioat_ring_reserve(channel, ring, cmd);
928	if (e != DCOPY_SUCCESS) {
929		mutex_exit(&ring->cr_cmpl_mutex);
930		return (DCOPY_NORESOURCES);
931	}
932
933	/* if we support DCA, and the DCA flag is set, post a DCA desc */
934	if ((channel->ic_ver == IOAT_CBv2) &&
935	    (cmd->dp_flags & DCOPY_CMD_DCA)) {
936		ioat_cmd_post_dca(ring, cmd->dp_dca_id);
937	}
938
939	/*
940	 * the dma copy may have to be broken up into multiple descriptors
941	 * since we can't cross a page boundary.
942	 */
943	ASSERT(cmd->dp_version == DCOPY_CMD_V0);
944	ASSERT(cmd->dp_cmd == DCOPY_CMD_COPY);
945	src_addr = cmd->dp.copy.cc_source;
946	dest_addr = cmd->dp.copy.cc_dest;
947	size = cmd->dp.copy.cc_size;
948	while (size > 0) {
949		src_paddr = pa_to_ma(src_addr);
950		dest_paddr = pa_to_ma(dest_addr);
951
952		/* adjust for any offset into the page */
953		if ((src_addr & PAGEOFFSET) == 0) {
954			src_size = PAGESIZE;
955		} else {
956			src_size = PAGESIZE - (src_addr & PAGEOFFSET);
957		}
958		if ((dest_addr & PAGEOFFSET) == 0) {
959			dest_size = PAGESIZE;
960		} else {
961			dest_size = PAGESIZE - (dest_addr & PAGEOFFSET);
962		}
963
964		/* take the smallest of the three */
965		xfer_size = MIN(src_size, dest_size);
966		xfer_size = MIN(xfer_size, size);
967
968		/*
969		 * if this is the last descriptor, and we are supposed to
970		 * generate a completion, generate a completion. same logic
971		 * for interrupt.
972		 */
973		ctrl = 0;
974		if (xfer_size == size) {
975			if (!(cmd->dp_flags & DCOPY_CMD_NOSTAT)) {
976				ctrl |= IOAT_DESC_CTRL_CMPL;
977			}
978			if ((cmd->dp_flags & DCOPY_CMD_INTR)) {
979				ctrl |= IOAT_DESC_CTRL_INTR;
980			}
981		}
982
983		ioat_cmd_post_copy(ring, src_paddr, dest_paddr, xfer_size,
984		    ctrl);
985
986		/* go to the next page */
987		src_addr += xfer_size;
988		dest_addr += xfer_size;
989		size -= xfer_size;
990	}
991
992	/*
993	 * if we are going to create a completion, save away the state so we
994	 * can poll on it.
995	 */
996	if (!(cmd->dp_flags & DCOPY_CMD_NOSTAT)) {
997		priv->ip_generation = ring->cr_desc_gen_prev;
998		priv->ip_index = ring->cr_desc_prev;
999	}
1000
1001	/* if queue not defined, tell the DMA engine about it */
1002	if (!(cmd->dp_flags & DCOPY_CMD_QUEUE)) {
1003		if (channel->ic_ver == IOAT_CBv1) {
1004			ddi_put8(state->is_reg_handle,
1005			    (uint8_t *)&channel->ic_regs[IOAT_V1_CHAN_CMD],
1006			    0x2);
1007		} else {
1008			ASSERT(channel->ic_ver == IOAT_CBv2);
1009			ddi_put16(state->is_reg_handle,
1010			    (uint16_t *)&channel->ic_regs[IOAT_V2_CHAN_CNT],
1011			    (uint16_t)(ring->cr_post_cnt & 0xFFFF));
1012		}
1013	}
1014
1015	mutex_exit(&ring->cr_desc_mutex);
1016
1017	return (DCOPY_SUCCESS);
1018}
1019
1020
1021/*
1022 * ioat_cmd_post_dca()
1023 */
1024static void
1025ioat_cmd_post_dca(ioat_channel_ring_t *ring, uint32_t dca_id)
1026{
1027	ioat_chan_dca_desc_t *desc;
1028	ioat_chan_dca_desc_t *prev;
1029	ioat_channel_t channel;
1030
1031
1032	channel = ring->cr_chan;
1033	desc = (ioat_chan_dca_desc_t *)&ring->cr_desc[ring->cr_desc_next];
1034	prev = (ioat_chan_dca_desc_t *)&ring->cr_desc[ring->cr_desc_prev];
1035
1036	/* keep track of the number of descs posted for cbv2 */
1037	ring->cr_post_cnt++;
1038
1039	/*
1040	 * post a context change desriptor. If dca has never been used on
1041	 * this channel, or if the id doesn't match the last id used on this
1042	 * channel, set CONTEXT_CHANGE bit and dca id, set dca state to active,
1043	 * and save away the id we're using.
1044	 */
1045	desc->dd_ctrl = IOAT_DESC_CTRL_OP_CNTX;
1046	desc->dd_next_desc = 0x0;
1047	if (!channel->ic_dca_active || (channel->ic_dca_current != dca_id)) {
1048		channel->ic_dca_active = B_TRUE;
1049		channel->ic_dca_current = dca_id;
1050		desc->dd_ctrl |= IOAT_DESC_CTRL_CNTX_CHNG;
1051		desc->dd_cntx = dca_id;
1052	}
1053
1054	/* Put the descriptors physical address in the previous descriptor */
1055	/*LINTED:E_TRUE_LOGICAL_EXPR*/
1056	ASSERT(sizeof (ioat_chan_dca_desc_t) == 64);
1057
1058	/* sync the current desc */
1059	(void) ddi_dma_sync(channel->ic_desc_dma_handle,
1060	    ring->cr_desc_next << 6, 64, DDI_DMA_SYNC_FORDEV);
1061
1062	/* update the previous desc and sync it too */
1063	prev->dd_next_desc = ring->cr_phys_desc +
1064	    (ring->cr_desc_next << 6);
1065	(void) ddi_dma_sync(channel->ic_desc_dma_handle,
1066	    ring->cr_desc_prev << 6, 64, DDI_DMA_SYNC_FORDEV);
1067
1068	/* save the current desc_next and desc_last for the completion */
1069	ring->cr_desc_prev = ring->cr_desc_next;
1070	ring->cr_desc_gen_prev = ring->cr_desc_gen;
1071
1072	/* increment next/gen so it points to the next free desc */
1073	ring->cr_desc_next++;
1074	if (ring->cr_desc_next > ring->cr_desc_last) {
1075		ring->cr_desc_next = 0;
1076		ring->cr_desc_gen++;
1077	}
1078
1079	/*
1080	 * if this is CBv2, link the descriptor to an empty descriptor. Since
1081	 * we always leave on desc empty to detect full, this works out.
1082	 */
1083	if (ring->cr_chan->ic_ver == IOAT_CBv2) {
1084		desc = (ioat_chan_dca_desc_t *)
1085		    &ring->cr_desc[ring->cr_desc_next];
1086		prev = (ioat_chan_dca_desc_t *)
1087		    &ring->cr_desc[ring->cr_desc_prev];
1088		desc->dd_ctrl = 0;
1089		desc->dd_next_desc = 0x0;
1090
1091		prev->dd_next_desc = ring->cr_phys_desc +
1092		    (ring->cr_desc_next << 6);
1093	}
1094}
1095
1096
1097/*
1098 * ioat_cmd_post_copy()
1099 *
1100 */
1101static void
1102ioat_cmd_post_copy(ioat_channel_ring_t *ring, uint64_t src_addr,
1103    uint64_t dest_addr, uint32_t size, uint32_t ctrl)
1104{
1105	ioat_chan_dma_desc_t *desc;
1106	ioat_chan_dma_desc_t *prev;
1107	ioat_channel_t channel;
1108
1109
1110	channel = ring->cr_chan;
1111	desc = (ioat_chan_dma_desc_t *)&ring->cr_desc[ring->cr_desc_next];
1112	prev = (ioat_chan_dma_desc_t *)&ring->cr_desc[ring->cr_desc_prev];
1113
1114	/* keep track of the number of descs posted for cbv2 */
1115	ring->cr_post_cnt++;
1116
1117	/* write in the DMA desc */
1118	desc->dd_ctrl = IOAT_DESC_CTRL_OP_DMA | ctrl;
1119	desc->dd_size = size;
1120	desc->dd_src_paddr = src_addr;
1121	desc->dd_dest_paddr = dest_addr;
1122	desc->dd_next_desc = 0x0;
1123
1124	/* Put the descriptors physical address in the previous descriptor */
1125	/*LINTED:E_TRUE_LOGICAL_EXPR*/
1126	ASSERT(sizeof (ioat_chan_dma_desc_t) == 64);
1127
1128	/* sync the current desc */
1129	(void) ddi_dma_sync(channel->ic_desc_dma_handle,
1130	    ring->cr_desc_next << 6, 64, DDI_DMA_SYNC_FORDEV);
1131
1132	/* update the previous desc and sync it too */
1133	prev->dd_next_desc = ring->cr_phys_desc +
1134	    (ring->cr_desc_next << 6);
1135	(void) ddi_dma_sync(channel->ic_desc_dma_handle,
1136	    ring->cr_desc_prev << 6, 64, DDI_DMA_SYNC_FORDEV);
1137
1138	/* increment next/gen so it points to the next free desc */
1139	ring->cr_desc_prev = ring->cr_desc_next;
1140	ring->cr_desc_gen_prev = ring->cr_desc_gen;
1141
1142	/* increment next/gen so it points to the next free desc */
1143	ring->cr_desc_next++;
1144	if (ring->cr_desc_next > ring->cr_desc_last) {
1145		ring->cr_desc_next = 0;
1146		ring->cr_desc_gen++;
1147	}
1148
1149	/*
1150	 * if this is CBv2, link the descriptor to an empty descriptor. Since
1151	 * we always leave on desc empty to detect full, this works out.
1152	 */
1153	if (ring->cr_chan->ic_ver == IOAT_CBv2) {
1154		desc = (ioat_chan_dma_desc_t *)
1155		    &ring->cr_desc[ring->cr_desc_next];
1156		prev = (ioat_chan_dma_desc_t *)
1157		    &ring->cr_desc[ring->cr_desc_prev];
1158		desc->dd_size = 0;
1159		desc->dd_ctrl = 0;
1160		desc->dd_next_desc = 0x0;
1161
1162		prev->dd_next_desc = ring->cr_phys_desc +
1163		    (ring->cr_desc_next << 6);
1164	}
1165}
1166
1167
1168/*
1169 * ioat_cmd_poll()
1170 */
1171int
1172ioat_cmd_poll(void *private, dcopy_cmd_t cmd)
1173{
1174	ioat_channel_ring_t *ring;
1175	ioat_cmd_private_t *priv;
1176	ioat_channel_t channel;
1177	uint64_t generation;
1178	uint64_t last_cmpl;
1179
1180
1181	channel = (ioat_channel_t)private;
1182	priv = cmd->dp_private->pr_device_cmd_private;
1183
1184	ring = channel->ic_ring;
1185	ASSERT(ring != NULL);
1186
1187	mutex_enter(&ring->cr_cmpl_mutex);
1188
1189	/* if the channel had a fatal failure, fail all polls */
1190	if ((channel->ic_channel_state == IOAT_CHANNEL_IN_FAILURE) ||
1191	    IOAT_CMPL_FAILED(channel)) {
1192		mutex_exit(&ring->cr_cmpl_mutex);
1193		return (DCOPY_FAILURE);
1194	}
1195
1196	/*
1197	 * if the current completion is the same as the last time we read one,
1198	 * post is still pending, nothing further to do. We track completions
1199	 * as indexes into the ring since post uses VAs and the H/W returns
1200	 * PAs. We grab a snapshot of generation and last_cmpl in the mutex.
1201	 */
1202	(void) ddi_dma_sync(channel->ic_cmpl_dma_handle, 0, 0,
1203	    DDI_DMA_SYNC_FORCPU);
1204	last_cmpl = IOAT_CMPL_INDEX(channel);
1205	if (last_cmpl != ring->cr_cmpl_last) {
1206		/*
1207		 * if we wrapped the ring, increment the generation. Store
1208		 * the last cmpl. This logic assumes a physically contiguous
1209		 * ring.
1210		 */
1211		if (last_cmpl < ring->cr_cmpl_last) {
1212			ring->cr_cmpl_gen++;
1213		}
1214		ring->cr_cmpl_last = last_cmpl;
1215		generation = ring->cr_cmpl_gen;
1216
1217	} else {
1218		generation = ring->cr_cmpl_gen;
1219	}
1220
1221	mutex_exit(&ring->cr_cmpl_mutex);
1222
1223	/*
1224	 * if cmd isn't passed in, well return.  Useful for updating the
1225	 * consumer pointer (ring->cr_cmpl_last).
1226	 */
1227	if (cmd == NULL) {
1228		return (DCOPY_PENDING);
1229	}
1230
1231	/*
1232	 * if the post's generation is old, this post has completed. No reason
1233	 * to go check the last completion. if the generation is the same
1234	 * and if the post is before or = to the last completion processed,
1235	 * the post has completed.
1236	 */
1237	if (priv->ip_generation < generation) {
1238		return (DCOPY_COMPLETED);
1239	} else if ((priv->ip_generation == generation) &&
1240	    (priv->ip_index <= last_cmpl)) {
1241		return (DCOPY_COMPLETED);
1242	}
1243
1244	return (DCOPY_PENDING);
1245}
1246
1247
1248/*
1249 * ioat_ring_reserve()
1250 */
1251int
1252ioat_ring_reserve(ioat_channel_t channel, ioat_channel_ring_t *ring,
1253    dcopy_cmd_t cmd)
1254{
1255	uint64_t dest_addr;
1256	uint32_t dest_size;
1257	uint64_t src_addr;
1258	uint32_t src_size;
1259	size_t xfer_size;
1260	uint64_t desc;
1261	int num_desc;
1262	size_t size;
1263	int i;
1264
1265
1266	/*
1267	 * figure out how many descriptors we need. This can include a dca
1268	 * desc and multiple desc for a dma copy.
1269	 */
1270	num_desc = 0;
1271	if ((channel->ic_ver == IOAT_CBv2) &&
1272	    (cmd->dp_flags & DCOPY_CMD_DCA)) {
1273		num_desc++;
1274	}
1275	src_addr = cmd->dp.copy.cc_source;
1276	dest_addr = cmd->dp.copy.cc_dest;
1277	size = cmd->dp.copy.cc_size;
1278	while (size > 0) {
1279		num_desc++;
1280
1281		/* adjust for any offset into the page */
1282		if ((src_addr & PAGEOFFSET) == 0) {
1283			src_size = PAGESIZE;
1284		} else {
1285			src_size = PAGESIZE - (src_addr & PAGEOFFSET);
1286		}
1287		if ((dest_addr & PAGEOFFSET) == 0) {
1288			dest_size = PAGESIZE;
1289		} else {
1290			dest_size = PAGESIZE - (dest_addr & PAGEOFFSET);
1291		}
1292
1293		/* take the smallest of the three */
1294		xfer_size = MIN(src_size, dest_size);
1295		xfer_size = MIN(xfer_size, size);
1296
1297		/* go to the next page */
1298		src_addr += xfer_size;
1299		dest_addr += xfer_size;
1300		size -= xfer_size;
1301	}
1302
1303	/* Make sure we have space for these descriptors */
1304	desc = ring->cr_desc_next;
1305	for (i = 0; i < num_desc; i++) {
1306
1307		/*
1308		 * if this is the last descriptor in the ring, see if the
1309		 * last completed descriptor is #0.
1310		 */
1311		if (desc == ring->cr_desc_last) {
1312			if (ring->cr_cmpl_last == 0) {
1313				/*
1314				 * if we think the ring is full, update where
1315				 * the H/W really is and check for full again.
1316				 */
1317				(void) ioat_cmd_poll(channel, NULL);
1318				if (ring->cr_cmpl_last == 0) {
1319					return (DCOPY_NORESOURCES);
1320				}
1321			}
1322
1323			/*
1324			 * go to the next descriptor which is zero in this
1325			 * case.
1326			 */
1327			desc = 0;
1328
1329		/*
1330		 * if this is not the last descriptor in the ring, see if
1331		 * the last completion we saw was the next descriptor.
1332		 */
1333		} else {
1334			if ((desc + 1) == ring->cr_cmpl_last) {
1335				/*
1336				 * if we think the ring is full, update where
1337				 * the H/W really is and check for full again.
1338				 */
1339				(void) ioat_cmd_poll(channel, NULL);
1340				if ((desc + 1) == ring->cr_cmpl_last) {
1341					return (DCOPY_NORESOURCES);
1342				}
1343			}
1344
1345			/* go to the next descriptor */
1346			desc++;
1347		}
1348	}
1349
1350	return (DCOPY_SUCCESS);
1351}
1352