mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
[SCSI] fnic: Add new Cisco PCI-Express FCoE HBA
fnic is a driver for the Cisco PCI-Express FCoE HBA Signed-off-by: Abhijeet Joglekar <abjoglek@cisco.com> Signed-off-by: Joe Eykholt <jeykholt@cisco.com> Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
committed by
James Bottomley
parent
210af919c9
commit
5df6d737dd
@@ -1431,6 +1431,14 @@ P: Russell King
|
||||
M: linux@arm.linux.org.uk
|
||||
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
|
||||
P: Jan Harkes
|
||||
M: jaharkes@cs.cmu.edu
|
||||
|
||||
@@ -628,6 +628,17 @@ config FCOE
|
||||
---help---
|
||||
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
|
||||
tristate "DMX3191D SCSI support"
|
||||
depends on PCI && SCSI
|
||||
|
||||
@@ -39,6 +39,7 @@ obj-$(CONFIG_SCSI_DH) += device_handler/
|
||||
obj-$(CONFIG_LIBFC) += libfc/
|
||||
obj-$(CONFIG_LIBFCOE) += fcoe/
|
||||
obj-$(CONFIG_FCOE) += fcoe/
|
||||
obj-$(CONFIG_FCOE_FNIC) += fnic/
|
||||
obj-$(CONFIG_ISCSI_TCP) += libiscsi.o libiscsi_tcp.o iscsi_tcp.o
|
||||
obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
|
||||
obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o
|
||||
|
||||
15
drivers/scsi/fnic/Makefile
Normal file
15
drivers/scsi/fnic/Makefile
Normal file
@@ -0,0 +1,15 @@
|
||||
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
|
||||
78
drivers/scsi/fnic/cq_desc.h
Normal file
78
drivers/scsi/fnic/cq_desc.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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_ */
|
||||
167
drivers/scsi/fnic/cq_enet_desc.h
Normal file
167
drivers/scsi/fnic/cq_enet_desc.h
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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_ */
|
||||
182
drivers/scsi/fnic/cq_exch_desc.h
Normal file
182
drivers/scsi/fnic/cq_exch_desc.h
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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_ */
|
||||
780
drivers/scsi/fnic/fcpio.h
Normal file
780
drivers/scsi/fnic/fcpio.h
Normal file
File diff suppressed because it is too large
Load Diff
265
drivers/scsi/fnic/fnic.h
Normal file
265
drivers/scsi/fnic/fnic.h
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* 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_ */
|
||||
56
drivers/scsi/fnic/fnic_attrs.c
Normal file
56
drivers/scsi/fnic/fnic_attrs.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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,
|
||||
};
|
||||
742
drivers/scsi/fnic/fnic_fcs.c
Normal file
742
drivers/scsi/fnic/fnic_fcs.c
Normal file
File diff suppressed because it is too large
Load Diff
67
drivers/scsi/fnic/fnic_io.h
Normal file
67
drivers/scsi/fnic/fnic_io.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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_ */
|
||||
332
drivers/scsi/fnic/fnic_isr.c
Normal file
332
drivers/scsi/fnic/fnic_isr.c
Normal file
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
942
drivers/scsi/fnic/fnic_main.c
Normal file
942
drivers/scsi/fnic/fnic_main.c
Normal file
File diff suppressed because it is too large
Load Diff
444
drivers/scsi/fnic/fnic_res.c
Normal file
444
drivers/scsi/fnic/fnic_res.c
Normal file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* 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 "wq_enet_desc.h"
|
||||
#include "rq_enet_desc.h"
|
||||
#include "cq_enet_desc.h"
|
||||
#include "vnic_resource.h"
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_wq.h"
|
||||
#include "vnic_rq.h"
|
||||
#include "vnic_cq.h"
|
||||
#include "vnic_intr.h"
|
||||
#include "vnic_stats.h"
|
||||
#include "vnic_nic.h"
|
||||
#include "fnic.h"
|
||||
|
||||
int fnic_get_vnic_config(struct fnic *fnic)
|
||||
{
|
||||
struct vnic_fc_config *c = &fnic->config;
|
||||
int err;
|
||||
|
||||
#define GET_CONFIG(m) \
|
||||
do { \
|
||||
err = vnic_dev_spec(fnic->vdev, \
|
||||
offsetof(struct vnic_fc_config, m), \
|
||||
sizeof(c->m), &c->m); \
|
||||
if (err) { \
|
||||
shost_printk(KERN_ERR, fnic->lport->host, \
|
||||
"Error getting %s, %d\n", #m, \
|
||||
err); \
|
||||
return err; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
GET_CONFIG(node_wwn);
|
||||
GET_CONFIG(port_wwn);
|
||||
GET_CONFIG(wq_enet_desc_count);
|
||||
GET_CONFIG(wq_copy_desc_count);
|
||||
GET_CONFIG(rq_desc_count);
|
||||
GET_CONFIG(maxdatafieldsize);
|
||||
GET_CONFIG(ed_tov);
|
||||
GET_CONFIG(ra_tov);
|
||||
GET_CONFIG(intr_timer);
|
||||
GET_CONFIG(intr_timer_type);
|
||||
GET_CONFIG(flags);
|
||||
GET_CONFIG(flogi_retries);
|
||||
GET_CONFIG(flogi_timeout);
|
||||
GET_CONFIG(plogi_retries);
|
||||
GET_CONFIG(plogi_timeout);
|
||||
GET_CONFIG(io_throttle_count);
|
||||
GET_CONFIG(link_down_timeout);
|
||||
GET_CONFIG(port_down_timeout);
|
||||
GET_CONFIG(port_down_io_retries);
|
||||
GET_CONFIG(luns_per_tgt);
|
||||
|
||||
c->wq_enet_desc_count =
|
||||
min_t(u32, VNIC_FNIC_WQ_DESCS_MAX,
|
||||
max_t(u32, VNIC_FNIC_WQ_DESCS_MIN,
|
||||
c->wq_enet_desc_count));
|
||||
c->wq_enet_desc_count = ALIGN(c->wq_enet_desc_count, 16);
|
||||
|
||||
c->wq_copy_desc_count =
|
||||
min_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MAX,
|
||||
max_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MIN,
|
||||
c->wq_copy_desc_count));
|
||||
c->wq_copy_desc_count = ALIGN(c->wq_copy_desc_count, 16);
|
||||
|
||||
c->rq_desc_count =
|
||||
min_t(u32, VNIC_FNIC_RQ_DESCS_MAX,
|
||||
max_t(u32, VNIC_FNIC_RQ_DESCS_MIN,
|
||||
c->rq_desc_count));
|
||||
c->rq_desc_count = ALIGN(c->rq_desc_count, 16);
|
||||
|
||||
c->maxdatafieldsize =
|
||||
min_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MAX,
|
||||
max_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MIN,
|
||||
c->maxdatafieldsize));
|
||||
c->ed_tov =
|
||||
min_t(u32, VNIC_FNIC_EDTOV_MAX,
|
||||
max_t(u32, VNIC_FNIC_EDTOV_MIN,
|
||||
c->ed_tov));
|
||||
|
||||
c->ra_tov =
|
||||
min_t(u32, VNIC_FNIC_RATOV_MAX,
|
||||
max_t(u32, VNIC_FNIC_RATOV_MIN,
|
||||
c->ra_tov));
|
||||
|
||||
c->flogi_retries =
|
||||
min_t(u32, VNIC_FNIC_FLOGI_RETRIES_MAX, c->flogi_retries);
|
||||
|
||||
c->flogi_timeout =
|
||||
min_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MAX,
|
||||
max_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MIN,
|
||||
c->flogi_timeout));
|
||||
|
||||
c->plogi_retries =
|
||||
min_t(u32, VNIC_FNIC_PLOGI_RETRIES_MAX, c->plogi_retries);
|
||||
|
||||
c->plogi_timeout =
|
||||
min_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MAX,
|
||||
max_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MIN,
|
||||
c->plogi_timeout));
|
||||
|
||||
c->io_throttle_count =
|
||||
min_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MAX,
|
||||
max_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MIN,
|
||||
c->io_throttle_count));
|
||||
|
||||
c->link_down_timeout =
|
||||
min_t(u32, VNIC_FNIC_LINK_DOWN_TIMEOUT_MAX,
|
||||
c->link_down_timeout);
|
||||
|
||||
c->port_down_timeout =
|
||||
min_t(u32, VNIC_FNIC_PORT_DOWN_TIMEOUT_MAX,
|
||||
c->port_down_timeout);
|
||||
|
||||
c->port_down_io_retries =
|
||||
min_t(u32, VNIC_FNIC_PORT_DOWN_IO_RETRIES_MAX,
|
||||
c->port_down_io_retries);
|
||||
|
||||
c->luns_per_tgt =
|
||||
min_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MAX,
|
||||
max_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MIN,
|
||||
c->luns_per_tgt));
|
||||
|
||||
c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer);
|
||||
c->intr_timer_type = c->intr_timer_type;
|
||||
|
||||
shost_printk(KERN_INFO, fnic->lport->host,
|
||||
"vNIC MAC addr %02x:%02x:%02x:%02x:%02x:%02x "
|
||||
"wq/wq_copy/rq %d/%d/%d\n",
|
||||
fnic->mac_addr[0], fnic->mac_addr[1], fnic->mac_addr[2],
|
||||
fnic->mac_addr[3], fnic->mac_addr[4], fnic->mac_addr[5],
|
||||
c->wq_enet_desc_count, c->wq_copy_desc_count,
|
||||
c->rq_desc_count);
|
||||
shost_printk(KERN_INFO, fnic->lport->host,
|
||||
"vNIC node wwn %llx port wwn %llx\n",
|
||||
c->node_wwn, c->port_wwn);
|
||||
shost_printk(KERN_INFO, fnic->lport->host,
|
||||
"vNIC ed_tov %d ra_tov %d\n",
|
||||
c->ed_tov, c->ra_tov);
|
||||
shost_printk(KERN_INFO, fnic->lport->host,
|
||||
"vNIC mtu %d intr timer %d\n",
|
||||
c->maxdatafieldsize, c->intr_timer);
|
||||
shost_printk(KERN_INFO, fnic->lport->host,
|
||||
"vNIC flags 0x%x luns per tgt %d\n",
|
||||
c->flags, c->luns_per_tgt);
|
||||
shost_printk(KERN_INFO, fnic->lport->host,
|
||||
"vNIC flogi_retries %d flogi timeout %d\n",
|
||||
c->flogi_retries, c->flogi_timeout);
|
||||
shost_printk(KERN_INFO, fnic->lport->host,
|
||||
"vNIC plogi retries %d plogi timeout %d\n",
|
||||
c->plogi_retries, c->plogi_timeout);
|
||||
shost_printk(KERN_INFO, fnic->lport->host,
|
||||
"vNIC io throttle count %d link dn timeout %d\n",
|
||||
c->io_throttle_count, c->link_down_timeout);
|
||||
shost_printk(KERN_INFO, fnic->lport->host,
|
||||
"vNIC port dn io retries %d port dn timeout %d\n",
|
||||
c->port_down_io_retries, c->port_down_timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
u64 a0, a1;
|
||||
u32 nic_cfg;
|
||||
int wait = 1000;
|
||||
|
||||
vnic_set_nic_cfg(&nic_cfg, rss_default_cpu,
|
||||
rss_hash_type, rss_hash_bits, rss_base_cpu,
|
||||
rss_enable, tso_ipid_split_en, ig_vlan_strip_en);
|
||||
|
||||
a0 = nic_cfg;
|
||||
a1 = 0;
|
||||
|
||||
return vnic_dev_cmd(fnic->vdev, CMD_NIC_CFG, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
void fnic_get_res_counts(struct fnic *fnic)
|
||||
{
|
||||
fnic->wq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_WQ);
|
||||
fnic->raw_wq_count = fnic->wq_count - 1;
|
||||
fnic->wq_copy_count = fnic->wq_count - fnic->raw_wq_count;
|
||||
fnic->rq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_RQ);
|
||||
fnic->cq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_CQ);
|
||||
fnic->intr_count = vnic_dev_get_res_count(fnic->vdev,
|
||||
RES_TYPE_INTR_CTRL);
|
||||
}
|
||||
|
||||
void fnic_free_vnic_resources(struct fnic *fnic)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < fnic->raw_wq_count; i++)
|
||||
vnic_wq_free(&fnic->wq[i]);
|
||||
|
||||
for (i = 0; i < fnic->wq_copy_count; i++)
|
||||
vnic_wq_copy_free(&fnic->wq_copy[i]);
|
||||
|
||||
for (i = 0; i < fnic->rq_count; i++)
|
||||
vnic_rq_free(&fnic->rq[i]);
|
||||
|
||||
for (i = 0; i < fnic->cq_count; i++)
|
||||
vnic_cq_free(&fnic->cq[i]);
|
||||
|
||||
for (i = 0; i < fnic->intr_count; i++)
|
||||
vnic_intr_free(&fnic->intr[i]);
|
||||
}
|
||||
|
||||
int fnic_alloc_vnic_resources(struct fnic *fnic)
|
||||
{
|
||||
enum vnic_dev_intr_mode intr_mode;
|
||||
unsigned int mask_on_assertion;
|
||||
unsigned int interrupt_offset;
|
||||
unsigned int error_interrupt_enable;
|
||||
unsigned int error_interrupt_offset;
|
||||
unsigned int i, cq_index;
|
||||
unsigned int wq_copy_cq_desc_count;
|
||||
int err;
|
||||
|
||||
intr_mode = vnic_dev_get_intr_mode(fnic->vdev);
|
||||
|
||||
shost_printk(KERN_INFO, fnic->lport->host, "vNIC interrupt mode: %s\n",
|
||||
intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
|
||||
intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
|
||||
intr_mode == VNIC_DEV_INTR_MODE_MSIX ?
|
||||
"MSI-X" : "unknown");
|
||||
|
||||
shost_printk(KERN_INFO, fnic->lport->host, "vNIC resources avail: "
|
||||
"wq %d cp_wq %d raw_wq %d rq %d cq %d intr %d\n",
|
||||
fnic->wq_count, fnic->wq_copy_count, fnic->raw_wq_count,
|
||||
fnic->rq_count, fnic->cq_count, fnic->intr_count);
|
||||
|
||||
/* Allocate Raw WQ used for FCS frames */
|
||||
for (i = 0; i < fnic->raw_wq_count; i++) {
|
||||
err = vnic_wq_alloc(fnic->vdev, &fnic->wq[i], i,
|
||||
fnic->config.wq_enet_desc_count,
|
||||
sizeof(struct wq_enet_desc));
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
/* Allocate Copy WQs used for SCSI IOs */
|
||||
for (i = 0; i < fnic->wq_copy_count; i++) {
|
||||
err = vnic_wq_copy_alloc(fnic->vdev, &fnic->wq_copy[i],
|
||||
(fnic->raw_wq_count + i),
|
||||
fnic->config.wq_copy_desc_count,
|
||||
sizeof(struct fcpio_host_req));
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
/* RQ for receiving FCS frames */
|
||||
for (i = 0; i < fnic->rq_count; i++) {
|
||||
err = vnic_rq_alloc(fnic->vdev, &fnic->rq[i], i,
|
||||
fnic->config.rq_desc_count,
|
||||
sizeof(struct rq_enet_desc));
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
/* CQ for each RQ */
|
||||
for (i = 0; i < fnic->rq_count; i++) {
|
||||
cq_index = i;
|
||||
err = vnic_cq_alloc(fnic->vdev,
|
||||
&fnic->cq[cq_index], cq_index,
|
||||
fnic->config.rq_desc_count,
|
||||
sizeof(struct cq_enet_rq_desc));
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
/* CQ for each WQ */
|
||||
for (i = 0; i < fnic->raw_wq_count; i++) {
|
||||
cq_index = fnic->rq_count + i;
|
||||
err = vnic_cq_alloc(fnic->vdev, &fnic->cq[cq_index], cq_index,
|
||||
fnic->config.wq_enet_desc_count,
|
||||
sizeof(struct cq_enet_wq_desc));
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
/* CQ for each COPY WQ */
|
||||
wq_copy_cq_desc_count = (fnic->config.wq_copy_desc_count * 3);
|
||||
for (i = 0; i < fnic->wq_copy_count; i++) {
|
||||
cq_index = fnic->raw_wq_count + fnic->rq_count + i;
|
||||
err = vnic_cq_alloc(fnic->vdev, &fnic->cq[cq_index],
|
||||
cq_index,
|
||||
wq_copy_cq_desc_count,
|
||||
sizeof(struct fcpio_fw_req));
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < fnic->intr_count; i++) {
|
||||
err = vnic_intr_alloc(fnic->vdev, &fnic->intr[i], i);
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
fnic->legacy_pba = vnic_dev_get_res(fnic->vdev,
|
||||
RES_TYPE_INTR_PBA_LEGACY, 0);
|
||||
|
||||
if (!fnic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
|
||||
shost_printk(KERN_ERR, fnic->lport->host,
|
||||
"Failed to hook legacy pba resource\n");
|
||||
err = -ENODEV;
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Init RQ/WQ resources.
|
||||
*
|
||||
* RQ[0 to n-1] point to CQ[0 to n-1]
|
||||
* WQ[0 to m-1] point to CQ[n to n+m-1]
|
||||
* WQ_COPY[0 to k-1] points to CQ[n+m to n+m+k-1]
|
||||
*
|
||||
* Note for copy wq we always initialize with cq_index = 0
|
||||
*
|
||||
* Error interrupt is not enabled for MSI.
|
||||
*/
|
||||
|
||||
switch (intr_mode) {
|
||||
case VNIC_DEV_INTR_MODE_INTX:
|
||||
case VNIC_DEV_INTR_MODE_MSIX:
|
||||
error_interrupt_enable = 1;
|
||||
error_interrupt_offset = fnic->err_intr_offset;
|
||||
break;
|
||||
default:
|
||||
error_interrupt_enable = 0;
|
||||
error_interrupt_offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < fnic->rq_count; i++) {
|
||||
cq_index = i;
|
||||
vnic_rq_init(&fnic->rq[i],
|
||||
cq_index,
|
||||
error_interrupt_enable,
|
||||
error_interrupt_offset);
|
||||
}
|
||||
|
||||
for (i = 0; i < fnic->raw_wq_count; i++) {
|
||||
cq_index = i + fnic->rq_count;
|
||||
vnic_wq_init(&fnic->wq[i],
|
||||
cq_index,
|
||||
error_interrupt_enable,
|
||||
error_interrupt_offset);
|
||||
}
|
||||
|
||||
for (i = 0; i < fnic->wq_copy_count; i++) {
|
||||
vnic_wq_copy_init(&fnic->wq_copy[i],
|
||||
0 /* cq_index 0 - always */,
|
||||
error_interrupt_enable,
|
||||
error_interrupt_offset);
|
||||
}
|
||||
|
||||
for (i = 0; i < fnic->cq_count; i++) {
|
||||
|
||||
switch (intr_mode) {
|
||||
case VNIC_DEV_INTR_MODE_MSIX:
|
||||
interrupt_offset = i;
|
||||
break;
|
||||
default:
|
||||
interrupt_offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
vnic_cq_init(&fnic->cq[i],
|
||||
0 /* flow_control_enable */,
|
||||
1 /* color_enable */,
|
||||
0 /* cq_head */,
|
||||
0 /* cq_tail */,
|
||||
1 /* cq_tail_color */,
|
||||
1 /* interrupt_enable */,
|
||||
1 /* cq_entry_enable */,
|
||||
0 /* cq_message_enable */,
|
||||
interrupt_offset,
|
||||
0 /* cq_message_addr */);
|
||||
}
|
||||
|
||||
/*
|
||||
* Init INTR resources
|
||||
*
|
||||
* mask_on_assertion is not used for INTx due to the level-
|
||||
* triggered nature of INTx
|
||||
*/
|
||||
|
||||
switch (intr_mode) {
|
||||
case VNIC_DEV_INTR_MODE_MSI:
|
||||
case VNIC_DEV_INTR_MODE_MSIX:
|
||||
mask_on_assertion = 1;
|
||||
break;
|
||||
default:
|
||||
mask_on_assertion = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < fnic->intr_count; i++) {
|
||||
vnic_intr_init(&fnic->intr[i],
|
||||
fnic->config.intr_timer,
|
||||
fnic->config.intr_timer_type,
|
||||
mask_on_assertion);
|
||||
}
|
||||
|
||||
/* init the stats memory by making the first call here */
|
||||
err = vnic_dev_stats_dump(fnic->vdev, &fnic->stats);
|
||||
if (err) {
|
||||
shost_printk(KERN_ERR, fnic->lport->host,
|
||||
"vnic_dev_stats_dump failed - x%x\n", err);
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
/* Clear LIF stats */
|
||||
vnic_dev_stats_clear(fnic->vdev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_cleanup:
|
||||
fnic_free_vnic_resources(fnic);
|
||||
|
||||
return err;
|
||||
}
|
||||
197
drivers/scsi/fnic/fnic_res.h
Normal file
197
drivers/scsi/fnic/fnic_res.h
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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_ */
|
||||
1850
drivers/scsi/fnic/fnic_scsi.c
Normal file
1850
drivers/scsi/fnic/fnic_scsi.c
Normal file
File diff suppressed because it is too large
Load Diff
58
drivers/scsi/fnic/rq_enet_desc.h
Normal file
58
drivers/scsi/fnic/rq_enet_desc.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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_ */
|
||||
85
drivers/scsi/fnic/vnic_cq.c
Normal file
85
drivers/scsi/fnic/vnic_cq.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
121
drivers/scsi/fnic/vnic_cq.h
Normal file
121
drivers/scsi/fnic/vnic_cq.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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_ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user