Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband: (48 commits)
  IB/srp: Clean up error path in srp_create_target_ib()
  IB/srp: Split send and recieve CQs to reduce number of interrupts
  RDMA/nes: Add support for KR device id 0x0110
  IB/uverbs: Use anon_inodes instead of private infinibandeventfs
  IB/core: Fix and clean up ib_ud_header_init()
  RDMA/cxgb3: Mark RDMA device with CXIO_ERROR_FATAL when removing
  RDMA/cxgb3: Don't allocate the SW queue for user mode CQs
  RDMA/cxgb3: Increase the max CQ depth
  RDMA/cxgb3: Doorbell overflow avoidance and recovery
  IB/core: Pack struct ib_device a little tighter
  IB/ucm: Clean whitespace errors
  IB/ucm: Increase maximum devices supported
  IB/ucm: Use stack variable 'base' in ib_ucm_add_one
  IB/ucm: Use stack variable 'devnum' in ib_ucm_add_one
  IB/umad: Clean whitespace
  IB/umad: Increase maximum devices supported
  IB/umad: Use stack variable 'base' in ib_umad_init_port
  IB/umad: Use stack variable 'devnum' in ib_umad_init_port
  IB/umad: Remove port_table[]
  IB/umad: Convert *cdev to cdev in struct ib_umad_port
  ...
This commit is contained in:
Linus Torvalds 2010-03-03 07:33:17 -08:00
commit 3ff1562ea4
44 changed files with 1238 additions and 1227 deletions

View file

@ -20,6 +20,7 @@ config INFINIBAND_USER_MAD
config INFINIBAND_USER_ACCESS config INFINIBAND_USER_ACCESS
tristate "InfiniBand userspace access (verbs and CM)" tristate "InfiniBand userspace access (verbs and CM)"
select ANON_INODES
---help--- ---help---
Userspace InfiniBand access support. This enables the Userspace InfiniBand access support. This enables the
kernel side of userspace verbs and the userspace kernel side of userspace verbs and the userspace

View file

@ -1215,7 +1215,10 @@ static void ib_ucm_release_dev(struct device *dev)
ucm_dev = container_of(dev, struct ib_ucm_device, dev); ucm_dev = container_of(dev, struct ib_ucm_device, dev);
cdev_del(&ucm_dev->cdev); cdev_del(&ucm_dev->cdev);
if (ucm_dev->devnum < IB_UCM_MAX_DEVICES)
clear_bit(ucm_dev->devnum, dev_map); clear_bit(ucm_dev->devnum, dev_map);
else
clear_bit(ucm_dev->devnum - IB_UCM_MAX_DEVICES, dev_map);
kfree(ucm_dev); kfree(ucm_dev);
} }
@ -1237,8 +1240,32 @@ static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr,
} }
static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
static dev_t overflow_maj;
static DECLARE_BITMAP(overflow_map, IB_UCM_MAX_DEVICES);
static int find_overflow_devnum(void)
{
int ret;
if (!overflow_maj) {
ret = alloc_chrdev_region(&overflow_maj, 0, IB_UCM_MAX_DEVICES,
"infiniband_cm");
if (ret) {
printk(KERN_ERR "ucm: couldn't register dynamic device number\n");
return ret;
}
}
ret = find_first_zero_bit(overflow_map, IB_UCM_MAX_DEVICES);
if (ret >= IB_UCM_MAX_DEVICES)
return -1;
return ret;
}
static void ib_ucm_add_one(struct ib_device *device) static void ib_ucm_add_one(struct ib_device *device)
{ {
int devnum;
dev_t base;
struct ib_ucm_device *ucm_dev; struct ib_ucm_device *ucm_dev;
if (!device->alloc_ucontext || if (!device->alloc_ucontext ||
@ -1251,16 +1278,25 @@ static void ib_ucm_add_one(struct ib_device *device)
ucm_dev->ib_dev = device; ucm_dev->ib_dev = device;
ucm_dev->devnum = find_first_zero_bit(dev_map, IB_UCM_MAX_DEVICES); devnum = find_first_zero_bit(dev_map, IB_UCM_MAX_DEVICES);
if (ucm_dev->devnum >= IB_UCM_MAX_DEVICES) if (devnum >= IB_UCM_MAX_DEVICES) {
devnum = find_overflow_devnum();
if (devnum < 0)
goto err; goto err;
set_bit(ucm_dev->devnum, dev_map); ucm_dev->devnum = devnum + IB_UCM_MAX_DEVICES;
base = devnum + overflow_maj;
set_bit(devnum, overflow_map);
} else {
ucm_dev->devnum = devnum;
base = devnum + IB_UCM_BASE_DEV;
set_bit(devnum, dev_map);
}
cdev_init(&ucm_dev->cdev, &ucm_fops); cdev_init(&ucm_dev->cdev, &ucm_fops);
ucm_dev->cdev.owner = THIS_MODULE; ucm_dev->cdev.owner = THIS_MODULE;
kobject_set_name(&ucm_dev->cdev.kobj, "ucm%d", ucm_dev->devnum); kobject_set_name(&ucm_dev->cdev.kobj, "ucm%d", ucm_dev->devnum);
if (cdev_add(&ucm_dev->cdev, IB_UCM_BASE_DEV + ucm_dev->devnum, 1)) if (cdev_add(&ucm_dev->cdev, base, 1))
goto err; goto err;
ucm_dev->dev.class = &cm_class; ucm_dev->dev.class = &cm_class;
@ -1281,7 +1317,10 @@ err_dev:
device_unregister(&ucm_dev->dev); device_unregister(&ucm_dev->dev);
err_cdev: err_cdev:
cdev_del(&ucm_dev->cdev); cdev_del(&ucm_dev->cdev);
clear_bit(ucm_dev->devnum, dev_map); if (ucm_dev->devnum < IB_UCM_MAX_DEVICES)
clear_bit(devnum, dev_map);
else
clear_bit(devnum, overflow_map);
err: err:
kfree(ucm_dev); kfree(ucm_dev);
return; return;
@ -1340,6 +1379,8 @@ static void __exit ib_ucm_cleanup(void)
ib_unregister_client(&ucm_client); ib_unregister_client(&ucm_client);
class_remove_file(&cm_class, &class_attr_abi_version); class_remove_file(&cm_class, &class_attr_abi_version);
unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
if (overflow_maj)
unregister_chrdev_region(overflow_maj, IB_UCM_MAX_DEVICES);
idr_destroy(&ctx_id_table); idr_destroy(&ctx_id_table);
} }

View file

@ -181,6 +181,7 @@ static const struct ib_field deth_table[] = {
* ib_ud_header_init - Initialize UD header structure * ib_ud_header_init - Initialize UD header structure
* @payload_bytes:Length of packet payload * @payload_bytes:Length of packet payload
* @grh_present:GRH flag (if non-zero, GRH will be included) * @grh_present:GRH flag (if non-zero, GRH will be included)
* @immediate_present: specify if immediate data should be used
* @header:Structure to initialize * @header:Structure to initialize
* *
* ib_ud_header_init() initializes the lrh.link_version, lrh.link_next_header, * ib_ud_header_init() initializes the lrh.link_version, lrh.link_next_header,
@ -191,21 +192,13 @@ static const struct ib_field deth_table[] = {
*/ */
void ib_ud_header_init(int payload_bytes, void ib_ud_header_init(int payload_bytes,
int grh_present, int grh_present,
int immediate_present,
struct ib_ud_header *header) struct ib_ud_header *header)
{ {
int header_len;
u16 packet_length; u16 packet_length;
memset(header, 0, sizeof *header); memset(header, 0, sizeof *header);
header_len =
IB_LRH_BYTES +
IB_BTH_BYTES +
IB_DETH_BYTES;
if (grh_present) {
header_len += IB_GRH_BYTES;
}
header->lrh.link_version = 0; header->lrh.link_version = 0;
header->lrh.link_next_header = header->lrh.link_next_header =
grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL; grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
@ -231,7 +224,8 @@ void ib_ud_header_init(int payload_bytes,
header->lrh.packet_length = cpu_to_be16(packet_length); header->lrh.packet_length = cpu_to_be16(packet_length);
if (header->immediate_present) header->immediate_present = immediate_present;
if (immediate_present)
header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
else else
header->bth.opcode = IB_OPCODE_UD_SEND_ONLY; header->bth.opcode = IB_OPCODE_UD_SEND_ONLY;

View file

@ -136,7 +136,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
down_write(&current->mm->mmap_sem); down_write(&current->mm->mmap_sem);
locked = npages + current->mm->locked_vm; locked = npages + current->mm->locked_vm;
lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT; lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) { if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) {
ret = -ENOMEM; ret = -ENOMEM;

View file

@ -65,12 +65,9 @@ enum {
}; };
/* /*
* Our lifetime rules for these structs are the following: each time a * Our lifetime rules for these structs are the following:
* device special file is opened, we look up the corresponding struct * device special file is opened, we take a reference on the
* ib_umad_port by minor in the umad_port[] table while holding the * ib_umad_port's struct ib_umad_device. We drop these
* port_lock. If this lookup succeeds, we take a reference on the
* ib_umad_port's struct ib_umad_device while still holding the
* port_lock; if the lookup fails, we fail the open(). We drop these
* references in the corresponding close(). * references in the corresponding close().
* *
* In addition to references coming from open character devices, there * In addition to references coming from open character devices, there
@ -78,19 +75,14 @@ enum {
* module's reference taken when allocating the ib_umad_device in * module's reference taken when allocating the ib_umad_device in
* ib_umad_add_one(). * ib_umad_add_one().
* *
* When destroying an ib_umad_device, we clear all of its * When destroying an ib_umad_device, we drop the module's reference.
* ib_umad_ports from umad_port[] while holding port_lock before
* dropping the module's reference to the ib_umad_device. This is
* always safe because any open() calls will either succeed and obtain
* a reference before we clear the umad_port[] entries, or fail after
* we clear the umad_port[] entries.
*/ */
struct ib_umad_port { struct ib_umad_port {
struct cdev *cdev; struct cdev cdev;
struct device *dev; struct device *dev;
struct cdev *sm_cdev; struct cdev sm_cdev;
struct device *sm_dev; struct device *sm_dev;
struct semaphore sm_sem; struct semaphore sm_sem;
@ -136,7 +128,6 @@ static struct class *umad_class;
static const dev_t base_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE); static const dev_t base_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE);
static DEFINE_SPINLOCK(port_lock); static DEFINE_SPINLOCK(port_lock);
static struct ib_umad_port *umad_port[IB_UMAD_MAX_PORTS];
static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS); static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS);
static void ib_umad_add_one(struct ib_device *device); static void ib_umad_add_one(struct ib_device *device);
@ -779,15 +770,11 @@ static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd,
/* /*
* ib_umad_open() does not need the BKL: * ib_umad_open() does not need the BKL:
* *
* - umad_port[] accesses are protected by port_lock, the * - the ib_umad_port structures are properly reference counted, and
* ib_umad_port structures are properly reference counted, and
* everything else is purely local to the file being created, so * everything else is purely local to the file being created, so
* races against other open calls are not a problem; * races against other open calls are not a problem;
* - the ioctl method does not affect any global state outside of the * - the ioctl method does not affect any global state outside of the
* file structure being operated on; * file structure being operated on;
* - the port is added to umad_port[] as the last part of module
* initialization so the open method will either immediately run
* -ENXIO, or all required initialization will be done.
*/ */
static int ib_umad_open(struct inode *inode, struct file *filp) static int ib_umad_open(struct inode *inode, struct file *filp)
{ {
@ -795,13 +782,10 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
struct ib_umad_file *file; struct ib_umad_file *file;
int ret = 0; int ret = 0;
spin_lock(&port_lock); port = container_of(inode->i_cdev, struct ib_umad_port, cdev);
port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE];
if (port) if (port)
kref_get(&port->umad_dev->ref); kref_get(&port->umad_dev->ref);
spin_unlock(&port_lock); else
if (!port)
return -ENXIO; return -ENXIO;
mutex_lock(&port->file_mutex); mutex_lock(&port->file_mutex);
@ -892,13 +876,10 @@ static int ib_umad_sm_open(struct inode *inode, struct file *filp)
}; };
int ret; int ret;
spin_lock(&port_lock); port = container_of(inode->i_cdev, struct ib_umad_port, sm_cdev);
port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE - IB_UMAD_MAX_PORTS];
if (port) if (port)
kref_get(&port->umad_dev->ref); kref_get(&port->umad_dev->ref);
spin_unlock(&port_lock); else
if (!port)
return -ENXIO; return -ENXIO;
if (filp->f_flags & O_NONBLOCK) { if (filp->f_flags & O_NONBLOCK) {
@ -990,16 +971,51 @@ static ssize_t show_abi_version(struct class *class, char *buf)
} }
static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
static dev_t overflow_maj;
static DECLARE_BITMAP(overflow_map, IB_UMAD_MAX_PORTS);
static int find_overflow_devnum(void)
{
int ret;
if (!overflow_maj) {
ret = alloc_chrdev_region(&overflow_maj, 0, IB_UMAD_MAX_PORTS * 2,
"infiniband_mad");
if (ret) {
printk(KERN_ERR "user_mad: couldn't register dynamic device number\n");
return ret;
}
}
ret = find_first_zero_bit(overflow_map, IB_UMAD_MAX_PORTS);
if (ret >= IB_UMAD_MAX_PORTS)
return -1;
return ret;
}
static int ib_umad_init_port(struct ib_device *device, int port_num, static int ib_umad_init_port(struct ib_device *device, int port_num,
struct ib_umad_port *port) struct ib_umad_port *port)
{ {
int devnum;
dev_t base;
spin_lock(&port_lock); spin_lock(&port_lock);
port->dev_num = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS);
if (port->dev_num >= IB_UMAD_MAX_PORTS) { if (devnum >= IB_UMAD_MAX_PORTS) {
spin_unlock(&port_lock); spin_unlock(&port_lock);
devnum = find_overflow_devnum();
if (devnum < 0)
return -1; return -1;
spin_lock(&port_lock);
port->dev_num = devnum + IB_UMAD_MAX_PORTS;
base = devnum + overflow_maj;
set_bit(devnum, overflow_map);
} else {
port->dev_num = devnum;
base = devnum + base_dev;
set_bit(devnum, dev_map);
} }
set_bit(port->dev_num, dev_map);
spin_unlock(&port_lock); spin_unlock(&port_lock);
port->ib_dev = device; port->ib_dev = device;
@ -1008,17 +1024,14 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
mutex_init(&port->file_mutex); mutex_init(&port->file_mutex);
INIT_LIST_HEAD(&port->file_list); INIT_LIST_HEAD(&port->file_list);
port->cdev = cdev_alloc(); cdev_init(&port->cdev, &umad_fops);
if (!port->cdev) port->cdev.owner = THIS_MODULE;
return -1; kobject_set_name(&port->cdev.kobj, "umad%d", port->dev_num);
port->cdev->owner = THIS_MODULE; if (cdev_add(&port->cdev, base, 1))
port->cdev->ops = &umad_fops;
kobject_set_name(&port->cdev->kobj, "umad%d", port->dev_num);
if (cdev_add(port->cdev, base_dev + port->dev_num, 1))
goto err_cdev; goto err_cdev;
port->dev = device_create(umad_class, device->dma_device, port->dev = device_create(umad_class, device->dma_device,
port->cdev->dev, port, port->cdev.dev, port,
"umad%d", port->dev_num); "umad%d", port->dev_num);
if (IS_ERR(port->dev)) if (IS_ERR(port->dev))
goto err_cdev; goto err_cdev;
@ -1028,17 +1041,15 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
if (device_create_file(port->dev, &dev_attr_port)) if (device_create_file(port->dev, &dev_attr_port))
goto err_dev; goto err_dev;
port->sm_cdev = cdev_alloc(); base += IB_UMAD_MAX_PORTS;
if (!port->sm_cdev) cdev_init(&port->sm_cdev, &umad_sm_fops);
goto err_dev; port->sm_cdev.owner = THIS_MODULE;
port->sm_cdev->owner = THIS_MODULE; kobject_set_name(&port->sm_cdev.kobj, "issm%d", port->dev_num);
port->sm_cdev->ops = &umad_sm_fops; if (cdev_add(&port->sm_cdev, base, 1))
kobject_set_name(&port->sm_cdev->kobj, "issm%d", port->dev_num);
if (cdev_add(port->sm_cdev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1))
goto err_sm_cdev; goto err_sm_cdev;
port->sm_dev = device_create(umad_class, device->dma_device, port->sm_dev = device_create(umad_class, device->dma_device,
port->sm_cdev->dev, port, port->sm_cdev.dev, port,
"issm%d", port->dev_num); "issm%d", port->dev_num);
if (IS_ERR(port->sm_dev)) if (IS_ERR(port->sm_dev))
goto err_sm_cdev; goto err_sm_cdev;
@ -1048,24 +1059,23 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
if (device_create_file(port->sm_dev, &dev_attr_port)) if (device_create_file(port->sm_dev, &dev_attr_port))
goto err_sm_dev; goto err_sm_dev;
spin_lock(&port_lock);
umad_port[port->dev_num] = port;
spin_unlock(&port_lock);
return 0; return 0;
err_sm_dev: err_sm_dev:
device_destroy(umad_class, port->sm_cdev->dev); device_destroy(umad_class, port->sm_cdev.dev);
err_sm_cdev: err_sm_cdev:
cdev_del(port->sm_cdev); cdev_del(&port->sm_cdev);
err_dev: err_dev:
device_destroy(umad_class, port->cdev->dev); device_destroy(umad_class, port->cdev.dev);
err_cdev: err_cdev:
cdev_del(port->cdev); cdev_del(&port->cdev);
clear_bit(port->dev_num, dev_map); if (port->dev_num < IB_UMAD_MAX_PORTS)
clear_bit(devnum, dev_map);
else
clear_bit(devnum, overflow_map);
return -1; return -1;
} }
@ -1079,15 +1089,11 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
dev_set_drvdata(port->dev, NULL); dev_set_drvdata(port->dev, NULL);
dev_set_drvdata(port->sm_dev, NULL); dev_set_drvdata(port->sm_dev, NULL);
device_destroy(umad_class, port->cdev->dev); device_destroy(umad_class, port->cdev.dev);
device_destroy(umad_class, port->sm_cdev->dev); device_destroy(umad_class, port->sm_cdev.dev);
cdev_del(port->cdev); cdev_del(&port->cdev);
cdev_del(port->sm_cdev); cdev_del(&port->sm_cdev);
spin_lock(&port_lock);
umad_port[port->dev_num] = NULL;
spin_unlock(&port_lock);
mutex_lock(&port->file_mutex); mutex_lock(&port->file_mutex);
@ -1106,7 +1112,10 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
mutex_unlock(&port->file_mutex); mutex_unlock(&port->file_mutex);
if (port->dev_num < IB_UMAD_MAX_PORTS)
clear_bit(port->dev_num, dev_map); clear_bit(port->dev_num, dev_map);
else
clear_bit(port->dev_num - IB_UMAD_MAX_PORTS, overflow_map);
} }
static void ib_umad_add_one(struct ib_device *device) static void ib_umad_add_one(struct ib_device *device)
@ -1214,6 +1223,8 @@ static void __exit ib_umad_cleanup(void)
ib_unregister_client(&umad_client); ib_unregister_client(&umad_client);
class_destroy(umad_class); class_destroy(umad_class);
unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2); unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2);
if (overflow_maj)
unregister_chrdev_region(overflow_maj, IB_UMAD_MAX_PORTS * 2);
} }
module_init(ib_umad_init); module_init(ib_umad_init);

View file

@ -41,6 +41,7 @@
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/cdev.h>
#include <rdma/ib_verbs.h> #include <rdma/ib_verbs.h>
#include <rdma/ib_umem.h> #include <rdma/ib_umem.h>
@ -69,23 +70,23 @@
struct ib_uverbs_device { struct ib_uverbs_device {
struct kref ref; struct kref ref;
int num_comp_vectors;
struct completion comp; struct completion comp;
int devnum;
struct cdev *cdev;
struct device *dev; struct device *dev;
struct ib_device *ib_dev; struct ib_device *ib_dev;
int num_comp_vectors; int devnum;
struct cdev cdev;
}; };
struct ib_uverbs_event_file { struct ib_uverbs_event_file {
struct kref ref; struct kref ref;
int is_async;
struct ib_uverbs_file *uverbs_file; struct ib_uverbs_file *uverbs_file;
spinlock_t lock; spinlock_t lock;
int is_closed;
wait_queue_head_t poll_wait; wait_queue_head_t poll_wait;
struct fasync_struct *async_queue; struct fasync_struct *async_queue;
struct list_head event_list; struct list_head event_list;
int is_async;
int is_closed;
}; };
struct ib_uverbs_file { struct ib_uverbs_file {

View file

@ -42,8 +42,8 @@
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/mount.h>
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/anon_inodes.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
@ -53,8 +53,6 @@ MODULE_AUTHOR("Roland Dreier");
MODULE_DESCRIPTION("InfiniBand userspace verbs access"); MODULE_DESCRIPTION("InfiniBand userspace verbs access");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
#define INFINIBANDEVENTFS_MAGIC 0x49426576 /* "IBev" */
enum { enum {
IB_UVERBS_MAJOR = 231, IB_UVERBS_MAJOR = 231,
IB_UVERBS_BASE_MINOR = 192, IB_UVERBS_BASE_MINOR = 192,
@ -75,7 +73,6 @@ DEFINE_IDR(ib_uverbs_qp_idr);
DEFINE_IDR(ib_uverbs_srq_idr); DEFINE_IDR(ib_uverbs_srq_idr);
static DEFINE_SPINLOCK(map_lock); static DEFINE_SPINLOCK(map_lock);
static struct ib_uverbs_device *dev_table[IB_UVERBS_MAX_DEVICES];
static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
@ -111,8 +108,6 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
[IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq, [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq,
}; };
static struct vfsmount *uverbs_event_mnt;
static void ib_uverbs_add_one(struct ib_device *device); static void ib_uverbs_add_one(struct ib_device *device);
static void ib_uverbs_remove_one(struct ib_device *device); static void ib_uverbs_remove_one(struct ib_device *device);
@ -492,7 +487,6 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
int is_async, int *fd) int is_async, int *fd)
{ {
struct ib_uverbs_event_file *ev_file; struct ib_uverbs_event_file *ev_file;
struct path path;
struct file *filp; struct file *filp;
int ret; int ret;
@ -515,27 +509,16 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
goto err; goto err;
} }
/* filp = anon_inode_getfile("[uverbs-event]", &uverbs_event_fops,
* fops_get() can't fail here, because we're coming from a ev_file, O_RDONLY);
* system call on a uverbs file, which will already have a
* module reference.
*/
path.mnt = uverbs_event_mnt;
path.dentry = uverbs_event_mnt->mnt_root;
path_get(&path);
filp = alloc_file(&path, FMODE_READ, fops_get(&uverbs_event_fops));
if (!filp) { if (!filp) {
ret = -ENFILE; ret = -ENFILE;
goto err_fd; goto err_fd;
} }
filp->private_data = ev_file;
return filp; return filp;
err_fd: err_fd:
fops_put(&uverbs_event_fops);
path_put(&path);
put_unused_fd(*fd); put_unused_fd(*fd);
err: err:
@ -617,14 +600,12 @@ static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma)
/* /*
* ib_uverbs_open() does not need the BKL: * ib_uverbs_open() does not need the BKL:
* *
* - dev_table[] accesses are protected by map_lock, the * - the ib_uverbs_device structures are properly reference counted and
* ib_uverbs_device structures are properly reference counted, and
* everything else is purely local to the file being created, so * everything else is purely local to the file being created, so
* races against other open calls are not a problem; * races against other open calls are not a problem;
* - there is no ioctl method to race against; * - there is no ioctl method to race against;
* - the device is added to dev_table[] as the last part of module * - the open method will either immediately run -ENXIO, or all
* initialization, the open method will either immediately run * required initialization will be done.
* -ENXIO, or all required initialization will be done.
*/ */
static int ib_uverbs_open(struct inode *inode, struct file *filp) static int ib_uverbs_open(struct inode *inode, struct file *filp)
{ {
@ -632,13 +613,10 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
struct ib_uverbs_file *file; struct ib_uverbs_file *file;
int ret; int ret;
spin_lock(&map_lock); dev = container_of(inode->i_cdev, struct ib_uverbs_device, cdev);
dev = dev_table[iminor(inode) - IB_UVERBS_BASE_MINOR];
if (dev) if (dev)
kref_get(&dev->ref); kref_get(&dev->ref);
spin_unlock(&map_lock); else
if (!dev)
return -ENXIO; return -ENXIO;
if (!try_module_get(dev->ib_dev->owner)) { if (!try_module_get(dev->ib_dev->owner)) {
@ -735,8 +713,38 @@ static ssize_t show_abi_version(struct class *class, char *buf)
} }
static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
static dev_t overflow_maj;
static DECLARE_BITMAP(overflow_map, IB_UVERBS_MAX_DEVICES);
/*
* If we have more than IB_UVERBS_MAX_DEVICES, dynamically overflow by
* requesting a new major number and doubling the number of max devices we
* support. It's stupid, but simple.
*/
static int find_overflow_devnum(void)
{
int ret;
if (!overflow_maj) {
ret = alloc_chrdev_region(&overflow_maj, 0, IB_UVERBS_MAX_DEVICES,
"infiniband_verbs");
if (ret) {
printk(KERN_ERR "user_verbs: couldn't register dynamic device number\n");
return ret;
}
}
ret = find_first_zero_bit(overflow_map, IB_UVERBS_MAX_DEVICES);
if (ret >= IB_UVERBS_MAX_DEVICES)
return -1;
return ret;
}
static void ib_uverbs_add_one(struct ib_device *device) static void ib_uverbs_add_one(struct ib_device *device)
{ {
int devnum;
dev_t base;
struct ib_uverbs_device *uverbs_dev; struct ib_uverbs_device *uverbs_dev;
if (!device->alloc_ucontext) if (!device->alloc_ucontext)
@ -750,28 +758,36 @@ static void ib_uverbs_add_one(struct ib_device *device)
init_completion(&uverbs_dev->comp); init_completion(&uverbs_dev->comp);
spin_lock(&map_lock); spin_lock(&map_lock);
uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
if (uverbs_dev->devnum >= IB_UVERBS_MAX_DEVICES) { if (devnum >= IB_UVERBS_MAX_DEVICES) {
spin_unlock(&map_lock); spin_unlock(&map_lock);
devnum = find_overflow_devnum();
if (devnum < 0)
goto err; goto err;
spin_lock(&map_lock);
uverbs_dev->devnum = devnum + IB_UVERBS_MAX_DEVICES;
base = devnum + overflow_maj;
set_bit(devnum, overflow_map);
} else {
uverbs_dev->devnum = devnum;
base = devnum + IB_UVERBS_BASE_DEV;
set_bit(devnum, dev_map);
} }
set_bit(uverbs_dev->devnum, dev_map);
spin_unlock(&map_lock); spin_unlock(&map_lock);
uverbs_dev->ib_dev = device; uverbs_dev->ib_dev = device;
uverbs_dev->num_comp_vectors = device->num_comp_vectors; uverbs_dev->num_comp_vectors = device->num_comp_vectors;
uverbs_dev->cdev = cdev_alloc(); cdev_init(&uverbs_dev->cdev, NULL);
if (!uverbs_dev->cdev) uverbs_dev->cdev.owner = THIS_MODULE;
goto err; uverbs_dev->cdev.ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops;
uverbs_dev->cdev->owner = THIS_MODULE; kobject_set_name(&uverbs_dev->cdev.kobj, "uverbs%d", uverbs_dev->devnum);
uverbs_dev->cdev->ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; if (cdev_add(&uverbs_dev->cdev, base, 1))
kobject_set_name(&uverbs_dev->cdev->kobj, "uverbs%d", uverbs_dev->devnum);
if (cdev_add(uverbs_dev->cdev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1))
goto err_cdev; goto err_cdev;
uverbs_dev->dev = device_create(uverbs_class, device->dma_device, uverbs_dev->dev = device_create(uverbs_class, device->dma_device,
uverbs_dev->cdev->dev, uverbs_dev, uverbs_dev->cdev.dev, uverbs_dev,
"uverbs%d", uverbs_dev->devnum); "uverbs%d", uverbs_dev->devnum);
if (IS_ERR(uverbs_dev->dev)) if (IS_ERR(uverbs_dev->dev))
goto err_cdev; goto err_cdev;
@ -781,20 +797,19 @@ static void ib_uverbs_add_one(struct ib_device *device)
if (device_create_file(uverbs_dev->dev, &dev_attr_abi_version)) if (device_create_file(uverbs_dev->dev, &dev_attr_abi_version))
goto err_class; goto err_class;
spin_lock(&map_lock);
dev_table[uverbs_dev->devnum] = uverbs_dev;
spin_unlock(&map_lock);
ib_set_client_data(device, &uverbs_client, uverbs_dev); ib_set_client_data(device, &uverbs_client, uverbs_dev);
return; return;
err_class: err_class:
device_destroy(uverbs_class, uverbs_dev->cdev->dev); device_destroy(uverbs_class, uverbs_dev->cdev.dev);
err_cdev: err_cdev:
cdev_del(uverbs_dev->cdev); cdev_del(&uverbs_dev->cdev);
clear_bit(uverbs_dev->devnum, dev_map); if (uverbs_dev->devnum < IB_UVERBS_MAX_DEVICES)
clear_bit(devnum, dev_map);
else
clear_bit(devnum, overflow_map);
err: err:
kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
@ -811,35 +826,19 @@ static void ib_uverbs_remove_one(struct ib_device *device)
return; return;
dev_set_drvdata(uverbs_dev->dev, NULL); dev_set_drvdata(uverbs_dev->dev, NULL);
device_destroy(uverbs_class, uverbs_dev->cdev->dev); device_destroy(uverbs_class, uverbs_dev->cdev.dev);
cdev_del(uverbs_dev->cdev); cdev_del(&uverbs_dev->cdev);
spin_lock(&map_lock);
dev_table[uverbs_dev->devnum] = NULL;
spin_unlock(&map_lock);
if (uverbs_dev->devnum < IB_UVERBS_MAX_DEVICES)
clear_bit(uverbs_dev->devnum, dev_map); clear_bit(uverbs_dev->devnum, dev_map);
else
clear_bit(uverbs_dev->devnum - IB_UVERBS_MAX_DEVICES, overflow_map);
kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
wait_for_completion(&uverbs_dev->comp); wait_for_completion(&uverbs_dev->comp);
kfree(uverbs_dev); kfree(uverbs_dev);
} }
static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data,
struct vfsmount *mnt)
{
return get_sb_pseudo(fs_type, "infinibandevent:", NULL,
INFINIBANDEVENTFS_MAGIC, mnt);
}
static struct file_system_type uverbs_event_fs = {
/* No owner field so module can be unloaded */
.name = "infinibandeventfs",
.get_sb = uverbs_event_get_sb,
.kill_sb = kill_litter_super
};
static int __init ib_uverbs_init(void) static int __init ib_uverbs_init(void)
{ {
int ret; int ret;
@ -864,33 +863,14 @@ static int __init ib_uverbs_init(void)
goto out_class; goto out_class;
} }
ret = register_filesystem(&uverbs_event_fs);
if (ret) {
printk(KERN_ERR "user_verbs: couldn't register infinibandeventfs\n");
goto out_class;
}
uverbs_event_mnt = kern_mount(&uverbs_event_fs);
if (IS_ERR(uverbs_event_mnt)) {
ret = PTR_ERR(uverbs_event_mnt);
printk(KERN_ERR "user_verbs: couldn't mount infinibandeventfs\n");
goto out_fs;
}
ret = ib_register_client(&uverbs_client); ret = ib_register_client(&uverbs_client);
if (ret) { if (ret) {
printk(KERN_ERR "user_verbs: couldn't register client\n"); printk(KERN_ERR "user_verbs: couldn't register client\n");
goto out_mnt; goto out_class;
} }
return 0; return 0;
out_mnt:
mntput(uverbs_event_mnt);
out_fs:
unregister_filesystem(&uverbs_event_fs);
out_class: out_class:
class_destroy(uverbs_class); class_destroy(uverbs_class);
@ -904,10 +884,10 @@ out:
static void __exit ib_uverbs_cleanup(void) static void __exit ib_uverbs_cleanup(void)
{ {
ib_unregister_client(&uverbs_client); ib_unregister_client(&uverbs_client);
mntput(uverbs_event_mnt);
unregister_filesystem(&uverbs_event_fs);
class_destroy(uverbs_class); class_destroy(uverbs_class);
unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES);
if (overflow_maj)
unregister_chrdev_region(overflow_maj, IB_UVERBS_MAX_DEVICES);
idr_destroy(&ib_uverbs_pd_idr); idr_destroy(&ib_uverbs_pd_idr);
idr_destroy(&ib_uverbs_mr_idr); idr_destroy(&ib_uverbs_mr_idr);
idr_destroy(&ib_uverbs_mw_idr); idr_destroy(&ib_uverbs_mw_idr);

View file

@ -109,7 +109,6 @@ int cxio_hal_cq_op(struct cxio_rdev *rdev_p, struct t3_cq *cq,
while (!CQ_VLD_ENTRY(rptr, cq->size_log2, cqe)) { while (!CQ_VLD_ENTRY(rptr, cq->size_log2, cqe)) {
udelay(1); udelay(1);
if (i++ > 1000000) { if (i++ > 1000000) {
BUG_ON(1);
printk(KERN_ERR "%s: stalled rnic\n", printk(KERN_ERR "%s: stalled rnic\n",
rdev_p->dev_name); rdev_p->dev_name);
return -EIO; return -EIO;
@ -155,7 +154,7 @@ static int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev_p, u32 qpid)
return iwch_cxgb3_ofld_send(rdev_p->t3cdev_p, skb); return iwch_cxgb3_ofld_send(rdev_p->t3cdev_p, skb);
} }
int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq) int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq, int kernel)
{ {
struct rdma_cq_setup setup; struct rdma_cq_setup setup;
int size = (1UL << (cq->size_log2)) * sizeof(struct t3_cqe); int size = (1UL << (cq->size_log2)) * sizeof(struct t3_cqe);
@ -163,12 +162,12 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
cq->cqid = cxio_hal_get_cqid(rdev_p->rscp); cq->cqid = cxio_hal_get_cqid(rdev_p->rscp);
if (!cq->cqid) if (!cq->cqid)
return -ENOMEM; return -ENOMEM;
if (kernel) {
cq->sw_queue = kzalloc(size, GFP_KERNEL); cq->sw_queue = kzalloc(size, GFP_KERNEL);
if (!cq->sw_queue) if (!cq->sw_queue)
return -ENOMEM; return -ENOMEM;
cq->queue = dma_alloc_coherent(&(rdev_p->rnic_info.pdev->dev), }
(1UL << (cq->size_log2)) * cq->queue = dma_alloc_coherent(&(rdev_p->rnic_info.pdev->dev), size,
sizeof(struct t3_cqe),
&(cq->dma_addr), GFP_KERNEL); &(cq->dma_addr), GFP_KERNEL);
if (!cq->queue) { if (!cq->queue) {
kfree(cq->sw_queue); kfree(cq->sw_queue);

View file

@ -53,7 +53,7 @@
#define T3_MAX_PBL_SIZE 256 #define T3_MAX_PBL_SIZE 256
#define T3_MAX_RQ_SIZE 1024 #define T3_MAX_RQ_SIZE 1024
#define T3_MAX_QP_DEPTH (T3_MAX_RQ_SIZE-1) #define T3_MAX_QP_DEPTH (T3_MAX_RQ_SIZE-1)
#define T3_MAX_CQ_DEPTH 8192 #define T3_MAX_CQ_DEPTH 262144
#define T3_MAX_NUM_STAG (1<<15) #define T3_MAX_NUM_STAG (1<<15)
#define T3_MAX_MR_SIZE 0x100000000ULL #define T3_MAX_MR_SIZE 0x100000000ULL
#define T3_PAGESIZE_MASK 0xffff000 /* 4KB-128MB */ #define T3_PAGESIZE_MASK 0xffff000 /* 4KB-128MB */
@ -157,7 +157,7 @@ int cxio_rdev_open(struct cxio_rdev *rdev);
void cxio_rdev_close(struct cxio_rdev *rdev); void cxio_rdev_close(struct cxio_rdev *rdev);
int cxio_hal_cq_op(struct cxio_rdev *rdev, struct t3_cq *cq, int cxio_hal_cq_op(struct cxio_rdev *rdev, struct t3_cq *cq,
enum t3_cq_opcode op, u32 credit); enum t3_cq_opcode op, u32 credit);
int cxio_create_cq(struct cxio_rdev *rdev, struct t3_cq *cq); int cxio_create_cq(struct cxio_rdev *rdev, struct t3_cq *cq, int kernel);
int cxio_destroy_cq(struct cxio_rdev *rdev, struct t3_cq *cq); int cxio_destroy_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
int cxio_resize_cq(struct cxio_rdev *rdev, struct t3_cq *cq); int cxio_resize_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
void cxio_release_ucontext(struct cxio_rdev *rdev, struct cxio_ucontext *uctx); void cxio_release_ucontext(struct cxio_rdev *rdev, struct cxio_ucontext *uctx);

View file

@ -730,7 +730,22 @@ struct t3_cq {
static inline void cxio_set_wq_in_error(struct t3_wq *wq) static inline void cxio_set_wq_in_error(struct t3_wq *wq)
{ {
wq->queue->wq_in_err.err = 1; wq->queue->wq_in_err.err |= 1;
}
static inline void cxio_disable_wq_db(struct t3_wq *wq)
{
wq->queue->wq_in_err.err |= 2;
}
static inline void cxio_enable_wq_db(struct t3_wq *wq)
{
wq->queue->wq_in_err.err &= ~2;
}
static inline int cxio_wq_db_enabled(struct t3_wq *wq)
{
return !(wq->queue->wq_in_err.err & 2);
} }
static inline struct t3_cqe *cxio_next_hw_cqe(struct t3_cq *cq) static inline struct t3_cqe *cxio_next_hw_cqe(struct t3_cq *cq)

View file

@ -65,6 +65,46 @@ struct cxgb3_client t3c_client = {
static LIST_HEAD(dev_list); static LIST_HEAD(dev_list);
static DEFINE_MUTEX(dev_mutex); static DEFINE_MUTEX(dev_mutex);
static int disable_qp_db(int id, void *p, void *data)
{
struct iwch_qp *qhp = p;
cxio_disable_wq_db(&qhp->wq);
return 0;
}
static int enable_qp_db(int id, void *p, void *data)
{
struct iwch_qp *qhp = p;
if (data)
ring_doorbell(qhp->rhp->rdev.ctrl_qp.doorbell, qhp->wq.qpid);
cxio_enable_wq_db(&qhp->wq);
return 0;
}
static void disable_dbs(struct iwch_dev *rnicp)
{
spin_lock_irq(&rnicp->lock);
idr_for_each(&rnicp->qpidr, disable_qp_db, NULL);
spin_unlock_irq(&rnicp->lock);
}
static void enable_dbs(struct iwch_dev *rnicp, int ring_db)
{
spin_lock_irq(&rnicp->lock);
idr_for_each(&rnicp->qpidr, enable_qp_db,
(void *)(unsigned long)ring_db);
spin_unlock_irq(&rnicp->lock);
}
static void iwch_db_drop_task(struct work_struct *work)
{
struct iwch_dev *rnicp = container_of(work, struct iwch_dev,
db_drop_task.work);
enable_dbs(rnicp, 1);
}
static void rnic_init(struct iwch_dev *rnicp) static void rnic_init(struct iwch_dev *rnicp)
{ {
PDBG("%s iwch_dev %p\n", __func__, rnicp); PDBG("%s iwch_dev %p\n", __func__, rnicp);
@ -72,6 +112,7 @@ static void rnic_init(struct iwch_dev *rnicp)
idr_init(&rnicp->qpidr); idr_init(&rnicp->qpidr);
idr_init(&rnicp->mmidr); idr_init(&rnicp->mmidr);
spin_lock_init(&rnicp->lock); spin_lock_init(&rnicp->lock);
INIT_DELAYED_WORK(&rnicp->db_drop_task, iwch_db_drop_task);
rnicp->attr.max_qps = T3_MAX_NUM_QP - 32; rnicp->attr.max_qps = T3_MAX_NUM_QP - 32;
rnicp->attr.max_wrs = T3_MAX_QP_DEPTH; rnicp->attr.max_wrs = T3_MAX_QP_DEPTH;
@ -147,6 +188,8 @@ static void close_rnic_dev(struct t3cdev *tdev)
mutex_lock(&dev_mutex); mutex_lock(&dev_mutex);
list_for_each_entry_safe(dev, tmp, &dev_list, entry) { list_for_each_entry_safe(dev, tmp, &dev_list, entry) {
if (dev->rdev.t3cdev_p == tdev) { if (dev->rdev.t3cdev_p == tdev) {
dev->rdev.flags = CXIO_ERROR_FATAL;
cancel_delayed_work_sync(&dev->db_drop_task);
list_del(&dev->entry); list_del(&dev->entry);
iwch_unregister_device(dev); iwch_unregister_device(dev);
cxio_rdev_close(&dev->rdev); cxio_rdev_close(&dev->rdev);
@ -166,6 +209,7 @@ static void iwch_event_handler(struct t3cdev *tdev, u32 evt, u32 port_id)
struct iwch_dev *rnicp; struct iwch_dev *rnicp;
struct ib_event event; struct ib_event event;
u32 portnum = port_id + 1; u32 portnum = port_id + 1;
int dispatch = 0;
if (!rdev) if (!rdev)
return; return;
@ -174,21 +218,49 @@ static void iwch_event_handler(struct t3cdev *tdev, u32 evt, u32 port_id)
case OFFLOAD_STATUS_DOWN: { case OFFLOAD_STATUS_DOWN: {
rdev->flags = CXIO_ERROR_FATAL; rdev->flags = CXIO_ERROR_FATAL;
event.event = IB_EVENT_DEVICE_FATAL; event.event = IB_EVENT_DEVICE_FATAL;
dispatch = 1;
break; break;
} }
case OFFLOAD_PORT_DOWN: { case OFFLOAD_PORT_DOWN: {
event.event = IB_EVENT_PORT_ERR; event.event = IB_EVENT_PORT_ERR;
dispatch = 1;
break; break;
} }
case OFFLOAD_PORT_UP: { case OFFLOAD_PORT_UP: {
event.event = IB_EVENT_PORT_ACTIVE; event.event = IB_EVENT_PORT_ACTIVE;
dispatch = 1;
break;
}
case OFFLOAD_DB_FULL: {
disable_dbs(rnicp);
break;
}
case OFFLOAD_DB_EMPTY: {
enable_dbs(rnicp, 1);
break;
}
case OFFLOAD_DB_DROP: {
unsigned long delay = 1000;
unsigned short r;
disable_dbs(rnicp);
get_random_bytes(&r, 2);
delay += r & 1023;
/*
* delay is between 1000-2023 usecs.
*/
schedule_delayed_work(&rnicp->db_drop_task,
usecs_to_jiffies(delay));
break; break;
} }
} }
if (dispatch) {
event.device = &rnicp->ibdev; event.device = &rnicp->ibdev;
event.element.port_num = portnum; event.element.port_num = portnum;
ib_dispatch_event(&event); ib_dispatch_event(&event);
}
return; return;
} }

View file

@ -36,6 +36,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/workqueue.h>
#include <rdma/ib_verbs.h> #include <rdma/ib_verbs.h>
@ -110,6 +111,7 @@ struct iwch_dev {
struct idr mmidr; struct idr mmidr;
spinlock_t lock; spinlock_t lock;
struct list_head entry; struct list_head entry;
struct delayed_work db_drop_task;
}; };
static inline struct iwch_dev *to_iwch_dev(struct ib_device *ibdev) static inline struct iwch_dev *to_iwch_dev(struct ib_device *ibdev)

View file

@ -187,7 +187,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
entries = roundup_pow_of_two(entries); entries = roundup_pow_of_two(entries);
chp->cq.size_log2 = ilog2(entries); chp->cq.size_log2 = ilog2(entries);
if (cxio_create_cq(&rhp->rdev, &chp->cq)) { if (cxio_create_cq(&rhp->rdev, &chp->cq, !ucontext)) {
kfree(chp); kfree(chp);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }

View file

@ -452,6 +452,7 @@ int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
++(qhp->wq.sq_wptr); ++(qhp->wq.sq_wptr);
} }
spin_unlock_irqrestore(&qhp->lock, flag); spin_unlock_irqrestore(&qhp->lock, flag);
if (cxio_wq_db_enabled(&qhp->wq))
ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid); ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);
out: out:
@ -514,6 +515,7 @@ int iwch_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
num_wrs--; num_wrs--;
} }
spin_unlock_irqrestore(&qhp->lock, flag); spin_unlock_irqrestore(&qhp->lock, flag);
if (cxio_wq_db_enabled(&qhp->wq))
ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid); ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);
out: out:
@ -597,6 +599,7 @@ int iwch_bind_mw(struct ib_qp *qp,
++(qhp->wq.sq_wptr); ++(qhp->wq.sq_wptr);
spin_unlock_irqrestore(&qhp->lock, flag); spin_unlock_irqrestore(&qhp->lock, flag);
if (cxio_wq_db_enabled(&qhp->wq))
ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid); ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);
return err; return err;

View file

@ -548,11 +548,10 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq)
struct ehca_eq *eq = &shca->eq; struct ehca_eq *eq = &shca->eq;
struct ehca_eqe_cache_entry *eqe_cache = eq->eqe_cache; struct ehca_eqe_cache_entry *eqe_cache = eq->eqe_cache;
u64 eqe_value, ret; u64 eqe_value, ret;
unsigned long flags;
int eqe_cnt, i; int eqe_cnt, i;
int eq_empty = 0; int eq_empty = 0;
spin_lock_irqsave(&eq->irq_spinlock, flags); spin_lock(&eq->irq_spinlock);
if (is_irq) { if (is_irq) {
const int max_query_cnt = 100; const int max_query_cnt = 100;
int query_cnt = 0; int query_cnt = 0;
@ -643,7 +642,7 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq)
} while (1); } while (1);
unlock_irq_spinlock: unlock_irq_spinlock:
spin_unlock_irqrestore(&eq->irq_spinlock, flags); spin_unlock(&eq->irq_spinlock);
} }
void ehca_tasklet_eq(unsigned long data) void ehca_tasklet_eq(unsigned long data)

View file

@ -55,9 +55,7 @@ static struct kmem_cache *qp_cache;
/* /*
* attributes not supported by query qp * attributes not supported by query qp
*/ */
#define QP_ATTR_QUERY_NOT_SUPPORTED (IB_QP_MAX_DEST_RD_ATOMIC | \ #define QP_ATTR_QUERY_NOT_SUPPORTED (IB_QP_ACCESS_FLAGS | \
IB_QP_MAX_QP_RD_ATOMIC | \
IB_QP_ACCESS_FLAGS | \
IB_QP_EN_SQD_ASYNC_NOTIFY) IB_QP_EN_SQD_ASYNC_NOTIFY)
/* /*

View file

@ -222,7 +222,7 @@ int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
{ {
int ret; int ret;
if (!port_num || port_num > ibdev->phys_port_cnt) if (!port_num || port_num > ibdev->phys_port_cnt || !in_wc)
return IB_MAD_RESULT_FAILURE; return IB_MAD_RESULT_FAILURE;
/* accept only pma request */ /* accept only pma request */

View file

@ -59,8 +59,7 @@ static int __get_user_pages(unsigned long start_page, size_t num_pages,
size_t got; size_t got;
int ret; int ret;
lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
PAGE_SHIFT;
if (num_pages > lock_limit) { if (num_pages > lock_limit) {
ret = -ENOMEM; ret = -ENOMEM;

View file

@ -1214,7 +1214,7 @@ out:
static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
void *wqe, unsigned *mlx_seg_len) void *wqe, unsigned *mlx_seg_len)
{ {
struct ib_device *ib_dev = &to_mdev(sqp->qp.ibqp.device)->ib_dev; struct ib_device *ib_dev = sqp->qp.ibqp.device;
struct mlx4_wqe_mlx_seg *mlx = wqe; struct mlx4_wqe_mlx_seg *mlx = wqe;
struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx; struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah); struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
@ -1228,7 +1228,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
for (i = 0; i < wr->num_sge; ++i) for (i = 0; i < wr->num_sge; ++i)
send_size += wr->sg_list[i].length; send_size += wr->sg_list[i].length;
ib_ud_header_init(send_size, mlx4_ib_ah_grh_present(ah), &sqp->ud_header); ib_ud_header_init(send_size, mlx4_ib_ah_grh_present(ah), 0, &sqp->ud_header);
sqp->ud_header.lrh.service_level = sqp->ud_header.lrh.service_level =
be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28; be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28;

View file

@ -1494,7 +1494,7 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
u16 pkey; u16 pkey;
ib_ud_header_init(256, /* assume a MAD */ ib_ud_header_init(256, /* assume a MAD */
mthca_ah_grh_present(to_mah(wr->wr.ud.ah)), mthca_ah_grh_present(to_mah(wr->wr.ud.ah)), 0,
&sqp->ud_header); &sqp->ud_header);
err = mthca_read_ah(dev, to_mah(wr->wr.ud.ah), &sqp->ud_header); err = mthca_read_ah(dev, to_mah(wr->wr.ud.ah), &sqp->ud_header);

View file

@ -110,6 +110,7 @@ static unsigned int sysfs_idx_addr;
static struct pci_device_id nes_pci_table[] = { static struct pci_device_id nes_pci_table[] = {
{PCI_VENDOR_ID_NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020, PCI_ANY_ID, PCI_ANY_ID}, {PCI_VENDOR_ID_NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020, PCI_ANY_ID, PCI_ANY_ID},
{PCI_VENDOR_ID_NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020_KR, PCI_ANY_ID, PCI_ANY_ID},
{0} {0}
}; };

View file

@ -66,6 +66,7 @@
#ifndef PCI_VENDOR_ID_NETEFFECT /* not in pci.ids yet */ #ifndef PCI_VENDOR_ID_NETEFFECT /* not in pci.ids yet */
#define PCI_VENDOR_ID_NETEFFECT 0x1678 #define PCI_VENDOR_ID_NETEFFECT 0x1678
#define PCI_DEVICE_ID_NETEFFECT_NE020 0x0100 #define PCI_DEVICE_ID_NETEFFECT_NE020 0x0100
#define PCI_DEVICE_ID_NETEFFECT_NE020_KR 0x0110
#endif #endif
#define NE020_REV 4 #define NE020_REV 4
@ -193,8 +194,8 @@ extern u32 cm_packets_created;
extern u32 cm_packets_received; extern u32 cm_packets_received;
extern u32 cm_packets_dropped; extern u32 cm_packets_dropped;
extern u32 cm_packets_retrans; extern u32 cm_packets_retrans;
extern u32 cm_listens_created; extern atomic_t cm_listens_created;
extern u32 cm_listens_destroyed; extern atomic_t cm_listens_destroyed;
extern u32 cm_backlog_drops; extern u32 cm_backlog_drops;
extern atomic_t cm_loopbacks; extern atomic_t cm_loopbacks;
extern atomic_t cm_nodes_created; extern atomic_t cm_nodes_created;

View file

@ -67,8 +67,8 @@ u32 cm_packets_dropped;
u32 cm_packets_retrans; u32 cm_packets_retrans;
u32 cm_packets_created; u32 cm_packets_created;
u32 cm_packets_received; u32 cm_packets_received;
u32 cm_listens_created; atomic_t cm_listens_created;
u32 cm_listens_destroyed; atomic_t cm_listens_destroyed;
u32 cm_backlog_drops; u32 cm_backlog_drops;
atomic_t cm_loopbacks; atomic_t cm_loopbacks;
atomic_t cm_nodes_created; atomic_t cm_nodes_created;
@ -1011,9 +1011,10 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
event.cm_info.loc_port = event.cm_info.loc_port =
loopback->loc_port; loopback->loc_port;
event.cm_info.cm_id = loopback->cm_id; event.cm_info.cm_id = loopback->cm_id;
add_ref_cm_node(loopback);
loopback->state = NES_CM_STATE_CLOSED;
cm_event_connect_error(&event); cm_event_connect_error(&event);
cm_node->state = NES_CM_STATE_LISTENER_DESTROYED; cm_node->state = NES_CM_STATE_LISTENER_DESTROYED;
loopback->state = NES_CM_STATE_CLOSED;
rem_ref_cm_node(cm_node->cm_core, rem_ref_cm_node(cm_node->cm_core,
cm_node); cm_node);
@ -1042,7 +1043,7 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
kfree(listener); kfree(listener);
listener = NULL; listener = NULL;
ret = 0; ret = 0;
cm_listens_destroyed++; atomic_inc(&cm_listens_destroyed);
} else { } else {
spin_unlock_irqrestore(&cm_core->listen_list_lock, flags); spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
} }
@ -3172,7 +3173,7 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node); g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node);
return err; return err;
} }
cm_listens_created++; atomic_inc(&cm_listens_created);
} }
cm_id->add_ref(cm_id); cm_id->add_ref(cm_id);

View file

@ -748,16 +748,28 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
if (hw_rev != NE020_REV) { if (hw_rev != NE020_REV) {
/* init serdes 0 */ /* init serdes 0 */
if (wide_ppm_offset && (nesadapter->phy_type[0] == NES_PHY_TYPE_CX4)) switch (nesadapter->phy_type[0]) {
case NES_PHY_TYPE_CX4:
if (wide_ppm_offset)
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000FFFAA); nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000FFFAA);
else else
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF); nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
break;
if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) { case NES_PHY_TYPE_KR:
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x00000000);
break;
case NES_PHY_TYPE_PUMA_1G:
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0); sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0);
sds |= 0x00000100; sds |= 0x00000100;
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds); nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds);
break;
default:
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
break;
} }
if (!OneG_Mode) if (!OneG_Mode)
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0, 0x11110000); nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0, 0x11110000);
@ -778,6 +790,9 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
if (wide_ppm_offset) if (wide_ppm_offset)
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000FFFAA); nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000FFFAA);
break; break;
case NES_PHY_TYPE_KR:
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x00000000);
break;
case NES_PHY_TYPE_PUMA_1G: case NES_PHY_TYPE_PUMA_1G:
sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1); sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
sds |= 0x000000100; sds |= 0x000000100;
@ -1279,30 +1294,13 @@ int nes_destroy_cqp(struct nes_device *nesdev)
/** /**
* nes_init_phy * nes_init_1g_phy
*/ */
int nes_init_phy(struct nes_device *nesdev) int nes_init_1g_phy(struct nes_device *nesdev, u8 phy_type, u8 phy_index)
{ {
struct nes_adapter *nesadapter = nesdev->nesadapter;
u32 counter = 0; u32 counter = 0;
u32 sds;
u32 mac_index = nesdev->mac_index;
u32 tx_config = 0;
u16 phy_data; u16 phy_data;
u32 temp_phy_data = 0; int ret = 0;
u32 temp_phy_data2 = 0;
u8 phy_type = nesadapter->phy_type[mac_index];
u8 phy_index = nesadapter->phy_index[mac_index];
if ((nesadapter->OneG_Mode) &&
(phy_type != NES_PHY_TYPE_PUMA_1G)) {
nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index);
if (phy_type == NES_PHY_TYPE_1G) {
tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
tx_config &= 0xFFFFFFE3;
tx_config |= 0x04;
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
}
nes_read_1G_phy_reg(nesdev, 1, phy_index, &phy_data); nes_read_1G_phy_reg(nesdev, 1, phy_index, &phy_data);
nes_write_1G_phy_reg(nesdev, 23, phy_index, 0xb000); nes_write_1G_phy_reg(nesdev, 23, phy_index, 0xb000);
@ -1313,8 +1311,10 @@ int nes_init_phy(struct nes_device *nesdev)
counter = 0; counter = 0;
do { do {
nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data); nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
if (counter++ > 100) if (counter++ > 100) {
ret = -1;
break; break;
}
} while (phy_data & 0x8000); } while (phy_data & 0x8000);
/* Setting no phy loopback */ /* Setting no phy loopback */
@ -1343,21 +1343,22 @@ int nes_init_phy(struct nes_device *nesdev)
nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data); nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data | 0x0300); nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data | 0x0300);
return 0; return ret;
} }
if ((phy_type == NES_PHY_TYPE_IRIS) ||
(phy_type == NES_PHY_TYPE_ARGUS) || /**
(phy_type == NES_PHY_TYPE_SFP_D)) { * nes_init_2025_phy
/* setup 10G MDIO operation */ */
tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG); int nes_init_2025_phy(struct nes_device *nesdev, u8 phy_type, u8 phy_index)
tx_config &= 0xFFFFFFE3; {
tx_config |= 0x15; u32 temp_phy_data = 0;
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config); u32 temp_phy_data2 = 0;
} u32 counter = 0;
if ((phy_type == NES_PHY_TYPE_ARGUS) || u32 sds;
(phy_type == NES_PHY_TYPE_SFP_D)) { u32 mac_index = nesdev->mac_index;
u32 first_time = 1; int ret = 0;
unsigned int first_attempt = 1;
/* Check firmware heartbeat */ /* Check firmware heartbeat */
nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee); nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
@ -1371,7 +1372,7 @@ int nes_init_phy(struct nes_device *nesdev)
temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
if ((temp_phy_data & 0xff) > 0x20) if ((temp_phy_data & 0xff) > 0x20)
return 0; return 0;
printk(PFX "Reinitializing PHY\n"); printk(PFX "Reinitialize external PHY\n");
} }
/* no heartbeat, configure the PHY */ /* no heartbeat, configure the PHY */
@ -1379,15 +1380,14 @@ int nes_init_phy(struct nes_device *nesdev)
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0000); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0000);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052);
if (phy_type == NES_PHY_TYPE_ARGUS) {
switch (phy_type) {
case NES_PHY_TYPE_ARGUS:
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x000C); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x000C);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0008); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0008);
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0001); nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0001);
} else {
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x0004);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0038);
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0013);
}
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0098); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0098);
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00); nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00);
@ -1395,6 +1395,41 @@ int nes_init_phy(struct nes_device *nesdev)
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x0007); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x0007);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x000A); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x000A);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0009); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0009);
break;
case NES_PHY_TYPE_SFP_D:
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x0004);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0038);
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0013);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0098);
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00);
/* setup LEDs */
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x0007);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x000A);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0009);
break;
case NES_PHY_TYPE_KR:
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x000C);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0010);
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0013);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0080);
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00);
/* setup LEDs */
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x000B);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x0003);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0004);
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0022, 0x406D);
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0023, 0x0020);
break;
}
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0028, 0xA528); nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0028, 0xA528);
@ -1422,15 +1457,15 @@ int nes_init_phy(struct nes_device *nesdev)
nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7fd); nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7fd);
temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
if (counter++ > 300) { if (counter++ > 300) {
if (((temp_phy_data & 0xff) == 0x0) && first_time) { if (((temp_phy_data & 0xff) == 0x0) && first_attempt) {
first_time = 0; first_attempt = 0;
counter = 0; counter = 0;
/* reset AMCC PHY and try again */ /* reset AMCC PHY and try again */
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x00c0); nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x00c0);
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x0040); nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x0040);
continue; continue;
} else { } else {
printk(PFX "PHY did not track\n"); ret = 1;
break; break;
} }
} }
@ -1441,25 +1476,70 @@ int nes_init_phy(struct nes_device *nesdev)
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd003, 0x0000); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd003, 0x0000);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00D, 0x00FE); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00D, 0x00FE);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00E, 0x0032); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00E, 0x0032);
if (phy_type == NES_PHY_TYPE_KR) {
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00F, 0x000C);
} else {
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00F, 0x0002); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00F, 0x0002);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc314, 0x0063); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc314, 0x0063);
}
/* reset serdes */ /* reset serdes */
sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + mac_index * 0x200);
mac_index * 0x200);
sds |= 0x1; sds |= 0x1;
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + mac_index * 0x200, sds);
mac_index * 0x200, sds);
sds &= 0xfffffffe; sds &= 0xfffffffe;
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + mac_index * 0x200, sds);
mac_index * 0x200, sds);
counter = 0; counter = 0;
while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040) while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040)
&& (counter++ < 5000)) && (counter++ < 5000))
; ;
return ret;
} }
return 0;
/**
* nes_init_phy
*/
int nes_init_phy(struct nes_device *nesdev)
{
struct nes_adapter *nesadapter = nesdev->nesadapter;
u32 mac_index = nesdev->mac_index;
u32 tx_config = 0;
unsigned long flags;
u8 phy_type = nesadapter->phy_type[mac_index];
u8 phy_index = nesadapter->phy_index[mac_index];
int ret = 0;
tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
if (phy_type == NES_PHY_TYPE_1G) {
/* setup 1G MDIO operation */
tx_config &= 0xFFFFFFE3;
tx_config |= 0x04;
} else {
/* setup 10G MDIO operation */
tx_config &= 0xFFFFFFE3;
tx_config |= 0x15;
}
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags);
switch (phy_type) {
case NES_PHY_TYPE_1G:
ret = nes_init_1g_phy(nesdev, phy_type, phy_index);
break;
case NES_PHY_TYPE_ARGUS:
case NES_PHY_TYPE_SFP_D:
case NES_PHY_TYPE_KR:
ret = nes_init_2025_phy(nesdev, phy_type, phy_index);
break;
}
spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags);
return ret;
} }
@ -2460,23 +2540,9 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
} }
} else { } else {
switch (nesadapter->phy_type[mac_index]) { switch (nesadapter->phy_type[mac_index]) {
case NES_PHY_TYPE_IRIS:
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1);
temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
u32temp = 20;
do {
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1);
phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
if ((phy_data == temp_phy_data) || (!(--u32temp)))
break;
temp_phy_data = phy_data;
} while (1);
nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
__func__, phy_data, nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP");
break;
case NES_PHY_TYPE_ARGUS: case NES_PHY_TYPE_ARGUS:
case NES_PHY_TYPE_SFP_D: case NES_PHY_TYPE_SFP_D:
case NES_PHY_TYPE_KR:
/* clear the alarms */ /* clear the alarms */
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0x0008); nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0x0008);
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc001); nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc001);
@ -3352,8 +3418,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
u16 async_event_id; u16 async_event_id;
u8 tcp_state; u8 tcp_state;
u8 iwarp_state; u8 iwarp_state;
int must_disconn = 1;
int must_terminate = 0;
struct ib_event ibevent; struct ib_event ibevent;
nes_debug(NES_DBG_AEQ, "\n"); nes_debug(NES_DBG_AEQ, "\n");
@ -3367,6 +3431,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
BUG_ON(!context); BUG_ON(!context);
} }
/* context is nesqp unless async_event_id == CQ ERROR */
nesqp = (struct nes_qp *)(unsigned long)context;
async_event_id = (u16)aeq_info; async_event_id = (u16)aeq_info;
tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT; tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT;
iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT; iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT;
@ -3378,8 +3444,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
switch (async_event_id) { switch (async_event_id) {
case NES_AEQE_AEID_LLP_FIN_RECEIVED: case NES_AEQE_AEID_LLP_FIN_RECEIVED:
nesqp = (struct nes_qp *)(unsigned long)context;
if (nesqp->term_flags) if (nesqp->term_flags)
return; /* Ignore it, wait for close complete */ return; /* Ignore it, wait for close complete */
@ -3394,79 +3458,48 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
async_event_id, nesqp->last_aeq, tcp_state); async_event_id, nesqp->last_aeq, tcp_state);
} }
if ((tcp_state != NES_AEQE_TCP_STATE_CLOSE_WAIT) || break;
(nesqp->ibqp_state != IB_QPS_RTS)) {
/* FIN Received but tcp state or IB state moved on,
should expect a close complete */
return;
}
case NES_AEQE_AEID_LLP_CLOSE_COMPLETE: case NES_AEQE_AEID_LLP_CLOSE_COMPLETE:
nesqp = (struct nes_qp *)(unsigned long)context;
if (nesqp->term_flags) { if (nesqp->term_flags) {
nes_terminate_done(nesqp, 0); nes_terminate_done(nesqp, 0);
return; return;
} }
spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING;
spin_unlock_irqrestore(&nesqp->lock, flags);
nes_hw_modify_qp(nesdev, nesqp, NES_CQP_QP_IWARP_STATE_CLOSING, 0, 0);
nes_cm_disconn(nesqp);
break;
case NES_AEQE_AEID_LLP_CONNECTION_RESET:
case NES_AEQE_AEID_RESET_SENT: case NES_AEQE_AEID_RESET_SENT:
nesqp = (struct nes_qp *)(unsigned long)context;
if (async_event_id == NES_AEQE_AEID_RESET_SENT) {
tcp_state = NES_AEQE_TCP_STATE_CLOSED; tcp_state = NES_AEQE_TCP_STATE_CLOSED;
}
spin_lock_irqsave(&nesqp->lock, flags); spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = iwarp_state; nesqp->hw_iwarp_state = iwarp_state;
nesqp->hw_tcp_state = tcp_state; nesqp->hw_tcp_state = tcp_state;
nesqp->last_aeq = async_event_id; nesqp->last_aeq = async_event_id;
if ((tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
(tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT)) {
nesqp->hte_added = 0; nesqp->hte_added = 0;
next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE;
}
if ((nesqp->ibqp_state == IB_QPS_RTS) &&
((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
(async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
switch (nesqp->hw_iwarp_state) {
case NES_AEQE_IWARP_STATE_RTS:
next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING;
break;
case NES_AEQE_IWARP_STATE_TERMINATE:
must_disconn = 0; /* terminate path takes care of disconn */
if (nesqp->term_flags == 0)
must_terminate = 1;
break;
}
} else {
if (async_event_id == NES_AEQE_AEID_LLP_FIN_RECEIVED) {
/* FIN Received but ib state not RTS,
close complete will be on its way */
must_disconn = 0;
}
}
spin_unlock_irqrestore(&nesqp->lock, flags); spin_unlock_irqrestore(&nesqp->lock, flags);
next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE;
if (must_terminate)
nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL);
else if (must_disconn) {
if (next_iwarp_state) {
nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X\n",
nesqp->hwqp.qp_id, next_iwarp_state);
nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0); nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0);
}
nes_cm_disconn(nesqp); nes_cm_disconn(nesqp);
} break;
case NES_AEQE_AEID_LLP_CONNECTION_RESET:
if (atomic_read(&nesqp->close_timer_started))
return;
spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = iwarp_state;
nesqp->hw_tcp_state = tcp_state;
nesqp->last_aeq = async_event_id;
spin_unlock_irqrestore(&nesqp->lock, flags);
nes_cm_disconn(nesqp);
break; break;
case NES_AEQE_AEID_TERMINATE_SENT: case NES_AEQE_AEID_TERMINATE_SENT:
nesqp = (struct nes_qp *)(unsigned long)context;
nes_terminate_send_fin(nesdev, nesqp, aeqe); nes_terminate_send_fin(nesdev, nesqp, aeqe);
break; break;
case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED: case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED:
nesqp = (struct nes_qp *)(unsigned long)context;
nes_terminate_received(nesdev, nesqp, aeqe); nes_terminate_received(nesdev, nesqp, aeqe);
break; break;
@ -3480,7 +3513,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER:
case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION:
case NES_AEQE_AEID_AMP_TO_WRAP: case NES_AEQE_AEID_AMP_TO_WRAP:
nesqp = (struct nes_qp *)(unsigned long)context; printk(KERN_ERR PFX "QP[%u] async_event_id=0x%04X IB_EVENT_QP_ACCESS_ERR\n",
nesqp->hwqp.qp_id, async_event_id);
nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_ACCESS_ERR); nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_ACCESS_ERR);
break; break;
@ -3488,7 +3522,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL: case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL:
case NES_AEQE_AEID_DDP_UBE_INVALID_MO: case NES_AEQE_AEID_DDP_UBE_INVALID_MO:
case NES_AEQE_AEID_DDP_UBE_INVALID_QN: case NES_AEQE_AEID_DDP_UBE_INVALID_QN:
nesqp = (struct nes_qp *)(unsigned long)context;
if (iwarp_opcode(nesqp, aeq_info) > IWARP_OPCODE_TERM) { if (iwarp_opcode(nesqp, aeq_info) > IWARP_OPCODE_TERM) {
aeq_info &= 0xffff0000; aeq_info &= 0xffff0000;
aeq_info |= NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE; aeq_info |= NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE;
@ -3530,7 +3563,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
case NES_AEQE_AEID_STAG_ZERO_INVALID: case NES_AEQE_AEID_STAG_ZERO_INVALID:
case NES_AEQE_AEID_ROE_INVALID_RDMA_READ_REQUEST: case NES_AEQE_AEID_ROE_INVALID_RDMA_READ_REQUEST:
case NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP: case NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP:
nesqp = (struct nes_qp *)(unsigned long)context; printk(KERN_ERR PFX "QP[%u] async_event_id=0x%04X IB_EVENT_QP_FATAL\n",
nesqp->hwqp.qp_id, async_event_id);
nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL);
break; break;

View file

@ -37,12 +37,12 @@
#define NES_PHY_TYPE_CX4 1 #define NES_PHY_TYPE_CX4 1
#define NES_PHY_TYPE_1G 2 #define NES_PHY_TYPE_1G 2
#define NES_PHY_TYPE_IRIS 3
#define NES_PHY_TYPE_ARGUS 4 #define NES_PHY_TYPE_ARGUS 4
#define NES_PHY_TYPE_PUMA_1G 5 #define NES_PHY_TYPE_PUMA_1G 5
#define NES_PHY_TYPE_PUMA_10G 6 #define NES_PHY_TYPE_PUMA_10G 6
#define NES_PHY_TYPE_GLADIUS 7 #define NES_PHY_TYPE_GLADIUS 7
#define NES_PHY_TYPE_SFP_D 8 #define NES_PHY_TYPE_SFP_D 8
#define NES_PHY_TYPE_KR 9
#define NES_MULTICAST_PF_MAX 8 #define NES_MULTICAST_PF_MAX 8

View file

@ -1243,8 +1243,8 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
target_stat_values[++index] = cm_packets_received; target_stat_values[++index] = cm_packets_received;
target_stat_values[++index] = cm_packets_dropped; target_stat_values[++index] = cm_packets_dropped;
target_stat_values[++index] = cm_packets_retrans; target_stat_values[++index] = cm_packets_retrans;
target_stat_values[++index] = cm_listens_created; target_stat_values[++index] = atomic_read(&cm_listens_created);
target_stat_values[++index] = cm_listens_destroyed; target_stat_values[++index] = atomic_read(&cm_listens_destroyed);
target_stat_values[++index] = cm_backlog_drops; target_stat_values[++index] = cm_backlog_drops;
target_stat_values[++index] = atomic_read(&cm_loopbacks); target_stat_values[++index] = atomic_read(&cm_loopbacks);
target_stat_values[++index] = atomic_read(&cm_nodes_created); target_stat_values[++index] = atomic_read(&cm_nodes_created);
@ -1474,9 +1474,9 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd
} }
return 0; return 0;
} }
if ((phy_type == NES_PHY_TYPE_IRIS) || if ((phy_type == NES_PHY_TYPE_ARGUS) ||
(phy_type == NES_PHY_TYPE_ARGUS) || (phy_type == NES_PHY_TYPE_SFP_D) ||
(phy_type == NES_PHY_TYPE_SFP_D)) { (phy_type == NES_PHY_TYPE_KR)) {
et_cmd->transceiver = XCVR_EXTERNAL; et_cmd->transceiver = XCVR_EXTERNAL;
et_cmd->port = PORT_FIBRE; et_cmd->port = PORT_FIBRE;
et_cmd->supported = SUPPORTED_FIBRE; et_cmd->supported = SUPPORTED_FIBRE;
@ -1596,8 +1596,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
struct net_device *netdev; struct net_device *netdev;
struct nic_qp_map *curr_qp_map; struct nic_qp_map *curr_qp_map;
u32 u32temp; u32 u32temp;
u16 phy_data; u8 phy_type = nesdev->nesadapter->phy_type[nesdev->mac_index];
u16 temp_phy_data;
netdev = alloc_etherdev(sizeof(struct nes_vnic)); netdev = alloc_etherdev(sizeof(struct nes_vnic));
if (!netdev) { if (!netdev) {
@ -1705,64 +1704,22 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
if ((nesdev->netdev_count == 0) && if ((nesdev->netdev_count == 0) &&
((PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index) || ((PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index) ||
((nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) && ((phy_type == NES_PHY_TYPE_PUMA_1G) &&
(((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) || (((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) ||
((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) { ((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) {
/*
* nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n",
* NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesvnic->logical_port & 1)));
*/
u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
(0x200 * (nesdev->mac_index & 1))); (0x200 * (nesdev->mac_index & 1)));
if (nesdev->nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G) { if (phy_type != NES_PHY_TYPE_PUMA_1G) {
u32temp |= 0x00200000; u32temp |= 0x00200000;
nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
(0x200 * (nesdev->mac_index & 1)), u32temp); (0x200 * (nesdev->mac_index & 1)), u32temp);
} }
u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
(0x200 * (nesdev->mac_index & 1)));
if ((u32temp&0x0f1f0000) == 0x0f0f0000) {
if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_IRIS) {
nes_init_phy(nesdev);
nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1);
temp_phy_data = (u16)nes_read_indexed(nesdev,
NES_IDX_MAC_MDIO_CONTROL);
u32temp = 20;
do {
nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1);
phy_data = (u16)nes_read_indexed(nesdev,
NES_IDX_MAC_MDIO_CONTROL);
if ((phy_data == temp_phy_data) || (!(--u32temp)))
break;
temp_phy_data = phy_data;
} while (1);
if (phy_data & 4) {
nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
nesvnic->linkup = 1;
} else {
nes_debug(NES_DBG_INIT, "The Link is DOWN!!.\n");
}
} else {
nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
nesvnic->linkup = 1;
}
} else if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) {
nes_debug(NES_DBG_INIT, "mac_index=%d, logical_port=%d, u32temp=0x%04X, PCI_FUNC=%d\n",
nesdev->mac_index, nesvnic->logical_port, u32temp, PCI_FUNC(nesdev->pcidev->devfn));
if (((nesdev->mac_index < 2) && ((u32temp&0x01010000) == 0x01010000)) ||
((nesdev->mac_index > 1) && ((u32temp&0x02020000) == 0x02020000))) {
nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
nesvnic->linkup = 1;
}
}
/* clear the MAC interrupt status, assumes direct logical to physical mapping */ /* clear the MAC interrupt status, assumes direct logical to physical mapping */
u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index)); u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index));
nes_debug(NES_DBG_INIT, "Phy interrupt status = 0x%X.\n", u32temp); nes_debug(NES_DBG_INIT, "Phy interrupt status = 0x%X.\n", u32temp);
nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index), u32temp); nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index), u32temp);
if (nesdev->nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_IRIS)
nes_init_phy(nesdev); nes_init_phy(nesdev);
} }

View file

@ -228,7 +228,7 @@ static int nes_bind_mw(struct ib_qp *ibqp, struct ib_mw *ibmw,
/* Check for SQ overflow */ /* Check for SQ overflow */
if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) { if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) {
spin_unlock_irqrestore(&nesqp->lock, flags); spin_unlock_irqrestore(&nesqp->lock, flags);
return -EINVAL; return -ENOMEM;
} }
wqe = &nesqp->hwqp.sq_vbase[head]; wqe = &nesqp->hwqp.sq_vbase[head];
@ -3294,7 +3294,7 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
/* Check for SQ overflow */ /* Check for SQ overflow */
if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) { if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) {
err = -EINVAL; err = -ENOMEM;
break; break;
} }
@ -3577,7 +3577,7 @@ static int nes_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
} }
/* Check for RQ overflow */ /* Check for RQ overflow */
if (((head + (2 * qsize) - nesqp->hwqp.rq_tail) % qsize) == (qsize - 1)) { if (((head + (2 * qsize) - nesqp->hwqp.rq_tail) % qsize) == (qsize - 1)) {
err = -EINVAL; err = -ENOMEM;
break; break;
} }

View file

@ -55,9 +55,7 @@ static int ipoib_get_coalesce(struct net_device *dev,
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
coal->rx_coalesce_usecs = priv->ethtool.coalesce_usecs; coal->rx_coalesce_usecs = priv->ethtool.coalesce_usecs;
coal->tx_coalesce_usecs = priv->ethtool.coalesce_usecs;
coal->rx_max_coalesced_frames = priv->ethtool.max_coalesced_frames; coal->rx_max_coalesced_frames = priv->ethtool.max_coalesced_frames;
coal->tx_max_coalesced_frames = priv->ethtool.max_coalesced_frames;
return 0; return 0;
} }
@ -69,10 +67,8 @@ static int ipoib_set_coalesce(struct net_device *dev,
int ret; int ret;
/* /*
* Since IPoIB uses a single CQ for both rx and tx, we assume * These values are saved in the private data and returned
* that rx params dictate the configuration. These values are * when ipoib_get_coalesce() is called
* saved in the private data and returned when ipoib_get_coalesce()
* is called.
*/ */
if (coal->rx_coalesce_usecs > 0xffff || if (coal->rx_coalesce_usecs > 0xffff ||
coal->rx_max_coalesced_frames > 0xffff) coal->rx_max_coalesced_frames > 0xffff)
@ -85,8 +81,6 @@ static int ipoib_set_coalesce(struct net_device *dev,
return ret; return ret;
} }
coal->tx_coalesce_usecs = coal->rx_coalesce_usecs;
coal->tx_max_coalesced_frames = coal->rx_max_coalesced_frames;
priv->ethtool.coalesce_usecs = coal->rx_coalesce_usecs; priv->ethtool.coalesce_usecs = coal->rx_coalesce_usecs;
priv->ethtool.max_coalesced_frames = coal->rx_max_coalesced_frames; priv->ethtool.max_coalesced_frames = coal->rx_max_coalesced_frames;

View file

@ -128,6 +128,28 @@ static int iscsi_iser_pdu_alloc(struct iscsi_task *task, uint8_t opcode)
return 0; return 0;
} }
int iser_initialize_task_headers(struct iscsi_task *task,
struct iser_tx_desc *tx_desc)
{
struct iscsi_iser_conn *iser_conn = task->conn->dd_data;
struct iser_device *device = iser_conn->ib_conn->device;
struct iscsi_iser_task *iser_task = task->dd_data;
u64 dma_addr;
dma_addr = ib_dma_map_single(device->ib_device, (void *)tx_desc,
ISER_HEADERS_LEN, DMA_TO_DEVICE);
if (ib_dma_mapping_error(device->ib_device, dma_addr))
return -ENOMEM;
tx_desc->dma_addr = dma_addr;
tx_desc->tx_sg[0].addr = tx_desc->dma_addr;
tx_desc->tx_sg[0].length = ISER_HEADERS_LEN;
tx_desc->tx_sg[0].lkey = device->mr->lkey;
iser_task->headers_initialized = 1;
iser_task->iser_conn = iser_conn;
return 0;
}
/** /**
* iscsi_iser_task_init - Initialize task * iscsi_iser_task_init - Initialize task
* @task: iscsi task * @task: iscsi task
@ -137,17 +159,17 @@ static int iscsi_iser_pdu_alloc(struct iscsi_task *task, uint8_t opcode)
static int static int
iscsi_iser_task_init(struct iscsi_task *task) iscsi_iser_task_init(struct iscsi_task *task)
{ {
struct iscsi_iser_conn *iser_conn = task->conn->dd_data;
struct iscsi_iser_task *iser_task = task->dd_data; struct iscsi_iser_task *iser_task = task->dd_data;
if (!iser_task->headers_initialized)
if (iser_initialize_task_headers(task, &iser_task->desc))
return -ENOMEM;
/* mgmt task */ /* mgmt task */
if (!task->sc) { if (!task->sc)
iser_task->desc.data = task->data;
return 0; return 0;
}
iser_task->command_sent = 0; iser_task->command_sent = 0;
iser_task->iser_conn = iser_conn;
iser_task_rdma_init(iser_task); iser_task_rdma_init(iser_task);
return 0; return 0;
} }
@ -168,7 +190,7 @@ iscsi_iser_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
{ {
int error = 0; int error = 0;
iser_dbg("task deq [cid %d itt 0x%x]\n", conn->id, task->itt); iser_dbg("mtask xmit [cid %d itt 0x%x]\n", conn->id, task->itt);
error = iser_send_control(conn, task); error = iser_send_control(conn, task);
@ -178,9 +200,6 @@ iscsi_iser_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
* - if yes, the task is recycled at iscsi_complete_pdu * - if yes, the task is recycled at iscsi_complete_pdu
* - if no, the task is recycled at iser_snd_completion * - if no, the task is recycled at iser_snd_completion
*/ */
if (error && error != -ENOBUFS)
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return error; return error;
} }
@ -232,7 +251,7 @@ iscsi_iser_task_xmit(struct iscsi_task *task)
task->imm_count, task->unsol_r2t.data_length); task->imm_count, task->unsol_r2t.data_length);
} }
iser_dbg("task deq [cid %d itt 0x%x]\n", iser_dbg("ctask xmit [cid %d itt 0x%x]\n",
conn->id, task->itt); conn->id, task->itt);
/* Send the cmd PDU */ /* Send the cmd PDU */
@ -248,8 +267,6 @@ iscsi_iser_task_xmit(struct iscsi_task *task)
error = iscsi_iser_task_xmit_unsol_data(conn, task); error = iscsi_iser_task_xmit_unsol_data(conn, task);
iscsi_iser_task_xmit_exit: iscsi_iser_task_xmit_exit:
if (error && error != -ENOBUFS)
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return error; return error;
} }
@ -283,7 +300,7 @@ iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
* due to issues with the login code re iser sematics * due to issues with the login code re iser sematics
* this not set in iscsi_conn_setup - FIXME * this not set in iscsi_conn_setup - FIXME
*/ */
conn->max_recv_dlength = 128; conn->max_recv_dlength = ISER_RECV_DATA_SEG_LEN;
iser_conn = conn->dd_data; iser_conn = conn->dd_data;
conn->dd_data = iser_conn; conn->dd_data = iser_conn;
@ -401,7 +418,7 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep,
struct Scsi_Host *shost; struct Scsi_Host *shost;
struct iser_conn *ib_conn; struct iser_conn *ib_conn;
shost = iscsi_host_alloc(&iscsi_iser_sht, 0, 1); shost = iscsi_host_alloc(&iscsi_iser_sht, 0, 0);
if (!shost) if (!shost)
return NULL; return NULL;
shost->transportt = iscsi_iser_scsi_transport; shost->transportt = iscsi_iser_scsi_transport;
@ -675,7 +692,7 @@ static int __init iser_init(void)
memset(&ig, 0, sizeof(struct iser_global)); memset(&ig, 0, sizeof(struct iser_global));
ig.desc_cache = kmem_cache_create("iser_descriptors", ig.desc_cache = kmem_cache_create("iser_descriptors",
sizeof (struct iser_desc), sizeof(struct iser_tx_desc),
0, SLAB_HWCACHE_ALIGN, 0, SLAB_HWCACHE_ALIGN,
NULL); NULL);
if (ig.desc_cache == NULL) if (ig.desc_cache == NULL)

View file

@ -102,9 +102,9 @@
#define ISER_MAX_TX_MISC_PDUS 6 /* NOOP_OUT(2), TEXT(1), * #define ISER_MAX_TX_MISC_PDUS 6 /* NOOP_OUT(2), TEXT(1), *
* SCSI_TMFUNC(2), LOGOUT(1) */ * SCSI_TMFUNC(2), LOGOUT(1) */
#define ISER_QP_MAX_RECV_DTOS (ISCSI_DEF_XMIT_CMDS_MAX + \ #define ISER_QP_MAX_RECV_DTOS (ISCSI_DEF_XMIT_CMDS_MAX)
ISER_MAX_RX_MISC_PDUS + \
ISER_MAX_TX_MISC_PDUS) #define ISER_MIN_POSTED_RX (ISCSI_DEF_XMIT_CMDS_MAX >> 2)
/* the max TX (send) WR supported by the iSER QP is defined by * /* the max TX (send) WR supported by the iSER QP is defined by *
* max_send_wr = T * (1 + D) + C ; D is how many inflight dataouts we expect * * max_send_wr = T * (1 + D) + C ; D is how many inflight dataouts we expect *
@ -132,6 +132,12 @@ struct iser_hdr {
__be64 read_va; __be64 read_va;
} __attribute__((packed)); } __attribute__((packed));
/* Constant PDU lengths calculations */
#define ISER_HEADERS_LEN (sizeof(struct iser_hdr) + sizeof(struct iscsi_hdr))
#define ISER_RECV_DATA_SEG_LEN 128
#define ISER_RX_PAYLOAD_SIZE (ISER_HEADERS_LEN + ISER_RECV_DATA_SEG_LEN)
#define ISER_RX_LOGIN_SIZE (ISER_HEADERS_LEN + ISCSI_DEF_MAX_RECV_SEG_LEN)
/* Length of an object name string */ /* Length of an object name string */
#define ISER_OBJECT_NAME_SIZE 64 #define ISER_OBJECT_NAME_SIZE 64
@ -187,51 +193,43 @@ struct iser_regd_buf {
struct iser_mem_reg reg; /* memory registration info */ struct iser_mem_reg reg; /* memory registration info */
void *virt_addr; void *virt_addr;
struct iser_device *device; /* device->device for dma_unmap */ struct iser_device *device; /* device->device for dma_unmap */
u64 dma_addr; /* if non zero, addr for dma_unmap */
enum dma_data_direction direction; /* direction for dma_unmap */ enum dma_data_direction direction; /* direction for dma_unmap */
unsigned int data_size; unsigned int data_size;
atomic_t ref_count; /* refcount, freed when dec to 0 */
};
#define MAX_REGD_BUF_VECTOR_LEN 2
struct iser_dto {
struct iscsi_iser_task *task;
struct iser_conn *ib_conn;
int notify_enable;
/* vector of registered buffers */
unsigned int regd_vector_len;
struct iser_regd_buf *regd[MAX_REGD_BUF_VECTOR_LEN];
/* offset into the registered buffer may be specified */
unsigned int offset[MAX_REGD_BUF_VECTOR_LEN];
/* a smaller size may be specified, if 0, then full size is used */
unsigned int used_sz[MAX_REGD_BUF_VECTOR_LEN];
}; };
enum iser_desc_type { enum iser_desc_type {
ISCSI_RX,
ISCSI_TX_CONTROL , ISCSI_TX_CONTROL ,
ISCSI_TX_SCSI_COMMAND, ISCSI_TX_SCSI_COMMAND,
ISCSI_TX_DATAOUT ISCSI_TX_DATAOUT
}; };
struct iser_desc { struct iser_tx_desc {
struct iser_hdr iser_header; struct iser_hdr iser_header;
struct iscsi_hdr iscsi_header; struct iscsi_hdr iscsi_header;
struct iser_regd_buf hdr_regd_buf;
void *data; /* used by RX & TX_CONTROL */
struct iser_regd_buf data_regd_buf; /* used by RX & TX_CONTROL */
enum iser_desc_type type; enum iser_desc_type type;
struct iser_dto dto; u64 dma_addr;
/* sg[0] points to iser/iscsi headers, sg[1] optionally points to either
of immediate data, unsolicited data-out or control (login,text) */
struct ib_sge tx_sg[2];
int num_sge;
}; };
#define ISER_RX_PAD_SIZE (256 - (ISER_RX_PAYLOAD_SIZE + \
sizeof(u64) + sizeof(struct ib_sge)))
struct iser_rx_desc {
struct iser_hdr iser_header;
struct iscsi_hdr iscsi_header;
char data[ISER_RECV_DATA_SEG_LEN];
u64 dma_addr;
struct ib_sge rx_sg;
char pad[ISER_RX_PAD_SIZE];
} __attribute__((packed));
struct iser_device { struct iser_device {
struct ib_device *ib_device; struct ib_device *ib_device;
struct ib_pd *pd; struct ib_pd *pd;
struct ib_cq *cq; struct ib_cq *rx_cq;
struct ib_cq *tx_cq;
struct ib_mr *mr; struct ib_mr *mr;
struct tasklet_struct cq_tasklet; struct tasklet_struct cq_tasklet;
struct list_head ig_list; /* entry in ig devices list */ struct list_head ig_list; /* entry in ig devices list */
@ -250,15 +248,18 @@ struct iser_conn {
struct ib_fmr_pool *fmr_pool; /* pool of IB FMRs */ struct ib_fmr_pool *fmr_pool; /* pool of IB FMRs */
int disc_evt_flag; /* disconn event delivered */ int disc_evt_flag; /* disconn event delivered */
wait_queue_head_t wait; /* waitq for conn/disconn */ wait_queue_head_t wait; /* waitq for conn/disconn */
atomic_t post_recv_buf_count; /* posted rx count */ int post_recv_buf_count; /* posted rx count */
atomic_t post_send_buf_count; /* posted tx count */ atomic_t post_send_buf_count; /* posted tx count */
atomic_t unexpected_pdu_count;/* count of received *
* unexpected pdus *
* not yet retired */
char name[ISER_OBJECT_NAME_SIZE]; char name[ISER_OBJECT_NAME_SIZE];
struct iser_page_vec *page_vec; /* represents SG to fmr maps* struct iser_page_vec *page_vec; /* represents SG to fmr maps*
* maps serialized as tx is*/ * maps serialized as tx is*/
struct list_head conn_list; /* entry in ig conn list */ struct list_head conn_list; /* entry in ig conn list */
char *login_buf;
u64 login_dma;
unsigned int rx_desc_head;
struct iser_rx_desc *rx_descs;
struct ib_recv_wr rx_wr[ISER_MIN_POSTED_RX];
}; };
struct iscsi_iser_conn { struct iscsi_iser_conn {
@ -267,7 +268,7 @@ struct iscsi_iser_conn {
}; };
struct iscsi_iser_task { struct iscsi_iser_task {
struct iser_desc desc; struct iser_tx_desc desc;
struct iscsi_iser_conn *iser_conn; struct iscsi_iser_conn *iser_conn;
enum iser_task_status status; enum iser_task_status status;
int command_sent; /* set if command sent */ int command_sent; /* set if command sent */
@ -275,6 +276,7 @@ struct iscsi_iser_task {
struct iser_regd_buf rdma_regd[ISER_DIRS_NUM];/* regd rdma buf */ struct iser_regd_buf rdma_regd[ISER_DIRS_NUM];/* regd rdma buf */
struct iser_data_buf data[ISER_DIRS_NUM]; /* orig. data des*/ struct iser_data_buf data[ISER_DIRS_NUM]; /* orig. data des*/
struct iser_data_buf data_copy[ISER_DIRS_NUM];/* contig. copy */ struct iser_data_buf data_copy[ISER_DIRS_NUM];/* contig. copy */
int headers_initialized;
}; };
struct iser_page_vec { struct iser_page_vec {
@ -322,22 +324,17 @@ void iser_conn_put(struct iser_conn *ib_conn);
void iser_conn_terminate(struct iser_conn *ib_conn); void iser_conn_terminate(struct iser_conn *ib_conn);
void iser_rcv_completion(struct iser_desc *desc, void iser_rcv_completion(struct iser_rx_desc *desc,
unsigned long dto_xfer_len); unsigned long dto_xfer_len,
struct iser_conn *ib_conn);
void iser_snd_completion(struct iser_desc *desc); void iser_snd_completion(struct iser_tx_desc *desc, struct iser_conn *ib_conn);
void iser_task_rdma_init(struct iscsi_iser_task *task); void iser_task_rdma_init(struct iscsi_iser_task *task);
void iser_task_rdma_finalize(struct iscsi_iser_task *task); void iser_task_rdma_finalize(struct iscsi_iser_task *task);
void iser_dto_buffs_release(struct iser_dto *dto); void iser_free_rx_descriptors(struct iser_conn *ib_conn);
int iser_regd_buff_release(struct iser_regd_buf *regd_buf);
void iser_reg_single(struct iser_device *device,
struct iser_regd_buf *regd_buf,
enum dma_data_direction direction);
void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *task, void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *task,
enum iser_data_dir cmd_dir); enum iser_data_dir cmd_dir);
@ -356,11 +353,9 @@ int iser_reg_page_vec(struct iser_conn *ib_conn,
void iser_unreg_mem(struct iser_mem_reg *mem_reg); void iser_unreg_mem(struct iser_mem_reg *mem_reg);
int iser_post_recv(struct iser_desc *rx_desc); int iser_post_recvl(struct iser_conn *ib_conn);
int iser_post_send(struct iser_desc *tx_desc); int iser_post_recvm(struct iser_conn *ib_conn, int count);
int iser_post_send(struct iser_conn *ib_conn, struct iser_tx_desc *tx_desc);
int iser_conn_state_comp(struct iser_conn *ib_conn,
enum iser_ib_conn_state comp);
int iser_dma_map_task_data(struct iscsi_iser_task *iser_task, int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
struct iser_data_buf *data, struct iser_data_buf *data,
@ -368,4 +363,6 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
enum dma_data_direction dma_dir); enum dma_data_direction dma_dir);
void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task); void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task);
int iser_initialize_task_headers(struct iscsi_task *task,
struct iser_tx_desc *tx_desc);
#endif #endif

View file

@ -39,29 +39,6 @@
#include "iscsi_iser.h" #include "iscsi_iser.h"
/* Constant PDU lengths calculations */
#define ISER_TOTAL_HEADERS_LEN (sizeof (struct iser_hdr) + \
sizeof (struct iscsi_hdr))
/* iser_dto_add_regd_buff - increments the reference count for *
* the registered buffer & adds it to the DTO object */
static void iser_dto_add_regd_buff(struct iser_dto *dto,
struct iser_regd_buf *regd_buf,
unsigned long use_offset,
unsigned long use_size)
{
int add_idx;
atomic_inc(&regd_buf->ref_count);
add_idx = dto->regd_vector_len;
dto->regd[add_idx] = regd_buf;
dto->used_sz[add_idx] = use_size;
dto->offset[add_idx] = use_offset;
dto->regd_vector_len++;
}
/* Register user buffer memory and initialize passive rdma /* Register user buffer memory and initialize passive rdma
* dto descriptor. Total data size is stored in * dto descriptor. Total data size is stored in
* iser_task->data[ISER_DIR_IN].data_len * iser_task->data[ISER_DIR_IN].data_len
@ -122,9 +99,9 @@ iser_prepare_write_cmd(struct iscsi_task *task,
struct iscsi_iser_task *iser_task = task->dd_data; struct iscsi_iser_task *iser_task = task->dd_data;
struct iser_regd_buf *regd_buf; struct iser_regd_buf *regd_buf;
int err; int err;
struct iser_dto *send_dto = &iser_task->desc.dto;
struct iser_hdr *hdr = &iser_task->desc.iser_header; struct iser_hdr *hdr = &iser_task->desc.iser_header;
struct iser_data_buf *buf_out = &iser_task->data[ISER_DIR_OUT]; struct iser_data_buf *buf_out = &iser_task->data[ISER_DIR_OUT];
struct ib_sge *tx_dsg = &iser_task->desc.tx_sg[1];
err = iser_dma_map_task_data(iser_task, err = iser_dma_map_task_data(iser_task,
buf_out, buf_out,
@ -163,135 +140,100 @@ iser_prepare_write_cmd(struct iscsi_task *task,
if (imm_sz > 0) { if (imm_sz > 0) {
iser_dbg("Cmd itt:%d, WRITE, adding imm.data sz: %d\n", iser_dbg("Cmd itt:%d, WRITE, adding imm.data sz: %d\n",
task->itt, imm_sz); task->itt, imm_sz);
iser_dto_add_regd_buff(send_dto, tx_dsg->addr = regd_buf->reg.va;
regd_buf, tx_dsg->length = imm_sz;
0, tx_dsg->lkey = regd_buf->reg.lkey;
imm_sz); iser_task->desc.num_sge = 2;
} }
return 0; return 0;
} }
/**
* iser_post_receive_control - allocates, initializes and posts receive DTO.
*/
static int iser_post_receive_control(struct iscsi_conn *conn)
{
struct iscsi_iser_conn *iser_conn = conn->dd_data;
struct iser_desc *rx_desc;
struct iser_regd_buf *regd_hdr;
struct iser_regd_buf *regd_data;
struct iser_dto *recv_dto = NULL;
struct iser_device *device = iser_conn->ib_conn->device;
int rx_data_size, err;
int posts, outstanding_unexp_pdus;
/* for the login sequence we must support rx of upto 8K; login is done
* after conn create/bind (connect) and conn stop/bind (reconnect),
* what's common for both schemes is that the connection is not started
*/
if (conn->c_stage != ISCSI_CONN_STARTED)
rx_data_size = ISCSI_DEF_MAX_RECV_SEG_LEN;
else /* FIXME till user space sets conn->max_recv_dlength correctly */
rx_data_size = 128;
outstanding_unexp_pdus =
atomic_xchg(&iser_conn->ib_conn->unexpected_pdu_count, 0);
/*
* in addition to the response buffer, replace those consumed by
* unexpected pdus.
*/
for (posts = 0; posts < 1 + outstanding_unexp_pdus; posts++) {
rx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO);
if (rx_desc == NULL) {
iser_err("Failed to alloc desc for post recv %d\n",
posts);
err = -ENOMEM;
goto post_rx_cache_alloc_failure;
}
rx_desc->type = ISCSI_RX;
rx_desc->data = kmalloc(rx_data_size, GFP_NOIO);
if (rx_desc->data == NULL) {
iser_err("Failed to alloc data buf for post recv %d\n",
posts);
err = -ENOMEM;
goto post_rx_kmalloc_failure;
}
recv_dto = &rx_desc->dto;
recv_dto->ib_conn = iser_conn->ib_conn;
recv_dto->regd_vector_len = 0;
regd_hdr = &rx_desc->hdr_regd_buf;
memset(regd_hdr, 0, sizeof(struct iser_regd_buf));
regd_hdr->device = device;
regd_hdr->virt_addr = rx_desc; /* == &rx_desc->iser_header */
regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN;
iser_reg_single(device, regd_hdr, DMA_FROM_DEVICE);
iser_dto_add_regd_buff(recv_dto, regd_hdr, 0, 0);
regd_data = &rx_desc->data_regd_buf;
memset(regd_data, 0, sizeof(struct iser_regd_buf));
regd_data->device = device;
regd_data->virt_addr = rx_desc->data;
regd_data->data_size = rx_data_size;
iser_reg_single(device, regd_data, DMA_FROM_DEVICE);
iser_dto_add_regd_buff(recv_dto, regd_data, 0, 0);
err = iser_post_recv(rx_desc);
if (err) {
iser_err("Failed iser_post_recv for post %d\n", posts);
goto post_rx_post_recv_failure;
}
}
/* all posts successful */
return 0;
post_rx_post_recv_failure:
iser_dto_buffs_release(recv_dto);
kfree(rx_desc->data);
post_rx_kmalloc_failure:
kmem_cache_free(ig.desc_cache, rx_desc);
post_rx_cache_alloc_failure:
if (posts > 0) {
/*
* response buffer posted, but did not replace all unexpected
* pdu recv bufs. Ignore error, retry occurs next send
*/
outstanding_unexp_pdus -= (posts - 1);
err = 0;
}
atomic_add(outstanding_unexp_pdus,
&iser_conn->ib_conn->unexpected_pdu_count);
return err;
}
/* creates a new tx descriptor and adds header regd buffer */ /* creates a new tx descriptor and adds header regd buffer */
static void iser_create_send_desc(struct iscsi_iser_conn *iser_conn, static void iser_create_send_desc(struct iser_conn *ib_conn,
struct iser_desc *tx_desc) struct iser_tx_desc *tx_desc)
{ {
struct iser_regd_buf *regd_hdr = &tx_desc->hdr_regd_buf; struct iser_device *device = ib_conn->device;
struct iser_dto *send_dto = &tx_desc->dto;
memset(regd_hdr, 0, sizeof(struct iser_regd_buf)); ib_dma_sync_single_for_cpu(device->ib_device,
regd_hdr->device = iser_conn->ib_conn->device; tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE);
regd_hdr->virt_addr = tx_desc; /* == &tx_desc->iser_header */
regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN;
send_dto->ib_conn = iser_conn->ib_conn;
send_dto->notify_enable = 1;
send_dto->regd_vector_len = 0;
memset(&tx_desc->iser_header, 0, sizeof(struct iser_hdr)); memset(&tx_desc->iser_header, 0, sizeof(struct iser_hdr));
tx_desc->iser_header.flags = ISER_VER; tx_desc->iser_header.flags = ISER_VER;
iser_dto_add_regd_buff(send_dto, regd_hdr, 0, 0); tx_desc->num_sge = 1;
if (tx_desc->tx_sg[0].lkey != device->mr->lkey) {
tx_desc->tx_sg[0].lkey = device->mr->lkey;
iser_dbg("sdesc %p lkey mismatch, fixing\n", tx_desc);
}
}
int iser_alloc_rx_descriptors(struct iser_conn *ib_conn)
{
int i, j;
u64 dma_addr;
struct iser_rx_desc *rx_desc;
struct ib_sge *rx_sg;
struct iser_device *device = ib_conn->device;
ib_conn->rx_descs = kmalloc(ISER_QP_MAX_RECV_DTOS *
sizeof(struct iser_rx_desc), GFP_KERNEL);
if (!ib_conn->rx_descs)
goto rx_desc_alloc_fail;
rx_desc = ib_conn->rx_descs;
for (i = 0; i < ISER_QP_MAX_RECV_DTOS; i++, rx_desc++) {
dma_addr = ib_dma_map_single(device->ib_device, (void *)rx_desc,
ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
if (ib_dma_mapping_error(device->ib_device, dma_addr))
goto rx_desc_dma_map_failed;
rx_desc->dma_addr = dma_addr;
rx_sg = &rx_desc->rx_sg;
rx_sg->addr = rx_desc->dma_addr;
rx_sg->length = ISER_RX_PAYLOAD_SIZE;
rx_sg->lkey = device->mr->lkey;
}
ib_conn->rx_desc_head = 0;
return 0;
rx_desc_dma_map_failed:
rx_desc = ib_conn->rx_descs;
for (j = 0; j < i; j++, rx_desc++)
ib_dma_unmap_single(device->ib_device, rx_desc->dma_addr,
ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
kfree(ib_conn->rx_descs);
ib_conn->rx_descs = NULL;
rx_desc_alloc_fail:
iser_err("failed allocating rx descriptors / data buffers\n");
return -ENOMEM;
}
void iser_free_rx_descriptors(struct iser_conn *ib_conn)
{
int i;
struct iser_rx_desc *rx_desc;
struct iser_device *device = ib_conn->device;
if (ib_conn->login_buf) {
ib_dma_unmap_single(device->ib_device, ib_conn->login_dma,
ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE);
kfree(ib_conn->login_buf);
}
if (!ib_conn->rx_descs)
return;
rx_desc = ib_conn->rx_descs;
for (i = 0; i < ISER_QP_MAX_RECV_DTOS; i++, rx_desc++)
ib_dma_unmap_single(device->ib_device, rx_desc->dma_addr,
ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
kfree(ib_conn->rx_descs);
} }
/** /**
@ -301,46 +243,23 @@ int iser_conn_set_full_featured_mode(struct iscsi_conn *conn)
{ {
struct iscsi_iser_conn *iser_conn = conn->dd_data; struct iscsi_iser_conn *iser_conn = conn->dd_data;
int i; iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX);
/*
* FIXME this value should be declared to the target during login with
* the MaxOutstandingUnexpectedPDUs key when supported
*/
int initial_post_recv_bufs_num = ISER_MAX_RX_MISC_PDUS;
iser_dbg("Initially post: %d\n", initial_post_recv_bufs_num);
/* Check that there is no posted recv or send buffers left - */ /* Check that there is no posted recv or send buffers left - */
/* they must be consumed during the login phase */ /* they must be consumed during the login phase */
BUG_ON(atomic_read(&iser_conn->ib_conn->post_recv_buf_count) != 0); BUG_ON(iser_conn->ib_conn->post_recv_buf_count != 0);
BUG_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0); BUG_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0);
/* Initial post receive buffers */ if (iser_alloc_rx_descriptors(iser_conn->ib_conn))
for (i = 0; i < initial_post_recv_bufs_num; i++) {
if (iser_post_receive_control(conn) != 0) {
iser_err("Failed to post recv bufs at:%d conn:0x%p\n",
i, conn);
return -ENOMEM; return -ENOMEM;
}
} /* Initial post receive buffers */
iser_dbg("Posted %d post recv bufs, conn:0x%p\n", i, conn); if (iser_post_recvm(iser_conn->ib_conn, ISER_MIN_POSTED_RX))
return -ENOMEM;
return 0; return 0;
} }
static int
iser_check_xmit(struct iscsi_conn *conn, void *task)
{
struct iscsi_iser_conn *iser_conn = conn->dd_data;
if (atomic_read(&iser_conn->ib_conn->post_send_buf_count) ==
ISER_QP_MAX_REQ_DTOS) {
iser_dbg("%ld can't xmit task %p\n",jiffies,task);
return -ENOBUFS;
}
return 0;
}
/** /**
* iser_send_command - send command PDU * iser_send_command - send command PDU
*/ */
@ -349,27 +268,18 @@ int iser_send_command(struct iscsi_conn *conn,
{ {
struct iscsi_iser_conn *iser_conn = conn->dd_data; struct iscsi_iser_conn *iser_conn = conn->dd_data;
struct iscsi_iser_task *iser_task = task->dd_data; struct iscsi_iser_task *iser_task = task->dd_data;
struct iser_dto *send_dto = NULL;
unsigned long edtl; unsigned long edtl;
int err = 0; int err;
struct iser_data_buf *data_buf; struct iser_data_buf *data_buf;
struct iscsi_cmd *hdr = (struct iscsi_cmd *)task->hdr; struct iscsi_cmd *hdr = (struct iscsi_cmd *)task->hdr;
struct scsi_cmnd *sc = task->sc; struct scsi_cmnd *sc = task->sc;
struct iser_tx_desc *tx_desc = &iser_task->desc;
if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
return -EPERM;
}
if (iser_check_xmit(conn, task))
return -ENOBUFS;
edtl = ntohl(hdr->data_length); edtl = ntohl(hdr->data_length);
/* build the tx desc regd header and add it to the tx desc dto */ /* build the tx desc regd header and add it to the tx desc dto */
iser_task->desc.type = ISCSI_TX_SCSI_COMMAND; tx_desc->type = ISCSI_TX_SCSI_COMMAND;
send_dto = &iser_task->desc.dto; iser_create_send_desc(iser_conn->ib_conn, tx_desc);
send_dto->task = iser_task;
iser_create_send_desc(iser_conn, &iser_task->desc);
if (hdr->flags & ISCSI_FLAG_CMD_READ) if (hdr->flags & ISCSI_FLAG_CMD_READ)
data_buf = &iser_task->data[ISER_DIR_IN]; data_buf = &iser_task->data[ISER_DIR_IN];
@ -398,23 +308,13 @@ int iser_send_command(struct iscsi_conn *conn,
goto send_command_error; goto send_command_error;
} }
iser_reg_single(iser_conn->ib_conn->device,
send_dto->regd[0], DMA_TO_DEVICE);
if (iser_post_receive_control(conn) != 0) {
iser_err("post_recv failed!\n");
err = -ENOMEM;
goto send_command_error;
}
iser_task->status = ISER_TASK_STATUS_STARTED; iser_task->status = ISER_TASK_STATUS_STARTED;
err = iser_post_send(&iser_task->desc); err = iser_post_send(iser_conn->ib_conn, tx_desc);
if (!err) if (!err)
return 0; return 0;
send_command_error: send_command_error:
iser_dto_buffs_release(send_dto);
iser_err("conn %p failed task->itt %d err %d\n",conn, task->itt, err); iser_err("conn %p failed task->itt %d err %d\n",conn, task->itt, err);
return err; return err;
} }
@ -428,20 +328,13 @@ int iser_send_data_out(struct iscsi_conn *conn,
{ {
struct iscsi_iser_conn *iser_conn = conn->dd_data; struct iscsi_iser_conn *iser_conn = conn->dd_data;
struct iscsi_iser_task *iser_task = task->dd_data; struct iscsi_iser_task *iser_task = task->dd_data;
struct iser_desc *tx_desc = NULL; struct iser_tx_desc *tx_desc = NULL;
struct iser_dto *send_dto = NULL; struct iser_regd_buf *regd_buf;
unsigned long buf_offset; unsigned long buf_offset;
unsigned long data_seg_len; unsigned long data_seg_len;
uint32_t itt; uint32_t itt;
int err = 0; int err = 0;
struct ib_sge *tx_dsg;
if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
return -EPERM;
}
if (iser_check_xmit(conn, task))
return -ENOBUFS;
itt = (__force uint32_t)hdr->itt; itt = (__force uint32_t)hdr->itt;
data_seg_len = ntoh24(hdr->dlength); data_seg_len = ntoh24(hdr->dlength);
@ -450,28 +343,25 @@ int iser_send_data_out(struct iscsi_conn *conn,
iser_dbg("%s itt %d dseg_len %d offset %d\n", iser_dbg("%s itt %d dseg_len %d offset %d\n",
__func__,(int)itt,(int)data_seg_len,(int)buf_offset); __func__,(int)itt,(int)data_seg_len,(int)buf_offset);
tx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO); tx_desc = kmem_cache_zalloc(ig.desc_cache, GFP_ATOMIC);
if (tx_desc == NULL) { if (tx_desc == NULL) {
iser_err("Failed to alloc desc for post dataout\n"); iser_err("Failed to alloc desc for post dataout\n");
return -ENOMEM; return -ENOMEM;
} }
tx_desc->type = ISCSI_TX_DATAOUT; tx_desc->type = ISCSI_TX_DATAOUT;
tx_desc->iser_header.flags = ISER_VER;
memcpy(&tx_desc->iscsi_header, hdr, sizeof(struct iscsi_hdr)); memcpy(&tx_desc->iscsi_header, hdr, sizeof(struct iscsi_hdr));
/* build the tx desc regd header and add it to the tx desc dto */ /* build the tx desc */
send_dto = &tx_desc->dto; iser_initialize_task_headers(task, tx_desc);
send_dto->task = iser_task;
iser_create_send_desc(iser_conn, tx_desc);
iser_reg_single(iser_conn->ib_conn->device, regd_buf = &iser_task->rdma_regd[ISER_DIR_OUT];
send_dto->regd[0], DMA_TO_DEVICE); tx_dsg = &tx_desc->tx_sg[1];
tx_dsg->addr = regd_buf->reg.va + buf_offset;
/* all data was registered for RDMA, we can use the lkey */ tx_dsg->length = data_seg_len;
iser_dto_add_regd_buff(send_dto, tx_dsg->lkey = regd_buf->reg.lkey;
&iser_task->rdma_regd[ISER_DIR_OUT], tx_desc->num_sge = 2;
buf_offset,
data_seg_len);
if (buf_offset + data_seg_len > iser_task->data[ISER_DIR_OUT].data_len) { if (buf_offset + data_seg_len > iser_task->data[ISER_DIR_OUT].data_len) {
iser_err("Offset:%ld & DSL:%ld in Data-Out " iser_err("Offset:%ld & DSL:%ld in Data-Out "
@ -485,12 +375,11 @@ int iser_send_data_out(struct iscsi_conn *conn,
itt, buf_offset, data_seg_len); itt, buf_offset, data_seg_len);
err = iser_post_send(tx_desc); err = iser_post_send(iser_conn->ib_conn, tx_desc);
if (!err) if (!err)
return 0; return 0;
send_data_out_error: send_data_out_error:
iser_dto_buffs_release(send_dto);
kmem_cache_free(ig.desc_cache, tx_desc); kmem_cache_free(ig.desc_cache, tx_desc);
iser_err("conn %p failed err %d\n",conn, err); iser_err("conn %p failed err %d\n",conn, err);
return err; return err;
@ -501,64 +390,44 @@ int iser_send_control(struct iscsi_conn *conn,
{ {
struct iscsi_iser_conn *iser_conn = conn->dd_data; struct iscsi_iser_conn *iser_conn = conn->dd_data;
struct iscsi_iser_task *iser_task = task->dd_data; struct iscsi_iser_task *iser_task = task->dd_data;
struct iser_desc *mdesc = &iser_task->desc; struct iser_tx_desc *mdesc = &iser_task->desc;
struct iser_dto *send_dto = NULL;
unsigned long data_seg_len; unsigned long data_seg_len;
int err = 0; int err = 0;
struct iser_regd_buf *regd_buf;
struct iser_device *device; struct iser_device *device;
unsigned char opcode;
if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
return -EPERM;
}
if (iser_check_xmit(conn, task))
return -ENOBUFS;
/* build the tx desc regd header and add it to the tx desc dto */ /* build the tx desc regd header and add it to the tx desc dto */
mdesc->type = ISCSI_TX_CONTROL; mdesc->type = ISCSI_TX_CONTROL;
send_dto = &mdesc->dto; iser_create_send_desc(iser_conn->ib_conn, mdesc);
send_dto->task = NULL;
iser_create_send_desc(iser_conn, mdesc);
device = iser_conn->ib_conn->device; device = iser_conn->ib_conn->device;
iser_reg_single(device, send_dto->regd[0], DMA_TO_DEVICE);
data_seg_len = ntoh24(task->hdr->dlength); data_seg_len = ntoh24(task->hdr->dlength);
if (data_seg_len > 0) { if (data_seg_len > 0) {
regd_buf = &mdesc->data_regd_buf; struct ib_sge *tx_dsg = &mdesc->tx_sg[1];
memset(regd_buf, 0, sizeof(struct iser_regd_buf)); if (task != conn->login_task) {
regd_buf->device = device; iser_err("data present on non login task!!!\n");
regd_buf->virt_addr = task->data;
regd_buf->data_size = task->data_count;
iser_reg_single(device, regd_buf,
DMA_TO_DEVICE);
iser_dto_add_regd_buff(send_dto, regd_buf,
0,
data_seg_len);
}
opcode = task->hdr->opcode & ISCSI_OPCODE_MASK;
/* post recv buffer for response if one is expected */
if (!(opcode == ISCSI_OP_NOOP_OUT && task->hdr->itt == RESERVED_ITT)) {
if (iser_post_receive_control(conn) != 0) {
iser_err("post_rcv_buff failed!\n");
err = -ENOMEM;
goto send_control_error; goto send_control_error;
} }
memcpy(iser_conn->ib_conn->login_buf, task->data,
task->data_count);
tx_dsg->addr = iser_conn->ib_conn->login_dma;
tx_dsg->length = data_seg_len;
tx_dsg->lkey = device->mr->lkey;
mdesc->num_sge = 2;
} }
err = iser_post_send(mdesc); if (task == conn->login_task) {
err = iser_post_recvl(iser_conn->ib_conn);
if (err)
goto send_control_error;
}
err = iser_post_send(iser_conn->ib_conn, mdesc);
if (!err) if (!err)
return 0; return 0;
send_control_error: send_control_error:
iser_dto_buffs_release(send_dto);
iser_err("conn %p failed err %d\n",conn, err); iser_err("conn %p failed err %d\n",conn, err);
return err; return err;
} }
@ -566,104 +435,71 @@ send_control_error:
/** /**
* iser_rcv_dto_completion - recv DTO completion * iser_rcv_dto_completion - recv DTO completion
*/ */
void iser_rcv_completion(struct iser_desc *rx_desc, void iser_rcv_completion(struct iser_rx_desc *rx_desc,
unsigned long dto_xfer_len) unsigned long rx_xfer_len,
struct iser_conn *ib_conn)
{ {
struct iser_dto *dto = &rx_desc->dto; struct iscsi_iser_conn *conn = ib_conn->iser_conn;
struct iscsi_iser_conn *conn = dto->ib_conn->iser_conn;
struct iscsi_task *task;
struct iscsi_iser_task *iser_task;
struct iscsi_hdr *hdr; struct iscsi_hdr *hdr;
char *rx_data = NULL; u64 rx_dma;
int rx_data_len = 0; int rx_buflen, outstanding, count, err;
unsigned char opcode;
/* differentiate between login to all other PDUs */
if ((char *)rx_desc == ib_conn->login_buf) {
rx_dma = ib_conn->login_dma;
rx_buflen = ISER_RX_LOGIN_SIZE;
} else {
rx_dma = rx_desc->dma_addr;
rx_buflen = ISER_RX_PAYLOAD_SIZE;
}
ib_dma_sync_single_for_cpu(ib_conn->device->ib_device, rx_dma,
rx_buflen, DMA_FROM_DEVICE);
hdr = &rx_desc->iscsi_header; hdr = &rx_desc->iscsi_header;
iser_dbg("op 0x%x itt 0x%x\n", hdr->opcode,hdr->itt); iser_dbg("op 0x%x itt 0x%x dlen %d\n", hdr->opcode,
hdr->itt, (int)(rx_xfer_len - ISER_HEADERS_LEN));
if (dto_xfer_len > ISER_TOTAL_HEADERS_LEN) { /* we have data */ iscsi_iser_recv(conn->iscsi_conn, hdr,
rx_data_len = dto_xfer_len - ISER_TOTAL_HEADERS_LEN; rx_desc->data, rx_xfer_len - ISER_HEADERS_LEN);
rx_data = dto->regd[1]->virt_addr;
rx_data += dto->offset[1];
}
opcode = hdr->opcode & ISCSI_OPCODE_MASK; ib_dma_sync_single_for_device(ib_conn->device->ib_device, rx_dma,
rx_buflen, DMA_FROM_DEVICE);
if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
spin_lock(&conn->iscsi_conn->session->lock);
task = iscsi_itt_to_ctask(conn->iscsi_conn, hdr->itt);
if (task)
__iscsi_get_task(task);
spin_unlock(&conn->iscsi_conn->session->lock);
if (!task)
iser_err("itt can't be matched to task!!! "
"conn %p opcode %d itt %d\n",
conn->iscsi_conn, opcode, hdr->itt);
else {
iser_task = task->dd_data;
iser_dbg("itt %d task %p\n",hdr->itt, task);
iser_task->status = ISER_TASK_STATUS_COMPLETED;
iser_task_rdma_finalize(iser_task);
iscsi_put_task(task);
}
}
iser_dto_buffs_release(dto);
iscsi_iser_recv(conn->iscsi_conn, hdr, rx_data, rx_data_len);
kfree(rx_desc->data);
kmem_cache_free(ig.desc_cache, rx_desc);
/* decrementing conn->post_recv_buf_count only --after-- freeing the * /* decrementing conn->post_recv_buf_count only --after-- freeing the *
* task eliminates the need to worry on tasks which are completed in * * task eliminates the need to worry on tasks which are completed in *
* parallel to the execution of iser_conn_term. So the code that waits * * parallel to the execution of iser_conn_term. So the code that waits *
* for the posted rx bufs refcount to become zero handles everything */ * for the posted rx bufs refcount to become zero handles everything */
atomic_dec(&conn->ib_conn->post_recv_buf_count); conn->ib_conn->post_recv_buf_count--;
/* if (rx_dma == ib_conn->login_dma)
* if an unexpected PDU was received then the recv wr consumed must return;
* be replaced, this is done in the next send of a control-type PDU
*/ outstanding = ib_conn->post_recv_buf_count;
if (opcode == ISCSI_OP_NOOP_IN && hdr->itt == RESERVED_ITT) { if (outstanding + ISER_MIN_POSTED_RX <= ISER_QP_MAX_RECV_DTOS) {
/* nop-in with itt = 0xffffffff */ count = min(ISER_QP_MAX_RECV_DTOS - outstanding,
atomic_inc(&conn->ib_conn->unexpected_pdu_count); ISER_MIN_POSTED_RX);
err = iser_post_recvm(ib_conn, count);
if (err)
iser_err("posting %d rx bufs err %d\n", count, err);
} }
else if (opcode == ISCSI_OP_ASYNC_EVENT) {
/* asyncronous message */
atomic_inc(&conn->ib_conn->unexpected_pdu_count);
}
/* a reject PDU consumes the recv buf posted for the response */
} }
void iser_snd_completion(struct iser_desc *tx_desc) void iser_snd_completion(struct iser_tx_desc *tx_desc,
struct iser_conn *ib_conn)
{ {
struct iser_dto *dto = &tx_desc->dto;
struct iser_conn *ib_conn = dto->ib_conn;
struct iscsi_iser_conn *iser_conn = ib_conn->iser_conn;
struct iscsi_conn *conn = iser_conn->iscsi_conn;
struct iscsi_task *task; struct iscsi_task *task;
int resume_tx = 0; struct iser_device *device = ib_conn->device;
iser_dbg("Initiator, Data sent dto=0x%p\n", dto); if (tx_desc->type == ISCSI_TX_DATAOUT) {
ib_dma_unmap_single(device->ib_device, tx_desc->dma_addr,
iser_dto_buffs_release(dto); ISER_HEADERS_LEN, DMA_TO_DEVICE);
if (tx_desc->type == ISCSI_TX_DATAOUT)
kmem_cache_free(ig.desc_cache, tx_desc); kmem_cache_free(ig.desc_cache, tx_desc);
}
if (atomic_read(&iser_conn->ib_conn->post_send_buf_count) ==
ISER_QP_MAX_REQ_DTOS)
resume_tx = 1;
atomic_dec(&ib_conn->post_send_buf_count); atomic_dec(&ib_conn->post_send_buf_count);
if (resume_tx) {
iser_dbg("%ld resuming tx\n",jiffies);
iscsi_conn_queue_work(conn);
}
if (tx_desc->type == ISCSI_TX_CONTROL) { if (tx_desc->type == ISCSI_TX_CONTROL) {
/* this arithmetic is legal by libiscsi dd_data allocation */ /* this arithmetic is legal by libiscsi dd_data allocation */
task = (void *) ((long)(void *)tx_desc - task = (void *) ((long)(void *)tx_desc -
@ -692,7 +528,6 @@ void iser_task_rdma_init(struct iscsi_iser_task *iser_task)
void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task)
{ {
int deferred;
int is_rdma_aligned = 1; int is_rdma_aligned = 1;
struct iser_regd_buf *regd; struct iser_regd_buf *regd;
@ -710,32 +545,17 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task)
if (iser_task->dir[ISER_DIR_IN]) { if (iser_task->dir[ISER_DIR_IN]) {
regd = &iser_task->rdma_regd[ISER_DIR_IN]; regd = &iser_task->rdma_regd[ISER_DIR_IN];
deferred = iser_regd_buff_release(regd); if (regd->reg.is_fmr)
if (deferred) { iser_unreg_mem(&regd->reg);
iser_err("%d references remain for BUF-IN rdma reg\n",
atomic_read(&regd->ref_count));
}
} }
if (iser_task->dir[ISER_DIR_OUT]) { if (iser_task->dir[ISER_DIR_OUT]) {
regd = &iser_task->rdma_regd[ISER_DIR_OUT]; regd = &iser_task->rdma_regd[ISER_DIR_OUT];
deferred = iser_regd_buff_release(regd); if (regd->reg.is_fmr)
if (deferred) { iser_unreg_mem(&regd->reg);
iser_err("%d references remain for BUF-OUT rdma reg\n",
atomic_read(&regd->ref_count));
}
} }
/* if the data was unaligned, it was already unmapped and then copied */ /* if the data was unaligned, it was already unmapped and then copied */
if (is_rdma_aligned) if (is_rdma_aligned)
iser_dma_unmap_task_data(iser_task); iser_dma_unmap_task_data(iser_task);
} }
void iser_dto_buffs_release(struct iser_dto *dto)
{
int i;
for (i = 0; i < dto->regd_vector_len; i++)
iser_regd_buff_release(dto->regd[i]);
}

View file

@ -40,62 +40,6 @@
#define ISER_KMALLOC_THRESHOLD 0x20000 /* 128K - kmalloc limit */ #define ISER_KMALLOC_THRESHOLD 0x20000 /* 128K - kmalloc limit */
/**
* Decrements the reference count for the
* registered buffer & releases it
*
* returns 0 if released, 1 if deferred
*/
int iser_regd_buff_release(struct iser_regd_buf *regd_buf)
{
struct ib_device *dev;
if ((atomic_read(&regd_buf->ref_count) == 0) ||
atomic_dec_and_test(&regd_buf->ref_count)) {
/* if we used the dma mr, unreg is just NOP */
if (regd_buf->reg.is_fmr)
iser_unreg_mem(&regd_buf->reg);
if (regd_buf->dma_addr) {
dev = regd_buf->device->ib_device;
ib_dma_unmap_single(dev,
regd_buf->dma_addr,
regd_buf->data_size,
regd_buf->direction);
}
/* else this regd buf is associated with task which we */
/* dma_unmap_single/sg later */
return 0;
} else {
iser_dbg("Release deferred, regd.buff: 0x%p\n", regd_buf);
return 1;
}
}
/**
* iser_reg_single - fills registered buffer descriptor with
* registration information
*/
void iser_reg_single(struct iser_device *device,
struct iser_regd_buf *regd_buf,
enum dma_data_direction direction)
{
u64 dma_addr;
dma_addr = ib_dma_map_single(device->ib_device,
regd_buf->virt_addr,
regd_buf->data_size, direction);
BUG_ON(ib_dma_mapping_error(device->ib_device, dma_addr));
regd_buf->reg.lkey = device->mr->lkey;
regd_buf->reg.len = regd_buf->data_size;
regd_buf->reg.va = dma_addr;
regd_buf->reg.is_fmr = 0;
regd_buf->dma_addr = dma_addr;
regd_buf->direction = direction;
}
/** /**
* iser_start_rdma_unaligned_sg * iser_start_rdma_unaligned_sg
*/ */
@ -109,10 +53,10 @@ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
unsigned long cmd_data_len = data->data_len; unsigned long cmd_data_len = data->data_len;
if (cmd_data_len > ISER_KMALLOC_THRESHOLD) if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
mem = (void *)__get_free_pages(GFP_NOIO, mem = (void *)__get_free_pages(GFP_ATOMIC,
ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT); ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
else else
mem = kmalloc(cmd_data_len, GFP_NOIO); mem = kmalloc(cmd_data_len, GFP_ATOMIC);
if (mem == NULL) { if (mem == NULL) {
iser_err("Failed to allocate mem size %d %d for copying sglist\n", iser_err("Failed to allocate mem size %d %d for copying sglist\n",
@ -474,9 +418,5 @@ int iser_reg_rdma_mem(struct iscsi_iser_task *iser_task,
return err; return err;
} }
} }
/* take a reference on this regd buf such that it will not be released *
* (eg in send dto completion) before we get the scsi response */
atomic_inc(&regd_buf->ref_count);
return 0; return 0;
} }

View file

@ -37,9 +37,8 @@
#include "iscsi_iser.h" #include "iscsi_iser.h"
#define ISCSI_ISER_MAX_CONN 8 #define ISCSI_ISER_MAX_CONN 8
#define ISER_MAX_CQ_LEN ((ISER_QP_MAX_RECV_DTOS + \ #define ISER_MAX_RX_CQ_LEN (ISER_QP_MAX_RECV_DTOS * ISCSI_ISER_MAX_CONN)
ISER_QP_MAX_REQ_DTOS) * \ #define ISER_MAX_TX_CQ_LEN (ISER_QP_MAX_REQ_DTOS * ISCSI_ISER_MAX_CONN)
ISCSI_ISER_MAX_CONN)
static void iser_cq_tasklet_fn(unsigned long data); static void iser_cq_tasklet_fn(unsigned long data);
static void iser_cq_callback(struct ib_cq *cq, void *cq_context); static void iser_cq_callback(struct ib_cq *cq, void *cq_context);
@ -67,15 +66,23 @@ static int iser_create_device_ib_res(struct iser_device *device)
if (IS_ERR(device->pd)) if (IS_ERR(device->pd))
goto pd_err; goto pd_err;
device->cq = ib_create_cq(device->ib_device, device->rx_cq = ib_create_cq(device->ib_device,
iser_cq_callback, iser_cq_callback,
iser_cq_event_callback, iser_cq_event_callback,
(void *)device, (void *)device,
ISER_MAX_CQ_LEN, 0); ISER_MAX_RX_CQ_LEN, 0);
if (IS_ERR(device->cq)) if (IS_ERR(device->rx_cq))
goto cq_err; goto rx_cq_err;
if (ib_req_notify_cq(device->cq, IB_CQ_NEXT_COMP)) device->tx_cq = ib_create_cq(device->ib_device,
NULL, iser_cq_event_callback,
(void *)device,
ISER_MAX_TX_CQ_LEN, 0);
if (IS_ERR(device->tx_cq))
goto tx_cq_err;
if (ib_req_notify_cq(device->rx_cq, IB_CQ_NEXT_COMP))
goto cq_arm_err; goto cq_arm_err;
tasklet_init(&device->cq_tasklet, tasklet_init(&device->cq_tasklet,
@ -93,8 +100,10 @@ static int iser_create_device_ib_res(struct iser_device *device)
dma_mr_err: dma_mr_err:
tasklet_kill(&device->cq_tasklet); tasklet_kill(&device->cq_tasklet);
cq_arm_err: cq_arm_err:
ib_destroy_cq(device->cq); ib_destroy_cq(device->tx_cq);
cq_err: tx_cq_err:
ib_destroy_cq(device->rx_cq);
rx_cq_err:
ib_dealloc_pd(device->pd); ib_dealloc_pd(device->pd);
pd_err: pd_err:
iser_err("failed to allocate an IB resource\n"); iser_err("failed to allocate an IB resource\n");
@ -112,11 +121,13 @@ static void iser_free_device_ib_res(struct iser_device *device)
tasklet_kill(&device->cq_tasklet); tasklet_kill(&device->cq_tasklet);
(void)ib_dereg_mr(device->mr); (void)ib_dereg_mr(device->mr);
(void)ib_destroy_cq(device->cq); (void)ib_destroy_cq(device->tx_cq);
(void)ib_destroy_cq(device->rx_cq);
(void)ib_dealloc_pd(device->pd); (void)ib_dealloc_pd(device->pd);
device->mr = NULL; device->mr = NULL;
device->cq = NULL; device->tx_cq = NULL;
device->rx_cq = NULL;
device->pd = NULL; device->pd = NULL;
} }
@ -129,13 +140,23 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn)
{ {
struct iser_device *device; struct iser_device *device;
struct ib_qp_init_attr init_attr; struct ib_qp_init_attr init_attr;
int ret; int ret = -ENOMEM;
struct ib_fmr_pool_param params; struct ib_fmr_pool_param params;
BUG_ON(ib_conn->device == NULL); BUG_ON(ib_conn->device == NULL);
device = ib_conn->device; device = ib_conn->device;
ib_conn->login_buf = kmalloc(ISER_RX_LOGIN_SIZE, GFP_KERNEL);
if (!ib_conn->login_buf) {
goto alloc_err;
ret = -ENOMEM;
}
ib_conn->login_dma = ib_dma_map_single(ib_conn->device->ib_device,
(void *)ib_conn->login_buf, ISER_RX_LOGIN_SIZE,
DMA_FROM_DEVICE);
ib_conn->page_vec = kmalloc(sizeof(struct iser_page_vec) + ib_conn->page_vec = kmalloc(sizeof(struct iser_page_vec) +
(sizeof(u64) * (ISCSI_ISER_SG_TABLESIZE +1)), (sizeof(u64) * (ISCSI_ISER_SG_TABLESIZE +1)),
GFP_KERNEL); GFP_KERNEL);
@ -169,12 +190,12 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn)
init_attr.event_handler = iser_qp_event_callback; init_attr.event_handler = iser_qp_event_callback;
init_attr.qp_context = (void *)ib_conn; init_attr.qp_context = (void *)ib_conn;
init_attr.send_cq = device->cq; init_attr.send_cq = device->tx_cq;
init_attr.recv_cq = device->cq; init_attr.recv_cq = device->rx_cq;
init_attr.cap.max_send_wr = ISER_QP_MAX_REQ_DTOS; init_attr.cap.max_send_wr = ISER_QP_MAX_REQ_DTOS;
init_attr.cap.max_recv_wr = ISER_QP_MAX_RECV_DTOS; init_attr.cap.max_recv_wr = ISER_QP_MAX_RECV_DTOS;
init_attr.cap.max_send_sge = MAX_REGD_BUF_VECTOR_LEN; init_attr.cap.max_send_sge = 2;
init_attr.cap.max_recv_sge = 2; init_attr.cap.max_recv_sge = 1;
init_attr.sq_sig_type = IB_SIGNAL_REQ_WR; init_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
init_attr.qp_type = IB_QPT_RC; init_attr.qp_type = IB_QPT_RC;
@ -192,6 +213,7 @@ qp_err:
(void)ib_destroy_fmr_pool(ib_conn->fmr_pool); (void)ib_destroy_fmr_pool(ib_conn->fmr_pool);
fmr_pool_err: fmr_pool_err:
kfree(ib_conn->page_vec); kfree(ib_conn->page_vec);
kfree(ib_conn->login_buf);
alloc_err: alloc_err:
iser_err("unable to alloc mem or create resource, err %d\n", ret); iser_err("unable to alloc mem or create resource, err %d\n", ret);
return ret; return ret;
@ -278,17 +300,6 @@ static void iser_device_try_release(struct iser_device *device)
mutex_unlock(&ig.device_list_mutex); mutex_unlock(&ig.device_list_mutex);
} }
int iser_conn_state_comp(struct iser_conn *ib_conn,
enum iser_ib_conn_state comp)
{
int ret;
spin_lock_bh(&ib_conn->lock);
ret = (ib_conn->state == comp);
spin_unlock_bh(&ib_conn->lock);
return ret;
}
static int iser_conn_state_comp_exch(struct iser_conn *ib_conn, static int iser_conn_state_comp_exch(struct iser_conn *ib_conn,
enum iser_ib_conn_state comp, enum iser_ib_conn_state comp,
enum iser_ib_conn_state exch) enum iser_ib_conn_state exch)
@ -314,7 +325,7 @@ static void iser_conn_release(struct iser_conn *ib_conn)
mutex_lock(&ig.connlist_mutex); mutex_lock(&ig.connlist_mutex);
list_del(&ib_conn->conn_list); list_del(&ib_conn->conn_list);
mutex_unlock(&ig.connlist_mutex); mutex_unlock(&ig.connlist_mutex);
iser_free_rx_descriptors(ib_conn);
iser_free_ib_conn_res(ib_conn); iser_free_ib_conn_res(ib_conn);
ib_conn->device = NULL; ib_conn->device = NULL;
/* on EVENT_ADDR_ERROR there's no device yet for this conn */ /* on EVENT_ADDR_ERROR there's no device yet for this conn */
@ -442,7 +453,7 @@ static void iser_disconnected_handler(struct rdma_cm_id *cma_id)
ISCSI_ERR_CONN_FAILED); ISCSI_ERR_CONN_FAILED);
/* Complete the termination process if no posts are pending */ /* Complete the termination process if no posts are pending */
if ((atomic_read(&ib_conn->post_recv_buf_count) == 0) && if (ib_conn->post_recv_buf_count == 0 &&
(atomic_read(&ib_conn->post_send_buf_count) == 0)) { (atomic_read(&ib_conn->post_send_buf_count) == 0)) {
ib_conn->state = ISER_CONN_DOWN; ib_conn->state = ISER_CONN_DOWN;
wake_up_interruptible(&ib_conn->wait); wake_up_interruptible(&ib_conn->wait);
@ -489,9 +500,8 @@ void iser_conn_init(struct iser_conn *ib_conn)
{ {
ib_conn->state = ISER_CONN_INIT; ib_conn->state = ISER_CONN_INIT;
init_waitqueue_head(&ib_conn->wait); init_waitqueue_head(&ib_conn->wait);
atomic_set(&ib_conn->post_recv_buf_count, 0); ib_conn->post_recv_buf_count = 0;
atomic_set(&ib_conn->post_send_buf_count, 0); atomic_set(&ib_conn->post_send_buf_count, 0);
atomic_set(&ib_conn->unexpected_pdu_count, 0);
atomic_set(&ib_conn->refcount, 1); atomic_set(&ib_conn->refcount, 1);
INIT_LIST_HEAD(&ib_conn->conn_list); INIT_LIST_HEAD(&ib_conn->conn_list);
spin_lock_init(&ib_conn->lock); spin_lock_init(&ib_conn->lock);
@ -626,136 +636,97 @@ void iser_unreg_mem(struct iser_mem_reg *reg)
reg->mem_h = NULL; reg->mem_h = NULL;
} }
/** int iser_post_recvl(struct iser_conn *ib_conn)
* iser_dto_to_iov - builds IOV from a dto descriptor
*/
static void iser_dto_to_iov(struct iser_dto *dto, struct ib_sge *iov, int iov_len)
{ {
int i; struct ib_recv_wr rx_wr, *rx_wr_failed;
struct ib_sge *sge; struct ib_sge sge;
struct iser_regd_buf *regd_buf; int ib_ret;
if (dto->regd_vector_len > iov_len) { sge.addr = ib_conn->login_dma;
iser_err("iov size %d too small for posting dto of len %d\n", sge.length = ISER_RX_LOGIN_SIZE;
iov_len, dto->regd_vector_len); sge.lkey = ib_conn->device->mr->lkey;
BUG();
}
for (i = 0; i < dto->regd_vector_len; i++) { rx_wr.wr_id = (unsigned long)ib_conn->login_buf;
sge = &iov[i]; rx_wr.sg_list = &sge;
regd_buf = dto->regd[i]; rx_wr.num_sge = 1;
rx_wr.next = NULL;
sge->addr = regd_buf->reg.va; ib_conn->post_recv_buf_count++;
sge->length = regd_buf->reg.len; ib_ret = ib_post_recv(ib_conn->qp, &rx_wr, &rx_wr_failed);
sge->lkey = regd_buf->reg.lkey;
if (dto->used_sz[i] > 0) /* Adjust size */
sge->length = dto->used_sz[i];
/* offset and length should not exceed the regd buf length */
if (sge->length + dto->offset[i] > regd_buf->reg.len) {
iser_err("Used len:%ld + offset:%d, exceed reg.buf.len:"
"%ld in dto:0x%p [%d], va:0x%08lX\n",
(unsigned long)sge->length, dto->offset[i],
(unsigned long)regd_buf->reg.len, dto, i,
(unsigned long)sge->addr);
BUG();
}
sge->addr += dto->offset[i]; /* Adjust offset */
}
}
/**
* iser_post_recv - Posts a receive buffer.
*
* returns 0 on success, -1 on failure
*/
int iser_post_recv(struct iser_desc *rx_desc)
{
int ib_ret, ret_val = 0;
struct ib_recv_wr recv_wr, *recv_wr_failed;
struct ib_sge iov[2];
struct iser_conn *ib_conn;
struct iser_dto *recv_dto = &rx_desc->dto;
/* Retrieve conn */
ib_conn = recv_dto->ib_conn;
iser_dto_to_iov(recv_dto, iov, 2);
recv_wr.next = NULL;
recv_wr.sg_list = iov;
recv_wr.num_sge = recv_dto->regd_vector_len;
recv_wr.wr_id = (unsigned long)rx_desc;
atomic_inc(&ib_conn->post_recv_buf_count);
ib_ret = ib_post_recv(ib_conn->qp, &recv_wr, &recv_wr_failed);
if (ib_ret) { if (ib_ret) {
iser_err("ib_post_recv failed ret=%d\n", ib_ret); iser_err("ib_post_recv failed ret=%d\n", ib_ret);
atomic_dec(&ib_conn->post_recv_buf_count); ib_conn->post_recv_buf_count--;
ret_val = -1; }
return ib_ret;
} }
return ret_val; int iser_post_recvm(struct iser_conn *ib_conn, int count)
{
struct ib_recv_wr *rx_wr, *rx_wr_failed;
int i, ib_ret;
unsigned int my_rx_head = ib_conn->rx_desc_head;
struct iser_rx_desc *rx_desc;
for (rx_wr = ib_conn->rx_wr, i = 0; i < count; i++, rx_wr++) {
rx_desc = &ib_conn->rx_descs[my_rx_head];
rx_wr->wr_id = (unsigned long)rx_desc;
rx_wr->sg_list = &rx_desc->rx_sg;
rx_wr->num_sge = 1;
rx_wr->next = rx_wr + 1;
my_rx_head = (my_rx_head + 1) & (ISER_QP_MAX_RECV_DTOS - 1);
} }
rx_wr--;
rx_wr->next = NULL; /* mark end of work requests list */
ib_conn->post_recv_buf_count += count;
ib_ret = ib_post_recv(ib_conn->qp, ib_conn->rx_wr, &rx_wr_failed);
if (ib_ret) {
iser_err("ib_post_recv failed ret=%d\n", ib_ret);
ib_conn->post_recv_buf_count -= count;
} else
ib_conn->rx_desc_head = my_rx_head;
return ib_ret;
}
/** /**
* iser_start_send - Initiate a Send DTO operation * iser_start_send - Initiate a Send DTO operation
* *
* returns 0 on success, -1 on failure * returns 0 on success, -1 on failure
*/ */
int iser_post_send(struct iser_desc *tx_desc) int iser_post_send(struct iser_conn *ib_conn, struct iser_tx_desc *tx_desc)
{ {
int ib_ret, ret_val = 0; int ib_ret;
struct ib_send_wr send_wr, *send_wr_failed; struct ib_send_wr send_wr, *send_wr_failed;
struct ib_sge iov[MAX_REGD_BUF_VECTOR_LEN];
struct iser_conn *ib_conn;
struct iser_dto *dto = &tx_desc->dto;
ib_conn = dto->ib_conn; ib_dma_sync_single_for_device(ib_conn->device->ib_device,
tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE);
iser_dto_to_iov(dto, iov, MAX_REGD_BUF_VECTOR_LEN);
send_wr.next = NULL; send_wr.next = NULL;
send_wr.wr_id = (unsigned long)tx_desc; send_wr.wr_id = (unsigned long)tx_desc;
send_wr.sg_list = iov; send_wr.sg_list = tx_desc->tx_sg;
send_wr.num_sge = dto->regd_vector_len; send_wr.num_sge = tx_desc->num_sge;
send_wr.opcode = IB_WR_SEND; send_wr.opcode = IB_WR_SEND;
send_wr.send_flags = dto->notify_enable ? IB_SEND_SIGNALED : 0; send_wr.send_flags = IB_SEND_SIGNALED;
atomic_inc(&ib_conn->post_send_buf_count); atomic_inc(&ib_conn->post_send_buf_count);
ib_ret = ib_post_send(ib_conn->qp, &send_wr, &send_wr_failed); ib_ret = ib_post_send(ib_conn->qp, &send_wr, &send_wr_failed);
if (ib_ret) { if (ib_ret) {
iser_err("Failed to start SEND DTO, dto: 0x%p, IOV len: %d\n",
dto, dto->regd_vector_len);
iser_err("ib_post_send failed, ret:%d\n", ib_ret); iser_err("ib_post_send failed, ret:%d\n", ib_ret);
atomic_dec(&ib_conn->post_send_buf_count); atomic_dec(&ib_conn->post_send_buf_count);
ret_val = -1; }
return ib_ret;
} }
return ret_val; static void iser_handle_comp_error(struct iser_tx_desc *desc,
} struct iser_conn *ib_conn)
static void iser_handle_comp_error(struct iser_desc *desc)
{ {
struct iser_dto *dto = &desc->dto; if (desc && desc->type == ISCSI_TX_DATAOUT)
struct iser_conn *ib_conn = dto->ib_conn;
iser_dto_buffs_release(dto);
if (desc->type == ISCSI_RX) {
kfree(desc->data);
kmem_cache_free(ig.desc_cache, desc); kmem_cache_free(ig.desc_cache, desc);
atomic_dec(&ib_conn->post_recv_buf_count);
} else { /* type is TX control/command/dataout */
if (desc->type == ISCSI_TX_DATAOUT)
kmem_cache_free(ig.desc_cache, desc);
atomic_dec(&ib_conn->post_send_buf_count);
}
if (atomic_read(&ib_conn->post_recv_buf_count) == 0 && if (ib_conn->post_recv_buf_count == 0 &&
atomic_read(&ib_conn->post_send_buf_count) == 0) { atomic_read(&ib_conn->post_send_buf_count) == 0) {
/* getting here when the state is UP means that the conn is * /* getting here when the state is UP means that the conn is *
* being terminated asynchronously from the iSCSI layer's * * being terminated asynchronously from the iSCSI layer's *
@ -774,32 +745,74 @@ static void iser_handle_comp_error(struct iser_desc *desc)
} }
} }
static int iser_drain_tx_cq(struct iser_device *device)
{
struct ib_cq *cq = device->tx_cq;
struct ib_wc wc;
struct iser_tx_desc *tx_desc;
struct iser_conn *ib_conn;
int completed_tx = 0;
while (ib_poll_cq(cq, 1, &wc) == 1) {
tx_desc = (struct iser_tx_desc *) (unsigned long) wc.wr_id;
ib_conn = wc.qp->qp_context;
if (wc.status == IB_WC_SUCCESS) {
if (wc.opcode == IB_WC_SEND)
iser_snd_completion(tx_desc, ib_conn);
else
iser_err("expected opcode %d got %d\n",
IB_WC_SEND, wc.opcode);
} else {
iser_err("tx id %llx status %d vend_err %x\n",
wc.wr_id, wc.status, wc.vendor_err);
atomic_dec(&ib_conn->post_send_buf_count);
iser_handle_comp_error(tx_desc, ib_conn);
}
completed_tx++;
}
return completed_tx;
}
static void iser_cq_tasklet_fn(unsigned long data) static void iser_cq_tasklet_fn(unsigned long data)
{ {
struct iser_device *device = (struct iser_device *)data; struct iser_device *device = (struct iser_device *)data;
struct ib_cq *cq = device->cq; struct ib_cq *cq = device->rx_cq;
struct ib_wc wc; struct ib_wc wc;
struct iser_desc *desc; struct iser_rx_desc *desc;
unsigned long xfer_len; unsigned long xfer_len;
struct iser_conn *ib_conn;
int completed_tx, completed_rx;
completed_tx = completed_rx = 0;
while (ib_poll_cq(cq, 1, &wc) == 1) { while (ib_poll_cq(cq, 1, &wc) == 1) {
desc = (struct iser_desc *) (unsigned long) wc.wr_id; desc = (struct iser_rx_desc *) (unsigned long) wc.wr_id;
BUG_ON(desc == NULL); BUG_ON(desc == NULL);
ib_conn = wc.qp->qp_context;
if (wc.status == IB_WC_SUCCESS) { if (wc.status == IB_WC_SUCCESS) {
if (desc->type == ISCSI_RX) { if (wc.opcode == IB_WC_RECV) {
xfer_len = (unsigned long)wc.byte_len; xfer_len = (unsigned long)wc.byte_len;
iser_rcv_completion(desc, xfer_len); iser_rcv_completion(desc, xfer_len, ib_conn);
} else /* type == ISCSI_TX_CONTROL/SCSI_CMD/DOUT */ } else
iser_snd_completion(desc); iser_err("expected opcode %d got %d\n",
IB_WC_RECV, wc.opcode);
} else { } else {
iser_err("comp w. error op %d status %d\n",desc->type,wc.status); if (wc.status != IB_WC_WR_FLUSH_ERR)
iser_handle_comp_error(desc); iser_err("rx id %llx status %d vend_err %x\n",
wc.wr_id, wc.status, wc.vendor_err);
ib_conn->post_recv_buf_count--;
iser_handle_comp_error(NULL, ib_conn);
} }
completed_rx++;
if (!(completed_rx & 63))
completed_tx += iser_drain_tx_cq(device);
} }
/* #warning "it is assumed here that arming CQ only once its empty" * /* #warning "it is assumed here that arming CQ only once its empty" *
* " would not cause interrupts to be missed" */ * " would not cause interrupts to be missed" */
ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
completed_tx += iser_drain_tx_cq(device);
iser_dbg("got %d rx %d tx completions\n", completed_rx, completed_tx);
} }
static void iser_cq_callback(struct ib_cq *cq, void *cq_context) static void iser_cq_callback(struct ib_cq *cq, void *cq_context)

View file

@ -80,7 +80,8 @@ MODULE_PARM_DESC(mellanox_workarounds,
static void srp_add_one(struct ib_device *device); static void srp_add_one(struct ib_device *device);
static void srp_remove_one(struct ib_device *device); static void srp_remove_one(struct ib_device *device);
static void srp_completion(struct ib_cq *cq, void *target_ptr); static void srp_recv_completion(struct ib_cq *cq, void *target_ptr);
static void srp_send_completion(struct ib_cq *cq, void *target_ptr);
static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event); static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
static struct scsi_transport_template *ib_srp_transport_template; static struct scsi_transport_template *ib_srp_transport_template;
@ -227,14 +228,21 @@ static int srp_create_target_ib(struct srp_target_port *target)
if (!init_attr) if (!init_attr)
return -ENOMEM; return -ENOMEM;
target->cq = ib_create_cq(target->srp_host->srp_dev->dev, target->recv_cq = ib_create_cq(target->srp_host->srp_dev->dev,
srp_completion, NULL, target, SRP_CQ_SIZE, 0); srp_recv_completion, NULL, target, SRP_RQ_SIZE, 0);
if (IS_ERR(target->cq)) { if (IS_ERR(target->recv_cq)) {
ret = PTR_ERR(target->cq); ret = PTR_ERR(target->recv_cq);
goto out; goto err;
} }
ib_req_notify_cq(target->cq, IB_CQ_NEXT_COMP); target->send_cq = ib_create_cq(target->srp_host->srp_dev->dev,
srp_send_completion, NULL, target, SRP_SQ_SIZE, 0);
if (IS_ERR(target->send_cq)) {
ret = PTR_ERR(target->send_cq);
goto err_recv_cq;
}
ib_req_notify_cq(target->recv_cq, IB_CQ_NEXT_COMP);
init_attr->event_handler = srp_qp_event; init_attr->event_handler = srp_qp_event;
init_attr->cap.max_send_wr = SRP_SQ_SIZE; init_attr->cap.max_send_wr = SRP_SQ_SIZE;
@ -243,24 +251,32 @@ static int srp_create_target_ib(struct srp_target_port *target)
init_attr->cap.max_send_sge = 1; init_attr->cap.max_send_sge = 1;
init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; init_attr->sq_sig_type = IB_SIGNAL_ALL_WR;
init_attr->qp_type = IB_QPT_RC; init_attr->qp_type = IB_QPT_RC;
init_attr->send_cq = target->cq; init_attr->send_cq = target->send_cq;
init_attr->recv_cq = target->cq; init_attr->recv_cq = target->recv_cq;
target->qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr); target->qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr);
if (IS_ERR(target->qp)) { if (IS_ERR(target->qp)) {
ret = PTR_ERR(target->qp); ret = PTR_ERR(target->qp);
ib_destroy_cq(target->cq); goto err_send_cq;
goto out;
} }
ret = srp_init_qp(target, target->qp); ret = srp_init_qp(target, target->qp);
if (ret) { if (ret)
ib_destroy_qp(target->qp); goto err_qp;
ib_destroy_cq(target->cq);
goto out;
}
out: kfree(init_attr);
return 0;
err_qp:
ib_destroy_qp(target->qp);
err_send_cq:
ib_destroy_cq(target->send_cq);
err_recv_cq:
ib_destroy_cq(target->recv_cq);
err:
kfree(init_attr); kfree(init_attr);
return ret; return ret;
} }
@ -270,7 +286,8 @@ static void srp_free_target_ib(struct srp_target_port *target)
int i; int i;
ib_destroy_qp(target->qp); ib_destroy_qp(target->qp);
ib_destroy_cq(target->cq); ib_destroy_cq(target->send_cq);
ib_destroy_cq(target->recv_cq);
for (i = 0; i < SRP_RQ_SIZE; ++i) for (i = 0; i < SRP_RQ_SIZE; ++i)
srp_free_iu(target->srp_host, target->rx_ring[i]); srp_free_iu(target->srp_host, target->rx_ring[i]);
@ -568,7 +585,9 @@ static int srp_reconnect_target(struct srp_target_port *target)
if (ret) if (ret)
goto err; goto err;
while (ib_poll_cq(target->cq, 1, &wc) > 0) while (ib_poll_cq(target->recv_cq, 1, &wc) > 0)
; /* nothing */
while (ib_poll_cq(target->send_cq, 1, &wc) > 0)
; /* nothing */ ; /* nothing */
spin_lock_irq(target->scsi_host->host_lock); spin_lock_irq(target->scsi_host->host_lock);
@ -851,7 +870,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
struct srp_iu *iu; struct srp_iu *iu;
u8 opcode; u8 opcode;
iu = target->rx_ring[wc->wr_id & ~SRP_OP_RECV]; iu = target->rx_ring[wc->wr_id];
dev = target->srp_host->srp_dev->dev; dev = target->srp_host->srp_dev->dev;
ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len, ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len,
@ -898,7 +917,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
} }
static void srp_completion(struct ib_cq *cq, void *target_ptr) static void srp_recv_completion(struct ib_cq *cq, void *target_ptr)
{ {
struct srp_target_port *target = target_ptr; struct srp_target_port *target = target_ptr;
struct ib_wc wc; struct ib_wc wc;
@ -907,16 +926,30 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr)
while (ib_poll_cq(cq, 1, &wc) > 0) { while (ib_poll_cq(cq, 1, &wc) > 0) {
if (wc.status) { if (wc.status) {
shost_printk(KERN_ERR, target->scsi_host, shost_printk(KERN_ERR, target->scsi_host,
PFX "failed %s status %d\n", PFX "failed receive status %d\n",
wc.wr_id & SRP_OP_RECV ? "receive" : "send",
wc.status); wc.status);
target->qp_in_error = 1; target->qp_in_error = 1;
break; break;
} }
if (wc.wr_id & SRP_OP_RECV)
srp_handle_recv(target, &wc); srp_handle_recv(target, &wc);
else }
}
static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
{
struct srp_target_port *target = target_ptr;
struct ib_wc wc;
while (ib_poll_cq(cq, 1, &wc) > 0) {
if (wc.status) {
shost_printk(KERN_ERR, target->scsi_host,
PFX "failed send status %d\n",
wc.status);
target->qp_in_error = 1;
break;
}
++target->tx_tail; ++target->tx_tail;
} }
} }
@ -930,7 +963,7 @@ static int __srp_post_recv(struct srp_target_port *target)
int ret; int ret;
next = target->rx_head & (SRP_RQ_SIZE - 1); next = target->rx_head & (SRP_RQ_SIZE - 1);
wr.wr_id = next | SRP_OP_RECV; wr.wr_id = next;
iu = target->rx_ring[next]; iu = target->rx_ring[next];
list.addr = iu->dma; list.addr = iu->dma;
@ -970,6 +1003,8 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
{ {
s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2; s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2;
srp_send_completion(target->send_cq, target);
if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE) if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
return NULL; return NULL;

View file

@ -60,7 +60,6 @@ enum {
SRP_RQ_SHIFT = 6, SRP_RQ_SHIFT = 6,
SRP_RQ_SIZE = 1 << SRP_RQ_SHIFT, SRP_RQ_SIZE = 1 << SRP_RQ_SHIFT,
SRP_SQ_SIZE = SRP_RQ_SIZE - 1, SRP_SQ_SIZE = SRP_RQ_SIZE - 1,
SRP_CQ_SIZE = SRP_SQ_SIZE + SRP_RQ_SIZE,
SRP_TAG_TSK_MGMT = 1 << (SRP_RQ_SHIFT + 1), SRP_TAG_TSK_MGMT = 1 << (SRP_RQ_SHIFT + 1),
@ -69,8 +68,6 @@ enum {
SRP_FMR_DIRTY_SIZE = SRP_FMR_POOL_SIZE / 4 SRP_FMR_DIRTY_SIZE = SRP_FMR_POOL_SIZE / 4
}; };
#define SRP_OP_RECV (1 << 31)
enum srp_target_state { enum srp_target_state {
SRP_TARGET_LIVE, SRP_TARGET_LIVE,
SRP_TARGET_CONNECTING, SRP_TARGET_CONNECTING,
@ -133,7 +130,8 @@ struct srp_target_port {
int path_query_id; int path_query_id;
struct ib_cm_id *cm_id; struct ib_cm_id *cm_id;
struct ib_cq *cq; struct ib_cq *recv_cq;
struct ib_cq *send_cq;
struct ib_qp *qp; struct ib_qp *qp;
int max_ti_iu_len; int max_ti_iu_len;

View file

@ -264,6 +264,10 @@ struct adapter {
struct work_struct fatal_error_handler_task; struct work_struct fatal_error_handler_task;
struct work_struct link_fault_handler_task; struct work_struct link_fault_handler_task;
struct work_struct db_full_task;
struct work_struct db_empty_task;
struct work_struct db_drop_task;
struct dentry *debugfs_root; struct dentry *debugfs_root;
struct mutex mdio_lock; struct mutex mdio_lock;
@ -335,6 +339,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx, int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
unsigned char *data); unsigned char *data);
irqreturn_t t3_sge_intr_msix(int irq, void *cookie); irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
extern struct workqueue_struct *cxgb3_wq;
int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size); int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size);

View file

@ -45,6 +45,7 @@
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/stringify.h> #include <linux/stringify.h>
#include <linux/sched.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "common.h" #include "common.h"
@ -140,7 +141,7 @@ MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not");
* will block keventd as it needs the rtnl lock, and we'll deadlock waiting * will block keventd as it needs the rtnl lock, and we'll deadlock waiting
* for our work to complete. Get our own work queue to solve this. * for our work to complete. Get our own work queue to solve this.
*/ */
static struct workqueue_struct *cxgb3_wq; struct workqueue_struct *cxgb3_wq;
/** /**
* link_report - show link status and link speed/duplex * link_report - show link status and link speed/duplex
@ -586,6 +587,19 @@ static void setup_rss(struct adapter *adap)
V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map); V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map);
} }
static void ring_dbs(struct adapter *adap)
{
int i, j;
for (i = 0; i < SGE_QSETS; i++) {
struct sge_qset *qs = &adap->sge.qs[i];
if (qs->adap)
for (j = 0; j < SGE_TXQ_PER_SET; j++)
t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | V_EGRCNTX(qs->txq[j].cntxt_id));
}
}
static void init_napi(struct adapter *adap) static void init_napi(struct adapter *adap)
{ {
int i; int i;
@ -2750,6 +2764,42 @@ static void t3_adap_check_task(struct work_struct *work)
spin_unlock_irq(&adapter->work_lock); spin_unlock_irq(&adapter->work_lock);
} }
static void db_full_task(struct work_struct *work)
{
struct adapter *adapter = container_of(work, struct adapter,
db_full_task);
cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_FULL, 0);
}
static void db_empty_task(struct work_struct *work)
{
struct adapter *adapter = container_of(work, struct adapter,
db_empty_task);
cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_EMPTY, 0);
}
static void db_drop_task(struct work_struct *work)
{
struct adapter *adapter = container_of(work, struct adapter,
db_drop_task);
unsigned long delay = 1000;
unsigned short r;
cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_DROP, 0);
/*
* Sleep a while before ringing the driver qset dbs.
* The delay is between 1000-2023 usecs.
*/
get_random_bytes(&r, 2);
delay += r & 1023;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(usecs_to_jiffies(delay));
ring_dbs(adapter);
}
/* /*
* Processes external (PHY) interrupts in process context. * Processes external (PHY) interrupts in process context.
*/ */
@ -3218,6 +3268,11 @@ static int __devinit init_one(struct pci_dev *pdev,
INIT_LIST_HEAD(&adapter->adapter_list); INIT_LIST_HEAD(&adapter->adapter_list);
INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task); INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task); INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task);
INIT_WORK(&adapter->db_full_task, db_full_task);
INIT_WORK(&adapter->db_empty_task, db_empty_task);
INIT_WORK(&adapter->db_drop_task, db_drop_task);
INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task); INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
for (i = 0; i < ai->nports0 + ai->nports1; ++i) { for (i = 0; i < ai->nports0 + ai->nports1; ++i) {

View file

@ -73,7 +73,10 @@ enum {
OFFLOAD_STATUS_UP, OFFLOAD_STATUS_UP,
OFFLOAD_STATUS_DOWN, OFFLOAD_STATUS_DOWN,
OFFLOAD_PORT_DOWN, OFFLOAD_PORT_DOWN,
OFFLOAD_PORT_UP OFFLOAD_PORT_UP,
OFFLOAD_DB_FULL,
OFFLOAD_DB_EMPTY,
OFFLOAD_DB_DROP
}; };
struct cxgb3_client { struct cxgb3_client {

View file

@ -254,6 +254,22 @@
#define V_LOPIODRBDROPERR(x) ((x) << S_LOPIODRBDROPERR) #define V_LOPIODRBDROPERR(x) ((x) << S_LOPIODRBDROPERR)
#define F_LOPIODRBDROPERR V_LOPIODRBDROPERR(1U) #define F_LOPIODRBDROPERR V_LOPIODRBDROPERR(1U)
#define S_HIPRIORITYDBFULL 7
#define V_HIPRIORITYDBFULL(x) ((x) << S_HIPRIORITYDBFULL)
#define F_HIPRIORITYDBFULL V_HIPRIORITYDBFULL(1U)
#define S_HIPRIORITYDBEMPTY 6
#define V_HIPRIORITYDBEMPTY(x) ((x) << S_HIPRIORITYDBEMPTY)
#define F_HIPRIORITYDBEMPTY V_HIPRIORITYDBEMPTY(1U)
#define S_LOPRIORITYDBFULL 5
#define V_LOPRIORITYDBFULL(x) ((x) << S_LOPRIORITYDBFULL)
#define F_LOPRIORITYDBFULL V_LOPRIORITYDBFULL(1U)
#define S_LOPRIORITYDBEMPTY 4
#define V_LOPRIORITYDBEMPTY(x) ((x) << S_LOPRIORITYDBEMPTY)
#define F_LOPRIORITYDBEMPTY V_LOPRIORITYDBEMPTY(1U)
#define S_RSPQDISABLED 3 #define S_RSPQDISABLED 3
#define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED) #define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED)
#define F_RSPQDISABLED V_RSPQDISABLED(1U) #define F_RSPQDISABLED V_RSPQDISABLED(1U)

View file

@ -42,6 +42,7 @@
#include "sge_defs.h" #include "sge_defs.h"
#include "t3_cpl.h" #include "t3_cpl.h"
#include "firmware_exports.h" #include "firmware_exports.h"
#include "cxgb3_offload.h"
#define USE_GTS 0 #define USE_GTS 0
@ -2841,8 +2842,13 @@ void t3_sge_err_intr_handler(struct adapter *adapter)
} }
if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR)) if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR))
CH_ALERT(adapter, "SGE dropped %s priority doorbell\n", queue_work(cxgb3_wq, &adapter->db_drop_task);
status & F_HIPIODRBDROPERR ? "high" : "lo");
if (status & (F_HIPRIORITYDBFULL | F_LOPRIORITYDBFULL))
queue_work(cxgb3_wq, &adapter->db_full_task);
if (status & (F_HIPRIORITYDBEMPTY | F_LOPRIORITYDBEMPTY))
queue_work(cxgb3_wq, &adapter->db_empty_task);
t3_write_reg(adapter, A_SG_INT_CAUSE, status); t3_write_reg(adapter, A_SG_INT_CAUSE, status);
if (status & SGE_FATALERR) if (status & SGE_FATALERR)

View file

@ -1433,7 +1433,10 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \
V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \
F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \
F_HIRCQPARITYERROR) F_HIRCQPARITYERROR | F_LOPRIORITYDBFULL | \
F_HIPRIORITYDBFULL | F_LOPRIORITYDBEMPTY | \
F_HIPRIORITYDBEMPTY | F_HIPIODRBDROPERR | \
F_LOPIODRBDROPERR)
#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \ #define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \ F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
F_NFASRCHFAIL) F_NFASRCHFAIL)

View file

@ -232,6 +232,7 @@ void ib_unpack(const struct ib_field *desc,
void ib_ud_header_init(int payload_bytes, void ib_ud_header_init(int payload_bytes,
int grh_present, int grh_present,
int immediate_present,
struct ib_ud_header *header); struct ib_ud_header *header);
int ib_ud_header_pack(struct ib_ud_header *header, int ib_ud_header_pack(struct ib_ud_header *header,

View file

@ -984,9 +984,9 @@ struct ib_device {
struct list_head event_handler_list; struct list_head event_handler_list;
spinlock_t event_handler_lock; spinlock_t event_handler_lock;
spinlock_t client_data_lock;
struct list_head core_list; struct list_head core_list;
struct list_head client_data_list; struct list_head client_data_list;
spinlock_t client_data_lock;
struct ib_cache cache; struct ib_cache cache;
int *pkey_tbl_len; int *pkey_tbl_len;
@ -1144,8 +1144,8 @@ struct ib_device {
IB_DEV_UNREGISTERED IB_DEV_UNREGISTERED
} reg_state; } reg_state;
u64 uverbs_cmd_mask;
int uverbs_abi_ver; int uverbs_abi_ver;
u64 uverbs_cmd_mask;
char node_desc[64]; char node_desc[64];
__be64 node_guid; __be64 node_guid;

View file

@ -67,7 +67,6 @@ enum rdma_port_space {
RDMA_PS_IPOIB = 0x0002, RDMA_PS_IPOIB = 0x0002,
RDMA_PS_TCP = 0x0106, RDMA_PS_TCP = 0x0106,
RDMA_PS_UDP = 0x0111, RDMA_PS_UDP = 0x0111,
RDMA_PS_SCTP = 0x0183
}; };
struct rdma_addr { struct rdma_addr {