Commit 5df6d737 authored by Abhijeet Joglekar's avatar Abhijeet Joglekar Committed by James Bottomley

[SCSI] fnic: Add new Cisco PCI-Express FCoE HBA

fnic is a driver for the Cisco PCI-Express FCoE HBA
Signed-off-by: default avatarAbhijeet Joglekar <abjoglek@cisco.com>
Signed-off-by: default avatarJoe Eykholt <jeykholt@cisco.com>
Signed-off-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 210af919
...@@ -1431,6 +1431,14 @@ P: Russell King ...@@ -1431,6 +1431,14 @@ P: Russell King
M: linux@arm.linux.org.uk M: linux@arm.linux.org.uk
F: include/linux/clk.h F: include/linux/clk.h
CISCO FCOE HBA DRIVER
P: Abhijeet Joglekar
M: abjoglek@cisco.com
P: Joe Eykholt
M: jeykholt@cisco.com
L: linux-scsi@vger.kernel.org
S: Supported
CODA FILE SYSTEM CODA FILE SYSTEM
P: Jan Harkes P: Jan Harkes
M: jaharkes@cs.cmu.edu M: jaharkes@cs.cmu.edu
......
...@@ -628,6 +628,17 @@ config FCOE ...@@ -628,6 +628,17 @@ config FCOE
---help--- ---help---
Fibre Channel over Ethernet module Fibre Channel over Ethernet module
config FCOE_FNIC
tristate "Cisco FNIC Driver"
depends on PCI && X86
select LIBFC
help
This is support for the Cisco PCI-Express FCoE HBA.
To compile this driver as a module, choose M here and read
<file:Documentation/scsi/scsi.txt>.
The module will be called fnic.
config SCSI_DMX3191D config SCSI_DMX3191D
tristate "DMX3191D SCSI support" tristate "DMX3191D SCSI support"
depends on PCI && SCSI depends on PCI && SCSI
......
...@@ -39,6 +39,7 @@ obj-$(CONFIG_SCSI_DH) += device_handler/ ...@@ -39,6 +39,7 @@ obj-$(CONFIG_SCSI_DH) += device_handler/
obj-$(CONFIG_LIBFC) += libfc/ obj-$(CONFIG_LIBFC) += libfc/
obj-$(CONFIG_LIBFCOE) += fcoe/ obj-$(CONFIG_LIBFCOE) += fcoe/
obj-$(CONFIG_FCOE) += fcoe/ obj-$(CONFIG_FCOE) += fcoe/
obj-$(CONFIG_FCOE_FNIC) += fnic/
obj-$(CONFIG_ISCSI_TCP) += libiscsi.o libiscsi_tcp.o iscsi_tcp.o obj-$(CONFIG_ISCSI_TCP) += libiscsi.o libiscsi_tcp.o iscsi_tcp.o
obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o
......
obj-$(CONFIG_FCOE_FNIC) += fnic.o
fnic-y := \
fnic_attrs.o \
fnic_isr.o \
fnic_main.o \
fnic_res.o \
fnic_fcs.o \
fnic_scsi.o \
vnic_cq.o \
vnic_dev.o \
vnic_intr.o \
vnic_rq.o \
vnic_wq_copy.o \
vnic_wq.o
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _CQ_DESC_H_
#define _CQ_DESC_H_
/*
* Completion queue descriptor types
*/
enum cq_desc_types {
CQ_DESC_TYPE_WQ_ENET = 0,
CQ_DESC_TYPE_DESC_COPY = 1,
CQ_DESC_TYPE_WQ_EXCH = 2,
CQ_DESC_TYPE_RQ_ENET = 3,
CQ_DESC_TYPE_RQ_FCP = 4,
};
/* Completion queue descriptor: 16B
*
* All completion queues have this basic layout. The
* type_specfic area is unique for each completion
* queue type.
*/
struct cq_desc {
__le16 completed_index;
__le16 q_number;
u8 type_specfic[11];
u8 type_color;
};
#define CQ_DESC_TYPE_BITS 4
#define CQ_DESC_TYPE_MASK ((1 << CQ_DESC_TYPE_BITS) - 1)
#define CQ_DESC_COLOR_MASK 1
#define CQ_DESC_COLOR_SHIFT 7
#define CQ_DESC_Q_NUM_BITS 10
#define CQ_DESC_Q_NUM_MASK ((1 << CQ_DESC_Q_NUM_BITS) - 1)
#define CQ_DESC_COMP_NDX_BITS 12
#define CQ_DESC_COMP_NDX_MASK ((1 << CQ_DESC_COMP_NDX_BITS) - 1)
static inline void cq_desc_dec(const struct cq_desc *desc_arg,
u8 *type, u8 *color, u16 *q_number, u16 *completed_index)
{
const struct cq_desc *desc = desc_arg;
const u8 type_color = desc->type_color;
*color = (type_color >> CQ_DESC_COLOR_SHIFT) & CQ_DESC_COLOR_MASK;
/*
* Make sure color bit is read from desc *before* other fields
* are read from desc. Hardware guarantees color bit is last
* bit (byte) written. Adding the rmb() prevents the compiler
* and/or CPU from reordering the reads which would potentially
* result in reading stale values.
*/
rmb();
*type = type_color & CQ_DESC_TYPE_MASK;
*q_number = le16_to_cpu(desc->q_number) & CQ_DESC_Q_NUM_MASK;
*completed_index = le16_to_cpu(desc->completed_index) &
CQ_DESC_COMP_NDX_MASK;
}
#endif /* _CQ_DESC_H_ */
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _CQ_ENET_DESC_H_
#define _CQ_ENET_DESC_H_
#include "cq_desc.h"
/* Ethernet completion queue descriptor: 16B */
struct cq_enet_wq_desc {
__le16 completed_index;
__le16 q_number;
u8 reserved[11];
u8 type_color;
};
static inline void cq_enet_wq_desc_dec(struct cq_enet_wq_desc *desc,
u8 *type, u8 *color, u16 *q_number, u16 *completed_index)
{
cq_desc_dec((struct cq_desc *)desc, type,
color, q_number, completed_index);
}
/* Completion queue descriptor: Ethernet receive queue, 16B */
struct cq_enet_rq_desc {
__le16 completed_index_flags;
__le16 q_number_rss_type_flags;
__le32 rss_hash;
__le16 bytes_written_flags;
__le16 vlan;
__le16 checksum_fcoe;
u8 flags;
u8 type_color;
};
#define CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT (0x1 << 12)
#define CQ_ENET_RQ_DESC_FLAGS_FCOE (0x1 << 13)
#define CQ_ENET_RQ_DESC_FLAGS_EOP (0x1 << 14)
#define CQ_ENET_RQ_DESC_FLAGS_SOP (0x1 << 15)
#define CQ_ENET_RQ_DESC_RSS_TYPE_BITS 4
#define CQ_ENET_RQ_DESC_RSS_TYPE_MASK \
((1 << CQ_ENET_RQ_DESC_RSS_TYPE_BITS) - 1)
#define CQ_ENET_RQ_DESC_RSS_TYPE_NONE 0
#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv4 1
#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv4 2
#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6 3
#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6 4
#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6_EX 5
#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6_EX 6
#define CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC (0x1 << 14)
#define CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS 14
#define CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK \
((1 << CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS) - 1)
#define CQ_ENET_RQ_DESC_FLAGS_TRUNCATED (0x1 << 14)
#define CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED (0x1 << 15)
#define CQ_ENET_RQ_DESC_FCOE_SOF_BITS 4
#define CQ_ENET_RQ_DESC_FCOE_SOF_MASK \
((1 << CQ_ENET_RQ_DESC_FCOE_SOF_BITS) - 1)
#define CQ_ENET_RQ_DESC_FCOE_EOF_BITS 8
#define CQ_ENET_RQ_DESC_FCOE_EOF_MASK \
((1 << CQ_ENET_RQ_DESC_FCOE_EOF_BITS) - 1)
#define CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT 8
#define CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK (0x1 << 0)
#define CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK (0x1 << 0)
#define CQ_ENET_RQ_DESC_FLAGS_UDP (0x1 << 1)
#define CQ_ENET_RQ_DESC_FCOE_ENC_ERROR (0x1 << 1)
#define CQ_ENET_RQ_DESC_FLAGS_TCP (0x1 << 2)
#define CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK (0x1 << 3)
#define CQ_ENET_RQ_DESC_FLAGS_IPV6 (0x1 << 4)
#define CQ_ENET_RQ_DESC_FLAGS_IPV4 (0x1 << 5)
#define CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT (0x1 << 6)
#define CQ_ENET_RQ_DESC_FLAGS_FCS_OK (0x1 << 7)
static inline void cq_enet_rq_desc_dec(struct cq_enet_rq_desc *desc,
u8 *type, u8 *color, u16 *q_number, u16 *completed_index,
u8 *ingress_port, u8 *fcoe, u8 *eop, u8 *sop, u8 *rss_type,
u8 *csum_not_calc, u32 *rss_hash, u16 *bytes_written, u8 *packet_error,
u8 *vlan_stripped, u16 *vlan, u16 *checksum, u8 *fcoe_sof,
u8 *fcoe_fc_crc_ok, u8 *fcoe_enc_error, u8 *fcoe_eof,
u8 *tcp_udp_csum_ok, u8 *udp, u8 *tcp, u8 *ipv4_csum_ok,
u8 *ipv6, u8 *ipv4, u8 *ipv4_fragment, u8 *fcs_ok)
{
u16 completed_index_flags = le16_to_cpu(desc->completed_index_flags);
u16 q_number_rss_type_flags =
le16_to_cpu(desc->q_number_rss_type_flags);
u16 bytes_written_flags = le16_to_cpu(desc->bytes_written_flags);
cq_desc_dec((struct cq_desc *)desc, type,
color, q_number, completed_index);
*ingress_port = (completed_index_flags &
CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT) ? 1 : 0;
*fcoe = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_FCOE) ?
1 : 0;
*eop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_EOP) ?
1 : 0;
*sop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_SOP) ?
1 : 0;
*rss_type = (u8)((q_number_rss_type_flags >> CQ_DESC_Q_NUM_BITS) &
CQ_ENET_RQ_DESC_RSS_TYPE_MASK);
*csum_not_calc = (q_number_rss_type_flags &
CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC) ? 1 : 0;
*rss_hash = le32_to_cpu(desc->rss_hash);
*bytes_written = bytes_written_flags &
CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK;
*packet_error = (bytes_written_flags &
CQ_ENET_RQ_DESC_FLAGS_TRUNCATED) ? 1 : 0;
*vlan_stripped = (bytes_written_flags &
CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED) ? 1 : 0;
*vlan = le16_to_cpu(desc->vlan);
if (*fcoe) {
*fcoe_sof = (u8)(le16_to_cpu(desc->checksum_fcoe) &
CQ_ENET_RQ_DESC_FCOE_SOF_MASK);
*fcoe_fc_crc_ok = (desc->flags &
CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK) ? 1 : 0;
*fcoe_enc_error = (desc->flags &
CQ_ENET_RQ_DESC_FCOE_ENC_ERROR) ? 1 : 0;
*fcoe_eof = (u8)((desc->checksum_fcoe >>
CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT) &
CQ_ENET_RQ_DESC_FCOE_EOF_MASK);
*checksum = 0;
} else {
*fcoe_sof = 0;
*fcoe_fc_crc_ok = 0;
*fcoe_enc_error = 0;
*fcoe_eof = 0;
*checksum = le16_to_cpu(desc->checksum_fcoe);
}
*tcp_udp_csum_ok =
(desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK) ? 1 : 0;
*udp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_UDP) ? 1 : 0;
*tcp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP) ? 1 : 0;
*ipv4_csum_ok =
(desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK) ? 1 : 0;
*ipv6 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV6) ? 1 : 0;
*ipv4 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4) ? 1 : 0;
*ipv4_fragment =
(desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT) ? 1 : 0;
*fcs_ok = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_FCS_OK) ? 1 : 0;
}
#endif /* _CQ_ENET_DESC_H_ */
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _CQ_EXCH_DESC_H_
#define _CQ_EXCH_DESC_H_
#include "cq_desc.h"
/* Exchange completion queue descriptor: 16B */
struct cq_exch_wq_desc {
u16 completed_index;
u16 q_number;
u16 exchange_id;
u8 tmpl;
u8 reserved0;
u32 reserved1;
u8 exch_status;
u8 reserved2[2];
u8 type_color;
};
#define CQ_EXCH_WQ_STATUS_BITS 2
#define CQ_EXCH_WQ_STATUS_MASK ((1 << CQ_EXCH_WQ_STATUS_BITS) - 1)
enum cq_exch_status_types {
CQ_EXCH_WQ_STATUS_TYPE_COMPLETE = 0,
CQ_EXCH_WQ_STATUS_TYPE_ABORT = 1,
CQ_EXCH_WQ_STATUS_TYPE_SGL_EOF = 2,
CQ_EXCH_WQ_STATUS_TYPE_TMPL_ERR = 3,
};
static inline void cq_exch_wq_desc_dec(struct cq_exch_wq_desc *desc_ptr,
u8 *type,
u8 *color,
u16 *q_number,
u16 *completed_index,
u8 *exch_status)
{
cq_desc_dec((struct cq_desc *)desc_ptr, type,
color, q_number, completed_index);
*exch_status = desc_ptr->exch_status & CQ_EXCH_WQ_STATUS_MASK;
}
struct cq_fcp_rq_desc {
u16 completed_index_eop_sop_prt;
u16 q_number;
u16 exchange_id;
u16 tmpl;
u16 bytes_written;
u16 vlan;
u8 sof;
u8 eof;
u8 fcs_fer_fck;
u8 type_color;
};
#define CQ_FCP_RQ_DESC_FLAGS_SOP (1 << 15)
#define CQ_FCP_RQ_DESC_FLAGS_EOP (1 << 14)
#define CQ_FCP_RQ_DESC_FLAGS_PRT (1 << 12)
#define CQ_FCP_RQ_DESC_TMPL_MASK 0x1f
#define CQ_FCP_RQ_DESC_BYTES_WRITTEN_MASK 0x3fff
#define CQ_FCP_RQ_DESC_PACKET_ERR_SHIFT 14
#define CQ_FCP_RQ_DESC_PACKET_ERR_MASK (1 << CQ_FCP_RQ_DESC_PACKET_ERR_SHIFT)
#define CQ_FCP_RQ_DESC_VS_STRIPPED_SHIFT 15
#define CQ_FCP_RQ_DESC_VS_STRIPPED_MASK (1 << CQ_FCP_RQ_DESC_VS_STRIPPED_SHIFT)
#define CQ_FCP_RQ_DESC_FC_CRC_OK_MASK 0x1
#define CQ_FCP_RQ_DESC_FCOE_ERR_SHIFT 1
#define CQ_FCP_RQ_DESC_FCOE_ERR_MASK (1 << CQ_FCP_RQ_DESC_FCOE_ERR_SHIFT)
#define CQ_FCP_RQ_DESC_FCS_OK_SHIFT 7
#define CQ_FCP_RQ_DESC_FCS_OK_MASK (1 << CQ_FCP_RQ_DESC_FCS_OK_SHIFT)
static inline void cq_fcp_rq_desc_dec(struct cq_fcp_rq_desc *desc_ptr,
u8 *type,
u8 *color,
u16 *q_number,
u16 *completed_index,
u8 *eop,
u8 *sop,
u8 *fck,
u16 *exchange_id,
u16 *tmpl,
u32 *bytes_written,
u8 *sof,
u8 *eof,
u8 *ingress_port,
u8 *packet_err,
u8 *fcoe_err,
u8 *fcs_ok,
u8 *vlan_stripped,
u16 *vlan)
{
cq_desc_dec((struct cq_desc *)desc_ptr, type,
color, q_number, completed_index);
*eop = (desc_ptr->completed_index_eop_sop_prt &
CQ_FCP_RQ_DESC_FLAGS_EOP) ? 1 : 0;
*sop = (desc_ptr->completed_index_eop_sop_prt &
CQ_FCP_RQ_DESC_FLAGS_SOP) ? 1 : 0;
*ingress_port =
(desc_ptr->completed_index_eop_sop_prt &
CQ_FCP_RQ_DESC_FLAGS_PRT) ? 1 : 0;
*exchange_id = desc_ptr->exchange_id;
*tmpl = desc_ptr->tmpl & CQ_FCP_RQ_DESC_TMPL_MASK;
*bytes_written =
desc_ptr->bytes_written & CQ_FCP_RQ_DESC_BYTES_WRITTEN_MASK;
*packet_err =
(desc_ptr->bytes_written & CQ_FCP_RQ_DESC_PACKET_ERR_MASK) >>
CQ_FCP_RQ_DESC_PACKET_ERR_SHIFT;
*vlan_stripped =
(desc_ptr->bytes_written & CQ_FCP_RQ_DESC_VS_STRIPPED_MASK) >>
CQ_FCP_RQ_DESC_VS_STRIPPED_SHIFT;
*vlan = desc_ptr->vlan;
*sof = desc_ptr->sof;
*fck = desc_ptr->fcs_fer_fck & CQ_FCP_RQ_DESC_FC_CRC_OK_MASK;
*fcoe_err = (desc_ptr->fcs_fer_fck & CQ_FCP_RQ_DESC_FCOE_ERR_MASK) >>
CQ_FCP_RQ_DESC_FCOE_ERR_SHIFT;
*eof = desc_ptr->eof;
*fcs_ok =
(desc_ptr->fcs_fer_fck & CQ_FCP_RQ_DESC_FCS_OK_MASK) >>
CQ_FCP_RQ_DESC_FCS_OK_SHIFT;
}
struct cq_sgl_desc {
u16 exchange_id;
u16 q_number;
u32 active_burst_offset;
u32 tot_data_bytes;
u16 tmpl;
u8 sgl_err;
u8 type_color;
};
enum cq_sgl_err_types {
CQ_SGL_ERR_NO_ERROR = 0,
CQ_SGL_ERR_OVERFLOW, /* data ran beyond end of SGL */
CQ_SGL_ERR_SGL_LCL_ADDR_ERR, /* sgl access to local vnic addr illegal*/
CQ_SGL_ERR_ADDR_RSP_ERR, /* sgl address error */
CQ_SGL_ERR_DATA_RSP_ERR, /* sgl data rsp error */
CQ_SGL_ERR_CNT_ZERO_ERR, /* SGL count is 0 */
CQ_SGL_ERR_CNT_MAX_ERR, /* SGL count is larger than supported */
CQ_SGL_ERR_ORDER_ERR, /* frames recv on both ports, order err */
CQ_SGL_ERR_DATA_LCL_ADDR_ERR,/* sgl data buf to local vnic addr ill */
CQ_SGL_ERR_HOST_CQ_ERR, /* host cq entry to local vnic addr ill */
};
#define CQ_SGL_SGL_ERR_MASK 0x1f
#define CQ_SGL_TMPL_MASK 0x1f
static inline void cq_sgl_desc_dec(struct cq_sgl_desc *desc_ptr,
u8 *type,
u8 *color,
u16 *q_number,
u16 *exchange_id,
u32 *active_burst_offset,
u32 *tot_data_bytes,
u16 *tmpl,
u8 *sgl_err)
{
/* Cheat a little by assuming exchange_id is the same as completed
index */
cq_desc_dec((struct cq_desc *)desc_ptr, type, color, q_number,
exchange_id);
*active_burst_offset = desc_ptr->active_burst_offset;
*tot_data_bytes = desc_ptr->tot_data_bytes;
*tmpl = desc_ptr->tmpl & CQ_SGL_TMPL_MASK;
*sgl_err = desc_ptr->sgl_err & CQ_SGL_SGL_ERR_MASK;
}
#endif /* _CQ_EXCH_DESC_H_ */
This diff is collapsed.
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _FNIC_H_
#define _FNIC_H_
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/workqueue.h>
#include <scsi/libfc.h>
#include "fnic_io.h"
#include "fnic_res.h"
#include "vnic_dev.h"
#include "vnic_wq.h"
#include "vnic_rq.h"
#include "vnic_cq.h"
#include "vnic_wq_copy.h"
#include "vnic_intr.h"
#include "vnic_stats.h"
#include "vnic_scsi.h"
#define DRV_NAME "fnic"
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
#define DRV_VERSION "1.0.0.1121"
#define PFX DRV_NAME ": "
#define DFX DRV_NAME "%d: "
#define DESC_CLEAN_LOW_WATERMARK 8
#define FNIC_MAX_IO_REQ 2048 /* scsi_cmnd tag map entries */
#define FNIC_IO_LOCKS 64 /* IO locks: power of 2 */
#define FNIC_DFLT_QUEUE_DEPTH 32
#define FNIC_STATS_RATE_LIMIT 4 /* limit rate at which stats are pulled up */
/*
* Tag bits used for special requests.
*/
#define BIT(nr) (1UL << (nr))
#define FNIC_TAG_ABORT BIT(30) /* tag bit indicating abort */
#define FNIC_TAG_DEV_RST BIT(29) /* indicates device reset */
#define FNIC_TAG_MASK (BIT(24) - 1) /* mask for lookup */
#define FNIC_NO_TAG -1
/*
* Usage of the scsi_cmnd scratchpad.
* These fields are locked by the hashed io_req_lock.
*/
#define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr)
#define CMD_STATE(Cmnd) ((Cmnd)->SCp.phase)
#define CMD_ABTS_STATUS(Cmnd) ((Cmnd)->SCp.Message)
#define CMD_LR_STATUS(Cmnd) ((Cmnd)->SCp.have_data_in)
#define CMD_TAG(Cmnd) ((Cmnd)->SCp.sent_command)
#define FCPIO_INVALID_CODE 0x100 /* hdr_status value unused by firmware */
#define FNIC_LUN_RESET_TIMEOUT 10000 /* mSec */
#define FNIC_HOST_RESET_TIMEOUT 10000 /* mSec */
#define FNIC_RMDEVICE_TIMEOUT 1000 /* mSec */
#define FNIC_HOST_RESET_SETTLE_TIME 30 /* Sec */
#define FNIC_MAX_FCP_TARGET 256
extern unsigned int fnic_log_level;
#define FNIC_MAIN_LOGGING 0x01
#define FNIC_FCS_LOGGING 0x02
#define FNIC_SCSI_LOGGING 0x04
#define FNIC_ISR_LOGGING 0x08
#define FNIC_CHECK_LOGGING(LEVEL, CMD) \
do { \
if (unlikely(fnic_log_level & LEVEL)) \
do { \
CMD; \
} while (0); \
} while (0)
#define FNIC_MAIN_DBG(kern_level, host, fmt, args...) \
FNIC_CHECK_LOGGING(FNIC_MAIN_LOGGING, \
shost_printk(kern_level, host, fmt, ##args);)
#define FNIC_FCS_DBG(kern_level, host, fmt, args...) \
FNIC_CHECK_LOGGING(FNIC_FCS_LOGGING, \
shost_printk(kern_level, host, fmt, ##args);)
#define FNIC_SCSI_DBG(kern_level, host, fmt, args...) \
FNIC_CHECK_LOGGING(FNIC_SCSI_LOGGING, \
shost_printk(kern_level, host, fmt, ##args);)
#define FNIC_ISR_DBG(kern_level, host, fmt, args...) \
FNIC_CHECK_LOGGING(FNIC_ISR_LOGGING, \
shost_printk(kern_level, host, fmt, ##args);)
extern const char *fnic_state_str[];
enum fnic_intx_intr_index {
FNIC_INTX_WQ_RQ_COPYWQ,
FNIC_INTX_ERR,
FNIC_INTX_NOTIFY,
FNIC_INTX_INTR_MAX,
};
enum fnic_msix_intr_index {
FNIC_MSIX_RQ,
FNIC_MSIX_WQ,
FNIC_MSIX_WQ_COPY,
FNIC_MSIX_ERR_NOTIFY,
FNIC_MSIX_INTR_MAX,
};
struct fnic_msix_entry {
int requested;
char devname[IFNAMSIZ];
irqreturn_t (*isr)(int, void *);
void *devid;
};
enum fnic_state {
FNIC_IN_FC_MODE = 0,
FNIC_IN_FC_TRANS_ETH_MODE,
FNIC_IN_ETH_MODE,
FNIC_IN_ETH_TRANS_FC_MODE,
};
#define FNIC_WQ_COPY_MAX 1
#define FNIC_WQ_MAX 1
#define FNIC_RQ_MAX 1
#define FNIC_CQ_MAX (FNIC_WQ_COPY_MAX + FNIC_WQ_MAX + FNIC_RQ_MAX)
struct mempool;
/* Per-instance private data structure */
struct fnic {
struct fc_lport *lport;
struct vnic_dev_bar bar0;
struct msix_entry msix_entry[FNIC_MSIX_INTR_MAX];
struct fnic_msix_entry msix[FNIC_MSIX_INTR_MAX];
struct vnic_stats *stats;
unsigned long stats_time; /* time of stats update */
struct vnic_nic_cfg *nic_cfg;
char name[IFNAMSIZ];
struct timer_list notify_timer; /* used for MSI interrupts */
unsigned int err_intr_offset;
unsigned int link_intr_offset;
unsigned int wq_count;
unsigned int cq_count;
u32 fcoui_mode:1; /* use fcoui address*/
u32 vlan_hw_insert:1; /* let hw insert the tag */
u32 in_remove:1; /* fnic device in removal */
u32 stop_rx_link_events:1; /* stop proc. rx frames, link events */
struct completion *remove_wait; /* device remove thread blocks */
struct fc_frame *flogi;
struct fc_frame *flogi_resp;
u16 flogi_oxid;
unsigned long s_id;
enum fnic_state state;
spinlock_t fnic_lock;
u16 vlan_id; /* VLAN tag including priority */
u8 mac_addr[ETH_ALEN];
u8 dest_addr[ETH_ALEN];
u8 data_src_addr[ETH_ALEN];
u64 fcp_input_bytes; /* internal statistic */
u64 fcp_output_bytes; /* internal statistic */
u32 link_down_cnt;
int link_status;
struct list_head list;
struct pci_dev *pdev;
struct vnic_fc_config config;
struct vnic_dev *vdev;
unsigned int raw_wq_count;
unsigned int wq_copy_count;
unsigned int rq_count;
int fw_ack_index[FNIC_WQ_COPY_MAX];
unsigned short fw_ack_recd[FNIC_WQ_COPY_MAX];
unsigned short wq_copy_desc_low[FNIC_WQ_COPY_MAX];
unsigned int intr_count;
u32 __iomem *legacy_pba;
struct fnic_host_tag *tags;
mempool_t *io_req_pool;
mempool_t *io_sgl_pool[FNIC_SGL_NUM_CACHES];
spinlock_t io_req_lock[FNIC_IO_LOCKS]; /* locks for scsi cmnds */
struct work_struct link_work;
struct work_struct frame_work;
struct sk_buff_head frame_queue;
/* copy work queue cache line section */
____cacheline_aligned struct vnic_wq_copy wq_copy[FNIC_WQ_COPY_MAX];
/* completion queue cache line section */
____cacheline_aligned struct vnic_cq cq[FNIC_CQ_MAX];
spinlock_t wq_copy_lock[FNIC_WQ_COPY_MAX];
/* work queue cache line section */
____cacheline_aligned struct vnic_wq wq[FNIC_WQ_MAX];
spinlock_t wq_lock[FNIC_WQ_MAX];
/* receive queue cache line section */
____cacheline_aligned struct vnic_rq rq[FNIC_RQ_MAX];
/* interrupt resource cache line section */
____cacheline_aligned struct vnic_intr intr[FNIC_MSIX_INTR_MAX];
};
extern struct workqueue_struct *fnic_event_queue;
extern struct device_attribute *fnic_attrs[];
void fnic_clear_intr_mode(struct fnic *fnic);
int fnic_set_intr_mode(struct fnic *fnic);
void fnic_free_intr(struct fnic *fnic);
int fnic_request_intr(struct fnic *fnic);
int fnic_send(struct fc_lport *, struct fc_frame *);
void fnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf);
void fnic_handle_frame(struct work_struct *work);
void fnic_handle_link(struct work_struct *work);
int fnic_rq_cmpl_handler(struct fnic *fnic, int);
int fnic_alloc_rq_frame(struct vnic_rq *rq);
void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf);
int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp);
int fnic_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
int fnic_abort_cmd(struct scsi_cmnd *);
int fnic_device_reset(struct scsi_cmnd *);
int fnic_host_reset(struct scsi_cmnd *);
int fnic_reset(struct Scsi_Host *);
void fnic_scsi_cleanup(struct fc_lport *);
void fnic_scsi_abort_io(struct fc_lport *);
void fnic_empty_scsi_cleanup(struct fc_lport *);
void fnic_exch_mgr_reset(struct fc_lport *, u32, u32);
int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int);
int fnic_wq_cmpl_handler(struct fnic *fnic, int);
int fnic_flogi_reg_handler(struct fnic *fnic);
void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq,
struct fcpio_host_req *desc);
int fnic_fw_reset_handler(struct fnic *fnic);
void fnic_terminate_rport_io(struct fc_rport *);
const char *fnic_state_to_str(unsigned int state);
void fnic_log_q_error(struct fnic *fnic);
void fnic_handle_link_event(struct fnic *fnic);
#endif /* _FNIC_H_ */
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/string.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include "fnic.h"
static ssize_t fnic_show_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct fc_lport *lp = shost_priv(class_to_shost(dev));
struct fnic *fnic = lport_priv(lp);
return snprintf(buf, PAGE_SIZE, "%s\n", fnic_state_str[fnic->state]);
}
static ssize_t fnic_show_drv_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", DRV_VERSION);
}
static ssize_t fnic_show_link_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct fc_lport *lp = shost_priv(class_to_shost(dev));
return snprintf(buf, PAGE_SIZE, "%s\n", (lp->link_up)
? "Link Up" : "Link Down");
}
static DEVICE_ATTR(fnic_state, S_IRUGO, fnic_show_state, NULL);
static DEVICE_ATTR(drv_version, S_IRUGO, fnic_show_drv_version, NULL);
static DEVICE_ATTR(link_state, S_IRUGO, fnic_show_link_state, NULL);
struct device_attribute *fnic_attrs[] = {
&dev_attr_fnic_state,
&dev_attr_drv_version,
&dev_attr_link_state,
NULL,
};
This diff is collapsed.
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _FNIC_IO_H_
#define _FNIC_IO_H_
#include <scsi/fc/fc_fcp.h>
#define FNIC_DFLT_SG_DESC_CNT 32
#define FNIC_MAX_SG_DESC_CNT 1024 /* Maximum descriptors per sgl */
#define FNIC_SG_DESC_ALIGN 16 /* Descriptor address alignment */
struct host_sg_desc {
__le64 addr;
__le32 len;
u32 _resvd;
};
struct fnic_dflt_sgl_list {
struct host_sg_desc sg_desc[FNIC_DFLT_SG_DESC_CNT];
};
struct fnic_sgl_list {
struct host_sg_desc sg_desc[FNIC_MAX_SG_DESC_CNT];
};
enum fnic_sgl_list_type {
FNIC_SGL_CACHE_DFLT = 0, /* cache with default size sgl */
FNIC_SGL_CACHE_MAX, /* cache with max size sgl */
FNIC_SGL_NUM_CACHES /* number of sgl caches */
};
enum fnic_ioreq_state {
FNIC_IOREQ_CMD_PENDING = 0,
FNIC_IOREQ_ABTS_PENDING,
FNIC_IOREQ_ABTS_COMPLETE,
FNIC_IOREQ_CMD_COMPLETE,
};
struct fnic_io_req {
struct host_sg_desc *sgl_list; /* sgl list */
void *sgl_list_alloc; /* sgl list address used for free */
dma_addr_t sense_buf_pa; /* dma address for sense buffer*/
dma_addr_t sgl_list_pa; /* dma address for sgl list */
u16 sgl_cnt;
u8 sgl_type; /* device DMA descriptor list type */
u8 io_completed:1; /* set to 1 when fw completes IO */
u32 port_id; /* remote port DID */
struct completion *abts_done; /* completion for abts */
struct completion *dr_done; /* completion for device reset */
};
#endif /* _FNIC_IO_H_ */
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <scsi/libfc.h>
#include <scsi/fc_frame.h>
#include "vnic_dev.h"
#include "vnic_intr.h"
#include "vnic_stats.h"
#include "fnic_io.h"
#include "fnic.h"
static irqreturn_t fnic_isr_legacy(int irq, void *data)
{
struct fnic *fnic = data;
u32 pba;
unsigned long work_done = 0;
pba = vnic_intr_legacy_pba(fnic->legacy_pba);
if (!pba)
return IRQ_NONE;
if (pba & (1 << FNIC_INTX_NOTIFY)) {
vnic_intr_return_all_credits(&fnic->intr[FNIC_INTX_NOTIFY]);
fnic_handle_link_event(fnic);
}
if (pba & (1 << FNIC_INTX_ERR)) {
vnic_intr_return_all_credits(&fnic->intr[FNIC_INTX_ERR]);
fnic_log_q_error(fnic);
}
if (pba & (1 << FNIC_INTX_WQ_RQ_COPYWQ)) {
work_done += fnic_wq_copy_cmpl_handler(fnic, 8);
work_done += fnic_wq_cmpl_handler(fnic, 4);
work_done += fnic_rq_cmpl_handler(fnic, 4);
vnic_intr_return_credits(&fnic->intr[FNIC_INTX_WQ_RQ_COPYWQ],
work_done,
1 /* unmask intr */,
1 /* reset intr timer */);
}
return IRQ_HANDLED;
}
static irqreturn_t fnic_isr_msi(int irq, void *data)
{
struct fnic *fnic = data;
unsigned long work_done = 0;
work_done += fnic_wq_copy_cmpl_handler(fnic, 8);
work_done += fnic_wq_cmpl_handler(fnic, 4);
work_done += fnic_rq_cmpl_handler(fnic, 4);
vnic_intr_return_credits(&fnic->intr[0],
work_done,
1 /* unmask intr */,
1 /* reset intr timer */);
return IRQ_HANDLED;
}
static irqreturn_t fnic_isr_msix_rq(int irq, void *data)
{
struct fnic *fnic = data;
unsigned long rq_work_done = 0;
rq_work_done = fnic_rq_cmpl_handler(fnic, 4);
vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_RQ],
rq_work_done,
1 /* unmask intr */,
1 /* reset intr timer */);
return IRQ_HANDLED;
}
static irqreturn_t fnic_isr_msix_wq(int irq, void *data)
{
struct fnic *fnic = data;
unsigned long wq_work_done = 0;
wq_work_done = fnic_wq_cmpl_handler(fnic, 4);
vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_WQ],
wq_work_done,
1 /* unmask intr */,
1 /* reset intr timer */);
return IRQ_HANDLED;
}
static irqreturn_t fnic_isr_msix_wq_copy(int irq, void *data)
{
struct fnic *fnic = data;
unsigned long wq_copy_work_done = 0;
wq_copy_work_done = fnic_wq_copy_cmpl_handler(fnic, 8);
vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_WQ_COPY],
wq_copy_work_done,
1 /* unmask intr */,
1 /* reset intr timer */);
return IRQ_HANDLED;
}
static irqreturn_t fnic_isr_msix_err_notify(int irq, void *data)
{
struct fnic *fnic = data;
vnic_intr_return_all_credits(&fnic->intr[FNIC_MSIX_ERR_NOTIFY]);
fnic_log_q_error(fnic);
fnic_handle_link_event(fnic);
return IRQ_HANDLED;
}
void fnic_free_intr(struct fnic *fnic)
{
int i;
switch (vnic_dev_get_intr_mode(fnic->vdev)) {
case VNIC_DEV_INTR_MODE_INTX:
case VNIC_DEV_INTR_MODE_MSI:
free_irq(fnic->pdev->irq, fnic);
break;
case VNIC_DEV_INTR_MODE_MSIX:
for (i = 0; i < ARRAY_SIZE(fnic->msix); i++)
if (fnic->msix[i].requested)
free_irq(fnic->msix_entry[i].vector,
fnic->msix[i].devid);
break;
default:
break;
}
}
int fnic_request_intr(struct fnic *fnic)
{
int err = 0;
int i;
switch (vnic_dev_get_intr_mode(fnic->vdev)) {
case VNIC_DEV_INTR_MODE_INTX:
err = request_irq(fnic->pdev->irq, &fnic_isr_legacy,
IRQF_SHARED, DRV_NAME, fnic);
break;
case VNIC_DEV_INTR_MODE_MSI:
err = request_irq(fnic->pdev->irq, &fnic_isr_msi,
0, fnic->name, fnic);
break;
case VNIC_DEV_INTR_MODE_MSIX:
sprintf(fnic->msix[FNIC_MSIX_RQ].devname,
"%.11s-fcs-rq", fnic->name);
fnic->msix[FNIC_MSIX_RQ].isr = fnic_isr_msix_rq;
fnic->msix[FNIC_MSIX_RQ].devid = fnic;
sprintf(fnic->msix[FNIC_MSIX_WQ].devname,
"%.11s-fcs-wq", fnic->name);
fnic->msix[FNIC_MSIX_WQ].isr = fnic_isr_msix_wq;
fnic->msix[FNIC_MSIX_WQ].devid = fnic;
sprintf(fnic->msix[FNIC_MSIX_WQ_COPY].devname,
"%.11s-scsi-wq", fnic->name);
fnic->msix[FNIC_MSIX_WQ_COPY].isr = fnic_isr_msix_wq_copy;
fnic->msix[FNIC_MSIX_WQ_COPY].devid = fnic;
sprintf(fnic->msix[FNIC_MSIX_ERR_NOTIFY].devname,
"%.11s-err-notify", fnic->name);
fnic->msix[FNIC_MSIX_ERR_NOTIFY].isr =
fnic_isr_msix_err_notify;
fnic->msix[FNIC_MSIX_ERR_NOTIFY].devid = fnic;
for (i = 0; i < ARRAY_SIZE(fnic->msix); i++) {
err = request_irq(fnic->msix_entry[i].vector,
fnic->msix[i].isr, 0,
fnic->msix[i].devname,
fnic->msix[i].devid);
if (err) {
shost_printk(KERN_ERR, fnic->lport->host,
"MSIX: request_irq"
" failed %d\n", err);
fnic_free_intr(fnic);
break;
}
fnic->msix[i].requested = 1;
}
break;
default:
break;
}
return err;
}
int fnic_set_intr_mode(struct fnic *fnic)
{
unsigned int n = ARRAY_SIZE(fnic->rq);
unsigned int m = ARRAY_SIZE(fnic->wq);
unsigned int o = ARRAY_SIZE(fnic->wq_copy);
unsigned int i;
/*
* Set interrupt mode (INTx, MSI, MSI-X) depending
* system capabilities.
*
* Try MSI-X first
*
* We need n RQs, m WQs, o Copy WQs, n+m+o CQs, and n+m+o+1 INTRs
* (last INTR is used for WQ/RQ errors and notification area)
*/
BUG_ON(ARRAY_SIZE(fnic->msix_entry) < n + m + o + 1);
for (i = 0; i < n + m + o + 1; i++)
fnic->msix_entry[i].entry = i;
if (fnic->rq_count >= n &&
fnic->raw_wq_count >= m &&
fnic->wq_copy_count >= o &&
fnic->cq_count >= n + m + o) {
if (!pci_enable_msix(fnic->pdev, fnic->msix_entry,
n + m + o + 1)) {
fnic->rq_count = n;
fnic->raw_wq_count = m;
fnic->wq_copy_count = o;
fnic->wq_count = m + o;
fnic->cq_count = n + m + o;
fnic->intr_count = n + m + o + 1;
fnic->err_intr_offset = FNIC_MSIX_ERR_NOTIFY;
FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host,
"Using MSI-X Interrupts\n");
vnic_dev_set_intr_mode(fnic->vdev,
VNIC_DEV_INTR_MODE_MSIX);
return 0;
}
}
/*
* Next try MSI
* We need 1 RQ, 1 WQ, 1 WQ_COPY, 3 CQs, and 1 INTR
*/
if (fnic->rq_count >= 1 &&
fnic->raw_wq_count >= 1 &&
fnic->wq_copy_count >= 1 &&
fnic->cq_count >= 3 &&
fnic->intr_count >= 1 &&
!pci_enable_msi(fnic->pdev)) {
fnic->rq_count = 1;
fnic->raw_wq_count = 1;
fnic->wq_copy_count = 1;
fnic->wq_count = 2;
fnic->cq_count = 3;
fnic->intr_count = 1;
fnic->err_intr_offset = 0;
FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host,
"Using MSI Interrupts\n");
vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_MSI);
return 0;
}
/*
* Next try INTx
* We need 1 RQ, 1 WQ, 1 WQ_COPY, 3 CQs, and 3 INTRs
* 1 INTR is used for all 3 queues, 1 INTR for queue errors
* 1 INTR for notification area
*/
if (fnic->rq_count >= 1 &&
fnic->raw_wq_count >= 1 &&
fnic->wq_copy_count >= 1 &&
fnic->cq_count >= 3 &&
fnic->intr_count >= 3) {
fnic->rq_count = 1;
fnic->raw_wq_count = 1;
fnic->wq_copy_count = 1;
fnic->cq_count = 3;
fnic->intr_count = 3;
FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host,
"Using Legacy Interrupts\n");
vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX);
return 0;
}
vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
return -EINVAL;
}
void fnic_clear_intr_mode(struct fnic *fnic)
{
switch (vnic_dev_get_intr_mode(fnic->vdev)) {
case VNIC_DEV_INTR_MODE_MSIX:
pci_disable_msix(fnic->pdev);
break;
case VNIC_DEV_INTR_MODE_MSI:
pci_disable_msi(fnic->pdev);
break;
default:
break;
}
vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX);
}
This diff is collapsed.
This diff is collapsed.
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _FNIC_RES_H_
#define _FNIC_RES_H_
#include "wq_enet_desc.h"
#include "rq_enet_desc.h"
#include "vnic_wq.h"
#include "vnic_rq.h"
#include "fnic_io.h"
#include "fcpio.h"
#include "vnic_wq_copy.h"
#include "vnic_cq_copy.h"
static inline void fnic_queue_wq_desc(struct vnic_wq *wq,
void *os_buf, dma_addr_t dma_addr,
unsigned int len, unsigned int fc_eof,
int vlan_tag_insert,
unsigned int vlan_tag,
int cq_entry, int sop, int eop)
{
struct wq_enet_desc *desc = vnic_wq_next_desc(wq);
wq_enet_desc_enc(desc,
(u64)dma_addr | VNIC_PADDR_TARGET,
(u16)len,
0, /* mss_or_csum_offset */
(u16)fc_eof,
0, /* offload_mode */
(u8)eop, (u8)cq_entry,
1, /* fcoe_encap */
(u8)vlan_tag_insert,
(u16)vlan_tag,
0 /* loopback */);
vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop);
}
static inline void fnic_queue_wq_copy_desc_icmnd_16(struct vnic_wq_copy *wq,
u32 req_id,
u32 lunmap_id, u8 spl_flags,
u32 sgl_cnt, u32 sense_len,
u64 sgl_addr, u64 sns_addr,
u8 crn, u8 pri_ta,
u8 flags, u8 *scsi_cdb,
u32 data_len, u8 *lun,
u32 d_id, u16 mss,
u32 ratov, u32 edtov)
{
struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq);
desc->hdr.type = FCPIO_ICMND_16; /* enum fcpio_type */
desc->hdr.status = 0; /* header status entry */
desc->hdr._resvd = 0; /* reserved */
desc->hdr.tag.u.req_id = req_id; /* id for this request */
desc->u.icmnd_16.lunmap_id = lunmap_id; /* index into lunmap table */
desc->u.icmnd_16.special_req_flags = spl_flags; /* exch req flags */
desc->u.icmnd_16._resvd0[0] = 0; /* reserved */
desc->u.icmnd_16._resvd0[1] = 0; /* reserved */
desc->u.icmnd_16._resvd0[2] = 0; /* reserved */
desc->u.icmnd_16.sgl_cnt = sgl_cnt; /* scatter-gather list count */
desc->u.icmnd_16.sense_len = sense_len; /* sense buffer length */
desc->u.icmnd_16.sgl_addr = sgl_addr; /* scatter-gather list addr */
desc->u.icmnd_16.sense_addr = sns_addr; /* sense buffer address */
desc->u.icmnd_16.crn = crn; /* SCSI Command Reference No.*/
desc->u.icmnd_16.pri_ta = pri_ta; /* SCSI Pri & Task attribute */
desc->u.icmnd_16._resvd1 = 0; /* reserved: should be 0 */
desc->u.icmnd_16.flags = flags; /* command flags */
memcpy(desc->u.icmnd_16.scsi_cdb, scsi_cdb, CDB_16); /* SCSI CDB */
desc->u.icmnd_16.data_len = data_len; /* length of data expected */
memcpy(desc->u.icmnd_16.lun, lun, LUN_ADDRESS); /* LUN address */
desc->u.icmnd_16._resvd2 = 0; /* reserved */
hton24(desc->u.icmnd_16.d_id, d_id); /* FC vNIC only: Target D_ID */
desc->u.icmnd_16.mss = mss; /* FC vNIC only: max burst */
desc->u.icmnd_16.r_a_tov = ratov; /*FC vNIC only: Res. Alloc Timeout */
desc->u.icmnd_16.e_d_tov = edtov; /*FC vNIC only: Err Detect Timeout */
vnic_wq_copy_post(wq);
}
static inline void fnic_queue_wq_copy_desc_itmf(struct vnic_wq_copy *wq,
u32 req_id, u32 lunmap_id,
u32 tm_req, u32 tm_id, u8 *lun,
u32 d_id, u32 r_a_tov,
u32 e_d_tov)
{
struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq);
desc->hdr.type = FCPIO_ITMF; /* enum fcpio_type */
desc->hdr.status = 0; /* header status entry */
desc->hdr._resvd = 0; /* reserved */
desc->hdr.tag.u.req_id = req_id; /* id for this request */
desc->u.itmf.lunmap_id = lunmap_id; /* index into lunmap table */
desc->u.itmf.tm_req = tm_req; /* SCSI Task Management request */
desc->u.itmf.t_tag = tm_id; /* tag of fcpio to be aborted */
desc->u.itmf._resvd = 0;
memcpy(desc->u.itmf.lun, lun, LUN_ADDRESS); /* LUN address */
desc->u.itmf._resvd1 = 0;
hton24(desc->u.itmf.d_id, d_id); /* FC vNIC only: Target D_ID */
desc->u.itmf.r_a_tov = r_a_tov; /* FC vNIC only: R_A_TOV in msec */
desc->u.itmf.e_d_tov = e_d_tov; /* FC vNIC only: E_D_TOV in msec */
vnic_wq_copy_post(wq);
}
static inline void fnic_queue_wq_copy_desc_flogi_reg(struct vnic_wq_copy *wq,
u32 req_id, u8 format,
u32 s_id, u8 *gw_mac)
{
struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq);
desc->hdr.type = FCPIO_FLOGI_REG; /* enum fcpio_type */
desc->hdr.status = 0; /* header status entry */
desc->hdr._resvd = 0; /* reserved */
desc->hdr.tag.u.req_id = req_id; /* id for this request */
desc->u.flogi_reg.format = format;
hton24(desc->u.flogi_reg.s_id, s_id);
memcpy(desc->u.flogi_reg.gateway_mac, gw_mac, ETH_ALEN);
vnic_wq_copy_post(wq);
}
static inline void fnic_queue_wq_copy_desc_fw_reset(struct vnic_wq_copy *wq,
u32 req_id)
{
struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq);
desc->hdr.type = FCPIO_RESET; /* enum fcpio_type */
desc->hdr.status = 0; /* header status entry */
desc->hdr._resvd = 0; /* reserved */
desc->hdr.tag.u.req_id = req_id; /* id for this request */
vnic_wq_copy_post(wq);
}
static inline void fnic_queue_wq_copy_desc_lunmap(struct vnic_wq_copy *wq,
u32 req_id, u64 lunmap_addr,
u32 lunmap_len)
{
struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq);
desc->hdr.type = FCPIO_LUNMAP_REQ; /* enum fcpio_type */
desc->hdr.status = 0; /* header status entry */
desc->hdr._resvd = 0; /* reserved */
desc->hdr.tag.u.req_id = req_id; /* id for this request */
desc->u.lunmap_req.addr = lunmap_addr; /* address of the buffer */
desc->u.lunmap_req.len = lunmap_len; /* len of the buffer */
vnic_wq_copy_post(wq);
}
static inline void fnic_queue_rq_desc(struct vnic_rq *rq,
void *os_buf, dma_addr_t dma_addr,
u16 len)
{
struct rq_enet_desc *desc = vnic_rq_next_desc(rq);
rq_enet_desc_enc(desc,
(u64)dma_addr | VNIC_PADDR_TARGET,
RQ_ENET_TYPE_ONLY_SOP,
(u16)len);
vnic_rq_post(rq, os_buf, 0, dma_addr, len);
}
struct fnic;
int fnic_get_vnic_config(struct fnic *);
int fnic_alloc_vnic_resources(struct fnic *);
void fnic_free_vnic_resources(struct fnic *);
void fnic_get_res_counts(struct fnic *);
int fnic_set_nic_config(struct fnic *fnic, u8 rss_default_cpu,
u8 rss_hash_type, u8 rss_hash_bits, u8 rss_base_cpu,
u8 rss_enable, u8 tso_ipid_split_en,
u8 ig_vlan_strip_en);
#endif /* _FNIC_RES_H_ */
This diff is collapsed.
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _RQ_ENET_DESC_H_
#define _RQ_ENET_DESC_H_
/* Ethernet receive queue descriptor: 16B */
struct rq_enet_desc {
__le64 address;
__le16 length_type;
u8 reserved[6];
};
enum rq_enet_type_types {
RQ_ENET_TYPE_ONLY_SOP = 0,
RQ_ENET_TYPE_NOT_SOP = 1,
RQ_ENET_TYPE_RESV2 = 2,
RQ_ENET_TYPE_RESV3 = 3,
};
#define RQ_ENET_ADDR_BITS 64
#define RQ_ENET_LEN_BITS 14
#define RQ_ENET_LEN_MASK ((1 << RQ_ENET_LEN_BITS) - 1)
#define RQ_ENET_TYPE_BITS 2
#define RQ_ENET_TYPE_MASK ((1 << RQ_ENET_TYPE_BITS) - 1)
static inline void rq_enet_desc_enc(struct rq_enet_desc *desc,
u64 address, u8 type, u16 length)
{
desc->address = cpu_to_le64(address);
desc->length_type = cpu_to_le16((length & RQ_ENET_LEN_MASK) |
((type & RQ_ENET_TYPE_MASK) << RQ_ENET_LEN_BITS));
}
static inline void rq_enet_desc_dec(struct rq_enet_desc *desc,
u64 *address, u8 *type, u16 *length)
{
*address = le64_to_cpu(desc->address);
*length = le16_to_cpu(desc->length_type) & RQ_ENET_LEN_MASK;
*type = (u8)((le16_to_cpu(desc->length_type) >> RQ_ENET_LEN_BITS) &
RQ_ENET_TYPE_MASK);
}
#endif /* _RQ_ENET_DESC_H_ */
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/pci.h>
#include "vnic_dev.h"
#include "vnic_cq.h"
void vnic_cq_free(struct vnic_cq *cq)
{
vnic_dev_free_desc_ring(cq->vdev, &cq->ring);
cq->ctrl = NULL;
}
int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index,
unsigned int desc_count, unsigned int desc_size)
{
int err;
cq->index = index;
cq->vdev = vdev;
cq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_CQ, index);
if (!cq->ctrl) {
printk(KERN_ERR "Failed to hook CQ[%d] resource\n", index);
return -EINVAL;
}
err = vnic_dev_alloc_desc_ring(vdev, &cq->ring, desc_count, desc_size);
if (err)
return err;
return 0;
}
void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable,
unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail,
unsigned int cq_tail_color, unsigned int interrupt_enable,
unsigned int cq_entry_enable, unsigned int cq_message_enable,
unsigned int interrupt_offset, u64 cq_message_addr)
{
u64 paddr;
paddr = (u64)cq->ring.base_addr | VNIC_PADDR_TARGET;
writeq(paddr, &cq->ctrl->ring_base);
iowrite32(cq->ring.desc_count, &cq->ctrl->ring_size);
iowrite32(flow_control_enable, &cq->ctrl->flow_control_enable);
iowrite32(color_enable, &cq->ctrl->color_enable);
iowrite32(cq_head, &cq->ctrl->cq_head);
iowrite32(cq_tail, &cq->ctrl->cq_tail);
iowrite32(cq_tail_color, &cq->ctrl->cq_tail_color);
iowrite32(interrupt_enable, &cq->ctrl->interrupt_enable);
iowrite32(cq_entry_enable, &cq->ctrl->cq_entry_enable);
iowrite32(cq_message_enable, &cq->ctrl->cq_message_enable);
iowrite32(interrupt_offset, &cq->ctrl->interrupt_offset);
writeq(cq_message_addr, &cq->ctrl->cq_message_addr);
}
void vnic_cq_clean(struct vnic_cq *cq)
{
cq->to_clean = 0;
cq->last_color = 0;
iowrite32(0, &cq->ctrl->cq_head);
iowrite32(0, &cq->ctrl->cq_tail);
iowrite32(1, &cq->ctrl->cq_tail_color);
vnic_dev_clear_desc_ring(&cq->ring);
}
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _VNIC_CQ_H_
#define _VNIC_CQ_H_
#include "cq_desc.h"
#include "vnic_dev.h"
/*
* These defines avoid symbol clash between fnic and enic (Cisco 10G Eth
* Driver) when both are built with CONFIG options =y
*/
#define vnic_cq_service fnic_cq_service
#define vnic_cq_free fnic_cq_free
#define vnic_cq_alloc fnic_cq_alloc
#define vnic_cq_init fnic_cq_init
#define vnic_cq_clean fnic_cq_clean
/* Completion queue control */
struct vnic_cq_ctrl {
u64 ring_base; /* 0x00 */
u32 ring_size; /* 0x08 */
u32 pad0;
u32 flow_control_enable; /* 0x10 */
u32 pad1;
u32 color_enable; /* 0x18 */
u32 pad2;
u32 cq_head; /* 0x20 */
u32 pad3;
u32 cq_tail; /* 0x28 */
u32 pad4;
u32 cq_tail_color; /* 0x30 */
u32 pad5;
u32 interrupt_enable; /* 0x38 */
u32 pad6;
u32 cq_entry_enable; /* 0x40 */
u32 pad7;
u32 cq_message_enable; /* 0x48 */
u32 pad8;
u32 interrupt_offset; /* 0x50 */
u32 pad9;
u64 cq_message_addr; /* 0x58 */
u32 pad10;
};
struct vnic_cq {
unsigned int index;
struct vnic_dev *vdev;
struct vnic_cq_ctrl __iomem *ctrl; /* memory-mapped */
struct vnic_dev_ring ring;
unsigned int to_clean;
unsigned int last_color;
};
static inline unsigned int vnic_cq_service(struct vnic_cq *cq,
unsigned int work_to_do,
int (*q_service)(struct vnic_dev *vdev, struct cq_desc *cq_desc,
u8 type, u16 q_number, u16 completed_index, void *opaque),
void *opaque)
{
struct cq_desc *cq_desc;
unsigned int work_done = 0;
u16 q_number, completed_index;
u8 type, color;
cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs +
cq->ring.desc_size * cq->to_clean);
cq_desc_dec(cq_desc, &type, &color,
&q_number, &completed_index);
while (color != cq->last_color) {
if ((*q_service)(cq->vdev, cq_desc, type,
q_number, completed_index, opaque))
break;
cq->to_clean++;
if (cq->to_clean == cq->ring.desc_count) {
cq->to_clean = 0;
cq->last_color = cq->last_color ? 0 : 1;
}
cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs +
cq->ring.desc_size * cq->to_clean);
cq_desc_dec(cq_desc, &type, &color,
&q_number, &completed_index);
work_done++;
if (work_done >= work_to_do)
break;
}
return work_done;
}
void vnic_cq_free(struct vnic_cq *cq);
int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index,
unsigned int desc_count, unsigned int desc_size);
void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable,
unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail,
unsigned int cq_tail_color, unsigned int interrupt_enable,
unsigned int cq_entry_enable, unsigned int message_enable,
unsigned int interrupt_offset, u64 message_addr);
void vnic_cq_clean(struct vnic_cq *cq);
#endif /* _VNIC_CQ_H_ */
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _VNIC_CQ_COPY_H_
#define _VNIC_CQ_COPY_H_
#include "fcpio.h"
static inline unsigned int vnic_cq_copy_service(
struct vnic_cq *cq,
int (*q_service)(struct vnic_dev *vdev,
unsigned int index,
struct fcpio_fw_req *desc),
unsigned int work_to_do)
{
struct fcpio_fw_req *desc;
unsigned int work_done = 0;
u8 color;
desc = (struct fcpio_fw_req *)((u8 *)cq->ring.descs +
cq->ring.desc_size * cq->to_clean);
fcpio_color_dec(desc, &color);
while (color != cq->last_color) {
if ((*q_service)(cq->vdev, cq->index, desc))
break;
cq->to_clean++;
if (cq->to_clean == cq->ring.desc_count) {
cq->to_clean = 0;
cq->last_color = cq->last_color ? 0 : 1;
}
desc = (struct fcpio_fw_req *)((u8 *)cq->ring.descs +
cq->ring.desc_size * cq->to_clean);
fcpio_color_dec(desc, &color);
work_done++;
if (work_done >= work_to_do)
break;
}
return work_done;
}
#endif /* _VNIC_CQ_COPY_H_ */
This diff is collapsed.
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _VNIC_DEV_H_
#define _VNIC_DEV_H_
#include "vnic_resource.h"
#include "vnic_devcmd.h"
/*
* These defines avoid symbol clash between fnic and enic (Cisco 10G Eth
* Driver) when both are built with CONFIG options =y
*/
#define vnic_dev_priv fnic_dev_priv
#define vnic_dev_get_res_count fnic_dev_get_res_count
#define vnic_dev_get_res fnic_dev_get_res
#define vnic_dev_desc_ring_size fnic_dev_desc_ring_siz
#define vnic_dev_clear_desc_ring fnic_dev_clear_desc_ring
#define vnic_dev_alloc_desc_ring fnic_dev_alloc_desc_ring
#define vnic_dev_free_desc_ring fnic_dev_free_desc_ring
#define vnic_dev_cmd fnic_dev_cmd
#define vnic_dev_fw_info fnic_dev_fw_info
#define vnic_dev_spec fnic_dev_spec
#define vnic_dev_stats_clear fnic_dev_stats_clear
#define vnic_dev_stats_dump fnic_dev_stats_dump
#define vnic_dev_hang_notify fnic_dev_hang_notify
#define vnic_dev_packet_filter fnic_dev_packet_filter
#define vnic_dev_add_addr fnic_dev_add_addr
#define vnic_dev_del_addr fnic_dev_del_addr
#define vnic_dev_mac_addr fnic_dev_mac_addr
#define vnic_dev_notify_set fnic_dev_notify_set
#define vnic_dev_notify_unset fnic_dev_notify_unset
#define vnic_dev_link_status fnic_dev_link_status
#define vnic_dev_port_speed fnic_dev_port_speed
#define vnic_dev_msg_lvl fnic_dev_msg_lvl
#define vnic_dev_mtu fnic_dev_mtu
#define vnic_dev_link_down_cnt fnic_dev_link_down_cnt
#define vnic_dev_close fnic_dev_close
#define vnic_dev_enable fnic_dev_enable
#define vnic_dev_disable fnic_dev_disable
#define vnic_dev_open fnic_dev_open
#define vnic_dev_open_done fnic_dev_open_done
#define vnic_dev_init fnic_dev_init
#define vnic_dev_soft_reset fnic_dev_soft_reset
#define vnic_dev_soft_reset_done fnic_dev_soft_reset_done
#define vnic_dev_set_intr_mode fnic_dev_set_intr_mode
#define vnic_dev_get_intr_mode fnic_dev_get_intr_mode
#define vnic_dev_unregister fnic_dev_unregister
#define vnic_dev_register fnic_dev_register
#ifndef VNIC_PADDR_TARGET
#define VNIC_PADDR_TARGET 0x0000000000000000ULL
#endif
#ifndef readq
static inline u64 readq(void __iomem *reg)
{
return ((u64)readl(reg + 0x4UL) << 32) | (u64)readl(reg);
}
static inline void writeq(u64 val, void __iomem *reg)
{
writel(val & 0xffffffff, reg);
writel(val >> 32, reg + 0x4UL);
}
#endif
enum vnic_dev_intr_mode {
VNIC_DEV_INTR_MODE_UNKNOWN,
VNIC_DEV_INTR_MODE_INTX,
VNIC_DEV_INTR_MODE_MSI,
VNIC_DEV_INTR_MODE_MSIX,
};
struct vnic_dev_bar {
void __iomem *vaddr;
dma_addr_t bus_addr;
unsigned long len;
};
struct vnic_dev_ring {
void *descs;
size_t size;
dma_addr_t base_addr;
size_t base_align;
void *descs_unaligned;
size_t size_unaligned;
dma_addr_t base_addr_unaligned;
unsigned int desc_size;
unsigned int desc_count;
unsigned int desc_avail;
};
struct vnic_dev;
struct vnic_stats;
void *vnic_dev_priv(struct vnic_dev *vdev);
unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev,
enum vnic_res_type type);
void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type,
unsigned int index);
unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring,
unsigned int desc_count,
unsigned int desc_size);
void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring);
int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
unsigned int desc_count, unsigned int desc_size);
void vnic_dev_free_desc_ring(struct vnic_dev *vdev,
struct vnic_dev_ring *ring);
int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
u64 *a0, u64 *a1, int wait);
int vnic_dev_fw_info(struct vnic_dev *vdev,
struct vnic_devcmd_fw_info **fw_info);
int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset,
unsigned int size, void *value);
int vnic_dev_stats_clear(struct vnic_dev *vdev);
int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats);
int vnic_dev_hang_notify(struct vnic_dev *vdev);
void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
int broadcast, int promisc, int allmulti);
void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr);
void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr);
int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr);
void vnic_dev_notify_unset(struct vnic_dev *vdev);
int vnic_dev_link_status(struct vnic_dev *vdev);
u32 vnic_dev_port_speed(struct vnic_dev *vdev);
u32 vnic_dev_msg_lvl(struct vnic_dev *vdev);
u32 vnic_dev_mtu(struct vnic_dev *vdev);
u32 vnic_dev_link_down_cnt(struct vnic_dev *vdev);
int vnic_dev_close(struct vnic_dev *vdev);
int vnic_dev_enable(struct vnic_dev *vdev);
int vnic_dev_disable(struct vnic_dev *vdev);
int vnic_dev_open(struct vnic_dev *vdev, int arg);
int vnic_dev_open_done(struct vnic_dev *vdev, int *done);
int vnic_dev_init(struct vnic_dev *vdev, int arg);
int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg);
int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done);
void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
enum vnic_dev_intr_mode intr_mode);
enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev);
void vnic_dev_unregister(struct vnic_dev *vdev);
struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
void *priv, struct pci_dev *pdev,
struct vnic_dev_bar *bar);
#endif /* _VNIC_DEV_H_ */
This diff is collapsed.
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include "vnic_dev.h"
#include "vnic_intr.h"
void vnic_intr_free(struct vnic_intr *intr)
{
intr->ctrl = NULL;
}
int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
unsigned int index)
{
intr->index = index;
intr->vdev = vdev;
intr->ctrl = vnic_dev_get_res(vdev, RES_TYPE_INTR_CTRL, index);
if (!intr->ctrl) {
printk(KERN_ERR "Failed to hook INTR[%d].ctrl resource\n",
index);
return -EINVAL;
}
return 0;
}
void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
unsigned int coalescing_type, unsigned int mask_on_assertion)
{
iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer);
iowrite32(coalescing_type, &intr->ctrl->coalescing_type);
iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion);
iowrite32(0, &intr->ctrl->int_credits);
}
void vnic_intr_clean(struct vnic_intr *intr)
{
iowrite32(0, &intr->ctrl->int_credits);
}
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _VNIC_INTR_H_
#define _VNIC_INTR_H_
#include <linux/pci.h>
#include "vnic_dev.h"
/*
* These defines avoid symbol clash between fnic and enic (Cisco 10G Eth
* Driver) when both are built with CONFIG options =y
*/
#define vnic_intr_unmask fnic_intr_unmask
#define vnic_intr_mask fnic_intr_mask
#define vnic_intr_return_credits fnic_intr_return_credits
#define vnic_intr_credits fnic_intr_credits
#define vnic_intr_return_all_credits fnic_intr_return_all_credits
#define vnic_intr_legacy_pba fnic_intr_legacy_pba
#define vnic_intr_free fnic_intr_free
#define vnic_intr_alloc fnic_intr_alloc
#define vnic_intr_init fnic_intr_init
#define vnic_intr_clean fnic_intr_clean
#define VNIC_INTR_TIMER_MAX 0xffff
#define VNIC_INTR_TIMER_TYPE_ABS 0
#define VNIC_INTR_TIMER_TYPE_QUIET 1
/* Interrupt control */
struct vnic_intr_ctrl {
u32 coalescing_timer; /* 0x00 */
u32 pad0;
u32 coalescing_value; /* 0x08 */
u32 pad1;
u32 coalescing_type; /* 0x10 */
u32 pad2;
u32 mask_on_assertion; /* 0x18 */
u32 pad3;
u32 mask; /* 0x20 */
u32 pad4;
u32 int_credits; /* 0x28 */
u32 pad5;
u32 int_credit_return; /* 0x30 */
u32 pad6;
};
struct vnic_intr {
unsigned int index;
struct vnic_dev *vdev;
struct vnic_intr_ctrl __iomem *ctrl; /* memory-mapped */
};
static inline void vnic_intr_unmask(struct vnic_intr *intr)
{
iowrite32(0, &intr->ctrl->mask);
}
static inline void vnic_intr_mask(struct vnic_intr *intr)
{
iowrite32(1, &intr->ctrl->mask);
}
static inline void vnic_intr_return_credits(struct vnic_intr *intr,
unsigned int credits, int unmask, int reset_timer)
{
#define VNIC_INTR_UNMASK_SHIFT 16
#define VNIC_INTR_RESET_TIMER_SHIFT 17
u32 int_credit_return = (credits & 0xffff) |
(unmask ? (1 << VNIC_INTR_UNMASK_SHIFT) : 0) |
(reset_timer ? (1 << VNIC_INTR_RESET_TIMER_SHIFT) : 0);
iowrite32(int_credit_return, &intr->ctrl->int_credit_return);
}
static inline unsigned int vnic_intr_credits(struct vnic_intr *intr)
{
return ioread32(&intr->ctrl->int_credits);
}
static inline void vnic_intr_return_all_credits(struct vnic_intr *intr)
{
unsigned int credits = vnic_intr_credits(intr);
int unmask = 1;
int reset_timer = 1;
vnic_intr_return_credits(intr, credits, unmask, reset_timer);
}
static inline u32 vnic_intr_legacy_pba(u32 __iomem *legacy_pba)
{
/* read PBA without clearing */
return ioread32(legacy_pba);
}
void vnic_intr_free(struct vnic_intr *intr);
int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
unsigned int index);
void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
unsigned int coalescing_type, unsigned int mask_on_assertion);
void vnic_intr_clean(struct vnic_intr *intr);
#endif /* _VNIC_INTR_H_ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment