summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/dcopy.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/io/dcopy.c')
-rw-r--r--usr/src/uts/common/io/dcopy.c932
1 files changed, 0 insertions, 932 deletions
diff --git a/usr/src/uts/common/io/dcopy.c b/usr/src/uts/common/io/dcopy.c
deleted file mode 100644
index 2dc5a311bc..0000000000
--- a/usr/src/uts/common/io/dcopy.c
+++ /dev/null
@@ -1,932 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-/*
- * dcopy.c
- * dcopy misc module
- */
-
-#include <sys/conf.h>
-#include <sys/kmem.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/modctl.h>
-#include <sys/sysmacros.h>
-#include <sys/atomic.h>
-
-
-#include <sys/dcopy.h>
-#include <sys/dcopy_device.h>
-
-
-/* Number of entries per channel to allocate */
-uint_t dcopy_channel_size = 1024;
-
-
-typedef struct dcopy_list_s {
- list_t dl_list;
- kmutex_t dl_mutex;
- uint_t dl_cnt; /* num entries on list */
-} dcopy_list_t;
-
-/* device state for register/unregister */
-struct dcopy_device_s {
- /* DMA device drivers private pointer */
- void *dc_device_private;
-
- /* to track list of channels from this DMA device */
- dcopy_list_t dc_devchan_list;
- list_node_t dc_device_list_node;
-
- /*
- * dc_removing_cnt track how many channels still have to be freed up
- * before it's safe to allow the DMA device driver to detach.
- */
- uint_t dc_removing_cnt;
- dcopy_device_cb_t *dc_cb;
-
- dcopy_device_info_t dc_info;
-
-};
-
-typedef struct dcopy_stats_s {
- kstat_named_t cs_bytes_xfer;
- kstat_named_t cs_cmd_alloc;
- kstat_named_t cs_cmd_post;
- kstat_named_t cs_cmd_poll;
- kstat_named_t cs_notify_poll;
- kstat_named_t cs_notify_pending;
- kstat_named_t cs_id;
- kstat_named_t cs_capabilities;
-} dcopy_stats_t;
-
-/* DMA channel state */
-struct dcopy_channel_s {
- /* DMA driver channel private pointer */
- void *ch_channel_private;
-
- /* shortcut to device callbacks */
- dcopy_device_cb_t *ch_cb;
-
- /*
- * number of outstanding allocs for this channel. used to track when
- * it's safe to free up this channel so the DMA device driver can
- * detach.
- */
- uint64_t ch_ref_cnt;
-
- /* state for if channel needs to be removed when ch_ref_cnt gets to 0 */
- boolean_t ch_removing;
-
- list_node_t ch_devchan_list_node;
- list_node_t ch_globalchan_list_node;
-
- /*
- * per channel list of commands actively blocking waiting for
- * completion.
- */
- dcopy_list_t ch_poll_list;
-
- /* pointer back to our device */
- struct dcopy_device_s *ch_device;
-
- dcopy_query_channel_t ch_info;
-
- kstat_t *ch_kstat;
- dcopy_stats_t ch_stat;
-};
-
-/*
- * If grabbing both device_list mutex & globalchan_list mutex,
- * Always grab globalchan_list mutex before device_list mutex
- */
-typedef struct dcopy_state_s {
- dcopy_list_t d_device_list;
- dcopy_list_t d_globalchan_list;
-} dcopy_state_t;
-dcopy_state_t *dcopy_statep;
-
-
-/* Module Driver Info */
-static struct modlmisc dcopy_modlmisc = {
- &mod_miscops,
- "dcopy kernel module"
-};
-
-/* Module Linkage */
-static struct modlinkage dcopy_modlinkage = {
- MODREV_1,
- &dcopy_modlmisc,
- NULL
-};
-
-static int dcopy_init();
-static void dcopy_fini();
-
-static int dcopy_list_init(dcopy_list_t *list, size_t node_size,
- offset_t link_offset);
-static void dcopy_list_fini(dcopy_list_t *list);
-static void dcopy_list_push(dcopy_list_t *list, void *list_node);
-static void *dcopy_list_pop(dcopy_list_t *list);
-
-static void dcopy_device_cleanup(dcopy_device_handle_t device,
- boolean_t do_callback);
-
-static int dcopy_stats_init(dcopy_handle_t channel);
-static void dcopy_stats_fini(dcopy_handle_t channel);
-
-
-/*
- * _init()
- */
-int
-_init()
-{
- int e;
-
- e = dcopy_init();
- if (e != 0) {
- return (e);
- }
-
- return (mod_install(&dcopy_modlinkage));
-}
-
-
-/*
- * _info()
- */
-int
-_info(struct modinfo *modinfop)
-{
- return (mod_info(&dcopy_modlinkage, modinfop));
-}
-
-
-/*
- * _fini()
- */
-int
-_fini()
-{
- int e;
-
- e = mod_remove(&dcopy_modlinkage);
- if (e != 0) {
- return (e);
- }
-
- dcopy_fini();
-
- return (e);
-}
-
-/*
- * dcopy_init()
- */
-static int
-dcopy_init()
-{
- int e;
-
-
- dcopy_statep = kmem_zalloc(sizeof (*dcopy_statep), KM_SLEEP);
-
- /* Initialize the list we use to track device register/unregister */
- e = dcopy_list_init(&dcopy_statep->d_device_list,
- sizeof (struct dcopy_device_s),
- offsetof(struct dcopy_device_s, dc_device_list_node));
- if (e != DCOPY_SUCCESS) {
- goto dcopyinitfail_device;
- }
-
- /* Initialize the list we use to track all DMA channels */
- e = dcopy_list_init(&dcopy_statep->d_globalchan_list,
- sizeof (struct dcopy_channel_s),
- offsetof(struct dcopy_channel_s, ch_globalchan_list_node));
- if (e != DCOPY_SUCCESS) {
- goto dcopyinitfail_global;
- }
-
- return (0);
-
-dcopyinitfail_cback:
- dcopy_list_fini(&dcopy_statep->d_globalchan_list);
-dcopyinitfail_global:
- dcopy_list_fini(&dcopy_statep->d_device_list);
-dcopyinitfail_device:
- kmem_free(dcopy_statep, sizeof (*dcopy_statep));
-
- return (-1);
-}
-
-
-/*
- * dcopy_fini()
- */
-static void
-dcopy_fini()
-{
- /*
- * if mod_remove was successfull, we shouldn't have any
- * devices/channels to worry about.
- */
- ASSERT(list_head(&dcopy_statep->d_globalchan_list.dl_list) == NULL);
- ASSERT(list_head(&dcopy_statep->d_device_list.dl_list) == NULL);
-
- dcopy_list_fini(&dcopy_statep->d_globalchan_list);
- dcopy_list_fini(&dcopy_statep->d_device_list);
- kmem_free(dcopy_statep, sizeof (*dcopy_statep));
-}
-
-
-/* *** EXTERNAL INTERFACE *** */
-/*
- * dcopy_query()
- */
-void
-dcopy_query(dcopy_query_t *query)
-{
- query->dq_version = DCOPY_QUERY_V0;
- query->dq_num_channels = dcopy_statep->d_globalchan_list.dl_cnt;
-}
-
-
-/*
- * dcopy_alloc()
- */
-/*ARGSUSED*/
-int
-dcopy_alloc(int flags, dcopy_handle_t *handle)
-{
- dcopy_handle_t channel;
- dcopy_list_t *list;
-
-
- /*
- * we don't use the dcopy_list_* code here because we need to due
- * some non-standard stuff.
- */
-
- list = &dcopy_statep->d_globalchan_list;
-
- /*
- * if nothing is on the channel list, return DCOPY_NORESOURCES. This
- * can happen if there aren't any DMA device registered.
- */
- mutex_enter(&list->dl_mutex);
- channel = list_head(&list->dl_list);
- if (channel == NULL) {
- mutex_exit(&list->dl_mutex);
- return (DCOPY_NORESOURCES);
- }
-
- /*
- * increment the reference count, and pop the channel off the head and
- * push it on the tail. This ensures we rotate through the channels.
- * DMA channels are shared.
- */
- channel->ch_ref_cnt++;
- list_remove(&list->dl_list, channel);
- list_insert_tail(&list->dl_list, channel);
- mutex_exit(&list->dl_mutex);
-
- *handle = (dcopy_handle_t)channel;
- return (DCOPY_SUCCESS);
-}
-
-
-/*
- * dcopy_free()
- */
-void
-dcopy_free(dcopy_handle_t *channel)
-{
- dcopy_device_handle_t device;
- dcopy_list_t *list;
- boolean_t cleanup;
-
-
- ASSERT(*channel != NULL);
-
- /*
- * we don't need to add the channel back to the list since we never
- * removed it. decrement the reference count.
- */
- list = &dcopy_statep->d_globalchan_list;
- mutex_enter(&list->dl_mutex);
- (*channel)->ch_ref_cnt--;
-
- /*
- * if we need to remove this channel, and the reference count is down
- * to 0, decrement the number of channels which still need to be
- * removed on the device.
- */
- if ((*channel)->ch_removing && ((*channel)->ch_ref_cnt == 0)) {
- cleanup = B_FALSE;
- device = (*channel)->ch_device;
- mutex_enter(&device->dc_devchan_list.dl_mutex);
- device->dc_removing_cnt--;
- if (device->dc_removing_cnt == 0) {
- cleanup = B_TRUE;
- }
- mutex_exit(&device->dc_devchan_list.dl_mutex);
- }
- mutex_exit(&list->dl_mutex);
-
- /*
- * if there are no channels which still need to be removed, cleanup the
- * device state and call back into the DMA device driver to tell them
- * the device is free.
- */
- if (cleanup) {
- dcopy_device_cleanup(device, B_TRUE);
- }
-
- *channel = NULL;
-}
-
-
-/*
- * dcopy_query_channel()
- */
-void
-dcopy_query_channel(dcopy_handle_t channel, dcopy_query_channel_t *query)
-{
- *query = channel->ch_info;
-}
-
-
-/*
- * dcopy_cmd_alloc()
- */
-int
-dcopy_cmd_alloc(dcopy_handle_t handle, int flags, dcopy_cmd_t *cmd)
-{
- dcopy_handle_t channel;
- dcopy_cmd_priv_t priv;
- int e;
-
-
- channel = handle;
-
- atomic_inc_64(&channel->ch_stat.cs_cmd_alloc.value.ui64);
- e = channel->ch_cb->cb_cmd_alloc(channel->ch_channel_private, flags,
- cmd);
- if (e == DCOPY_SUCCESS) {
- priv = (*cmd)->dp_private;
- priv->pr_channel = channel;
- /*
- * we won't initialize the blocking state until we actually
- * need to block.
- */
- priv->pr_block_init = B_FALSE;
- }
-
- return (e);
-}
-
-
-/*
- * dcopy_cmd_free()
- */
-void
-dcopy_cmd_free(dcopy_cmd_t *cmd)
-{
- dcopy_handle_t channel;
- dcopy_cmd_priv_t priv;
-
-
- ASSERT(*cmd != NULL);
-
- priv = (*cmd)->dp_private;
- channel = priv->pr_channel;
-
- /* if we initialized the blocking state, clean it up too */
- if (priv->pr_block_init) {
- cv_destroy(&priv->pr_cv);
- mutex_destroy(&priv->pr_mutex);
- }
-
- channel->ch_cb->cb_cmd_free(channel->ch_channel_private, cmd);
-}
-
-
-/*
- * dcopy_cmd_post()
- */
-int
-dcopy_cmd_post(dcopy_cmd_t cmd)
-{
- dcopy_handle_t channel;
- int e;
-
-
- channel = cmd->dp_private->pr_channel;
-
- atomic_inc_64(&channel->ch_stat.cs_cmd_post.value.ui64);
- if (cmd->dp_cmd == DCOPY_CMD_COPY) {
- atomic_add_64(&channel->ch_stat.cs_bytes_xfer.value.ui64,
- cmd->dp.copy.cc_size);
- }
- e = channel->ch_cb->cb_cmd_post(channel->ch_channel_private, cmd);
- if (e != DCOPY_SUCCESS) {
- return (e);
- }
-
- return (DCOPY_SUCCESS);
-}
-
-
-/*
- * dcopy_cmd_poll()
- */
-int
-dcopy_cmd_poll(dcopy_cmd_t cmd, int flags)
-{
- dcopy_handle_t channel;
- dcopy_cmd_priv_t priv;
- int e;
-
-
- priv = cmd->dp_private;
- channel = priv->pr_channel;
-
- /*
- * if the caller is trying to block, they needed to post the
- * command with DCOPY_CMD_INTR set.
- */
- if ((flags & DCOPY_POLL_BLOCK) && !(cmd->dp_flags & DCOPY_CMD_INTR)) {
- return (DCOPY_FAILURE);
- }
-
- atomic_inc_64(&channel->ch_stat.cs_cmd_poll.value.ui64);
-
-repoll:
- e = channel->ch_cb->cb_cmd_poll(channel->ch_channel_private, cmd);
- if (e == DCOPY_PENDING) {
- /*
- * if the command is still active, and the blocking flag
- * is set.
- */
- if (flags & DCOPY_POLL_BLOCK) {
-
- /*
- * if we haven't initialized the state, do it now. A
- * command can be re-used, so it's possible it's
- * already been initialized.
- */
- if (!priv->pr_block_init) {
- priv->pr_block_init = B_TRUE;
- mutex_init(&priv->pr_mutex, NULL, MUTEX_DRIVER,
- NULL);
- cv_init(&priv->pr_cv, NULL, CV_DRIVER, NULL);
- priv->pr_cmd = cmd;
- }
-
- /* push it on the list for blocking commands */
- priv->pr_wait = B_TRUE;
- dcopy_list_push(&channel->ch_poll_list, priv);
-
- mutex_enter(&priv->pr_mutex);
- /*
- * it's possible we already cleared pr_wait before we
- * grabbed the mutex.
- */
- if (priv->pr_wait) {
- cv_wait(&priv->pr_cv, &priv->pr_mutex);
- }
- mutex_exit(&priv->pr_mutex);
-
- /*
- * the command has completed, go back and poll so we
- * get the status.
- */
- goto repoll;
- }
- }
-
- return (e);
-}
-
-/* *** END OF EXTERNAL INTERFACE *** */
-
-/*
- * dcopy_list_init()
- */
-static int
-dcopy_list_init(dcopy_list_t *list, size_t node_size, offset_t link_offset)
-{
- mutex_init(&list->dl_mutex, NULL, MUTEX_DRIVER, NULL);
- list_create(&list->dl_list, node_size, link_offset);
- list->dl_cnt = 0;
-
- return (DCOPY_SUCCESS);
-}
-
-
-/*
- * dcopy_list_fini()
- */
-static void
-dcopy_list_fini(dcopy_list_t *list)
-{
- list_destroy(&list->dl_list);
- mutex_destroy(&list->dl_mutex);
-}
-
-
-/*
- * dcopy_list_push()
- */
-static void
-dcopy_list_push(dcopy_list_t *list, void *list_node)
-{
- mutex_enter(&list->dl_mutex);
- list_insert_tail(&list->dl_list, list_node);
- list->dl_cnt++;
- mutex_exit(&list->dl_mutex);
-}
-
-
-/*
- * dcopy_list_pop()
- */
-static void *
-dcopy_list_pop(dcopy_list_t *list)
-{
- list_node_t *list_node;
-
- mutex_enter(&list->dl_mutex);
- list_node = list_head(&list->dl_list);
- if (list_node == NULL) {
- mutex_exit(&list->dl_mutex);
- return (list_node);
- }
- list->dl_cnt--;
- list_remove(&list->dl_list, list_node);
- mutex_exit(&list->dl_mutex);
-
- return (list_node);
-}
-
-
-/* *** DEVICE INTERFACE *** */
-/*
- * dcopy_device_register()
- */
-int
-dcopy_device_register(void *device_private, dcopy_device_info_t *info,
- dcopy_device_handle_t *handle)
-{
- struct dcopy_channel_s *channel;
- struct dcopy_device_s *device;
- int e;
- int i;
-
-
- /* initialize the per device state */
- device = kmem_zalloc(sizeof (*device), KM_SLEEP);
- device->dc_device_private = device_private;
- device->dc_info = *info;
- device->dc_removing_cnt = 0;
- device->dc_cb = info->di_cb;
-
- /*
- * we have a per device channel list so we can remove a device in the
- * future.
- */
- e = dcopy_list_init(&device->dc_devchan_list,
- sizeof (struct dcopy_channel_s),
- offsetof(struct dcopy_channel_s, ch_devchan_list_node));
- if (e != DCOPY_SUCCESS) {
- goto registerfail_devchan;
- }
-
- /*
- * allocate state for each channel, allocate the channel, and then add
- * the devices dma channels to the devices channel list.
- */
- for (i = 0; i < info->di_num_dma; i++) {
- channel = kmem_zalloc(sizeof (*channel), KM_SLEEP);
- channel->ch_device = device;
- channel->ch_removing = B_FALSE;
- channel->ch_ref_cnt = 0;
- channel->ch_cb = info->di_cb;
-
- e = info->di_cb->cb_channel_alloc(device_private, channel,
- DCOPY_SLEEP, dcopy_channel_size, &channel->ch_info,
- &channel->ch_channel_private);
- if (e != DCOPY_SUCCESS) {
- kmem_free(channel, sizeof (*channel));
- goto registerfail_alloc;
- }
-
- e = dcopy_stats_init(channel);
- if (e != DCOPY_SUCCESS) {
- info->di_cb->cb_channel_free(
- &channel->ch_channel_private);
- kmem_free(channel, sizeof (*channel));
- goto registerfail_alloc;
- }
-
- e = dcopy_list_init(&channel->ch_poll_list,
- sizeof (struct dcopy_cmd_priv_s),
- offsetof(struct dcopy_cmd_priv_s, pr_poll_list_node));
- if (e != DCOPY_SUCCESS) {
- dcopy_stats_fini(channel);
- info->di_cb->cb_channel_free(
- &channel->ch_channel_private);
- kmem_free(channel, sizeof (*channel));
- goto registerfail_alloc;
- }
-
- dcopy_list_push(&device->dc_devchan_list, channel);
- }
-
- /* add the device to device list */
- dcopy_list_push(&dcopy_statep->d_device_list, device);
-
- /*
- * add the device's dma channels to the global channel list (where
- * dcopy_alloc's come from)
- */
- mutex_enter(&dcopy_statep->d_globalchan_list.dl_mutex);
- mutex_enter(&dcopy_statep->d_device_list.dl_mutex);
- channel = list_head(&device->dc_devchan_list.dl_list);
- while (channel != NULL) {
- list_insert_tail(&dcopy_statep->d_globalchan_list.dl_list,
- channel);
- dcopy_statep->d_globalchan_list.dl_cnt++;
- channel = list_next(&device->dc_devchan_list.dl_list, channel);
- }
- mutex_exit(&dcopy_statep->d_device_list.dl_mutex);
- mutex_exit(&dcopy_statep->d_globalchan_list.dl_mutex);
-
- *handle = device;
- return (DCOPY_SUCCESS);
-
-registerfail_alloc:
- channel = list_head(&device->dc_devchan_list.dl_list);
- while (channel != NULL) {
- /* remove from the list */
- channel = dcopy_list_pop(&device->dc_devchan_list);
- ASSERT(channel != NULL);
-
- dcopy_list_fini(&channel->ch_poll_list);
- dcopy_stats_fini(channel);
- info->di_cb->cb_channel_free(&channel->ch_channel_private);
- kmem_free(channel, sizeof (*channel));
- }
-
- dcopy_list_fini(&device->dc_devchan_list);
-registerfail_devchan:
- kmem_free(device, sizeof (*device));
-
- return (DCOPY_FAILURE);
-}
-
-
-/*
- * dcopy_device_unregister()
- */
-/*ARGSUSED*/
-int
-dcopy_device_unregister(dcopy_device_handle_t *handle)
-{
- struct dcopy_channel_s *channel;
- dcopy_device_handle_t device;
- boolean_t device_busy;
-
-
- device = *handle;
- device_busy = B_FALSE;
-
- /*
- * remove the devices dma channels from the global channel list (where
- * dcopy_alloc's come from)
- */
- mutex_enter(&dcopy_statep->d_globalchan_list.dl_mutex);
- mutex_enter(&device->dc_devchan_list.dl_mutex);
- channel = list_head(&device->dc_devchan_list.dl_list);
- while (channel != NULL) {
- /*
- * if the channel has outstanding allocs, mark it as having
- * to be removed and increment the number of channels which
- * need to be removed in the device state too.
- */
- if (channel->ch_ref_cnt != 0) {
- channel->ch_removing = B_TRUE;
- device_busy = B_TRUE;
- device->dc_removing_cnt++;
- }
- dcopy_statep->d_globalchan_list.dl_cnt--;
- list_remove(&dcopy_statep->d_globalchan_list.dl_list, channel);
- channel = list_next(&device->dc_devchan_list.dl_list, channel);
- }
- mutex_exit(&device->dc_devchan_list.dl_mutex);
- mutex_exit(&dcopy_statep->d_globalchan_list.dl_mutex);
-
- /*
- * if there are channels which still need to be removed, we will clean
- * up the device state after they are freed up.
- */
- if (device_busy) {
- return (DCOPY_PENDING);
- }
-
- dcopy_device_cleanup(device, B_FALSE);
-
- *handle = NULL;
- return (DCOPY_SUCCESS);
-}
-
-
-/*
- * dcopy_device_cleanup()
- */
-static void
-dcopy_device_cleanup(dcopy_device_handle_t device, boolean_t do_callback)
-{
- struct dcopy_channel_s *channel;
-
- /*
- * remove all the channels in the device list, free them, and clean up
- * the state.
- */
- mutex_enter(&dcopy_statep->d_device_list.dl_mutex);
- channel = list_head(&device->dc_devchan_list.dl_list);
- while (channel != NULL) {
- device->dc_devchan_list.dl_cnt--;
- list_remove(&device->dc_devchan_list.dl_list, channel);
- dcopy_list_fini(&channel->ch_poll_list);
- dcopy_stats_fini(channel);
- channel->ch_cb->cb_channel_free(&channel->ch_channel_private);
- kmem_free(channel, sizeof (*channel));
- channel = list_head(&device->dc_devchan_list.dl_list);
- }
-
- /* remove it from the list of devices */
- list_remove(&dcopy_statep->d_device_list.dl_list, device);
-
- mutex_exit(&dcopy_statep->d_device_list.dl_mutex);
-
- /*
- * notify the DMA device driver that the device is free to be
- * detached.
- */
- if (do_callback) {
- device->dc_cb->cb_unregister_complete(
- device->dc_device_private, DCOPY_SUCCESS);
- }
-
- dcopy_list_fini(&device->dc_devchan_list);
- kmem_free(device, sizeof (*device));
-}
-
-
-/*
- * dcopy_device_channel_notify()
- */
-/*ARGSUSED*/
-void
-dcopy_device_channel_notify(dcopy_handle_t handle, int status)
-{
- struct dcopy_channel_s *channel;
- dcopy_list_t *poll_list;
- dcopy_cmd_priv_t priv;
- int e;
-
-
- ASSERT(status == DCOPY_COMPLETION);
- channel = handle;
-
- poll_list = &channel->ch_poll_list;
-
- /*
- * when we get a completion notification from the device, go through
- * all of the commands blocking on this channel and see if they have
- * completed. Remove the command and wake up the block thread if they
- * have. Once we hit a command which is still pending, we are done
- * polling since commands in a channel complete in order.
- */
- mutex_enter(&poll_list->dl_mutex);
- if (poll_list->dl_cnt != 0) {
- priv = list_head(&poll_list->dl_list);
- while (priv != NULL) {
- atomic_inc_64(&channel->
- ch_stat.cs_notify_poll.value.ui64);
- e = channel->ch_cb->cb_cmd_poll(
- channel->ch_channel_private,
- priv->pr_cmd);
- if (e == DCOPY_PENDING) {
- atomic_inc_64(&channel->
- ch_stat.cs_notify_pending.value.ui64);
- break;
- }
-
- poll_list->dl_cnt--;
- list_remove(&poll_list->dl_list, priv);
-
- mutex_enter(&priv->pr_mutex);
- priv->pr_wait = B_FALSE;
- cv_signal(&priv->pr_cv);
- mutex_exit(&priv->pr_mutex);
-
- priv = list_head(&poll_list->dl_list);
- }
- }
-
- mutex_exit(&poll_list->dl_mutex);
-}
-
-
-/*
- * dcopy_stats_init()
- */
-static int
-dcopy_stats_init(dcopy_handle_t channel)
-{
-#define CHANSTRSIZE 20
- char chanstr[CHANSTRSIZE];
- dcopy_stats_t *stats;
- int instance;
- char *name;
-
-
- stats = &channel->ch_stat;
- name = (char *)ddi_driver_name(channel->ch_device->dc_info.di_dip);
- instance = ddi_get_instance(channel->ch_device->dc_info.di_dip);
-
- (void) snprintf(chanstr, CHANSTRSIZE, "channel%d",
- (uint32_t)channel->ch_info.qc_chan_num);
-
- channel->ch_kstat = kstat_create(name, instance, chanstr, "misc",
- KSTAT_TYPE_NAMED, sizeof (dcopy_stats_t) / sizeof (kstat_named_t),
- KSTAT_FLAG_VIRTUAL);
- if (channel->ch_kstat == NULL) {
- return (DCOPY_FAILURE);
- }
- channel->ch_kstat->ks_data = stats;
-
- kstat_named_init(&stats->cs_bytes_xfer, "bytes_xfer",
- KSTAT_DATA_UINT64);
- kstat_named_init(&stats->cs_cmd_alloc, "cmd_alloc",
- KSTAT_DATA_UINT64);
- kstat_named_init(&stats->cs_cmd_post, "cmd_post",
- KSTAT_DATA_UINT64);
- kstat_named_init(&stats->cs_cmd_poll, "cmd_poll",
- KSTAT_DATA_UINT64);
- kstat_named_init(&stats->cs_notify_poll, "notify_poll",
- KSTAT_DATA_UINT64);
- kstat_named_init(&stats->cs_notify_pending, "notify_pending",
- KSTAT_DATA_UINT64);
- kstat_named_init(&stats->cs_id, "id",
- KSTAT_DATA_UINT64);
- kstat_named_init(&stats->cs_capabilities, "capabilities",
- KSTAT_DATA_UINT64);
-
- kstat_install(channel->ch_kstat);
-
- channel->ch_stat.cs_id.value.ui64 = channel->ch_info.qc_id;
- channel->ch_stat.cs_capabilities.value.ui64 =
- channel->ch_info.qc_capabilities;
-
- return (DCOPY_SUCCESS);
-}
-
-
-/*
- * dcopy_stats_fini()
- */
-static void
-dcopy_stats_fini(dcopy_handle_t channel)
-{
- kstat_delete(channel->ch_kstat);
-}
-/* *** END OF DEVICE INTERFACE *** */