diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/net/qeth_core.h | 22 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 71 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_sys.c | 65 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l2.h | 7 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 412 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3.h | 4 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 88 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_sys.c | 64 |
8 files changed, 338 insertions, 395 deletions
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 2c14012ca35d..f321eabefbe4 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -195,8 +195,8 @@ struct qeth_vnicc_info { #define QETH_IN_BUF_SIZE_DEFAULT 65536 #define QETH_IN_BUF_COUNT_DEFAULT 64 #define QETH_IN_BUF_COUNT_HSDEFAULT 128 -#define QETH_IN_BUF_COUNT_MIN 8 -#define QETH_IN_BUF_COUNT_MAX 128 +#define QETH_IN_BUF_COUNT_MIN 8U +#define QETH_IN_BUF_COUNT_MAX 128U #define QETH_MAX_BUFFER_ELEMENTS(card) ((card)->qdio.in_buf_size >> 12) #define QETH_IN_BUF_REQUEUE_THRESHOLD(card) \ ((card)->qdio.in_buf_pool.buf_count / 2) @@ -753,7 +753,7 @@ struct qeth_discipline { const struct device_type *devtype; int (*setup) (struct ccwgroup_device *); void (*remove) (struct ccwgroup_device *); - int (*set_online)(struct qeth_card *card); + int (*set_online)(struct qeth_card *card, bool carrier_ok); void (*set_offline)(struct qeth_card *card); int (*do_ioctl)(struct net_device *dev, struct ifreq *rq, int cmd); int (*control_event_handler)(struct qeth_card *card, @@ -814,12 +814,16 @@ struct qeth_card { struct workqueue_struct *event_wq; struct workqueue_struct *cmd_wq; wait_queue_head_t wait_q; + + struct mutex ip_lock; + /* protected by ip_lock: */ DECLARE_HASHTABLE(ip_htable, 4); + struct qeth_ipato ipato; + DECLARE_HASHTABLE(local_addrs4, 4); DECLARE_HASHTABLE(local_addrs6, 4); spinlock_t local_addrs4_lock; spinlock_t local_addrs6_lock; - struct mutex ip_lock; DECLARE_HASHTABLE(rx_mode_addrs, 4); struct work_struct rx_mode_work; struct work_struct kernel_thread_starter; @@ -827,7 +831,6 @@ struct qeth_card { unsigned long thread_start_mask; unsigned long thread_allowed_mask; unsigned long thread_running_mask; - struct qeth_ipato ipato; struct list_head cmd_waiter_list; /* QDIO buffer handling */ struct qeth_qdio_info qdio; @@ -1034,11 +1037,8 @@ struct net_device *qeth_clone_netdev(struct net_device *orig); struct qeth_card *qeth_get_card_by_busid(char *bus_id); void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int); int qeth_threads_running(struct qeth_card *, unsigned long); -int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok); -int qeth_stop_channel(struct qeth_channel *channel); int qeth_set_offline(struct qeth_card *card, bool resetting); -void qeth_print_status_message(struct qeth_card *); int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *, int (*reply_cb) (struct qeth_card *, struct qeth_reply *, unsigned long), @@ -1062,12 +1062,7 @@ void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason); void qeth_put_cmd(struct qeth_cmd_buffer *iob); int qeth_schedule_recovery(struct qeth_card *card); -void qeth_flush_local_addrs(struct qeth_card *card); int qeth_poll(struct napi_struct *napi, int budget); -void qeth_clear_ipacmd_list(struct qeth_card *); -int qeth_qdio_clear_card(struct qeth_card *, int); -void qeth_clear_working_pool_list(struct qeth_card *); -void qeth_drain_output_queues(struct qeth_card *card); void qeth_setadp_promisc_mode(struct qeth_card *card, bool enable); int qeth_setadpparms_change_macaddr(struct qeth_card *); void qeth_tx_timeout(struct net_device *, unsigned int txqueue); @@ -1091,7 +1086,6 @@ int qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...); int qeth_configure_cq(struct qeth_card *, enum qeth_cq); int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action); -void qeth_trace_features(struct qeth_card *); int qeth_setassparms_cb(struct qeth_card *, struct qeth_reply *, unsigned long); int qeth_setup_netdev(struct qeth_card *card); int qeth_set_features(struct net_device *, netdev_features_t); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 7cd0cbf8a4f0..fc2c3db9259f 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -201,7 +201,7 @@ int qeth_threads_running(struct qeth_card *card, unsigned long threads) } EXPORT_SYMBOL_GPL(qeth_threads_running); -void qeth_clear_working_pool_list(struct qeth_card *card) +static void qeth_clear_working_pool_list(struct qeth_card *card) { struct qeth_buffer_pool_entry *pool_entry, *tmp; struct qeth_qdio_q *queue = card->qdio.in_q; @@ -216,7 +216,6 @@ void qeth_clear_working_pool_list(struct qeth_card *card) for (i = 0; i < ARRAY_SIZE(queue->bufs); i++) queue->bufs[i].pool_entry = NULL; } -EXPORT_SYMBOL_GPL(qeth_clear_working_pool_list); static void qeth_free_pool_entry(struct qeth_buffer_pool_entry *entry) { @@ -658,12 +657,11 @@ static void qeth_flush_local_addrs6(struct qeth_card *card) spin_unlock_irq(&card->local_addrs6_lock); } -void qeth_flush_local_addrs(struct qeth_card *card) +static void qeth_flush_local_addrs(struct qeth_card *card) { qeth_flush_local_addrs4(card); qeth_flush_local_addrs6(card); } -EXPORT_SYMBOL_GPL(qeth_flush_local_addrs); static void qeth_add_local_addrs4(struct qeth_card *card, struct qeth_ipacmd_local_addrs4 *cmd) @@ -965,7 +963,7 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, } } -void qeth_clear_ipacmd_list(struct qeth_card *card) +static void qeth_clear_ipacmd_list(struct qeth_card *card) { struct qeth_cmd_buffer *iob; unsigned long flags; @@ -977,7 +975,6 @@ void qeth_clear_ipacmd_list(struct qeth_card *card) qeth_notify_cmd(iob, -ECANCELED); spin_unlock_irqrestore(&card->lock, flags); } -EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list); static int qeth_check_idx_response(struct qeth_card *card, unsigned char *buffer) @@ -1502,7 +1499,7 @@ static void qeth_drain_output_queue(struct qeth_qdio_out_q *q, bool free) } } -void qeth_drain_output_queues(struct qeth_card *card) +static void qeth_drain_output_queues(struct qeth_card *card) { int i; @@ -1513,7 +1510,6 @@ void qeth_drain_output_queues(struct qeth_card *card) qeth_drain_output_queue(card->qdio.out_qs[i], false); } } -EXPORT_SYMBOL_GPL(qeth_drain_output_queues); static int qeth_osa_set_output_queues(struct qeth_card *card, bool single) { @@ -1754,7 +1750,7 @@ static int qeth_halt_channel(struct qeth_card *card, return 0; } -int qeth_stop_channel(struct qeth_channel *channel) +static int qeth_stop_channel(struct qeth_channel *channel) { struct ccw_device *cdev = channel->ccwdev; int rc; @@ -1772,7 +1768,6 @@ int qeth_stop_channel(struct qeth_channel *channel) return rc; } -EXPORT_SYMBOL_GPL(qeth_stop_channel); static int qeth_start_channel(struct qeth_channel *channel) { @@ -1842,7 +1837,7 @@ static int qeth_clear_halt_card(struct qeth_card *card, int halt) return qeth_clear_channels(card); } -int qeth_qdio_clear_card(struct qeth_card *card, int use_halt) +static int qeth_qdio_clear_card(struct qeth_card *card, int use_halt) { int rc = 0; @@ -1870,7 +1865,6 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt) QETH_CARD_TEXT_(card, 3, "2err%d", rc); return rc; } -EXPORT_SYMBOL_GPL(qeth_qdio_clear_card); static enum qeth_discipline_id qeth_vm_detect_layer(struct qeth_card *card) { @@ -2867,7 +2861,7 @@ static int qeth_mpc_initialize(struct qeth_card *card) return 0; } -void qeth_print_status_message(struct qeth_card *card) +static void qeth_print_status_message(struct qeth_card *card) { switch (card->info.type) { case QETH_CARD_TYPE_OSD: @@ -2908,7 +2902,6 @@ void qeth_print_status_message(struct qeth_card *card) (card->info.mcl_level[0]) ? ")" : "", qeth_get_cardname_short(card)); } -EXPORT_SYMBOL_GPL(qeth_print_status_message); static void qeth_initialize_working_pool_list(struct qeth_card *card) { @@ -5124,7 +5117,7 @@ static void qeth_core_free_card(struct qeth_card *card) kfree(card); } -void qeth_trace_features(struct qeth_card *card) +static void qeth_trace_features(struct qeth_card *card) { QETH_CARD_TEXT(card, 2, "features"); QETH_CARD_HEX(card, 2, &card->options.ipa4, sizeof(card->options.ipa4)); @@ -5133,7 +5126,6 @@ void qeth_trace_features(struct qeth_card *card) QETH_CARD_HEX(card, 2, &card->info.diagass_support, sizeof(card->info.diagass_support)); } -EXPORT_SYMBOL_GPL(qeth_trace_features); static struct ccw_device_id qeth_ids[] = { {CCW_DEVICE_DEVTYPE(0x1731, 0x01, 0x1732, 0x01), @@ -5164,7 +5156,7 @@ static struct ccw_driver qeth_ccw_driver = { .remove = ccwgroup_remove_ccwdev, }; -int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok) +static int qeth_hardsetup_card(struct qeth_card *card, bool *carrier_ok) { int retries = 3; int rc; @@ -5278,6 +5270,8 @@ retriable: QETH_CARD_TEXT_(card, 2, "8err%d", rc); } + qeth_trace_features(card); + if (!qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP) || (card->info.hwtrap && qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM))) card->info.hwtrap = 0; @@ -5303,21 +5297,49 @@ out: CARD_DEVID(card), rc); return rc; } -EXPORT_SYMBOL_GPL(qeth_core_hardsetup_card); static int qeth_set_online(struct qeth_card *card) { + bool carrier_ok; int rc; mutex_lock(&card->discipline_mutex); mutex_lock(&card->conf_mutex); QETH_CARD_TEXT(card, 2, "setonlin"); - rc = card->discipline->set_online(card); + rc = qeth_hardsetup_card(card, &carrier_ok); + if (rc) { + QETH_CARD_TEXT_(card, 2, "2err%04x", rc); + rc = -ENODEV; + goto err_hardsetup; + } + + qeth_print_status_message(card); + + rc = card->discipline->set_online(card, carrier_ok); + if (rc) + goto err_online; + + /* let user_space know that device is online */ + kobject_uevent(&card->gdev->dev.kobj, KOBJ_CHANGE); mutex_unlock(&card->conf_mutex); mutex_unlock(&card->discipline_mutex); + return 0; +err_online: +err_hardsetup: + qeth_qdio_clear_card(card, 0); + qeth_clear_working_pool_list(card); + qeth_flush_local_addrs(card); + + qeth_stop_channel(&card->data); + qeth_stop_channel(&card->write); + qeth_stop_channel(&card->read); + qdio_free(CARD_DDEV(card)); + + mutex_unlock(&card->conf_mutex); + mutex_unlock(&card->discipline_mutex); return rc; } @@ -5334,6 +5356,9 @@ int qeth_set_offline(struct qeth_card *card, bool resetting) card->info.hwtrap = 1; } + /* cancel any stalled cmd that might block the rtnl: */ + qeth_clear_ipacmd_list(card); + rtnl_lock(); card->info.open_when_online = card->dev->flags & IFF_UP; dev_close(card->dev); @@ -5341,8 +5366,16 @@ int qeth_set_offline(struct qeth_card *card, bool resetting) netif_carrier_off(card->dev); rtnl_unlock(); + cancel_work_sync(&card->rx_mode_work); + card->discipline->set_offline(card); + qeth_qdio_clear_card(card, 0); + qeth_drain_output_queues(card); + qeth_clear_working_pool_list(card); + qeth_flush_local_addrs(card); + card->info.promisc_mode = 0; + rc = qeth_stop_channel(&card->data); rc2 = qeth_stop_channel(&card->write); rc3 = qeth_stop_channel(&card->read); diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 8def82336f53..74c70364edc1 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -103,21 +103,21 @@ static ssize_t qeth_dev_portno_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev_get_drvdata(dev); - char *tmp; unsigned int portno, limit; int rc = 0; + rc = kstrtouint(buf, 16, &portno); + if (rc) + return rc; + if (portno > QETH_MAX_PORTNO) + return -EINVAL; + mutex_lock(&card->conf_mutex); if (card->state != CARD_STATE_DOWN) { rc = -EPERM; goto out; } - portno = simple_strtoul(buf, &tmp, 16); - if (portno > QETH_MAX_PORTNO) { - rc = -EINVAL; - goto out; - } limit = (card->ssqd.pcnt ? card->ssqd.pcnt - 1 : card->ssqd.pcnt); if (portno > limit) { rc = -EINVAL; @@ -248,19 +248,19 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev, { struct qeth_card *card = dev_get_drvdata(dev); unsigned int cnt; - char *tmp; int rc = 0; + rc = kstrtouint(buf, 10, &cnt); + if (rc) + return rc; + mutex_lock(&card->conf_mutex); if (card->state != CARD_STATE_DOWN) { rc = -EPERM; goto out; } - cnt = simple_strtoul(buf, &tmp, 10); - cnt = (cnt < QETH_IN_BUF_COUNT_MIN) ? QETH_IN_BUF_COUNT_MIN : - ((cnt > QETH_IN_BUF_COUNT_MAX) ? QETH_IN_BUF_COUNT_MAX : cnt); - + cnt = clamp(cnt, QETH_IN_BUF_COUNT_MIN, QETH_IN_BUF_COUNT_MAX); rc = qeth_resize_buffer_pool(card, cnt); out: @@ -341,18 +341,15 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, { struct qeth_card *card = dev_get_drvdata(dev); struct net_device *ndev; - char *tmp; - int i, rc = 0; enum qeth_discipline_id newdis; + unsigned int input; + int rc; - mutex_lock(&card->discipline_mutex); - if (card->state != CARD_STATE_DOWN) { - rc = -EPERM; - goto out; - } + rc = kstrtouint(buf, 16, &input); + if (rc) + return rc; - i = simple_strtoul(buf, &tmp, 16); - switch (i) { + switch (input) { case 0: newdis = QETH_DISCIPLINE_LAYER3; break; @@ -360,7 +357,12 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, newdis = QETH_DISCIPLINE_LAYER2; break; default: - rc = -EINVAL; + return -EINVAL; + } + + mutex_lock(&card->discipline_mutex); + if (card->state != CARD_STATE_DOWN) { + rc = -EPERM; goto out; } @@ -551,20 +553,21 @@ static DEVICE_ATTR(hw_trap, 0644, qeth_hw_trap_show, static ssize_t qeth_dev_blkt_store(struct qeth_card *card, const char *buf, size_t count, int *value, int max_value) { - char *tmp; - int i, rc = 0; + unsigned int input; + int rc; + + rc = kstrtouint(buf, 10, &input); + if (rc) + return rc; + + if (input > max_value) + return -EINVAL; mutex_lock(&card->conf_mutex); - if (card->state != CARD_STATE_DOWN) { + if (card->state != CARD_STATE_DOWN) rc = -EPERM; - goto out; - } - i = simple_strtoul(buf, &tmp, 10); - if (i <= max_value) - *value = i; else - rc = -EINVAL; -out: + *value = input; mutex_unlock(&card->conf_mutex); return rc ? rc : count; } diff --git a/drivers/s390/net/qeth_l2.h b/drivers/s390/net/qeth_l2.h index cc95675c8bc4..296d73d84326 100644 --- a/drivers/s390/net/qeth_l2.h +++ b/drivers/s390/net/qeth_l2.h @@ -31,4 +31,11 @@ struct qeth_mac { struct hlist_node hnode; }; +static inline bool qeth_bridgeport_is_in_use(struct qeth_card *card) +{ + return card->options.sbp.role || + card->options.sbp.reflect_promisc || + card->options.sbp.hostnotification; +} + #endif /* __QETH_L2_H__ */ diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index e12ac32b8b47..1852d0a3c10a 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -28,17 +28,6 @@ #include "qeth_core.h" #include "qeth_l2.h" -static void qeth_bridgeport_query_support(struct qeth_card *card); -static void qeth_bridge_state_change(struct qeth_card *card, - struct qeth_ipa_cmd *cmd); -static void qeth_addr_change_event(struct qeth_card *card, - struct qeth_ipa_cmd *cmd); -static bool qeth_bridgeport_is_in_use(struct qeth_card *card); -static void qeth_l2_vnicc_set_defaults(struct qeth_card *card); -static void qeth_l2_vnicc_init(struct qeth_card *card); -static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc, - u32 *timeout); - static int qeth_l2_setdelmac_makerc(struct qeth_card *card, u16 retcode) { int rc; @@ -304,36 +293,6 @@ static void qeth_l2_dev2br_fdb_flush(struct qeth_card *card) card->dev, &info.info, NULL); } -static void qeth_l2_stop_card(struct qeth_card *card) -{ - struct qeth_priv *priv = netdev_priv(card->dev); - - QETH_CARD_TEXT(card, 2, "stopcard"); - - qeth_set_allowed_threads(card, 0, 1); - - cancel_work_sync(&card->rx_mode_work); - qeth_l2_drain_rx_mode_cache(card); - - if (card->state == CARD_STATE_SOFTSETUP) { - qeth_clear_ipacmd_list(card); - card->state = CARD_STATE_DOWN; - } - - qeth_qdio_clear_card(card, 0); - qeth_drain_output_queues(card); - qeth_clear_working_pool_list(card); - qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE); - qeth_flush_local_addrs(card); - card->info.promisc_mode = 0; - - if (priv->brport_features & BR_LEARNING_SYNC) { - rtnl_lock(); - qeth_l2_dev2br_fdb_flush(card); - rtnl_unlock(); - } -} - static int qeth_l2_request_initial_mac(struct qeth_card *card) { int rc = 0; @@ -617,49 +576,6 @@ static u16 qeth_l2_select_queue(struct net_device *dev, struct sk_buff *skb, qeth_get_priority_queue(card, skb); } -static const struct device_type qeth_l2_devtype = { - .name = "qeth_layer2", - .groups = qeth_l2_attr_groups, -}; - -static int qeth_l2_probe_device(struct ccwgroup_device *gdev) -{ - struct qeth_card *card = dev_get_drvdata(&gdev->dev); - int rc; - - if (IS_OSN(card)) - dev_notice(&gdev->dev, "OSN support will be dropped in 2021\n"); - - qeth_l2_vnicc_set_defaults(card); - mutex_init(&card->sbp_lock); - - if (gdev->dev.type == &qeth_generic_devtype) { - rc = qeth_l2_create_device_attributes(&gdev->dev); - if (rc) - return rc; - } - - INIT_WORK(&card->rx_mode_work, qeth_l2_rx_mode_work); - return 0; -} - -static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) -{ - struct qeth_card *card = dev_get_drvdata(&cgdev->dev); - - if (cgdev->dev.type == &qeth_generic_devtype) - qeth_l2_remove_device_attributes(&cgdev->dev); - qeth_set_allowed_threads(card, 0, 1); - wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); - - if (cgdev->state == CCWGROUP_ONLINE) - qeth_set_offline(card, false); - - cancel_work_sync(&card->close_dev_work); - if (card->dev->reg_state == NETREG_REGISTERED) - unregister_netdev(card->dev); -} - static void qeth_l2_set_rx_mode(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; @@ -1140,134 +1056,6 @@ static void qeth_l2_enable_brport_features(struct qeth_card *card) } } -static int qeth_l2_set_online(struct qeth_card *card) -{ - struct ccwgroup_device *gdev = card->gdev; - struct net_device *dev = card->dev; - int rc = 0; - bool carrier_ok; - - rc = qeth_core_hardsetup_card(card, &carrier_ok); - if (rc) { - QETH_CARD_TEXT_(card, 2, "2err%04x", rc); - rc = -ENODEV; - goto out_remove; - } - - /* query before bridgeport_notification may be enabled */ - qeth_l2_detect_dev2br_support(card); - - mutex_lock(&card->sbp_lock); - qeth_bridgeport_query_support(card); - if (card->options.sbp.supported_funcs) { - qeth_l2_setup_bridgeport_attrs(card); - dev_info(&card->gdev->dev, - "The device represents a Bridge Capable Port\n"); - } - mutex_unlock(&card->sbp_lock); - - qeth_l2_register_dev_addr(card); - - /* for the rx_bcast characteristic, init VNICC after setmac */ - qeth_l2_vnicc_init(card); - - qeth_trace_features(card); - qeth_l2_trace_features(card); - - qeth_print_status_message(card); - - /* softsetup */ - QETH_CARD_TEXT(card, 2, "softsetp"); - - card->state = CARD_STATE_SOFTSETUP; - - qeth_set_allowed_threads(card, 0xffffffff, 0); - - if (dev->reg_state != NETREG_REGISTERED) { - rc = qeth_l2_setup_netdev(card); - if (rc) - goto out_remove; - - if (carrier_ok) - netif_carrier_on(dev); - } else { - rtnl_lock(); - if (carrier_ok) - netif_carrier_on(dev); - else - netif_carrier_off(dev); - - netif_device_attach(dev); - qeth_enable_hw_features(dev); - qeth_l2_enable_brport_features(card); - - if (card->info.open_when_online) { - card->info.open_when_online = 0; - dev_open(dev, NULL); - } - rtnl_unlock(); - } - /* let user_space know that device is online */ - kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE); - return 0; - -out_remove: - qeth_l2_stop_card(card); - qeth_stop_channel(&card->data); - qeth_stop_channel(&card->write); - qeth_stop_channel(&card->read); - qdio_free(CARD_DDEV(card)); - return rc; -} - -static void qeth_l2_set_offline(struct qeth_card *card) -{ - qeth_l2_stop_card(card); -} - -static int __init qeth_l2_init(void) -{ - pr_info("register layer 2 discipline\n"); - return 0; -} - -static void __exit qeth_l2_exit(void) -{ - pr_info("unregister layer 2 discipline\n"); -} - -/* Returns zero if the command is successfully "consumed" */ -static int qeth_l2_control_event(struct qeth_card *card, - struct qeth_ipa_cmd *cmd) -{ - switch (cmd->hdr.command) { - case IPA_CMD_SETBRIDGEPORT_OSA: - case IPA_CMD_SETBRIDGEPORT_IQD: - if (cmd->data.sbp.hdr.command_code == - IPA_SBP_BRIDGE_PORT_STATE_CHANGE) { - qeth_bridge_state_change(card, cmd); - return 0; - } else - return 1; - case IPA_CMD_ADDRESS_CHANGE_NOTIF: - qeth_addr_change_event(card, cmd); - return 0; - default: - return 1; - } -} - -struct qeth_discipline qeth_l2_discipline = { - .devtype = &qeth_l2_devtype, - .setup = qeth_l2_probe_device, - .remove = qeth_l2_remove_device, - .set_online = qeth_l2_set_online, - .set_offline = qeth_l2_set_offline, - .do_ioctl = NULL, - .control_event_handler = qeth_l2_control_event, -}; -EXPORT_SYMBOL_GPL(qeth_l2_discipline); - #ifdef CONFIG_QETH_OSN static void qeth_osn_assist_cb(struct qeth_card *card, struct qeth_cmd_buffer *iob, @@ -1987,12 +1775,6 @@ int qeth_bridgeport_an_set(struct qeth_card *card, int enable) return rc; } -static bool qeth_bridgeport_is_in_use(struct qeth_card *card) -{ - return (card->options.sbp.role || card->options.sbp.reflect_promisc || - card->options.sbp.hostnotification); -} - /* VNIC Characteristics support */ /* handle VNICC IPA command return codes; convert to error codes */ @@ -2138,6 +1920,19 @@ static int qeth_l2_vnicc_getset_timeout(struct qeth_card *card, u32 vnicc, return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, timeout); } +/* recover user timeout setting */ +static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc, + u32 *timeout) +{ + if (card->options.vnicc.sup_chars & vnicc && + card->options.vnicc.getset_timeout_sup & vnicc && + !qeth_l2_vnicc_getset_timeout(card, vnicc, IPA_VNICC_SET_TIMEOUT, + timeout)) + return false; + *timeout = QETH_VNICC_DEFAULT_TIMEOUT; + return true; +} + /* set current VNICC flag state; called from sysfs store function */ int qeth_l2_vnicc_set_state(struct qeth_card *card, u32 vnicc, bool state) { @@ -2308,19 +2103,6 @@ bool qeth_bridgeport_allowed(struct qeth_card *card) !(priv->brport_features & BR_LEARNING_SYNC)); } -/* recover user timeout setting */ -static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc, - u32 *timeout) -{ - if (card->options.vnicc.sup_chars & vnicc && - card->options.vnicc.getset_timeout_sup & vnicc && - !qeth_l2_vnicc_getset_timeout(card, vnicc, IPA_VNICC_SET_TIMEOUT, - timeout)) - return false; - *timeout = QETH_VNICC_DEFAULT_TIMEOUT; - return true; -} - /* recover user characteristic setting */ static bool qeth_l2_vnicc_recover_char(struct qeth_card *card, u32 vnicc, bool enable) @@ -2409,6 +2191,174 @@ static void qeth_l2_vnicc_set_defaults(struct qeth_card *card) card->options.vnicc.wanted_chars = QETH_VNICC_DEFAULT; } +static const struct device_type qeth_l2_devtype = { + .name = "qeth_layer2", + .groups = qeth_l2_attr_groups, +}; + +static int qeth_l2_probe_device(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + int rc; + + if (IS_OSN(card)) + dev_notice(&gdev->dev, "OSN support will be dropped in 2021\n"); + + qeth_l2_vnicc_set_defaults(card); + mutex_init(&card->sbp_lock); + + if (gdev->dev.type == &qeth_generic_devtype) { + rc = qeth_l2_create_device_attributes(&gdev->dev); + if (rc) + return rc; + } + + INIT_WORK(&card->rx_mode_work, qeth_l2_rx_mode_work); + return 0; +} + +static void qeth_l2_remove_device(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + + if (gdev->dev.type == &qeth_generic_devtype) + qeth_l2_remove_device_attributes(&gdev->dev); + qeth_set_allowed_threads(card, 0, 1); + wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); + + if (gdev->state == CCWGROUP_ONLINE) + qeth_set_offline(card, false); + + cancel_work_sync(&card->close_dev_work); + if (card->dev->reg_state == NETREG_REGISTERED) + unregister_netdev(card->dev); +} + +static int qeth_l2_set_online(struct qeth_card *card, bool carrier_ok) +{ + struct net_device *dev = card->dev; + int rc = 0; + + /* query before bridgeport_notification may be enabled */ + qeth_l2_detect_dev2br_support(card); + + mutex_lock(&card->sbp_lock); + qeth_bridgeport_query_support(card); + if (card->options.sbp.supported_funcs) { + qeth_l2_setup_bridgeport_attrs(card); + dev_info(&card->gdev->dev, + "The device represents a Bridge Capable Port\n"); + } + mutex_unlock(&card->sbp_lock); + + qeth_l2_register_dev_addr(card); + + /* for the rx_bcast characteristic, init VNICC after setmac */ + qeth_l2_vnicc_init(card); + + qeth_l2_trace_features(card); + + /* softsetup */ + QETH_CARD_TEXT(card, 2, "softsetp"); + + card->state = CARD_STATE_SOFTSETUP; + + qeth_set_allowed_threads(card, 0xffffffff, 0); + + if (dev->reg_state != NETREG_REGISTERED) { + rc = qeth_l2_setup_netdev(card); + if (rc) + goto err_setup; + + if (carrier_ok) + netif_carrier_on(dev); + } else { + rtnl_lock(); + if (carrier_ok) + netif_carrier_on(dev); + else + netif_carrier_off(dev); + + netif_device_attach(dev); + qeth_enable_hw_features(dev); + qeth_l2_enable_brport_features(card); + + if (card->info.open_when_online) { + card->info.open_when_online = 0; + dev_open(dev, NULL); + } + rtnl_unlock(); + } + return 0; + +err_setup: + qeth_set_allowed_threads(card, 0, 1); + card->state = CARD_STATE_DOWN; + return rc; +} + +static void qeth_l2_set_offline(struct qeth_card *card) +{ + struct qeth_priv *priv = netdev_priv(card->dev); + + qeth_set_allowed_threads(card, 0, 1); + qeth_l2_drain_rx_mode_cache(card); + + if (card->state == CARD_STATE_SOFTSETUP) + card->state = CARD_STATE_DOWN; + + qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE); + if (priv->brport_features & BR_LEARNING_SYNC) { + rtnl_lock(); + qeth_l2_dev2br_fdb_flush(card); + rtnl_unlock(); + } +} + +/* Returns zero if the command is successfully "consumed" */ +static int qeth_l2_control_event(struct qeth_card *card, + struct qeth_ipa_cmd *cmd) +{ + switch (cmd->hdr.command) { + case IPA_CMD_SETBRIDGEPORT_OSA: + case IPA_CMD_SETBRIDGEPORT_IQD: + if (cmd->data.sbp.hdr.command_code == + IPA_SBP_BRIDGE_PORT_STATE_CHANGE) { + qeth_bridge_state_change(card, cmd); + return 0; + } + + return 1; + case IPA_CMD_ADDRESS_CHANGE_NOTIF: + qeth_addr_change_event(card, cmd); + return 0; + default: + return 1; + } +} + +struct qeth_discipline qeth_l2_discipline = { + .devtype = &qeth_l2_devtype, + .setup = qeth_l2_probe_device, + .remove = qeth_l2_remove_device, + .set_online = qeth_l2_set_online, + .set_offline = qeth_l2_set_offline, + .do_ioctl = NULL, + .control_event_handler = qeth_l2_control_event, +}; +EXPORT_SYMBOL_GPL(qeth_l2_discipline); + +static int __init qeth_l2_init(void) +{ + pr_info("register layer 2 discipline\n"); + return 0; +} + +static void __exit qeth_l2_exit(void) +{ + pr_info("unregister layer 2 discipline\n"); +} + module_init(qeth_l2_init); module_exit(qeth_l2_exit); MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>"); diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index 6ccfe2121095..acd130cfbab3 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h @@ -96,7 +96,7 @@ struct qeth_ipato_entry { struct list_head entry; enum qeth_prot_versions proto; char addr[16]; - int mask_bits; + unsigned int mask_bits; }; extern const struct attribute_group *qeth_l3_attr_groups[]; @@ -110,7 +110,7 @@ int qeth_l3_setrouting_v6(struct qeth_card *); int qeth_l3_add_ipato_entry(struct qeth_card *, struct qeth_ipato_entry *); int qeth_l3_del_ipato_entry(struct qeth_card *card, enum qeth_prot_versions proto, u8 *addr, - int mask_bits); + unsigned int mask_bits); void qeth_l3_update_ipato(struct qeth_card *card); int qeth_l3_modify_hsuid(struct qeth_card *card, bool add); int qeth_l3_modify_rxip_vipa(struct qeth_card *card, bool add, const u8 *ip, diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 33fdad1a6887..a6f8878b55c6 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -105,11 +105,9 @@ static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card, (ipatoe->proto == QETH_PROT_IPV4) ? 4 : 16); if (addr->proto == QETH_PROT_IPV4) - rc = !memcmp(addr_bits, ipatoe_bits, - min(32, ipatoe->mask_bits)); + rc = !memcmp(addr_bits, ipatoe_bits, ipatoe->mask_bits); else - rc = !memcmp(addr_bits, ipatoe_bits, - min(128, ipatoe->mask_bits)); + rc = !memcmp(addr_bits, ipatoe_bits, ipatoe->mask_bits); if (rc) break; } @@ -536,7 +534,6 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card, QETH_CARD_TEXT(card, 2, "addipato"); - mutex_lock(&card->conf_mutex); mutex_lock(&card->ip_lock); list_for_each_entry(ipatoe, &card->ipato.entries, entry) { @@ -556,21 +553,19 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card, } mutex_unlock(&card->ip_lock); - mutex_unlock(&card->conf_mutex); return rc; } int qeth_l3_del_ipato_entry(struct qeth_card *card, enum qeth_prot_versions proto, u8 *addr, - int mask_bits) + unsigned int mask_bits) { struct qeth_ipato_entry *ipatoe, *tmp; int rc = -ENOENT; QETH_CARD_TEXT(card, 2, "delipato"); - mutex_lock(&card->conf_mutex); mutex_lock(&card->ip_lock); list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry) { @@ -587,7 +582,6 @@ int qeth_l3_del_ipato_entry(struct qeth_card *card, } mutex_unlock(&card->ip_lock); - mutex_unlock(&card->conf_mutex); return rc; } @@ -597,7 +591,6 @@ int qeth_l3_modify_rxip_vipa(struct qeth_card *card, bool add, const u8 *ip, enum qeth_prot_versions proto) { struct qeth_ipaddr addr; - int rc; qeth_l3_init_ipaddr(&addr, type, proto); if (proto == QETH_PROT_IPV4) @@ -605,11 +598,7 @@ int qeth_l3_modify_rxip_vipa(struct qeth_card *card, bool add, const u8 *ip, else memcpy(&addr.u.a6.addr, ip, 16); - mutex_lock(&card->conf_mutex); - rc = qeth_l3_modify_ip(card, &addr, add); - mutex_unlock(&card->conf_mutex); - - return rc; + return qeth_l3_modify_ip(card, &addr, add); } int qeth_l3_modify_hsuid(struct qeth_card *card, bool add) @@ -1153,33 +1142,6 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev, return 0; } -static void qeth_l3_stop_card(struct qeth_card *card) -{ - QETH_CARD_TEXT(card, 2, "stopcard"); - - qeth_set_allowed_threads(card, 0, 1); - - cancel_work_sync(&card->rx_mode_work); - qeth_l3_drain_rx_mode_cache(card); - - if (card->options.sniffer && - (card->info.promisc_mode == SET_PROMISC_MODE_ON)) - qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE); - - if (card->state == CARD_STATE_SOFTSETUP) { - qeth_l3_clear_ip_htable(card, 1); - qeth_clear_ipacmd_list(card); - card->state = CARD_STATE_DOWN; - } - - qeth_qdio_clear_card(card, 0); - qeth_drain_output_queues(card); - qeth_clear_working_pool_list(card); - flush_workqueue(card->event_wq); - qeth_flush_local_addrs(card); - card->info.promisc_mode = 0; -} - static void qeth_l3_set_promisc_mode(struct qeth_card *card) { bool enable = card->dev->flags & IFF_PROMISC; @@ -1235,7 +1197,6 @@ static void qeth_l3_rx_mode_work(struct work_struct *work) kfree(addr); break; } - addr->ref_counter = 1; fallthrough; default: /* for next call to set_rx_mode(): */ @@ -2025,21 +1986,10 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) qeth_l3_clear_ipato_list(card); } -static int qeth_l3_set_online(struct qeth_card *card) +static int qeth_l3_set_online(struct qeth_card *card, bool carrier_ok) { - struct ccwgroup_device *gdev = card->gdev; struct net_device *dev = card->dev; int rc = 0; - bool carrier_ok; - - rc = qeth_core_hardsetup_card(card, &carrier_ok); - if (rc) { - QETH_CARD_TEXT_(card, 2, "2err%04x", rc); - rc = -ENODEV; - goto out_remove; - } - - qeth_print_status_message(card); /* softsetup */ QETH_CARD_TEXT(card, 2, "softsetp"); @@ -2066,7 +2016,7 @@ static int qeth_l3_set_online(struct qeth_card *card) if (dev->reg_state != NETREG_REGISTERED) { rc = qeth_l3_setup_netdev(card); if (rc) - goto out_remove; + goto err_setup; if (carrier_ok) netif_carrier_on(dev); @@ -2086,22 +2036,28 @@ static int qeth_l3_set_online(struct qeth_card *card) } rtnl_unlock(); } - qeth_trace_features(card); - /* let user_space know that device is online */ - kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE); return 0; -out_remove: - qeth_l3_stop_card(card); - qeth_stop_channel(&card->data); - qeth_stop_channel(&card->write); - qeth_stop_channel(&card->read); - qdio_free(CARD_DDEV(card)); + +err_setup: + qeth_set_allowed_threads(card, 0, 1); + card->state = CARD_STATE_DOWN; + qeth_l3_clear_ip_htable(card, 1); return rc; } static void qeth_l3_set_offline(struct qeth_card *card) { - qeth_l3_stop_card(card); + qeth_set_allowed_threads(card, 0, 1); + qeth_l3_drain_rx_mode_cache(card); + + if (card->options.sniffer && + (card->info.promisc_mode == SET_PROMISC_MODE_ON)) + qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE); + + if (card->state == CARD_STATE_SOFTSETUP) { + card->state = CARD_STATE_DOWN; + qeth_l3_clear_ip_htable(card, 1); + } } /* Returns zero if the command is successfully "consumed" */ diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index dd0b39082534..351763ae9b9c 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -301,19 +301,21 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, goto out; } + mutex_lock(&card->ip_lock); if (sysfs_streq(buf, "toggle")) { enable = !card->ipato.enabled; } else if (kstrtobool(buf, &enable)) { rc = -EINVAL; - goto out; + goto unlock_ip; } if (card->ipato.enabled != enable) { card->ipato.enabled = enable; - mutex_lock(&card->ip_lock); qeth_l3_update_ipato(card); - mutex_unlock(&card->ip_lock); } + +unlock_ip: + mutex_unlock(&card->ip_lock); out: mutex_unlock(&card->conf_mutex); return rc ? rc : count; @@ -339,7 +341,7 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev, bool invert; int rc = 0; - mutex_lock(&card->conf_mutex); + mutex_lock(&card->ip_lock); if (sysfs_streq(buf, "toggle")) { invert = !card->ipato.invert4; } else if (kstrtobool(buf, &invert)) { @@ -349,12 +351,11 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev, if (card->ipato.invert4 != invert) { card->ipato.invert4 = invert; - mutex_lock(&card->ip_lock); qeth_l3_update_ipato(card); - mutex_unlock(&card->ip_lock); } + out: - mutex_unlock(&card->conf_mutex); + mutex_unlock(&card->ip_lock); return rc ? rc : count; } @@ -406,29 +407,29 @@ static ssize_t qeth_l3_dev_ipato_add4_show(struct device *dev, } static int qeth_l3_parse_ipatoe(const char *buf, enum qeth_prot_versions proto, - u8 *addr, int *mask_bits) + u8 *addr, unsigned int *mask_bits) { - const char *start, *end; - char *tmp; - char buffer[40] = {0, }; + char *sep; + int rc; - start = buf; - /* get address string */ - end = strchr(start, '/'); - if (!end || (end - start >= 40)) { + /* Expected input pattern: %addr/%mask */ + sep = strnchr(buf, 40, '/'); + if (!sep) return -EINVAL; - } - strncpy(buffer, start, end - start); - if (qeth_l3_string_to_ipaddr(buffer, proto, addr)) { - return -EINVAL; - } - start = end + 1; - *mask_bits = simple_strtoul(start, &tmp, 10); - if (!strlen(start) || - (tmp == start) || - (*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128))) { + + /* Terminate the %addr sub-string, and parse it: */ + *sep = '\0'; + rc = qeth_l3_string_to_ipaddr(buf, proto, addr); + if (rc) + return rc; + + rc = kstrtouint(sep + 1, 10, mask_bits); + if (rc) + return rc; + + if (*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128)) return -EINVAL; - } + return 0; } @@ -436,8 +437,8 @@ static ssize_t qeth_l3_dev_ipato_add_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { struct qeth_ipato_entry *ipatoe; + unsigned int mask_bits; u8 addr[16]; - int mask_bits; int rc = 0; rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits); @@ -474,8 +475,8 @@ static QETH_DEVICE_ATTR(ipato_add4, add4, 0644, static ssize_t qeth_l3_dev_ipato_del_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { + unsigned int mask_bits; u8 addr[16]; - int mask_bits; int rc = 0; rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits); @@ -510,7 +511,7 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev, bool invert; int rc = 0; - mutex_lock(&card->conf_mutex); + mutex_lock(&card->ip_lock); if (sysfs_streq(buf, "toggle")) { invert = !card->ipato.invert6; } else if (kstrtobool(buf, &invert)) { @@ -520,12 +521,11 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev, if (card->ipato.invert6 != invert) { card->ipato.invert6 = invert; - mutex_lock(&card->ip_lock); qeth_l3_update_ipato(card); - mutex_unlock(&card->ip_lock); } + out: - mutex_unlock(&card->conf_mutex); + mutex_unlock(&card->ip_lock); return rc ? rc : count; } |