diff options
Diffstat (limited to 'drivers/infiniband/core/user_mad.c')
-rw-r--r-- | drivers/infiniband/core/user_mad.c | 188 |
1 files changed, 164 insertions, 24 deletions
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 1acb99100556..928cdd20e2d1 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c | |||
@@ -33,6 +33,8 @@ | |||
33 | * SOFTWARE. | 33 | * SOFTWARE. |
34 | */ | 34 | */ |
35 | 35 | ||
36 | #define pr_fmt(fmt) "user_mad: " fmt | ||
37 | |||
36 | #include <linux/module.h> | 38 | #include <linux/module.h> |
37 | #include <linux/init.h> | 39 | #include <linux/init.h> |
38 | #include <linux/device.h> | 40 | #include <linux/device.h> |
@@ -504,13 +506,15 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, | |||
504 | 506 | ||
505 | rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data; | 507 | rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data; |
506 | hdr_len = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class); | 508 | hdr_len = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class); |
507 | if (!ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class)) { | 509 | |
508 | copy_offset = IB_MGMT_MAD_HDR; | 510 | if (ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class) |
509 | rmpp_active = 0; | 511 | && ib_mad_kernel_rmpp_agent(agent)) { |
510 | } else { | ||
511 | copy_offset = IB_MGMT_RMPP_HDR; | 512 | copy_offset = IB_MGMT_RMPP_HDR; |
512 | rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & | 513 | rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & |
513 | IB_MGMT_RMPP_FLAG_ACTIVE; | 514 | IB_MGMT_RMPP_FLAG_ACTIVE; |
515 | } else { | ||
516 | copy_offset = IB_MGMT_MAD_HDR; | ||
517 | rmpp_active = 0; | ||
514 | } | 518 | } |
515 | 519 | ||
516 | data_len = count - hdr_size(file) - hdr_len; | 520 | data_len = count - hdr_size(file) - hdr_len; |
@@ -556,14 +560,22 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, | |||
556 | rmpp_mad->mad_hdr.tid = *tid; | 560 | rmpp_mad->mad_hdr.tid = *tid; |
557 | } | 561 | } |
558 | 562 | ||
559 | spin_lock_irq(&file->send_lock); | 563 | if (!ib_mad_kernel_rmpp_agent(agent) |
560 | ret = is_duplicate(file, packet); | 564 | && ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class) |
561 | if (!ret) | 565 | && (ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE)) { |
566 | spin_lock_irq(&file->send_lock); | ||
562 | list_add_tail(&packet->list, &file->send_list); | 567 | list_add_tail(&packet->list, &file->send_list); |
563 | spin_unlock_irq(&file->send_lock); | 568 | spin_unlock_irq(&file->send_lock); |
564 | if (ret) { | 569 | } else { |
565 | ret = -EINVAL; | 570 | spin_lock_irq(&file->send_lock); |
566 | goto err_msg; | 571 | ret = is_duplicate(file, packet); |
572 | if (!ret) | ||
573 | list_add_tail(&packet->list, &file->send_list); | ||
574 | spin_unlock_irq(&file->send_lock); | ||
575 | if (ret) { | ||
576 | ret = -EINVAL; | ||
577 | goto err_msg; | ||
578 | } | ||
567 | } | 579 | } |
568 | 580 | ||
569 | ret = ib_post_send_mad(packet->msg, NULL); | 581 | ret = ib_post_send_mad(packet->msg, NULL); |
@@ -614,6 +626,8 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg, | |||
614 | mutex_lock(&file->mutex); | 626 | mutex_lock(&file->mutex); |
615 | 627 | ||
616 | if (!file->port->ib_dev) { | 628 | if (!file->port->ib_dev) { |
629 | dev_notice(file->port->dev, | ||
630 | "ib_umad_reg_agent: invalid device\n"); | ||
617 | ret = -EPIPE; | 631 | ret = -EPIPE; |
618 | goto out; | 632 | goto out; |
619 | } | 633 | } |
@@ -624,6 +638,9 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg, | |||
624 | } | 638 | } |
625 | 639 | ||
626 | if (ureq.qpn != 0 && ureq.qpn != 1) { | 640 | if (ureq.qpn != 0 && ureq.qpn != 1) { |
641 | dev_notice(file->port->dev, | ||
642 | "ib_umad_reg_agent: invalid QPN %d specified\n", | ||
643 | ureq.qpn); | ||
627 | ret = -EINVAL; | 644 | ret = -EINVAL; |
628 | goto out; | 645 | goto out; |
629 | } | 646 | } |
@@ -632,11 +649,15 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg, | |||
632 | if (!__get_agent(file, agent_id)) | 649 | if (!__get_agent(file, agent_id)) |
633 | goto found; | 650 | goto found; |
634 | 651 | ||
652 | dev_notice(file->port->dev, | ||
653 | "ib_umad_reg_agent: Max Agents (%u) reached\n", | ||
654 | IB_UMAD_MAX_AGENTS); | ||
635 | ret = -ENOMEM; | 655 | ret = -ENOMEM; |
636 | goto out; | 656 | goto out; |
637 | 657 | ||
638 | found: | 658 | found: |
639 | if (ureq.mgmt_class) { | 659 | if (ureq.mgmt_class) { |
660 | memset(&req, 0, sizeof(req)); | ||
640 | req.mgmt_class = ureq.mgmt_class; | 661 | req.mgmt_class = ureq.mgmt_class; |
641 | req.mgmt_class_version = ureq.mgmt_class_version; | 662 | req.mgmt_class_version = ureq.mgmt_class_version; |
642 | memcpy(req.oui, ureq.oui, sizeof req.oui); | 663 | memcpy(req.oui, ureq.oui, sizeof req.oui); |
@@ -657,7 +678,7 @@ found: | |||
657 | ureq.qpn ? IB_QPT_GSI : IB_QPT_SMI, | 678 | ureq.qpn ? IB_QPT_GSI : IB_QPT_SMI, |
658 | ureq.mgmt_class ? &req : NULL, | 679 | ureq.mgmt_class ? &req : NULL, |
659 | ureq.rmpp_version, | 680 | ureq.rmpp_version, |
660 | send_handler, recv_handler, file); | 681 | send_handler, recv_handler, file, 0); |
661 | if (IS_ERR(agent)) { | 682 | if (IS_ERR(agent)) { |
662 | ret = PTR_ERR(agent); | 683 | ret = PTR_ERR(agent); |
663 | agent = NULL; | 684 | agent = NULL; |
@@ -673,10 +694,11 @@ found: | |||
673 | if (!file->already_used) { | 694 | if (!file->already_used) { |
674 | file->already_used = 1; | 695 | file->already_used = 1; |
675 | if (!file->use_pkey_index) { | 696 | if (!file->use_pkey_index) { |
676 | printk(KERN_WARNING "user_mad: process %s did not enable " | 697 | dev_warn(file->port->dev, |
677 | "P_Key index support.\n", current->comm); | 698 | "process %s did not enable P_Key index support.\n", |
678 | printk(KERN_WARNING "user_mad: Documentation/infiniband/user_mad.txt " | 699 | current->comm); |
679 | "has info on the new ABI.\n"); | 700 | dev_warn(file->port->dev, |
701 | " Documentation/infiniband/user_mad.txt has info on the new ABI.\n"); | ||
680 | } | 702 | } |
681 | } | 703 | } |
682 | 704 | ||
@@ -694,6 +716,119 @@ out: | |||
694 | return ret; | 716 | return ret; |
695 | } | 717 | } |
696 | 718 | ||
719 | static int ib_umad_reg_agent2(struct ib_umad_file *file, void __user *arg) | ||
720 | { | ||
721 | struct ib_user_mad_reg_req2 ureq; | ||
722 | struct ib_mad_reg_req req; | ||
723 | struct ib_mad_agent *agent = NULL; | ||
724 | int agent_id; | ||
725 | int ret; | ||
726 | |||
727 | mutex_lock(&file->port->file_mutex); | ||
728 | mutex_lock(&file->mutex); | ||
729 | |||
730 | if (!file->port->ib_dev) { | ||
731 | dev_notice(file->port->dev, | ||
732 | "ib_umad_reg_agent2: invalid device\n"); | ||
733 | ret = -EPIPE; | ||
734 | goto out; | ||
735 | } | ||
736 | |||
737 | if (copy_from_user(&ureq, arg, sizeof(ureq))) { | ||
738 | ret = -EFAULT; | ||
739 | goto out; | ||
740 | } | ||
741 | |||
742 | if (ureq.qpn != 0 && ureq.qpn != 1) { | ||
743 | dev_notice(file->port->dev, | ||
744 | "ib_umad_reg_agent2: invalid QPN %d specified\n", | ||
745 | ureq.qpn); | ||
746 | ret = -EINVAL; | ||
747 | goto out; | ||
748 | } | ||
749 | |||
750 | if (ureq.flags & ~IB_USER_MAD_REG_FLAGS_CAP) { | ||
751 | dev_notice(file->port->dev, | ||
752 | "ib_umad_reg_agent2 failed: invalid registration flags specified 0x%x; supported 0x%x\n", | ||
753 | ureq.flags, IB_USER_MAD_REG_FLAGS_CAP); | ||
754 | ret = -EINVAL; | ||
755 | |||
756 | if (put_user((u32)IB_USER_MAD_REG_FLAGS_CAP, | ||
757 | (u32 __user *) (arg + offsetof(struct | ||
758 | ib_user_mad_reg_req2, flags)))) | ||
759 | ret = -EFAULT; | ||
760 | |||
761 | goto out; | ||
762 | } | ||
763 | |||
764 | for (agent_id = 0; agent_id < IB_UMAD_MAX_AGENTS; ++agent_id) | ||
765 | if (!__get_agent(file, agent_id)) | ||
766 | goto found; | ||
767 | |||
768 | dev_notice(file->port->dev, | ||
769 | "ib_umad_reg_agent2: Max Agents (%u) reached\n", | ||
770 | IB_UMAD_MAX_AGENTS); | ||
771 | ret = -ENOMEM; | ||
772 | goto out; | ||
773 | |||
774 | found: | ||
775 | if (ureq.mgmt_class) { | ||
776 | memset(&req, 0, sizeof(req)); | ||
777 | req.mgmt_class = ureq.mgmt_class; | ||
778 | req.mgmt_class_version = ureq.mgmt_class_version; | ||
779 | if (ureq.oui & 0xff000000) { | ||
780 | dev_notice(file->port->dev, | ||
781 | "ib_umad_reg_agent2 failed: oui invalid 0x%08x\n", | ||
782 | ureq.oui); | ||
783 | ret = -EINVAL; | ||
784 | goto out; | ||
785 | } | ||
786 | req.oui[2] = ureq.oui & 0x0000ff; | ||
787 | req.oui[1] = (ureq.oui & 0x00ff00) >> 8; | ||
788 | req.oui[0] = (ureq.oui & 0xff0000) >> 16; | ||
789 | memcpy(req.method_mask, ureq.method_mask, | ||
790 | sizeof(req.method_mask)); | ||
791 | } | ||
792 | |||
793 | agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num, | ||
794 | ureq.qpn ? IB_QPT_GSI : IB_QPT_SMI, | ||
795 | ureq.mgmt_class ? &req : NULL, | ||
796 | ureq.rmpp_version, | ||
797 | send_handler, recv_handler, file, | ||
798 | ureq.flags); | ||
799 | if (IS_ERR(agent)) { | ||
800 | ret = PTR_ERR(agent); | ||
801 | agent = NULL; | ||
802 | goto out; | ||
803 | } | ||
804 | |||
805 | if (put_user(agent_id, | ||
806 | (u32 __user *)(arg + | ||
807 | offsetof(struct ib_user_mad_reg_req2, id)))) { | ||
808 | ret = -EFAULT; | ||
809 | goto out; | ||
810 | } | ||
811 | |||
812 | if (!file->already_used) { | ||
813 | file->already_used = 1; | ||
814 | file->use_pkey_index = 1; | ||
815 | } | ||
816 | |||
817 | file->agent[agent_id] = agent; | ||
818 | ret = 0; | ||
819 | |||
820 | out: | ||
821 | mutex_unlock(&file->mutex); | ||
822 | |||
823 | if (ret && agent) | ||
824 | ib_unregister_mad_agent(agent); | ||
825 | |||
826 | mutex_unlock(&file->port->file_mutex); | ||
827 | |||
828 | return ret; | ||
829 | } | ||
830 | |||
831 | |||
697 | static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg) | 832 | static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg) |
698 | { | 833 | { |
699 | struct ib_mad_agent *agent = NULL; | 834 | struct ib_mad_agent *agent = NULL; |
@@ -749,6 +884,8 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd, | |||
749 | return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg); | 884 | return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg); |
750 | case IB_USER_MAD_ENABLE_PKEY: | 885 | case IB_USER_MAD_ENABLE_PKEY: |
751 | return ib_umad_enable_pkey(filp->private_data); | 886 | return ib_umad_enable_pkey(filp->private_data); |
887 | case IB_USER_MAD_REGISTER_AGENT2: | ||
888 | return ib_umad_reg_agent2(filp->private_data, (void __user *) arg); | ||
752 | default: | 889 | default: |
753 | return -ENOIOCTLCMD; | 890 | return -ENOIOCTLCMD; |
754 | } | 891 | } |
@@ -765,6 +902,8 @@ static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd, | |||
765 | return ib_umad_unreg_agent(filp->private_data, compat_ptr(arg)); | 902 | return ib_umad_unreg_agent(filp->private_data, compat_ptr(arg)); |
766 | case IB_USER_MAD_ENABLE_PKEY: | 903 | case IB_USER_MAD_ENABLE_PKEY: |
767 | return ib_umad_enable_pkey(filp->private_data); | 904 | return ib_umad_enable_pkey(filp->private_data); |
905 | case IB_USER_MAD_REGISTER_AGENT2: | ||
906 | return ib_umad_reg_agent2(filp->private_data, compat_ptr(arg)); | ||
768 | default: | 907 | default: |
769 | return -ENOIOCTLCMD; | 908 | return -ENOIOCTLCMD; |
770 | } | 909 | } |
@@ -983,7 +1122,7 @@ static CLASS_ATTR_STRING(abi_version, S_IRUGO, | |||
983 | 1122 | ||
984 | static dev_t overflow_maj; | 1123 | static dev_t overflow_maj; |
985 | static DECLARE_BITMAP(overflow_map, IB_UMAD_MAX_PORTS); | 1124 | static DECLARE_BITMAP(overflow_map, IB_UMAD_MAX_PORTS); |
986 | static int find_overflow_devnum(void) | 1125 | static int find_overflow_devnum(struct ib_device *device) |
987 | { | 1126 | { |
988 | int ret; | 1127 | int ret; |
989 | 1128 | ||
@@ -991,7 +1130,8 @@ static int find_overflow_devnum(void) | |||
991 | ret = alloc_chrdev_region(&overflow_maj, 0, IB_UMAD_MAX_PORTS * 2, | 1130 | ret = alloc_chrdev_region(&overflow_maj, 0, IB_UMAD_MAX_PORTS * 2, |
992 | "infiniband_mad"); | 1131 | "infiniband_mad"); |
993 | if (ret) { | 1132 | if (ret) { |
994 | printk(KERN_ERR "user_mad: couldn't register dynamic device number\n"); | 1133 | dev_err(&device->dev, |
1134 | "couldn't register dynamic device number\n"); | ||
995 | return ret; | 1135 | return ret; |
996 | } | 1136 | } |
997 | } | 1137 | } |
@@ -1014,7 +1154,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, | |||
1014 | devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); | 1154 | devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); |
1015 | if (devnum >= IB_UMAD_MAX_PORTS) { | 1155 | if (devnum >= IB_UMAD_MAX_PORTS) { |
1016 | spin_unlock(&port_lock); | 1156 | spin_unlock(&port_lock); |
1017 | devnum = find_overflow_devnum(); | 1157 | devnum = find_overflow_devnum(device); |
1018 | if (devnum < 0) | 1158 | if (devnum < 0) |
1019 | return -1; | 1159 | return -1; |
1020 | 1160 | ||
@@ -1200,14 +1340,14 @@ static int __init ib_umad_init(void) | |||
1200 | ret = register_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2, | 1340 | ret = register_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2, |
1201 | "infiniband_mad"); | 1341 | "infiniband_mad"); |
1202 | if (ret) { | 1342 | if (ret) { |
1203 | printk(KERN_ERR "user_mad: couldn't register device number\n"); | 1343 | pr_err("couldn't register device number\n"); |
1204 | goto out; | 1344 | goto out; |
1205 | } | 1345 | } |
1206 | 1346 | ||
1207 | umad_class = class_create(THIS_MODULE, "infiniband_mad"); | 1347 | umad_class = class_create(THIS_MODULE, "infiniband_mad"); |
1208 | if (IS_ERR(umad_class)) { | 1348 | if (IS_ERR(umad_class)) { |
1209 | ret = PTR_ERR(umad_class); | 1349 | ret = PTR_ERR(umad_class); |
1210 | printk(KERN_ERR "user_mad: couldn't create class infiniband_mad\n"); | 1350 | pr_err("couldn't create class infiniband_mad\n"); |
1211 | goto out_chrdev; | 1351 | goto out_chrdev; |
1212 | } | 1352 | } |
1213 | 1353 | ||
@@ -1215,13 +1355,13 @@ static int __init ib_umad_init(void) | |||
1215 | 1355 | ||
1216 | ret = class_create_file(umad_class, &class_attr_abi_version.attr); | 1356 | ret = class_create_file(umad_class, &class_attr_abi_version.attr); |
1217 | if (ret) { | 1357 | if (ret) { |
1218 | printk(KERN_ERR "user_mad: couldn't create abi_version attribute\n"); | 1358 | pr_err("couldn't create abi_version attribute\n"); |
1219 | goto out_class; | 1359 | goto out_class; |
1220 | } | 1360 | } |
1221 | 1361 | ||
1222 | ret = ib_register_client(&umad_client); | 1362 | ret = ib_register_client(&umad_client); |
1223 | if (ret) { | 1363 | if (ret) { |
1224 | printk(KERN_ERR "user_mad: couldn't register ib_umad client\n"); | 1364 | pr_err("couldn't register ib_umad client\n"); |
1225 | goto out_class; | 1365 | goto out_class; |
1226 | } | 1366 | } |
1227 | 1367 | ||