fcoe.c revision 3b753e0506d00a3cd038199bce20003b3210a1b8
/*
* 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
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* The following notice accompanied the original version of this file:
*
* BSD LICENSE
*
* Copyright(c) 2007 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Common FCoE interface interacts with MAC and FCoE clients, managing
*/
#include <sys/byteorder.h>
#include <sys/sysmacros.h>
#include <sys/mac_client.h>
/*
* FCoE header files
*/
/*
* Driver's own header files
*/
#include <fcoe.h>
#include <fcoe_fc.h>
#include <fcoe_eth.h>
/*
* Function forward declaration
*/
void *obuf);
static void fcoe_watchdog(void *arg);
static void fcoe_worker_init();
static int fcoe_worker_fini();
static void fcoe_worker_frame();
/*
* Driver identificaton stuff
*/
static struct cb_ops fcoe_cb_ops = {
0,
};
static struct bus_ops fcoe_busops = {
nullbusmap, /* bus_map */
NULL, /* bus_get_intrspec */
NULL, /* bus_add_intrspec */
NULL, /* bus_remove_intrspec */
i_ddi_map_fault, /* bus_map_fault */
ddi_dma_map, /* bus_dma_map */
ddi_dma_allochdl, /* bus_dma_allochdl */
ddi_dma_freehdl, /* bus_dma_freehdl */
ddi_dma_bindhdl, /* bus_dma_bindhdl */
ddi_dma_unbindhdl, /* bus_unbindhdl */
ddi_dma_flush, /* bus_dma_flush */
ddi_dma_win, /* bus_dma_win */
ddi_dma_mctl, /* bus_dma_ctl */
fcoe_bus_ctl, /* bus_ctl */
ddi_bus_prop_op, /* bus_prop_op */
NULL, /* bus_get_eventcookie */
NULL, /* bus_add_eventcall */
NULL, /* bus_remove_event */
NULL, /* bus_post_event */
NULL, /* bus_intr_ctl */
NULL, /* bus_config */
NULL, /* bus_unconfig */
NULL, /* bus_fm_init */
NULL, /* bus_fm_fini */
NULL, /* bus_fm_access_enter */
NULL, /* bus_fm_access_exit */
NULL, /* bus_power */
};
0,
};
#define FCOE_VERSION "20090311-1.00"
#define TASKQ_NAME_LEN 32
&fcoe_ops,
};
static struct modlinkage modlinkage = {
};
/*
* TRACE for all FCoE related modules
*/
static kmutex_t fcoe_trace_buf_lock;
static int fcoe_trace_buf_curndx = 0;
static int fcoe_trace_on = 1;
static clock_t fcoe_trace_start = 0;
/*
* Driver's global variables
*/
static void *fcoe_state = NULL;
int fcoe_use_ext_log = 1;
static ddi_taskq_t *fcoe_worker_taskq;
static fcoe_worker_t *fcoe_workers;
static uint32_t fcoe_nworkers_running;
const char *fcoe_workers_num = "workers-number";
volatile int fcoe_nworkers;
/*
* Common loadable module entry points _init, _fini, _info
*/
int
_init(void)
{
int ret;
if (ret == 0) {
if (ret != 0) {
} else {
KM_SLEEP);
}
}
return (ret);
}
int
_fini(void)
{
int ret;
if (ret == 0) {
}
if (ret == 0) {
}
return (ret);
}
int
{
}
/*
* Autoconfiguration entry points: attach, detach, getinfo
*/
static int
{
int ret = DDI_FAILURE;
int fcoe_ret;
int instance;
switch (cmd) {
case DDI_ATTACH:
if (ret == DDI_FAILURE) {
return (ret);
}
fcoe_global_ss = ss;
if (fcoe_ret == FCOE_SUCCESS) {
ret = DDI_SUCCESS;
}
break;
case DDI_RESUME:
ret = DDI_SUCCESS;
break;
default:
break;
}
return (ret);
}
static int
{
int ret = DDI_FAILURE;
int fcoe_ret;
int instance;
return (ret);
}
switch (cmd) {
case DDI_DETACH:
if (fcoe_ret == FCOE_SUCCESS) {
ret = DDI_SUCCESS;
}
break;
case DDI_SUSPEND:
ret = DDI_SUCCESS;
break;
default:
break;
}
return (ret);
}
/*
* FCA driver's intercepted bus control operations.
*/
static int
{
int ret;
switch (op) {
case DDI_CTLOPS_REPORTDEV:
case DDI_CTLOPS_IOMIN:
ret = DDI_SUCCESS;
break;
case DDI_CTLOPS_INITCHILD:
break;
case DDI_CTLOPS_UNINITCHILD:
break;
default:
break;
}
return (ret);
}
/*
* We need specify the dev address for client driver's instance, or we
* can't online client driver's instance.
*/
/* ARGSUSED */
static int
{
char name[32];
static int inicounter = 0;
static int tgtcounter = 0;
int *counter;
counter = &tgtcounter;
tgtcounter++;
} else {
counter = &inicounter;
inicounter++;
}
return (DDI_SUCCESS);
}
/* ARGSUSED */
static int
{
return (DDI_SUCCESS);
}
/*
* Device access entry points
*/
static int
{
int instance;
return (EINVAL);
}
/*
* Since this is for debugging only, only allow root to issue ioctl now
*/
return (EPERM);
}
return (ENXIO);
}
/*
* It is already open for exclusive access.
* So shut the door on this caller.
*/
return (EBUSY);
}
/*
* Exclusive operation not possible
* as it is already opened
*/
return (EBUSY);
}
}
return (0);
}
/* ARGSUSED */
static int
{
int instance;
return (EINVAL);
}
return (ENXIO);
}
return (ENODEV);
}
return (0);
}
/* ARGSUSED */
static int
{
int ret = 0;
return (EPERM);
}
return (ENXIO);
}
return (ENXIO);
}
switch (cmd) {
case FCOEIO_CMD:
break;
default:
break;
}
return (ret);
}
static int
{
int ret = 0;
goto copyin_iocdata_fail;
}
goto copyin_iocdata_fail;
}
if ((*fcoeio)->fcoeio_ilen) {
goto copyin_iocdata_fail;
}
}
if ((*fcoeio)->fcoeio_alen) {
goto copyin_iocdata_fail;
}
}
if ((*fcoeio)->fcoeio_olen) {
}
return (ret);
if (*abuf) {
}
if (*ibuf) {
}
return (ret);
}
static int
{
if (fcoeio->fcoeio_olen) {
if (ddi_copyout(obuf,
(void *)(unsigned long)fcoeio->fcoeio_obuf,
return (EFAULT);
}
}
return (EFAULT);
}
return (0);
}
static int
{
int ret;
if (ret != 0) {
goto fcoeiocmd_release_buf;
}
/*
* If an exclusive open was demanded during open, ensure that
* only one thread can execute an ioctl at a time
*/
goto fcoeiocmd_release_buf;
}
}
fcoeio->fcoeio_status = 0;
switch (fcoeio->fcoeio_cmd) {
case FCOEIO_CREATE_FCOE_PORT: {
int cmpwwn = 0;
if (fcoeio->fcoeio_ilen !=
sizeof (fcoeio_create_port_param_t) ||
break;
}
break;
}
break;
} else {
&fcoeio->fcoeio_status);
if (ret != 0) {
if (fcoeio->fcoeio_status == 0) {
}
break;
} else {
}
}
/*
* Provide PWWN and NWWN based on mac address
*/
if (!param->fcp_pwwn_provided) {
} else {
}
if (!param->fcp_nwwn_provided) {
fcoe_mac->fm_current_addr, 0, 0);
} else {
}
if (cmpwwn != 0) {
if (cmpwwn == 1) {
} else if (cmpwwn == -1) {
}
(void) fcoe_close_mac(fcoe_mac);
break;
}
if (ret == 0) {
if (ret != 0) {
(void) fcoe_close_mac(fcoe_mac);
}
}
break;
}
case FCOEIO_DELETE_FCOE_PORT: {
break;
}
if (ret != 0) {
FCOE_LOG("fcoe",
"fcoe_delete_port failed: %d", ret);
}
break;
}
case FCOEIO_GET_FCOE_PORT_LIST: {
int count;
break;
}
sizeof (fcoe_port_list_t))/sizeof (fcoe_port_instance_t);
}
break;
}
default:
return (ENOTTY);
}
if (ret == 0) {
} else if (fcoeio->fcoeio_status) {
}
}
}
}
return (ret);
}
/*
* Finish final initialization
*/
static int
{
char taskq_name[TASKQ_NAME_LEN];
return (FCOE_FAILURE);
}
/*
* watchdog responsible for release frame and dispatch events
*/
return (FCOE_FAILURE);
}
ss->ss_ioctl_flags = 0;
delay(10);
}
if (fcoe_nworkers < 1) {
fcoe_nworkers = 4;
}
return (FCOE_SUCCESS);
}
/*
* Finish final uninitialization
*/
static int
{
int ret;
return (FCOE_FAILURE);
}
return (ret);
}
/*
* Stop watchdog
*/
delay(10);
}
}
return (FCOE_SUCCESS);
}
/*
* Return mac instance if it exist, or else return NULL.
*/
{
continue;
}
return (mac);
}
return (NULL);
}
/*
* port wwn will start with 20:..., node wwn will start with 10:...
*/
static void
{
}
/*
* Return fcoe_mac if it exists, otherwise create a new one
*/
static fcoe_mac_t *
{
linkid);
return (mac);
}
return (mac);
}
void
{
}
/*
* raw frame layout:
* ethernet header + vlan header (optional) + FCoE header +
* FC frame + FCoE tailer
*/
/* ARGSUSED */
mblk_t *
{
int err;
/*
* FCFH_SIZE + PADDING_SIZE
*/
return (NULL);
}
}
/*
* We should always zero FC frame header
*/
sizeof (fcoe_fc_frame_header_t));
return (mp);
}
static void
fcoe_watchdog(void *arg)
{
mac->fm_frm_cnt--;
}
}
}
static void
{
uint32_t i;
for (i = 0; i < fcoe_nworkers; i++) {
fcoe_worker_t *w = &fcoe_workers[i];
w->worker_flags &= ~FCOE_WORKER_TERMINATE;
w, DDI_SLEEP);
}
while (fcoe_nworkers_running != fcoe_nworkers) {
delay(10);
}
}
static int
{
uint32_t i;
for (i = 0; i < fcoe_nworkers; i++) {
fcoe_worker_t *w = &fcoe_workers[i];
mutex_enter(&w->worker_lock);
if (w->worker_flags & FCOE_WORKER_STARTED) {
}
mutex_exit(&w->worker_lock);
}
while (fcoe_nworkers_running != 0) {
}
fcoe_workers = NULL;
return (FCOE_SUCCESS);
}
static int
{
}
static void
fcoe_worker_frame(void *arg)
{
int ret;
mutex_enter(&w->worker_lock);
while ((w->worker_flags & FCOE_WORKER_TERMINATE) == 0) {
/*
* loop through the frames
*/
mutex_exit(&w->worker_lock);
/*
* do the checksum
*/
if (ret == FCOE_SUCCESS) {
} else {
}
mutex_enter(&w->worker_lock);
w->worker_ntasks--;
}
w->worker_flags &= ~FCOE_WORKER_ACTIVE;
w->worker_flags |= FCOE_WORKER_ACTIVE;
}
mutex_exit(&w->worker_lock);
list_destroy(&w->worker_frm_list);
}
void
{
fcoe_worker_t *w;
mutex_enter(&w->worker_lock);
w->worker_ntasks++;
if ((w->worker_flags & FCOE_WORKER_ACTIVE) == 0) {
}
mutex_exit(&w->worker_lock);
}
/*
* The max length of every LOG is 158
*/
void
{
char tbuf[160];
int len;
if (fcoe_trace_on == 0) {
return;
}
curclock = ddi_get_lbolt();
curclock, (ident ? ident : "unknown"));
if (len > 158) {
len = 158;
}
}
}
/*
* Check whether the pwwn or nwwn already exist or not
* Return value:
* 1: PWWN conflicted
* -1: NWWN conflicted
* 0: No conflict
*/
static int
{
if (mac == checkedmac) {
continue;
}
return (-1);
}
return (1);
}
}
return (0);
}
static int
{
int i = 0;
if (i < count) {
ports[i].fpi_port_type =
ports[i].fpi_mtu_size =
ports[i].fpi_mac_promisc =
}
i++;
}
return (i);
}