diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/block/dasd_genhd.c | 12 | ||||
-rw-r--r-- | drivers/s390/block/dcssblk.c | 26 | ||||
-rw-r--r-- | drivers/s390/block/scm_blk.c | 21 | ||||
-rw-r--r-- | drivers/s390/block/xpram.c | 26 | ||||
-rw-r--r-- | drivers/s390/char/con3215.c | 1 | ||||
-rw-r--r-- | drivers/s390/char/con3270.c | 1 | ||||
-rw-r--r-- | drivers/s390/char/sclp.c | 1 | ||||
-rw-r--r-- | drivers/s390/char/sclp_con.c | 1 | ||||
-rw-r--r-- | drivers/s390/char/sclp_vt220.c | 1 | ||||
-rw-r--r-- | drivers/s390/char/zcore.c | 1 | ||||
-rw-r--r-- | drivers/s390/crypto/ap_queue.c | 11 | ||||
-rw-r--r-- | drivers/s390/crypto/vfio_ap_ops.c | 10 | ||||
-rw-r--r-- | drivers/s390/net/netiucv.c | 28 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core.h | 42 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 349 | ||||
-rw-r--r-- | drivers/s390/net/qeth_ethtool.c | 7 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 12 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 5 |
18 files changed, 235 insertions, 320 deletions
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 8d6587ec73e2..493e8469893c 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -109,9 +109,9 @@ int dasd_scan_partitions(struct dasd_block *block) return -ENODEV; } - mutex_lock(&bdev->bd_mutex); - rc = bdev_disk_changed(bdev, false); - mutex_unlock(&bdev->bd_mutex); + mutex_lock(&block->gdp->open_mutex); + rc = bdev_disk_changed(block->gdp, false); + mutex_unlock(&block->gdp->open_mutex); if (rc) DBF_DEV_EVENT(DBF_ERR, block->base, "scan partitions error, rc %d", rc); @@ -145,9 +145,9 @@ void dasd_destroy_partitions(struct dasd_block *block) bdev = block->bdev; block->bdev = NULL; - mutex_lock(&bdev->bd_mutex); - bdev_disk_changed(bdev, true); - mutex_unlock(&bdev->bd_mutex); + mutex_lock(&bdev->bd_disk->open_mutex); + bdev_disk_changed(bdev->bd_disk, true); + mutex_unlock(&bdev->bd_disk->open_mutex); /* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */ blkdev_put(bdev, FMODE_READ); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index b92bddddd64d..29180bdf0977 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -89,7 +89,6 @@ struct dcssblk_dev_info { int segment_type; unsigned char save_pending; unsigned char is_shared; - struct request_queue *dcssblk_queue; int num_of_segments; struct list_head seg_list; struct dax_device *dax_dev; @@ -428,9 +427,7 @@ removeseg: kill_dax(dev_info->dax_dev); put_dax(dev_info->dax_dev); del_gendisk(dev_info->gd); - blk_cleanup_queue(dev_info->dcssblk_queue); - dev_info->gd->queue = NULL; - put_disk(dev_info->gd); + blk_cleanup_disk(dev_info->gd); up_write(&dcssblk_devices_sem); if (device_remove_file_self(dev, attr)) { @@ -643,18 +640,17 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char dev_info->dev.release = dcssblk_release_segment; dev_info->dev.groups = dcssblk_dev_attr_groups; INIT_LIST_HEAD(&dev_info->lh); - dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK); + dev_info->gd = blk_alloc_disk(NUMA_NO_NODE); if (dev_info->gd == NULL) { rc = -ENOMEM; goto seg_list_del; } dev_info->gd->major = dcssblk_major; + dev_info->gd->minors = DCSSBLK_MINORS_PER_DISK; dev_info->gd->fops = &dcssblk_devops; - dev_info->dcssblk_queue = blk_alloc_queue(NUMA_NO_NODE); - dev_info->gd->queue = dev_info->dcssblk_queue; dev_info->gd->private_data = dev_info; - blk_queue_logical_block_size(dev_info->dcssblk_queue, 4096); - blk_queue_flag_set(QUEUE_FLAG_DAX, dev_info->dcssblk_queue); + blk_queue_logical_block_size(dev_info->gd->queue, 4096); + blk_queue_flag_set(QUEUE_FLAG_DAX, dev_info->gd->queue); seg_byte_size = (dev_info->end - dev_info->start + 1); set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors @@ -718,9 +714,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char put_dev: list_del(&dev_info->lh); - blk_cleanup_queue(dev_info->dcssblk_queue); - dev_info->gd->queue = NULL; - put_disk(dev_info->gd); + blk_cleanup_disk(dev_info->gd); list_for_each_entry(seg_info, &dev_info->seg_list, lh) { segment_unload(seg_info->segment_name); } @@ -730,9 +724,7 @@ put_dev: dev_list_del: list_del(&dev_info->lh); release_gd: - blk_cleanup_queue(dev_info->dcssblk_queue); - dev_info->gd->queue = NULL; - put_disk(dev_info->gd); + blk_cleanup_disk(dev_info->gd); up_write(&dcssblk_devices_sem); seg_list_del: if (dev_info == NULL) @@ -800,9 +792,7 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch kill_dax(dev_info->dax_dev); put_dax(dev_info->dax_dev); del_gendisk(dev_info->gd); - blk_cleanup_queue(dev_info->dcssblk_queue); - dev_info->gd->queue = NULL; - put_disk(dev_info->gd); + blk_cleanup_disk(dev_info->gd); /* unload all related segments */ list_for_each_entry(entry, &dev_info->seg_list, lh) diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c index a4f6f2e62b1d..88cba6212ee2 100644 --- a/drivers/s390/block/scm_blk.c +++ b/drivers/s390/block/scm_blk.c @@ -462,12 +462,12 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev) if (ret) goto out; - rq = blk_mq_init_queue(&bdev->tag_set); - if (IS_ERR(rq)) { - ret = PTR_ERR(rq); + bdev->gendisk = blk_mq_alloc_disk(&bdev->tag_set, scmdev); + if (IS_ERR(bdev->gendisk)) { + ret = PTR_ERR(bdev->gendisk); goto out_tag; } - bdev->rq = rq; + rq = bdev->rq = bdev->gendisk->queue; nr_max_blk = min(scmdev->nr_max_block, (unsigned int) (PAGE_SIZE / sizeof(struct aidaw))); @@ -477,17 +477,11 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev) blk_queue_flag_set(QUEUE_FLAG_NONROT, rq); blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, rq); - bdev->gendisk = alloc_disk(SCM_NR_PARTS); - if (!bdev->gendisk) { - ret = -ENOMEM; - goto out_queue; - } - rq->queuedata = scmdev; bdev->gendisk->private_data = scmdev; bdev->gendisk->fops = &scm_blk_devops; - bdev->gendisk->queue = rq; bdev->gendisk->major = scm_major; bdev->gendisk->first_minor = devindex * SCM_NR_PARTS; + bdev->gendisk->minors = SCM_NR_PARTS; len = snprintf(bdev->gendisk->disk_name, DISK_NAME_LEN, "scm"); if (devindex > 25) { @@ -504,8 +498,6 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev) device_add_disk(&scmdev->dev, bdev->gendisk, NULL); return 0; -out_queue: - blk_cleanup_queue(rq); out_tag: blk_mq_free_tag_set(&bdev->tag_set); out: @@ -516,9 +508,8 @@ out: void scm_blk_dev_cleanup(struct scm_blk_dev *bdev) { del_gendisk(bdev->gendisk); - blk_cleanup_queue(bdev->gendisk->queue); + blk_cleanup_disk(bdev->gendisk); blk_mq_free_tag_set(&bdev->tag_set); - put_disk(bdev->gendisk); } void scm_blk_set_available(struct scm_blk_dev *bdev) diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 9f19d47fa118..ce98fab4d43c 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -54,7 +54,6 @@ typedef struct { static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; static unsigned int xpram_sizes[XPRAM_MAX_DEVS]; static struct gendisk *xpram_disks[XPRAM_MAX_DEVS]; -static struct request_queue *xpram_queues[XPRAM_MAX_DEVS]; static unsigned int xpram_pages; static int xpram_devs; @@ -339,17 +338,13 @@ static int __init xpram_setup_blkdev(void) int i, rc = -ENOMEM; for (i = 0; i < xpram_devs; i++) { - xpram_disks[i] = alloc_disk(1); + xpram_disks[i] = blk_alloc_disk(NUMA_NO_NODE); if (!xpram_disks[i]) goto out; - xpram_queues[i] = blk_alloc_queue(NUMA_NO_NODE); - if (!xpram_queues[i]) { - put_disk(xpram_disks[i]); - goto out; - } - blk_queue_flag_set(QUEUE_FLAG_NONROT, xpram_queues[i]); - blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, xpram_queues[i]); - blk_queue_logical_block_size(xpram_queues[i], 4096); + blk_queue_flag_set(QUEUE_FLAG_NONROT, xpram_disks[i]->queue); + blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, + xpram_disks[i]->queue); + blk_queue_logical_block_size(xpram_disks[i]->queue, 4096); } /* @@ -371,9 +366,9 @@ static int __init xpram_setup_blkdev(void) offset += xpram_devices[i].size; disk->major = XPRAM_MAJOR; disk->first_minor = i; + disk->minors = 1; disk->fops = &xpram_devops; disk->private_data = &xpram_devices[i]; - disk->queue = xpram_queues[i]; sprintf(disk->disk_name, "slram%d", i); set_capacity(disk, xpram_sizes[i] << 1); add_disk(disk); @@ -381,10 +376,8 @@ static int __init xpram_setup_blkdev(void) return 0; out: - while (i--) { - blk_cleanup_queue(xpram_queues[i]); - put_disk(xpram_disks[i]); - } + while (i--) + blk_cleanup_disk(xpram_disks[i]); return rc; } @@ -396,8 +389,7 @@ static void __exit xpram_exit(void) int i; for (i = 0; i < xpram_devs; i++) { del_gendisk(xpram_disks[i]); - blk_cleanup_queue(xpram_queues[i]); - put_disk(xpram_disks[i]); + blk_cleanup_disk(xpram_disks[i]); } unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); } diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 1fd5bca9fa20..02523f4e29f4 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -19,6 +19,7 @@ #include <linux/console.h> #include <linux/interrupt.h> #include <linux/err.h> +#include <linux/panic_notifier.h> #include <linux/reboot.h> #include <linux/serial.h> /* ASYNC_* flags */ #include <linux/slab.h> diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index e21962c0fd94..87cdbace1453 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/list.h> +#include <linux/panic_notifier.h> #include <linux/types.h> #include <linux/slab.h> #include <linux/err.h> diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 75269df63991..792b4bfa6d9a 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -11,6 +11,7 @@ #include <linux/kernel_stat.h> #include <linux/module.h> #include <linux/err.h> +#include <linux/panic_notifier.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/timer.h> diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index 67860769036c..de028868c6f4 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c @@ -10,6 +10,7 @@ #include <linux/kmod.h> #include <linux/console.h> #include <linux/init.h> +#include <linux/panic_notifier.h> #include <linux/timer.h> #include <linux/jiffies.h> #include <linux/termios.h> diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 43ef832ee079..fa40057fd18d 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/panic_notifier.h> #include <linux/list.h> #include <linux/wait.h> #include <linux/timer.h> diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index bd3c724bf695..b5b0848da93b 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/debugfs.h> +#include <linux/panic_notifier.h> #include <linux/reboot.h> #include <asm/asm-offsets.h> diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index ecefc25eff0c..337353c9655e 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -135,12 +135,13 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) { struct ap_queue_status status; struct ap_message *ap_msg; + bool found = false; status = ap_dqap(aq->qid, &aq->reply->psmid, aq->reply->msg, aq->reply->len); switch (status.response_code) { case AP_RESPONSE_NORMAL: - aq->queue_count--; + aq->queue_count = max_t(int, 0, aq->queue_count - 1); if (aq->queue_count > 0) mod_timer(&aq->timeout, jiffies + aq->request_timeout); @@ -150,8 +151,14 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) list_del_init(&ap_msg->list); aq->pendingq_count--; ap_msg->receive(aq, ap_msg, aq->reply); + found = true; break; } + if (!found) { + AP_DBF_WARN("%s unassociated reply psmid=0x%016llx on 0x%02x.%04x\n", + __func__, aq->reply->psmid, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + } fallthrough; case AP_RESPONSE_NO_PENDING_REPLY: if (!status.queue_empty || aq->queue_count <= 0) @@ -232,7 +239,7 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq) ap_msg->flags & AP_MSG_FLAG_SPECIAL); switch (status.response_code) { case AP_RESPONSE_NORMAL: - aq->queue_count++; + aq->queue_count = max_t(int, 1, aq->queue_count + 1); if (aq->queue_count == 1) mod_timer(&aq->timeout, jiffies + aq->request_timeout); list_move_tail(&ap_msg->list, &aq->pendingq); diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index b2c7e10dfdcd..122c85c22469 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -366,16 +366,6 @@ static int vfio_ap_mdev_remove(struct mdev_device *mdev) struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); mutex_lock(&matrix_dev->lock); - - /* - * If the KVM pointer is in flux or the guest is running, disallow - * un-assignment of control domain. - */ - if (matrix_mdev->kvm_busy || matrix_mdev->kvm) { - mutex_unlock(&matrix_dev->lock); - return -EBUSY; - } - vfio_ap_mdev_reset_queues(mdev); list_del(&matrix_mdev->node); kfree(matrix_mdev); diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 260860cf3aa1..5a0c2f07a3a2 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -118,24 +118,6 @@ static struct device_driver netiucv_driver = { .bus = &iucv_bus, }; -static int netiucv_callback_connreq(struct iucv_path *, u8 *, u8 *); -static void netiucv_callback_connack(struct iucv_path *, u8 *); -static void netiucv_callback_connrej(struct iucv_path *, u8 *); -static void netiucv_callback_connsusp(struct iucv_path *, u8 *); -static void netiucv_callback_connres(struct iucv_path *, u8 *); -static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *); -static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *); - -static struct iucv_handler netiucv_handler = { - .path_pending = netiucv_callback_connreq, - .path_complete = netiucv_callback_connack, - .path_severed = netiucv_callback_connrej, - .path_quiesced = netiucv_callback_connsusp, - .path_resumed = netiucv_callback_connres, - .message_pending = netiucv_callback_rx, - .message_complete = netiucv_callback_txdone -}; - /** * Per connection profiling data */ @@ -774,6 +756,16 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg) } } +static struct iucv_handler netiucv_handler = { + .path_pending = netiucv_callback_connreq, + .path_complete = netiucv_callback_connack, + .path_severed = netiucv_callback_connrej, + .path_quiesced = netiucv_callback_connsusp, + .path_resumed = netiucv_callback_connres, + .message_pending = netiucv_callback_rx, + .message_complete = netiucv_callback_txdone, +}; + static void conn_action_connaccept(fsm_instance *fi, int event, void *arg) { struct iucv_event *ev = arg; diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index fd9b869d278e..f4d554ea0c93 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -417,13 +417,17 @@ enum qeth_qdio_out_buffer_state { QETH_QDIO_BUF_EMPTY, /* Filled by driver; owned by hardware in order to be sent. */ QETH_QDIO_BUF_PRIMED, - /* Discovered by the TX completion code: */ - QETH_QDIO_BUF_PENDING, - /* Finished by the TX completion code: */ - QETH_QDIO_BUF_NEED_QAOB, - /* Received QAOB notification on CQ: */ - QETH_QDIO_BUF_QAOB_OK, - QETH_QDIO_BUF_QAOB_ERROR, +}; + +enum qeth_qaob_state { + QETH_QAOB_ISSUED, + QETH_QAOB_PENDING, + QETH_QAOB_DONE, +}; + +struct qeth_qaob_priv1 { + unsigned int state; + u8 queue_no; }; struct qeth_qdio_out_buffer { @@ -433,9 +437,8 @@ struct qeth_qdio_out_buffer { unsigned int frames; unsigned int bytes; struct sk_buff_head skb_list; - int is_header[QDIO_MAX_ELEMENTS_PER_BUFFER]; + DECLARE_BITMAP(from_kmem_cache, QDIO_MAX_ELEMENTS_PER_BUFFER); - struct qeth_qdio_out_q *q; struct list_head list_entry; struct qaob *aob; }; @@ -483,6 +486,7 @@ struct qeth_out_q_stats { u64 stopped; u64 doorbell; u64 coal_frames; + u64 completion_irq; u64 completion_yield; u64 completion_timer; @@ -526,6 +530,7 @@ struct qeth_qdio_out_q { unsigned int coalesce_usecs; unsigned int max_coalesced_frames; + unsigned int rescan_usecs; }; #define qeth_for_each_output_queue(card, q, i) \ @@ -612,7 +617,6 @@ struct qeth_channel { struct ccw_device *ccwdev; struct qeth_cmd_buffer *active_cmd; enum qeth_channel_states state; - atomic_t irq_pending; }; struct qeth_reply { @@ -662,11 +666,6 @@ static inline struct ccw1 *__ccw_from_cmd(struct qeth_cmd_buffer *iob) return (struct ccw1 *)(iob->data + ALIGN(iob->length, 8)); } -static inline bool qeth_trylock_channel(struct qeth_channel *channel) -{ - return atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0; -} - /** * OSA card related definitions */ @@ -886,13 +885,24 @@ static inline bool qeth_card_hw_is_reachable(struct qeth_card *card) return card->state == CARD_STATE_SOFTSETUP; } +static inline bool qeth_use_tx_irqs(struct qeth_card *card) +{ + return !IS_IQD(card); +} + static inline void qeth_unlock_channel(struct qeth_card *card, struct qeth_channel *channel) { - atomic_set(&channel->irq_pending, 0); + xchg(&channel->active_cmd, NULL); wake_up(&card->wait_q); } +static inline bool qeth_trylock_channel(struct qeth_channel *channel, + struct qeth_cmd_buffer *cmd) +{ + return cmpxchg(&channel->active_cmd, NULL, cmd) == NULL; +} + struct qeth_trap_id { __u16 lparnr; char vmname[8]; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index a1f08e9aa064..62f88ccbd03f 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -70,9 +70,6 @@ static void qeth_issue_next_read_cb(struct qeth_card *card, unsigned int data_length); static int qeth_qdio_establish(struct qeth_card *); static void qeth_free_qdio_queues(struct qeth_card *card); -static void qeth_notify_skbs(struct qeth_qdio_out_q *queue, - struct qeth_qdio_out_buffer *buf, - enum iucv_tx_notify notification); static void qeth_close_dev_handler(struct work_struct *work) { @@ -434,65 +431,6 @@ static enum iucv_tx_notify qeth_compute_cq_notification(int sbalf15, return n; } -static void qeth_qdio_handle_aob(struct qeth_card *card, - unsigned long phys_aob_addr) -{ - enum qeth_qdio_out_buffer_state new_state = QETH_QDIO_BUF_QAOB_OK; - struct qaob *aob; - struct qeth_qdio_out_buffer *buffer; - enum iucv_tx_notify notification; - struct qeth_qdio_out_q *queue; - unsigned int i; - - aob = (struct qaob *) phys_to_virt(phys_aob_addr); - QETH_CARD_TEXT(card, 5, "haob"); - QETH_CARD_TEXT_(card, 5, "%lx", phys_aob_addr); - buffer = (struct qeth_qdio_out_buffer *) aob->user1; - QETH_CARD_TEXT_(card, 5, "%lx", aob->user1); - - if (aob->aorc) { - QETH_CARD_TEXT_(card, 2, "aorc%02X", aob->aorc); - new_state = QETH_QDIO_BUF_QAOB_ERROR; - } - - switch (atomic_xchg(&buffer->state, new_state)) { - case QETH_QDIO_BUF_PRIMED: - /* Faster than TX completion code, let it handle the async - * completion for us. It will also recycle the QAOB. - */ - break; - case QETH_QDIO_BUF_PENDING: - /* TX completion code is active and will handle the async - * completion for us. It will also recycle the QAOB. - */ - break; - case QETH_QDIO_BUF_NEED_QAOB: - /* TX completion code is already finished. */ - notification = qeth_compute_cq_notification(aob->aorc, 1); - qeth_notify_skbs(buffer->q, buffer, notification); - - /* Free dangling allocations. The attached skbs are handled by - * qeth_tx_complete_pending_bufs(), and so is the QAOB. - */ - for (i = 0; - i < aob->sb_count && i < QETH_MAX_BUFFER_ELEMENTS(card); - i++) { - void *data = phys_to_virt(aob->sba[i]); - - if (data && buffer->is_header[i]) - kmem_cache_free(qeth_core_header_cache, data); - buffer->is_header[i] = 0; - } - - queue = buffer->q; - atomic_set(&buffer->state, QETH_QDIO_BUF_EMPTY); - napi_schedule(&queue->napi); - break; - default: - WARN_ON_ONCE(1); - } -} - static void qeth_setup_ccw(struct ccw1 *ccw, u8 cmd_code, u8 flags, u32 len, void *data) { @@ -1268,7 +1206,6 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, iob = (struct qeth_cmd_buffer *) (addr_t)intparm; } - channel->active_cmd = NULL; qeth_unlock_channel(card, channel); rc = qeth_check_irb_error(card, cdev, irb); @@ -1353,10 +1290,10 @@ static void qeth_notify_skbs(struct qeth_qdio_out_q *q, } } -static void qeth_tx_complete_buf(struct qeth_qdio_out_buffer *buf, bool error, +static void qeth_tx_complete_buf(struct qeth_qdio_out_q *queue, + struct qeth_qdio_out_buffer *buf, bool error, int budget) { - struct qeth_qdio_out_q *queue = buf->q; struct sk_buff *skb; /* Empty buffer? */ @@ -1400,17 +1337,18 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, int i; /* is PCI flag set on buffer? */ - if (buf->buffer->element[0].sflags & SBAL_SFLAGS0_PCI_REQ) + if (buf->buffer->element[0].sflags & SBAL_SFLAGS0_PCI_REQ) { atomic_dec(&queue->set_pci_flags_count); + QETH_TXQ_STAT_INC(queue, completion_irq); + } - qeth_tx_complete_buf(buf, error, budget); + qeth_tx_complete_buf(queue, buf, error, budget); for (i = 0; i < queue->max_elements; ++i) { void *data = phys_to_virt(buf->buffer->element[i].addr); - if (data && buf->is_header[i]) + if (__test_and_clear_bit(i, buf->from_kmem_cache) && data) kmem_cache_free(qeth_core_header_cache, data); - buf->is_header[i] = 0; } qeth_scrub_qdio_buffer(buf->buffer, queue->max_elements); @@ -1434,14 +1372,30 @@ static void qeth_tx_complete_pending_bufs(struct qeth_card *card, struct qeth_qdio_out_buffer *buf, *tmp; list_for_each_entry_safe(buf, tmp, &queue->pending_bufs, list_entry) { - if (drain || atomic_read(&buf->state) == QETH_QDIO_BUF_EMPTY) { + struct qeth_qaob_priv1 *priv; + struct qaob *aob = buf->aob; + enum iucv_tx_notify notify; + unsigned int i; + + priv = (struct qeth_qaob_priv1 *)&aob->user1; + if (drain || READ_ONCE(priv->state) == QETH_QAOB_DONE) { QETH_CARD_TEXT(card, 5, "fp"); QETH_CARD_TEXT_(card, 5, "%lx", (long) buf); - if (drain) - qeth_notify_skbs(queue, buf, - TX_NOTIFY_GENERALERROR); - qeth_tx_complete_buf(buf, drain, budget); + notify = drain ? TX_NOTIFY_GENERALERROR : + qeth_compute_cq_notification(aob->aorc, 1); + qeth_notify_skbs(queue, buf, notify); + qeth_tx_complete_buf(queue, buf, drain, budget); + + for (i = 0; + i < aob->sb_count && i < queue->max_elements; + i++) { + void *data = phys_to_virt(aob->sba[i]); + + if (test_bit(i, buf->from_kmem_cache) && data) + kmem_cache_free(qeth_core_header_cache, + data); + } list_del(&buf->list_entry); qeth_free_out_buf(buf); @@ -1713,11 +1667,10 @@ static int qeth_stop_channel(struct qeth_channel *channel) rc = ccw_device_set_offline(cdev); spin_lock_irq(get_ccwdev_lock(cdev)); - if (channel->active_cmd) { + if (channel->active_cmd) dev_err(&cdev->dev, "Stopped channel while cmd %px was still active\n", channel->active_cmd); - channel->active_cmd = NULL; - } + cdev->handler = NULL; spin_unlock_irq(get_ccwdev_lock(cdev)); @@ -1730,7 +1683,7 @@ static int qeth_start_channel(struct qeth_channel *channel) int rc; channel->state = CH_STATE_DOWN; - atomic_set(&channel->irq_pending, 0); + xchg(&channel->active_cmd, NULL); spin_lock_irq(get_ccwdev_lock(cdev)); cdev->handler = qeth_irq; @@ -2037,7 +1990,7 @@ static int qeth_send_control_data(struct qeth_card *card, reply->param = reply_param; timeout = wait_event_interruptible_timeout(card->wait_q, - qeth_trylock_channel(channel), + qeth_trylock_channel(channel, iob), timeout); if (timeout <= 0) { qeth_put_cmd(iob); @@ -2057,8 +2010,6 @@ static int qeth_send_control_data(struct qeth_card *card, spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); rc = ccw_device_start_timeout(channel->ccwdev, __ccw_from_cmd(iob), (addr_t) iob, 0, 0, timeout); - if (!rc) - channel->active_cmd = iob; spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); if (rc) { QETH_DBF_MESSAGE(2, "qeth_send_control_data on device %x: ccw_device_start rc = %i\n", @@ -2578,7 +2529,6 @@ static int qeth_alloc_out_buf(struct qeth_qdio_out_q *q, unsigned int bidx, newbuf->buffer = q->qdio_bufs[bidx]; skb_queue_head_init(&newbuf->skb_list); lockdep_set_class(&newbuf->skb_list.lock, &qdio_out_skb_queue_key); - newbuf->q = q; atomic_set(&newbuf->state, QETH_QDIO_BUF_EMPTY); q->bufs[bidx] = newbuf; return 0; @@ -2663,8 +2613,15 @@ static int qeth_alloc_qdio_queues(struct qeth_card *card) INIT_LIST_HEAD(&queue->pending_bufs); spin_lock_init(&queue->lock); timer_setup(&queue->timer, qeth_tx_completion_timer, 0); - queue->coalesce_usecs = QETH_TX_COALESCE_USECS; - queue->max_coalesced_frames = QETH_TX_MAX_COALESCED_FRAMES; + if (IS_IQD(card)) { + queue->coalesce_usecs = QETH_TX_COALESCE_USECS; + queue->max_coalesced_frames = QETH_TX_MAX_COALESCED_FRAMES; + queue->rescan_usecs = QETH_TX_TIMER_USECS; + } else { + queue->coalesce_usecs = USEC_PER_SEC; + queue->max_coalesced_frames = 0; + queue->rescan_usecs = 10 * USEC_PER_SEC; + } queue->priority = QETH_QIB_PQUE_PRIO_DEFAULT; } @@ -3601,8 +3558,8 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, int count) { struct qeth_qdio_out_buffer *buf = queue->bufs[index]; - unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT; struct qeth_card *card = queue->card; + unsigned int frames, usecs; struct qaob *aob = NULL; int rc; int i; @@ -3629,8 +3586,12 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, if (!buf->aob) buf->aob = qdio_allocate_aob(); if (buf->aob) { + struct qeth_qaob_priv1 *priv; + aob = buf->aob; - aob->user1 = (u64) buf; + priv = (struct qeth_qaob_priv1 *)&aob->user1; + priv->state = QETH_QAOB_ISSUED; + priv->queue_no = queue->queue_no; } } } else { @@ -3658,14 +3619,11 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, buf->buffer->element[0].sflags |= SBAL_SFLAGS0_PCI_REQ; } } - - if (atomic_read(&queue->set_pci_flags_count)) - qdio_flags |= QDIO_FLAG_PCI_OUT; } QETH_TXQ_STAT_INC(queue, doorbell); - rc = do_QDIO(CARD_DDEV(card), qdio_flags, queue->queue_no, index, count, - aob); + rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_OUTPUT, queue->queue_no, + index, count, aob); switch (rc) { case 0: @@ -3673,17 +3631,20 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, /* ignore temporary SIGA errors without busy condition */ /* Fake the TX completion interrupt: */ - if (IS_IQD(card)) { - unsigned int frames = READ_ONCE(queue->max_coalesced_frames); - unsigned int usecs = READ_ONCE(queue->coalesce_usecs); + frames = READ_ONCE(queue->max_coalesced_frames); + usecs = READ_ONCE(queue->coalesce_usecs); - if (frames && queue->coalesced_frames >= frames) { - napi_schedule(&queue->napi); - queue->coalesced_frames = 0; - QETH_TXQ_STAT_INC(queue, coal_frames); - } else if (usecs) { - qeth_tx_arm_timer(queue, usecs); - } + if (frames && queue->coalesced_frames >= frames) { + napi_schedule(&queue->napi); + queue->coalesced_frames = 0; + QETH_TXQ_STAT_INC(queue, coal_frames); + } else if (qeth_use_tx_irqs(card) && + atomic_read(&queue->used_buffers) >= 32) { + /* Old behaviour carried over from the qdio layer: */ + napi_schedule(&queue->napi); + QETH_TXQ_STAT_INC(queue, coal_frames); + } else if (usecs) { + qeth_tx_arm_timer(queue, usecs); } break; @@ -3769,6 +3730,18 @@ out: } EXPORT_SYMBOL_GPL(qeth_configure_cq); +static void qeth_qdio_handle_aob(struct qeth_card *card, struct qaob *aob) +{ + struct qeth_qaob_priv1 *priv = (struct qeth_qaob_priv1 *)&aob->user1; + unsigned int queue_no = priv->queue_no; + + BUILD_BUG_ON(sizeof(*priv) > ARRAY_SIZE(aob->user1)); + + if (xchg(&priv->state, QETH_QAOB_DONE) == QETH_QAOB_PENDING && + queue_no < card->qdio.no_out_queues) + napi_schedule(&card->qdio.out_qs[queue_no]->napi); +} + static void qeth_qdio_cq_handler(struct qeth_card *card, unsigned int qdio_err, unsigned int queue, int first_element, int count) @@ -3795,7 +3768,7 @@ static void qeth_qdio_cq_handler(struct qeth_card *card, unsigned int qdio_err, buffer->element[e].addr) { unsigned long phys_aob_addr = buffer->element[e].addr; - qeth_qdio_handle_aob(card, phys_aob_addr); + qeth_qdio_handle_aob(card, phys_to_virt(phys_aob_addr)); ++e; } qeth_scrub_qdio_buffer(buffer, QDIO_MAX_ELEMENTS_PER_BUFFER); @@ -3831,36 +3804,14 @@ static void qeth_qdio_output_handler(struct ccw_device *ccwdev, unsigned long card_ptr) { struct qeth_card *card = (struct qeth_card *) card_ptr; - struct qeth_qdio_out_q *queue = card->qdio.out_qs[__queue]; struct net_device *dev = card->dev; - struct netdev_queue *txq; - int i; QETH_CARD_TEXT(card, 6, "qdouhdl"); if (qdio_error & QDIO_ERROR_FATAL) { QETH_CARD_TEXT(card, 2, "achkcond"); netif_tx_stop_all_queues(dev); qeth_schedule_recovery(card); - return; } - - for (i = first_element; i < (first_element + count); ++i) { - struct qeth_qdio_out_buffer *buf = queue->bufs[QDIO_BUFNR(i)]; - - qeth_handle_send_error(card, buf, qdio_error); - qeth_clear_output_buffer(queue, buf, qdio_error, 0); - } - - atomic_sub(count, &queue->used_buffers); - qeth_check_outbound_queue(queue); - - txq = netdev_get_tx_queue(dev, __queue); - /* xmit may have observed the full-condition, but not yet stopped the - * txq. In which case the code below won't trigger. So before returning, - * xmit will re-check the txq's fill level and wake it up if needed. - */ - if (netif_tx_queue_stopped(txq) && !qeth_out_queue_is_full(queue)) - netif_tx_wake_queue(txq); } /** @@ -4101,7 +4052,7 @@ static unsigned int qeth_fill_buffer(struct qeth_qdio_out_buffer *buf, /* HW header is allocated from cache: */ if ((void *)hdr != skb->data) - buf->is_header[element] = 1; + __set_bit(element, buf->from_kmem_cache); /* HW header was pushed and is contiguous with linear part: */ else if (length > 0 && !PAGE_ALIGNED(data) && (data == (char *)hdr + hd_len)) @@ -5256,7 +5207,6 @@ static int qeth_qdio_establish(struct qeth_card *card) init_data.int_parm = (unsigned long) card; init_data.input_sbal_addr_array = in_sbal_ptrs; init_data.output_sbal_addr_array = out_sbal_ptrs; - init_data.scan_threshold = IS_IQD(card) ? 0 : 32; if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED, QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) { @@ -5956,9 +5906,10 @@ static unsigned int qeth_rx_poll(struct qeth_card *card, int budget) /* Fetch completed RX buffers: */ if (!card->rx.b_count) { card->rx.qdio_err = 0; - card->rx.b_count = qdio_get_next_buffers( - card->data.ccwdev, 0, &card->rx.b_index, - &card->rx.qdio_err); + card->rx.b_count = qdio_inspect_queue(CARD_DDEV(card), + 0, true, + &card->rx.b_index, + &card->rx.qdio_err); if (card->rx.b_count <= 0) { card->rx.b_count = 0; break; @@ -6022,6 +5973,16 @@ int qeth_poll(struct napi_struct *napi, int budget) work_done = qeth_rx_poll(card, budget); + if (qeth_use_tx_irqs(card)) { + struct qeth_qdio_out_q *queue; + unsigned int i; + + qeth_for_each_output_queue(card, queue, i) { + if (!qeth_out_queue_is_empty(queue)) + napi_schedule(&queue->napi); + } + } + if (card->options.cq == QETH_CQ_ENABLED) qeth_cq_poll(card); @@ -6055,6 +6016,8 @@ static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue, if (qdio_error == QDIO_ERROR_SLSB_PENDING) { struct qaob *aob = buffer->aob; + struct qeth_qaob_priv1 *priv; + enum iucv_tx_notify notify; if (!aob) { netdev_WARN_ONCE(card->dev, @@ -6066,60 +6029,27 @@ static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue, QETH_CARD_TEXT_(card, 5, "pel%u", bidx); - switch (atomic_cmpxchg(&buffer->state, - QETH_QDIO_BUF_PRIMED, - QETH_QDIO_BUF_PENDING)) { - case QETH_QDIO_BUF_PRIMED: - /* We have initial ownership, no QAOB (yet): */ + priv = (struct qeth_qaob_priv1 *)&aob->user1; + /* QAOB hasn't completed yet: */ + if (xchg(&priv->state, QETH_QAOB_PENDING) != QETH_QAOB_DONE) { qeth_notify_skbs(queue, buffer, TX_NOTIFY_PENDING); - /* Handle race with qeth_qdio_handle_aob(): */ - switch (atomic_xchg(&buffer->state, - QETH_QDIO_BUF_NEED_QAOB)) { - case QETH_QDIO_BUF_PENDING: - /* No concurrent QAOB notification. */ - - /* Prepare the queue slot for immediate re-use: */ - qeth_scrub_qdio_buffer(buffer->buffer, queue->max_elements); - if (qeth_alloc_out_buf(queue, bidx, - GFP_ATOMIC)) { - QETH_CARD_TEXT(card, 2, "outofbuf"); - qeth_schedule_recovery(card); - } - - list_add(&buffer->list_entry, - &queue->pending_bufs); - /* Skip clearing the buffer: */ - return; - case QETH_QDIO_BUF_QAOB_OK: - qeth_notify_skbs(queue, buffer, - TX_NOTIFY_DELAYED_OK); - error = false; - break; - case QETH_QDIO_BUF_QAOB_ERROR: - qeth_notify_skbs(queue, buffer, - TX_NOTIFY_DELAYED_GENERALERROR); - error = true; - break; - default: - WARN_ON_ONCE(1); + /* Prepare the queue slot for immediate re-use: */ + qeth_scrub_qdio_buffer(buffer->buffer, queue->max_elements); + if (qeth_alloc_out_buf(queue, bidx, GFP_ATOMIC)) { + QETH_CARD_TEXT(card, 2, "outofbuf"); + qeth_schedule_recovery(card); } - break; - case QETH_QDIO_BUF_QAOB_OK: - /* qeth_qdio_handle_aob() already received a QAOB: */ - qeth_notify_skbs(queue, buffer, TX_NOTIFY_OK); - error = false; - break; - case QETH_QDIO_BUF_QAOB_ERROR: - /* qeth_qdio_handle_aob() already received a QAOB: */ - qeth_notify_skbs(queue, buffer, TX_NOTIFY_GENERALERROR); - error = true; - break; - default: - WARN_ON_ONCE(1); + list_add(&buffer->list_entry, &queue->pending_bufs); + /* Skip clearing the buffer: */ + return; } + /* QAOB already completed: */ + notify = qeth_compute_cq_notification(aob->aorc, 0); + qeth_notify_skbs(queue, buffer, notify); + error = !!aob->aorc; memset(aob, 0, sizeof(*aob)); } else if (card->options.cq == QETH_CQ_ENABLED) { qeth_notify_skbs(queue, buffer, @@ -6138,7 +6068,10 @@ static int qeth_tx_poll(struct napi_struct *napi, int budget) unsigned int work_done = 0; struct netdev_queue *txq; - txq = netdev_get_tx_queue(dev, qeth_iqd_translate_txq(dev, queue_no)); + if (IS_IQD(card)) + txq = netdev_get_tx_queue(dev, qeth_iqd_translate_txq(dev, queue_no)); + else + txq = netdev_get_tx_queue(dev, queue_no); while (1) { unsigned int start, error, i; @@ -6165,8 +6098,9 @@ static int qeth_tx_poll(struct napi_struct *napi, int budget) &start, &error); if (completed <= 0) { /* Ensure we see TX completion for pending work: */ - if (napi_complete_done(napi, 0)) - qeth_tx_arm_timer(queue, QETH_TX_TIMER_USECS); + if (napi_complete_done(napi, 0) && + !atomic_read(&queue->set_pci_flags_count)) + qeth_tx_arm_timer(queue, queue->rescan_usecs); return 0; } @@ -6179,12 +6113,19 @@ static int qeth_tx_poll(struct napi_struct *napi, int budget) bytes += buffer->bytes; qeth_handle_send_error(card, buffer, error); - qeth_iqd_tx_complete(queue, bidx, error, budget); + if (IS_IQD(card)) + qeth_iqd_tx_complete(queue, bidx, error, budget); + else + qeth_clear_output_buffer(queue, buffer, error, + budget); } - netdev_tx_completed_queue(txq, packets, bytes); atomic_sub(completed, &queue->used_buffers); work_done += completed; + if (IS_IQD(card)) + netdev_tx_completed_queue(txq, packets, bytes); + else + qeth_check_outbound_queue(queue); /* xmit may have observed the full-condition, but not yet * stopped the txq. In which case the code below won't trigger. @@ -7228,6 +7169,8 @@ EXPORT_SYMBOL_GPL(qeth_iqd_select_queue); int qeth_open(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; + struct qeth_qdio_out_q *queue; + unsigned int i; QETH_CARD_TEXT(card, 4, "qethopen"); @@ -7235,16 +7178,11 @@ int qeth_open(struct net_device *dev) netif_tx_start_all_queues(dev); local_bh_disable(); - if (IS_IQD(card)) { - struct qeth_qdio_out_q *queue; - unsigned int i; - - qeth_for_each_output_queue(card, queue, i) { - netif_tx_napi_add(dev, &queue->napi, qeth_tx_poll, - QETH_NAPI_WEIGHT); - napi_enable(&queue->napi); - napi_schedule(&queue->napi); - } + qeth_for_each_output_queue(card, queue, i) { + netif_tx_napi_add(dev, &queue->napi, qeth_tx_poll, + QETH_NAPI_WEIGHT); + napi_enable(&queue->napi); + napi_schedule(&queue->napi); } napi_enable(&card->napi); @@ -7259,6 +7197,8 @@ EXPORT_SYMBOL_GPL(qeth_open); int qeth_stop(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; + struct qeth_qdio_out_q *queue; + unsigned int i; QETH_CARD_TEXT(card, 4, "qethstop"); @@ -7266,24 +7206,17 @@ int qeth_stop(struct net_device *dev) cancel_delayed_work_sync(&card->buffer_reclaim_work); qdio_stop_irq(CARD_DDEV(card)); - if (IS_IQD(card)) { - struct qeth_qdio_out_q *queue; - unsigned int i; - - /* Quiesce the NAPI instances: */ - qeth_for_each_output_queue(card, queue, i) - napi_disable(&queue->napi); + /* Quiesce the NAPI instances: */ + qeth_for_each_output_queue(card, queue, i) + napi_disable(&queue->napi); - /* Stop .ndo_start_xmit, might still access queue->napi. */ - netif_tx_disable(dev); + /* Stop .ndo_start_xmit, might still access queue->napi. */ + netif_tx_disable(dev); - qeth_for_each_output_queue(card, queue, i) { - del_timer_sync(&queue->timer); - /* Queues may get re-allocated, so remove the NAPIs. */ - netif_napi_del(&queue->napi); - } - } else { - netif_tx_disable(dev); + qeth_for_each_output_queue(card, queue, i) { + del_timer_sync(&queue->timer); + /* Queues may get re-allocated, so remove the NAPIs. */ + netif_napi_del(&queue->napi); } return 0; diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index 3a51bbff0ffe..2c4cb300a8fc 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -41,6 +41,7 @@ static const struct qeth_stats txq_stats[] = { QETH_TXQ_STAT("Queue stopped", stopped), QETH_TXQ_STAT("Doorbell", doorbell), QETH_TXQ_STAT("IRQ for frames", coal_frames), + QETH_TXQ_STAT("Completion IRQ", completion_irq), QETH_TXQ_STAT("Completion yield", completion_yield), QETH_TXQ_STAT("Completion timer", completion_timer), }; @@ -79,10 +80,8 @@ static void qeth_add_stat_strings(u8 **data, const char *prefix, { unsigned int i; - for (i = 0; i < size; i++) { - snprintf(*data, ETH_GSTRING_LEN, "%s%s", prefix, stats[i].name); - *data += ETH_GSTRING_LEN; - } + for (i = 0; i < size; i++) + ethtool_sprintf(data, "%s%s", prefix, stats[i].name); } static int qeth_get_sset_count(struct net_device *dev, int stringset) diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index ca44421a6d6e..2abf86c104d5 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -805,8 +805,6 @@ static int qeth_l2_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, if (!netif_device_present(dev)) return -ENODEV; - if (!(priv->brport_hw_features)) - return -EOPNOTSUPP; nlmsg_for_each_attr(attr, nlh, sizeof(struct ifinfomsg), rem1) { if (nla_type(attr) == IFLA_PROTINFO) { @@ -832,6 +830,16 @@ static int qeth_l2_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, return 0; if (!bp_tb[IFLA_BRPORT_LEARNING_SYNC]) return -EINVAL; + if (!(priv->brport_hw_features & BR_LEARNING_SYNC)) { + NL_SET_ERR_MSG_ATTR(extack, bp_tb[IFLA_BRPORT_LEARNING_SYNC], + "Operation not supported by HW"); + return -EOPNOTSUPP; + } + if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) { + NL_SET_ERR_MSG_ATTR(extack, bp_tb[IFLA_BRPORT_LEARNING_SYNC], + "Requires NET_SWITCHDEV"); + return -EOPNOTSUPP; + } enable = !!nla_get_u8(bp_tb[IFLA_BRPORT_LEARNING_SYNC]); if (enable == !!(priv->brport_features & BR_LEARNING_SYNC)) diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index d58bf79892f2..9da9b2b2a580 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -856,10 +856,7 @@ void zfcp_scsi_set_prot(struct zfcp_adapter *adapter) */ void zfcp_scsi_dif_sense_error(struct scsi_cmnd *scmd, int ascq) { - scsi_build_sense_buffer(1, scmd->sense_buffer, - ILLEGAL_REQUEST, 0x10, ascq); - set_driver_byte(scmd, DRIVER_SENSE); - scmd->result |= SAM_STAT_CHECK_CONDITION; + scsi_build_sense(scmd, 1, ILLEGAL_REQUEST, 0x10, ascq); set_host_byte(scmd, DID_SOFT_ERROR); } |