Commit 40fe2e0d authored by David S. Miller's avatar David S. Miller

Merge branch 's390-qeth-next'

Julian Wiedmann says:

====================
s390/qeth: updates 2020-09-23

please apply the following patch series for qeth to netdev's net-next tree.

This brings all sorts of cleanups. Highlights are more code sharing in
the init/teardown paths, and more fine-grained rollback on errors during
initialization (instead of a full-blown teardown).
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 46237bf3 58fa3575
...@@ -195,8 +195,8 @@ struct qeth_vnicc_info { ...@@ -195,8 +195,8 @@ struct qeth_vnicc_info {
#define QETH_IN_BUF_SIZE_DEFAULT 65536 #define QETH_IN_BUF_SIZE_DEFAULT 65536
#define QETH_IN_BUF_COUNT_DEFAULT 64 #define QETH_IN_BUF_COUNT_DEFAULT 64
#define QETH_IN_BUF_COUNT_HSDEFAULT 128 #define QETH_IN_BUF_COUNT_HSDEFAULT 128
#define QETH_IN_BUF_COUNT_MIN 8 #define QETH_IN_BUF_COUNT_MIN 8U
#define QETH_IN_BUF_COUNT_MAX 128 #define QETH_IN_BUF_COUNT_MAX 128U
#define QETH_MAX_BUFFER_ELEMENTS(card) ((card)->qdio.in_buf_size >> 12) #define QETH_MAX_BUFFER_ELEMENTS(card) ((card)->qdio.in_buf_size >> 12)
#define QETH_IN_BUF_REQUEUE_THRESHOLD(card) \ #define QETH_IN_BUF_REQUEUE_THRESHOLD(card) \
((card)->qdio.in_buf_pool.buf_count / 2) ((card)->qdio.in_buf_pool.buf_count / 2)
...@@ -753,7 +753,7 @@ struct qeth_discipline { ...@@ -753,7 +753,7 @@ struct qeth_discipline {
const struct device_type *devtype; const struct device_type *devtype;
int (*setup) (struct ccwgroup_device *); int (*setup) (struct ccwgroup_device *);
void (*remove) (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); void (*set_offline)(struct qeth_card *card);
int (*do_ioctl)(struct net_device *dev, struct ifreq *rq, int cmd); int (*do_ioctl)(struct net_device *dev, struct ifreq *rq, int cmd);
int (*control_event_handler)(struct qeth_card *card, int (*control_event_handler)(struct qeth_card *card,
...@@ -814,12 +814,16 @@ struct qeth_card { ...@@ -814,12 +814,16 @@ struct qeth_card {
struct workqueue_struct *event_wq; struct workqueue_struct *event_wq;
struct workqueue_struct *cmd_wq; struct workqueue_struct *cmd_wq;
wait_queue_head_t wait_q; wait_queue_head_t wait_q;
struct mutex ip_lock;
/* protected by ip_lock: */
DECLARE_HASHTABLE(ip_htable, 4); DECLARE_HASHTABLE(ip_htable, 4);
struct qeth_ipato ipato;
DECLARE_HASHTABLE(local_addrs4, 4); DECLARE_HASHTABLE(local_addrs4, 4);
DECLARE_HASHTABLE(local_addrs6, 4); DECLARE_HASHTABLE(local_addrs6, 4);
spinlock_t local_addrs4_lock; spinlock_t local_addrs4_lock;
spinlock_t local_addrs6_lock; spinlock_t local_addrs6_lock;
struct mutex ip_lock;
DECLARE_HASHTABLE(rx_mode_addrs, 4); DECLARE_HASHTABLE(rx_mode_addrs, 4);
struct work_struct rx_mode_work; struct work_struct rx_mode_work;
struct work_struct kernel_thread_starter; struct work_struct kernel_thread_starter;
...@@ -827,7 +831,6 @@ struct qeth_card { ...@@ -827,7 +831,6 @@ struct qeth_card {
unsigned long thread_start_mask; unsigned long thread_start_mask;
unsigned long thread_allowed_mask; unsigned long thread_allowed_mask;
unsigned long thread_running_mask; unsigned long thread_running_mask;
struct qeth_ipato ipato;
struct list_head cmd_waiter_list; struct list_head cmd_waiter_list;
/* QDIO buffer handling */ /* QDIO buffer handling */
struct qeth_qdio_info qdio; struct qeth_qdio_info qdio;
...@@ -1034,11 +1037,8 @@ struct net_device *qeth_clone_netdev(struct net_device *orig); ...@@ -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); struct qeth_card *qeth_get_card_by_busid(char *bus_id);
void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int); void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int);
int qeth_threads_running(struct qeth_card *, unsigned long); 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); 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 qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *,
int (*reply_cb) int (*reply_cb)
(struct qeth_card *, struct qeth_reply *, unsigned long), (struct qeth_card *, struct qeth_reply *, unsigned long),
...@@ -1062,12 +1062,7 @@ void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason); ...@@ -1062,12 +1062,7 @@ void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason);
void qeth_put_cmd(struct qeth_cmd_buffer *iob); void qeth_put_cmd(struct qeth_cmd_buffer *iob);
int qeth_schedule_recovery(struct qeth_card *card); 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); 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); void qeth_setadp_promisc_mode(struct qeth_card *card, bool enable);
int qeth_setadpparms_change_macaddr(struct qeth_card *); int qeth_setadpparms_change_macaddr(struct qeth_card *);
void qeth_tx_timeout(struct net_device *, unsigned int txqueue); 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); ...@@ -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, ...); void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
int qeth_configure_cq(struct qeth_card *, enum qeth_cq); int qeth_configure_cq(struct qeth_card *, enum qeth_cq);
int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action); 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_setassparms_cb(struct qeth_card *, struct qeth_reply *, unsigned long);
int qeth_setup_netdev(struct qeth_card *card); int qeth_setup_netdev(struct qeth_card *card);
int qeth_set_features(struct net_device *, netdev_features_t); int qeth_set_features(struct net_device *, netdev_features_t);
......
...@@ -201,7 +201,7 @@ int qeth_threads_running(struct qeth_card *card, unsigned long threads) ...@@ -201,7 +201,7 @@ int qeth_threads_running(struct qeth_card *card, unsigned long threads)
} }
EXPORT_SYMBOL_GPL(qeth_threads_running); 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_buffer_pool_entry *pool_entry, *tmp;
struct qeth_qdio_q *queue = card->qdio.in_q; struct qeth_qdio_q *queue = card->qdio.in_q;
...@@ -216,7 +216,6 @@ void qeth_clear_working_pool_list(struct qeth_card *card) ...@@ -216,7 +216,6 @@ void qeth_clear_working_pool_list(struct qeth_card *card)
for (i = 0; i < ARRAY_SIZE(queue->bufs); i++) for (i = 0; i < ARRAY_SIZE(queue->bufs); i++)
queue->bufs[i].pool_entry = NULL; 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) 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) ...@@ -658,12 +657,11 @@ static void qeth_flush_local_addrs6(struct qeth_card *card)
spin_unlock_irq(&card->local_addrs6_lock); 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_addrs4(card);
qeth_flush_local_addrs6(card); qeth_flush_local_addrs6(card);
} }
EXPORT_SYMBOL_GPL(qeth_flush_local_addrs);
static void qeth_add_local_addrs4(struct qeth_card *card, static void qeth_add_local_addrs4(struct qeth_card *card,
struct qeth_ipacmd_local_addrs4 *cmd) struct qeth_ipacmd_local_addrs4 *cmd)
...@@ -965,7 +963,7 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, ...@@ -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; struct qeth_cmd_buffer *iob;
unsigned long flags; unsigned long flags;
...@@ -977,7 +975,6 @@ void qeth_clear_ipacmd_list(struct qeth_card *card) ...@@ -977,7 +975,6 @@ void qeth_clear_ipacmd_list(struct qeth_card *card)
qeth_notify_cmd(iob, -ECANCELED); qeth_notify_cmd(iob, -ECANCELED);
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
} }
EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list);
static int qeth_check_idx_response(struct qeth_card *card, static int qeth_check_idx_response(struct qeth_card *card,
unsigned char *buffer) unsigned char *buffer)
...@@ -1502,7 +1499,7 @@ static void qeth_drain_output_queue(struct qeth_qdio_out_q *q, bool free) ...@@ -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; int i;
...@@ -1513,7 +1510,6 @@ void qeth_drain_output_queues(struct qeth_card *card) ...@@ -1513,7 +1510,6 @@ void qeth_drain_output_queues(struct qeth_card *card)
qeth_drain_output_queue(card->qdio.out_qs[i], false); 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) 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, ...@@ -1754,7 +1750,7 @@ static int qeth_halt_channel(struct qeth_card *card,
return 0; 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; struct ccw_device *cdev = channel->ccwdev;
int rc; int rc;
...@@ -1772,7 +1768,6 @@ int qeth_stop_channel(struct qeth_channel *channel) ...@@ -1772,7 +1768,6 @@ int qeth_stop_channel(struct qeth_channel *channel)
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(qeth_stop_channel);
static int qeth_start_channel(struct qeth_channel *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) ...@@ -1842,7 +1837,7 @@ static int qeth_clear_halt_card(struct qeth_card *card, int halt)
return qeth_clear_channels(card); 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; int rc = 0;
...@@ -1870,7 +1865,6 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt) ...@@ -1870,7 +1865,6 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
QETH_CARD_TEXT_(card, 3, "2err%d", rc); QETH_CARD_TEXT_(card, 3, "2err%d", rc);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(qeth_qdio_clear_card);
static enum qeth_discipline_id qeth_vm_detect_layer(struct qeth_card *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) ...@@ -2867,7 +2861,7 @@ static int qeth_mpc_initialize(struct qeth_card *card)
return 0; 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) { switch (card->info.type) {
case QETH_CARD_TYPE_OSD: case QETH_CARD_TYPE_OSD:
...@@ -2908,7 +2902,6 @@ void qeth_print_status_message(struct qeth_card *card) ...@@ -2908,7 +2902,6 @@ void qeth_print_status_message(struct qeth_card *card)
(card->info.mcl_level[0]) ? ")" : "", (card->info.mcl_level[0]) ? ")" : "",
qeth_get_cardname_short(card)); qeth_get_cardname_short(card));
} }
EXPORT_SYMBOL_GPL(qeth_print_status_message);
static void qeth_initialize_working_pool_list(struct qeth_card *card) 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) ...@@ -5124,7 +5117,7 @@ static void qeth_core_free_card(struct qeth_card *card)
kfree(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_TEXT(card, 2, "features");
QETH_CARD_HEX(card, 2, &card->options.ipa4, sizeof(card->options.ipa4)); QETH_CARD_HEX(card, 2, &card->options.ipa4, sizeof(card->options.ipa4));
...@@ -5133,7 +5126,6 @@ void qeth_trace_features(struct qeth_card *card) ...@@ -5133,7 +5126,6 @@ void qeth_trace_features(struct qeth_card *card)
QETH_CARD_HEX(card, 2, &card->info.diagass_support, QETH_CARD_HEX(card, 2, &card->info.diagass_support,
sizeof(card->info.diagass_support)); sizeof(card->info.diagass_support));
} }
EXPORT_SYMBOL_GPL(qeth_trace_features);
static struct ccw_device_id qeth_ids[] = { static struct ccw_device_id qeth_ids[] = {
{CCW_DEVICE_DEVTYPE(0x1731, 0x01, 0x1732, 0x01), {CCW_DEVICE_DEVTYPE(0x1731, 0x01, 0x1732, 0x01),
...@@ -5164,7 +5156,7 @@ static struct ccw_driver qeth_ccw_driver = { ...@@ -5164,7 +5156,7 @@ static struct ccw_driver qeth_ccw_driver = {
.remove = ccwgroup_remove_ccwdev, .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 retries = 3;
int rc; int rc;
...@@ -5278,6 +5270,8 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok) ...@@ -5278,6 +5270,8 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
QETH_CARD_TEXT_(card, 2, "8err%d", rc); QETH_CARD_TEXT_(card, 2, "8err%d", rc);
} }
qeth_trace_features(card);
if (!qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP) || if (!qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP) ||
(card->info.hwtrap && qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM))) (card->info.hwtrap && qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM)))
card->info.hwtrap = 0; card->info.hwtrap = 0;
...@@ -5303,21 +5297,49 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok) ...@@ -5303,21 +5297,49 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
CARD_DEVID(card), rc); CARD_DEVID(card), rc);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(qeth_core_hardsetup_card);
static int qeth_set_online(struct qeth_card *card) static int qeth_set_online(struct qeth_card *card)
{ {
bool carrier_ok;
int rc; int rc;
mutex_lock(&card->discipline_mutex); mutex_lock(&card->discipline_mutex);
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
QETH_CARD_TEXT(card, 2, "setonlin"); 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->conf_mutex);
mutex_unlock(&card->discipline_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; return rc;
} }
...@@ -5334,6 +5356,9 @@ int qeth_set_offline(struct qeth_card *card, bool resetting) ...@@ -5334,6 +5356,9 @@ int qeth_set_offline(struct qeth_card *card, bool resetting)
card->info.hwtrap = 1; card->info.hwtrap = 1;
} }
/* cancel any stalled cmd that might block the rtnl: */
qeth_clear_ipacmd_list(card);
rtnl_lock(); rtnl_lock();
card->info.open_when_online = card->dev->flags & IFF_UP; card->info.open_when_online = card->dev->flags & IFF_UP;
dev_close(card->dev); dev_close(card->dev);
...@@ -5341,8 +5366,16 @@ int qeth_set_offline(struct qeth_card *card, bool resetting) ...@@ -5341,8 +5366,16 @@ int qeth_set_offline(struct qeth_card *card, bool resetting)
netif_carrier_off(card->dev); netif_carrier_off(card->dev);
rtnl_unlock(); rtnl_unlock();
cancel_work_sync(&card->rx_mode_work);
card->discipline->set_offline(card); 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); rc = qeth_stop_channel(&card->data);
rc2 = qeth_stop_channel(&card->write); rc2 = qeth_stop_channel(&card->write);
rc3 = qeth_stop_channel(&card->read); rc3 = qeth_stop_channel(&card->read);
......
...@@ -103,21 +103,21 @@ static ssize_t qeth_dev_portno_store(struct device *dev, ...@@ -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 device_attribute *attr, const char *buf, size_t count)
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
char *tmp;
unsigned int portno, limit; unsigned int portno, limit;
int rc = 0; int rc = 0;
rc = kstrtouint(buf, 16, &portno);
if (rc)
return rc;
if (portno > QETH_MAX_PORTNO)
return -EINVAL;
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (card->state != CARD_STATE_DOWN) { if (card->state != CARD_STATE_DOWN) {
rc = -EPERM; rc = -EPERM;
goto out; 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); limit = (card->ssqd.pcnt ? card->ssqd.pcnt - 1 : card->ssqd.pcnt);
if (portno > limit) { if (portno > limit) {
rc = -EINVAL; rc = -EINVAL;
...@@ -248,19 +248,19 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev, ...@@ -248,19 +248,19 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
unsigned int cnt; unsigned int cnt;
char *tmp;
int rc = 0; int rc = 0;
rc = kstrtouint(buf, 10, &cnt);
if (rc)
return rc;
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (card->state != CARD_STATE_DOWN) { if (card->state != CARD_STATE_DOWN) {
rc = -EPERM; rc = -EPERM;
goto out; goto out;
} }
cnt = simple_strtoul(buf, &tmp, 10); cnt = clamp(cnt, QETH_IN_BUF_COUNT_MIN, QETH_IN_BUF_COUNT_MAX);
cnt = (cnt < QETH_IN_BUF_COUNT_MIN) ? QETH_IN_BUF_COUNT_MIN :
((cnt > QETH_IN_BUF_COUNT_MAX) ? QETH_IN_BUF_COUNT_MAX : cnt);
rc = qeth_resize_buffer_pool(card, cnt); rc = qeth_resize_buffer_pool(card, cnt);
out: out:
...@@ -341,18 +341,15 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, ...@@ -341,18 +341,15 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
struct net_device *ndev; struct net_device *ndev;
char *tmp;
int i, rc = 0;
enum qeth_discipline_id newdis; enum qeth_discipline_id newdis;
unsigned int input;
int rc;
mutex_lock(&card->discipline_mutex); rc = kstrtouint(buf, 16, &input);
if (card->state != CARD_STATE_DOWN) { if (rc)
rc = -EPERM; return rc;
goto out;
}
i = simple_strtoul(buf, &tmp, 16); switch (input) {
switch (i) {
case 0: case 0:
newdis = QETH_DISCIPLINE_LAYER3; newdis = QETH_DISCIPLINE_LAYER3;
break; break;
...@@ -360,7 +357,12 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, ...@@ -360,7 +357,12 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
newdis = QETH_DISCIPLINE_LAYER2; newdis = QETH_DISCIPLINE_LAYER2;
break; break;
default: default:
rc = -EINVAL; return -EINVAL;
}
mutex_lock(&card->discipline_mutex);
if (card->state != CARD_STATE_DOWN) {
rc = -EPERM;
goto out; goto out;
} }
...@@ -551,20 +553,21 @@ static DEVICE_ATTR(hw_trap, 0644, qeth_hw_trap_show, ...@@ -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, static ssize_t qeth_dev_blkt_store(struct qeth_card *card,
const char *buf, size_t count, int *value, int max_value) const char *buf, size_t count, int *value, int max_value)
{ {
char *tmp; unsigned int input;
int i, rc = 0; int rc;
rc = kstrtouint(buf, 10, &input);
if (rc)
return rc;
if (input > max_value)
return -EINVAL;
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (card->state != CARD_STATE_DOWN) { if (card->state != CARD_STATE_DOWN)
rc = -EPERM; rc = -EPERM;
goto out;
}
i = simple_strtoul(buf, &tmp, 10);
if (i <= max_value)
*value = i;
else else
rc = -EINVAL; *value = input;
out:
mutex_unlock(&card->conf_mutex); mutex_unlock(&card->conf_mutex);
return rc ? rc : count; return rc ? rc : count;
} }
......
...@@ -31,4 +31,11 @@ struct qeth_mac { ...@@ -31,4 +31,11 @@ struct qeth_mac {
struct hlist_node hnode; 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__ */ #endif /* __QETH_L2_H__ */
...@@ -28,17 +28,6 @@ ...@@ -28,17 +28,6 @@
#include "qeth_core.h" #include "qeth_core.h"
#include "qeth_l2.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) static int qeth_l2_setdelmac_makerc(struct qeth_card *card, u16 retcode)
{ {
int rc; int rc;
...@@ -304,36 +293,6 @@ static void qeth_l2_dev2br_fdb_flush(struct qeth_card *card) ...@@ -304,36 +293,6 @@ static void qeth_l2_dev2br_fdb_flush(struct qeth_card *card)
card->dev, &info.info, NULL); 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) static int qeth_l2_request_initial_mac(struct qeth_card *card)
{ {
int rc = 0; int rc = 0;
...@@ -617,49 +576,6 @@ static u16 qeth_l2_select_queue(struct net_device *dev, struct sk_buff *skb, ...@@ -617,49 +576,6 @@ static u16 qeth_l2_select_queue(struct net_device *dev, struct sk_buff *skb,
qeth_get_priority_queue(card, 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) static void qeth_l2_set_rx_mode(struct net_device *dev)
{ {
struct qeth_card *card = dev->ml_priv; struct qeth_card *card = dev->ml_priv;
...@@ -1140,134 +1056,6 @@ static void qeth_l2_enable_brport_features(struct qeth_card *card) ...@@ -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 #ifdef CONFIG_QETH_OSN
static void qeth_osn_assist_cb(struct qeth_card *card, static void qeth_osn_assist_cb(struct qeth_card *card,
struct qeth_cmd_buffer *iob, struct qeth_cmd_buffer *iob,
...@@ -1987,12 +1775,6 @@ int qeth_bridgeport_an_set(struct qeth_card *card, int enable) ...@@ -1987,12 +1775,6 @@ int qeth_bridgeport_an_set(struct qeth_card *card, int enable)
return rc; 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 */ /* VNIC Characteristics support */
/* handle VNICC IPA command return codes; convert to error codes */ /* 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, ...@@ -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); 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 */ /* set current VNICC flag state; called from sysfs store function */
int qeth_l2_vnicc_set_state(struct qeth_card *card, u32 vnicc, bool state) 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) ...@@ -2308,19 +2103,6 @@ bool qeth_bridgeport_allowed(struct qeth_card *card)
!(priv->brport_features & BR_LEARNING_SYNC)); !(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 */ /* recover user characteristic setting */
static bool qeth_l2_vnicc_recover_char(struct qeth_card *card, u32 vnicc, static bool qeth_l2_vnicc_recover_char(struct qeth_card *card, u32 vnicc,
bool enable) bool enable)
...@@ -2409,6 +2191,174 @@ static void qeth_l2_vnicc_set_defaults(struct qeth_card *card) ...@@ -2409,6 +2191,174 @@ static void qeth_l2_vnicc_set_defaults(struct qeth_card *card)
card->options.vnicc.wanted_chars = QETH_VNICC_DEFAULT; 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_init(qeth_l2_init);
module_exit(qeth_l2_exit); module_exit(qeth_l2_exit);
MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>"); MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>");
......
...@@ -96,7 +96,7 @@ struct qeth_ipato_entry { ...@@ -96,7 +96,7 @@ struct qeth_ipato_entry {
struct list_head entry; struct list_head entry;
enum qeth_prot_versions proto; enum qeth_prot_versions proto;
char addr[16]; char addr[16];
int mask_bits; unsigned int mask_bits;
}; };
extern const struct attribute_group *qeth_l3_attr_groups[]; extern const struct attribute_group *qeth_l3_attr_groups[];
...@@ -110,7 +110,7 @@ int qeth_l3_setrouting_v6(struct qeth_card *); ...@@ -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_add_ipato_entry(struct qeth_card *, struct qeth_ipato_entry *);
int qeth_l3_del_ipato_entry(struct qeth_card *card, int qeth_l3_del_ipato_entry(struct qeth_card *card,
enum qeth_prot_versions proto, u8 *addr, enum qeth_prot_versions proto, u8 *addr,
int mask_bits); unsigned int mask_bits);
void qeth_l3_update_ipato(struct qeth_card *card); void qeth_l3_update_ipato(struct qeth_card *card);
int qeth_l3_modify_hsuid(struct qeth_card *card, bool add); 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, int qeth_l3_modify_rxip_vipa(struct qeth_card *card, bool add, const u8 *ip,
......
...@@ -105,11 +105,9 @@ static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card, ...@@ -105,11 +105,9 @@ static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card,
(ipatoe->proto == QETH_PROT_IPV4) ? (ipatoe->proto == QETH_PROT_IPV4) ?
4 : 16); 4 : 16);
if (addr->proto == QETH_PROT_IPV4) if (addr->proto == QETH_PROT_IPV4)
rc = !memcmp(addr_bits, ipatoe_bits, rc = !memcmp(addr_bits, ipatoe_bits, ipatoe->mask_bits);
min(32, ipatoe->mask_bits));
else else
rc = !memcmp(addr_bits, ipatoe_bits, rc = !memcmp(addr_bits, ipatoe_bits, ipatoe->mask_bits);
min(128, ipatoe->mask_bits));
if (rc) if (rc)
break; break;
} }
...@@ -536,7 +534,6 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card, ...@@ -536,7 +534,6 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card,
QETH_CARD_TEXT(card, 2, "addipato"); QETH_CARD_TEXT(card, 2, "addipato");
mutex_lock(&card->conf_mutex);
mutex_lock(&card->ip_lock); mutex_lock(&card->ip_lock);
list_for_each_entry(ipatoe, &card->ipato.entries, entry) { list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
...@@ -556,21 +553,19 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card, ...@@ -556,21 +553,19 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card,
} }
mutex_unlock(&card->ip_lock); mutex_unlock(&card->ip_lock);
mutex_unlock(&card->conf_mutex);
return rc; return rc;
} }
int qeth_l3_del_ipato_entry(struct qeth_card *card, int qeth_l3_del_ipato_entry(struct qeth_card *card,
enum qeth_prot_versions proto, u8 *addr, enum qeth_prot_versions proto, u8 *addr,
int mask_bits) unsigned int mask_bits)
{ {
struct qeth_ipato_entry *ipatoe, *tmp; struct qeth_ipato_entry *ipatoe, *tmp;
int rc = -ENOENT; int rc = -ENOENT;
QETH_CARD_TEXT(card, 2, "delipato"); QETH_CARD_TEXT(card, 2, "delipato");
mutex_lock(&card->conf_mutex);
mutex_lock(&card->ip_lock); mutex_lock(&card->ip_lock);
list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry) { 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, ...@@ -587,7 +582,6 @@ int qeth_l3_del_ipato_entry(struct qeth_card *card,
} }
mutex_unlock(&card->ip_lock); mutex_unlock(&card->ip_lock);
mutex_unlock(&card->conf_mutex);
return rc; return rc;
} }
...@@ -597,7 +591,6 @@ int qeth_l3_modify_rxip_vipa(struct qeth_card *card, bool add, const u8 *ip, ...@@ -597,7 +591,6 @@ int qeth_l3_modify_rxip_vipa(struct qeth_card *card, bool add, const u8 *ip,
enum qeth_prot_versions proto) enum qeth_prot_versions proto)
{ {
struct qeth_ipaddr addr; struct qeth_ipaddr addr;
int rc;
qeth_l3_init_ipaddr(&addr, type, proto); qeth_l3_init_ipaddr(&addr, type, proto);
if (proto == QETH_PROT_IPV4) if (proto == QETH_PROT_IPV4)
...@@ -605,11 +598,7 @@ int qeth_l3_modify_rxip_vipa(struct qeth_card *card, bool add, const u8 *ip, ...@@ -605,11 +598,7 @@ int qeth_l3_modify_rxip_vipa(struct qeth_card *card, bool add, const u8 *ip,
else else
memcpy(&addr.u.a6.addr, ip, 16); memcpy(&addr.u.a6.addr, ip, 16);
mutex_lock(&card->conf_mutex); return qeth_l3_modify_ip(card, &addr, add);
rc = qeth_l3_modify_ip(card, &addr, add);
mutex_unlock(&card->conf_mutex);
return rc;
} }
int qeth_l3_modify_hsuid(struct qeth_card *card, bool 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, ...@@ -1153,33 +1142,6 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev,
return 0; 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) static void qeth_l3_set_promisc_mode(struct qeth_card *card)
{ {
bool enable = card->dev->flags & IFF_PROMISC; bool enable = card->dev->flags & IFF_PROMISC;
...@@ -1235,7 +1197,6 @@ static void qeth_l3_rx_mode_work(struct work_struct *work) ...@@ -1235,7 +1197,6 @@ static void qeth_l3_rx_mode_work(struct work_struct *work)
kfree(addr); kfree(addr);
break; break;
} }
addr->ref_counter = 1;
fallthrough; fallthrough;
default: default:
/* for next call to set_rx_mode(): */ /* for next call to set_rx_mode(): */
...@@ -2025,21 +1986,10 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) ...@@ -2025,21 +1986,10 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
qeth_l3_clear_ipato_list(card); 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; struct net_device *dev = card->dev;
int rc = 0; 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 */ /* softsetup */
QETH_CARD_TEXT(card, 2, "softsetp"); QETH_CARD_TEXT(card, 2, "softsetp");
...@@ -2066,7 +2016,7 @@ static int qeth_l3_set_online(struct qeth_card *card) ...@@ -2066,7 +2016,7 @@ static int qeth_l3_set_online(struct qeth_card *card)
if (dev->reg_state != NETREG_REGISTERED) { if (dev->reg_state != NETREG_REGISTERED) {
rc = qeth_l3_setup_netdev(card); rc = qeth_l3_setup_netdev(card);
if (rc) if (rc)
goto out_remove; goto err_setup;
if (carrier_ok) if (carrier_ok)
netif_carrier_on(dev); netif_carrier_on(dev);
...@@ -2086,22 +2036,28 @@ static int qeth_l3_set_online(struct qeth_card *card) ...@@ -2086,22 +2036,28 @@ static int qeth_l3_set_online(struct qeth_card *card)
} }
rtnl_unlock(); rtnl_unlock();
} }
qeth_trace_features(card);
/* let user_space know that device is online */
kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
return 0; return 0;
out_remove:
qeth_l3_stop_card(card); err_setup:
qeth_stop_channel(&card->data); qeth_set_allowed_threads(card, 0, 1);
qeth_stop_channel(&card->write); card->state = CARD_STATE_DOWN;
qeth_stop_channel(&card->read); qeth_l3_clear_ip_htable(card, 1);
qdio_free(CARD_DDEV(card));
return rc; return rc;
} }
static void qeth_l3_set_offline(struct qeth_card *card) 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" */ /* Returns zero if the command is successfully "consumed" */
......
...@@ -301,19 +301,21 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, ...@@ -301,19 +301,21 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
goto out; goto out;
} }
mutex_lock(&card->ip_lock);
if (sysfs_streq(buf, "toggle")) { if (sysfs_streq(buf, "toggle")) {
enable = !card->ipato.enabled; enable = !card->ipato.enabled;
} else if (kstrtobool(buf, &enable)) { } else if (kstrtobool(buf, &enable)) {
rc = -EINVAL; rc = -EINVAL;
goto out; goto unlock_ip;
} }
if (card->ipato.enabled != enable) { if (card->ipato.enabled != enable) {
card->ipato.enabled = enable; card->ipato.enabled = enable;
mutex_lock(&card->ip_lock);
qeth_l3_update_ipato(card); qeth_l3_update_ipato(card);
mutex_unlock(&card->ip_lock);
} }
unlock_ip:
mutex_unlock(&card->ip_lock);
out: out:
mutex_unlock(&card->conf_mutex); mutex_unlock(&card->conf_mutex);
return rc ? rc : count; return rc ? rc : count;
...@@ -339,7 +341,7 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev, ...@@ -339,7 +341,7 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
bool invert; bool invert;
int rc = 0; int rc = 0;
mutex_lock(&card->conf_mutex); mutex_lock(&card->ip_lock);
if (sysfs_streq(buf, "toggle")) { if (sysfs_streq(buf, "toggle")) {
invert = !card->ipato.invert4; invert = !card->ipato.invert4;
} else if (kstrtobool(buf, &invert)) { } else if (kstrtobool(buf, &invert)) {
...@@ -349,12 +351,11 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev, ...@@ -349,12 +351,11 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
if (card->ipato.invert4 != invert) { if (card->ipato.invert4 != invert) {
card->ipato.invert4 = invert; card->ipato.invert4 = invert;
mutex_lock(&card->ip_lock);
qeth_l3_update_ipato(card); qeth_l3_update_ipato(card);
mutex_unlock(&card->ip_lock);
} }
out: out:
mutex_unlock(&card->conf_mutex); mutex_unlock(&card->ip_lock);
return rc ? rc : count; return rc ? rc : count;
} }
...@@ -406,29 +407,29 @@ static ssize_t qeth_l3_dev_ipato_add4_show(struct device *dev, ...@@ -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, 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 *sep;
char *tmp; int rc;
char buffer[40] = {0, };
start = buf; /* Expected input pattern: %addr/%mask */
/* get address string */ sep = strnchr(buf, 40, '/');
end = strchr(start, '/'); if (!sep)
if (!end || (end - start >= 40)) {
return -EINVAL; return -EINVAL;
}
strncpy(buffer, start, end - start); /* Terminate the %addr sub-string, and parse it: */
if (qeth_l3_string_to_ipaddr(buffer, proto, addr)) { *sep = '\0';
return -EINVAL; rc = qeth_l3_string_to_ipaddr(buf, proto, addr);
} if (rc)
start = end + 1; return rc;
*mask_bits = simple_strtoul(start, &tmp, 10);
if (!strlen(start) || rc = kstrtouint(sep + 1, 10, mask_bits);
(tmp == start) || if (rc)
(*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128))) { return rc;
if (*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128))
return -EINVAL; return -EINVAL;
}
return 0; return 0;
} }
...@@ -436,8 +437,8 @@ static ssize_t qeth_l3_dev_ipato_add_store(const char *buf, size_t count, ...@@ -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_card *card, enum qeth_prot_versions proto)
{ {
struct qeth_ipato_entry *ipatoe; struct qeth_ipato_entry *ipatoe;
unsigned int mask_bits;
u8 addr[16]; u8 addr[16];
int mask_bits;
int rc = 0; int rc = 0;
rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits); rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
...@@ -474,8 +475,8 @@ static QETH_DEVICE_ATTR(ipato_add4, add4, 0644, ...@@ -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, static ssize_t qeth_l3_dev_ipato_del_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto) struct qeth_card *card, enum qeth_prot_versions proto)
{ {
unsigned int mask_bits;
u8 addr[16]; u8 addr[16];
int mask_bits;
int rc = 0; int rc = 0;
rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits); 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, ...@@ -510,7 +511,7 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
bool invert; bool invert;
int rc = 0; int rc = 0;
mutex_lock(&card->conf_mutex); mutex_lock(&card->ip_lock);
if (sysfs_streq(buf, "toggle")) { if (sysfs_streq(buf, "toggle")) {
invert = !card->ipato.invert6; invert = !card->ipato.invert6;
} else if (kstrtobool(buf, &invert)) { } else if (kstrtobool(buf, &invert)) {
...@@ -520,12 +521,11 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev, ...@@ -520,12 +521,11 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
if (card->ipato.invert6 != invert) { if (card->ipato.invert6 != invert) {
card->ipato.invert6 = invert; card->ipato.invert6 = invert;
mutex_lock(&card->ip_lock);
qeth_l3_update_ipato(card); qeth_l3_update_ipato(card);
mutex_unlock(&card->ip_lock);
} }
out: out:
mutex_unlock(&card->conf_mutex); mutex_unlock(&card->ip_lock);
return rc ? rc : count; return rc ? rc : count;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment