linux/drivers/s390/cio/eadm_sch.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Driver for s390 eadm subchannels
   4 *
   5 * Copyright IBM Corp. 2012
   6 * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com>
   7 */
   8
   9#include <linux/kernel_stat.h>
  10#include <linux/completion.h>
  11#include <linux/workqueue.h>
  12#include <linux/spinlock.h>
  13#include <linux/device.h>
  14#include <linux/module.h>
  15#include <linux/timer.h>
  16#include <linux/slab.h>
  17#include <linux/list.h>
  18
  19#include <asm/css_chars.h>
  20#include <asm/debug.h>
  21#include <asm/isc.h>
  22#include <asm/cio.h>
  23#include <asm/scsw.h>
  24#include <asm/eadm.h>
  25
  26#include "eadm_sch.h"
  27#include "ioasm.h"
  28#include "cio.h"
  29#include "css.h"
  30#include "orb.h"
  31
  32MODULE_DESCRIPTION("driver for s390 eadm subchannels");
  33MODULE_LICENSE("GPL");
  34
  35#define EADM_TIMEOUT (7 * HZ)
  36static DEFINE_SPINLOCK(list_lock);
  37static LIST_HEAD(eadm_list);
  38
  39static debug_info_t *eadm_debug;
  40
  41#define EADM_LOG(imp, txt) do {                                 \
  42                debug_text_event(eadm_debug, imp, txt);         \
  43        } while (0)
  44
  45static void EADM_LOG_HEX(int level, void *data, int length)
  46{
  47        debug_event(eadm_debug, level, data, length);
  48}
  49
  50static void orb_init(union orb *orb)
  51{
  52        memset(orb, 0, sizeof(union orb));
  53        orb->eadm.compat1 = 1;
  54        orb->eadm.compat2 = 1;
  55        orb->eadm.fmt = 1;
  56        orb->eadm.x = 1;
  57}
  58
  59static int eadm_subchannel_start(struct subchannel *sch, struct aob *aob)
  60{
  61        union orb *orb = &get_eadm_private(sch)->orb;
  62        int cc;
  63
  64        orb_init(orb);
  65        orb->eadm.aob = (u32)__pa(aob);
  66        orb->eadm.intparm = (u32)(addr_t)sch;
  67        orb->eadm.key = PAGE_DEFAULT_KEY >> 4;
  68
  69        EADM_LOG(6, "start");
  70        EADM_LOG_HEX(6, &sch->schid, sizeof(sch->schid));
  71
  72        cc = ssch(sch->schid, orb);
  73        switch (cc) {
  74        case 0:
  75                sch->schib.scsw.eadm.actl |= SCSW_ACTL_START_PEND;
  76                break;
  77        case 1:         /* status pending */
  78        case 2:         /* busy */
  79                return -EBUSY;
  80        case 3:         /* not operational */
  81                return -ENODEV;
  82        }
  83        return 0;
  84}
  85
  86static int eadm_subchannel_clear(struct subchannel *sch)
  87{
  88        int cc;
  89
  90        cc = csch(sch->schid);
  91        if (cc)
  92                return -ENODEV;
  93
  94        sch->schib.scsw.eadm.actl |= SCSW_ACTL_CLEAR_PEND;
  95        return 0;
  96}
  97
  98static void eadm_subchannel_timeout(struct timer_list *t)
  99{
 100        struct eadm_private *private = from_timer(private, t, timer);
 101        struct subchannel *sch = private->sch;
 102
 103        spin_lock_irq(sch->lock);
 104        EADM_LOG(1, "timeout");
 105        EADM_LOG_HEX(1, &sch->schid, sizeof(sch->schid));
 106        if (eadm_subchannel_clear(sch))
 107                EADM_LOG(0, "clear failed");
 108        spin_unlock_irq(sch->lock);
 109}
 110
 111static void eadm_subchannel_set_timeout(struct subchannel *sch, int expires)
 112{
 113        struct eadm_private *private = get_eadm_private(sch);
 114
 115        if (expires == 0) {
 116                del_timer(&private->timer);
 117                return;
 118        }
 119        if (timer_pending(&private->timer)) {
 120                if (mod_timer(&private->timer, jiffies + expires))
 121                        return;
 122        }
 123        private->timer.expires = jiffies + expires;
 124        add_timer(&private->timer);
 125}
 126
 127static void eadm_subchannel_irq(struct subchannel *sch)
 128{
 129        struct eadm_private *private = get_eadm_private(sch);
 130        struct eadm_scsw *scsw = &sch->schib.scsw.eadm;
 131        struct irb *irb = this_cpu_ptr(&cio_irb);
 132        blk_status_t error = BLK_STS_OK;
 133
 134        EADM_LOG(6, "irq");
 135        EADM_LOG_HEX(6, irb, sizeof(*irb));
 136
 137        inc_irq_stat(IRQIO_ADM);
 138
 139        if ((scsw->stctl & (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))
 140            && scsw->eswf == 1 && irb->esw.eadm.erw.r)
 141                error = BLK_STS_IOERR;
 142
 143        if (scsw->fctl & SCSW_FCTL_CLEAR_FUNC)
 144                error = BLK_STS_TIMEOUT;
 145
 146        eadm_subchannel_set_timeout(sch, 0);
 147
 148        if (private->state != EADM_BUSY) {
 149                EADM_LOG(1, "irq unsol");
 150                EADM_LOG_HEX(1, irb, sizeof(*irb));
 151                private->state = EADM_NOT_OPER;
 152                css_sched_sch_todo(sch, SCH_TODO_EVAL);
 153                return;
 154        }
 155        scm_irq_handler((struct aob *)(unsigned long)scsw->aob, error);
 156        private->state = EADM_IDLE;
 157
 158        if (private->completion)
 159                complete(private->completion);
 160}
 161
 162static struct subchannel *eadm_get_idle_sch(void)
 163{
 164        struct eadm_private *private;
 165        struct subchannel *sch;
 166        unsigned long flags;
 167
 168        spin_lock_irqsave(&list_lock, flags);
 169        list_for_each_entry(private, &eadm_list, head) {
 170                sch = private->sch;
 171                spin_lock(sch->lock);
 172                if (private->state == EADM_IDLE) {
 173                        private->state = EADM_BUSY;
 174                        list_move_tail(&private->head, &eadm_list);
 175                        spin_unlock(sch->lock);
 176                        spin_unlock_irqrestore(&list_lock, flags);
 177
 178                        return sch;
 179                }
 180                spin_unlock(sch->lock);
 181        }
 182        spin_unlock_irqrestore(&list_lock, flags);
 183
 184        return NULL;
 185}
 186
 187int eadm_start_aob(struct aob *aob)
 188{
 189        struct eadm_private *private;
 190        struct subchannel *sch;
 191        unsigned long flags;
 192        int ret;
 193
 194        sch = eadm_get_idle_sch();
 195        if (!sch)
 196                return -EBUSY;
 197
 198        spin_lock_irqsave(sch->lock, flags);
 199        eadm_subchannel_set_timeout(sch, EADM_TIMEOUT);
 200        ret = eadm_subchannel_start(sch, aob);
 201        if (!ret)
 202                goto out_unlock;
 203
 204        /* Handle start subchannel failure. */
 205        eadm_subchannel_set_timeout(sch, 0);
 206        private = get_eadm_private(sch);
 207        private->state = EADM_NOT_OPER;
 208        css_sched_sch_todo(sch, SCH_TODO_EVAL);
 209
 210out_unlock:
 211        spin_unlock_irqrestore(sch->lock, flags);
 212
 213        return ret;
 214}
 215EXPORT_SYMBOL_GPL(eadm_start_aob);
 216
 217static int eadm_subchannel_probe(struct subchannel *sch)
 218{
 219        struct eadm_private *private;
 220        int ret;
 221
 222        private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
 223        if (!private)
 224                return -ENOMEM;
 225
 226        INIT_LIST_HEAD(&private->head);
 227        timer_setup(&private->timer, eadm_subchannel_timeout, 0);
 228
 229        spin_lock_irq(sch->lock);
 230        set_eadm_private(sch, private);
 231        private->state = EADM_IDLE;
 232        private->sch = sch;
 233        sch->isc = EADM_SCH_ISC;
 234        ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
 235        if (ret) {
 236                set_eadm_private(sch, NULL);
 237                spin_unlock_irq(sch->lock);
 238                kfree(private);
 239                goto out;
 240        }
 241        spin_unlock_irq(sch->lock);
 242
 243        spin_lock_irq(&list_lock);
 244        list_add(&private->head, &eadm_list);
 245        spin_unlock_irq(&list_lock);
 246
 247        if (dev_get_uevent_suppress(&sch->dev)) {
 248                dev_set_uevent_suppress(&sch->dev, 0);
 249                kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
 250        }
 251out:
 252        return ret;
 253}
 254
 255static void eadm_quiesce(struct subchannel *sch)
 256{
 257        struct eadm_private *private = get_eadm_private(sch);
 258        DECLARE_COMPLETION_ONSTACK(completion);
 259        int ret;
 260
 261        spin_lock_irq(sch->lock);
 262        if (private->state != EADM_BUSY)
 263                goto disable;
 264
 265        if (eadm_subchannel_clear(sch))
 266                goto disable;
 267
 268        private->completion = &completion;
 269        spin_unlock_irq(sch->lock);
 270
 271        wait_for_completion_io(&completion);
 272
 273        spin_lock_irq(sch->lock);
 274        private->completion = NULL;
 275
 276disable:
 277        eadm_subchannel_set_timeout(sch, 0);
 278        do {
 279                ret = cio_disable_subchannel(sch);
 280        } while (ret == -EBUSY);
 281
 282        spin_unlock_irq(sch->lock);
 283}
 284
 285static int eadm_subchannel_remove(struct subchannel *sch)
 286{
 287        struct eadm_private *private = get_eadm_private(sch);
 288
 289        spin_lock_irq(&list_lock);
 290        list_del(&private->head);
 291        spin_unlock_irq(&list_lock);
 292
 293        eadm_quiesce(sch);
 294
 295        spin_lock_irq(sch->lock);
 296        set_eadm_private(sch, NULL);
 297        spin_unlock_irq(sch->lock);
 298
 299        kfree(private);
 300
 301        return 0;
 302}
 303
 304static void eadm_subchannel_shutdown(struct subchannel *sch)
 305{
 306        eadm_quiesce(sch);
 307}
 308
 309/**
 310 * eadm_subchannel_sch_event - process subchannel event
 311 * @sch: subchannel
 312 * @process: non-zero if function is called in process context
 313 *
 314 * An unspecified event occurred for this subchannel. Adjust data according
 315 * to the current operational state of the subchannel. Return zero when the
 316 * event has been handled sufficiently or -EAGAIN when this function should
 317 * be called again in process context.
 318 */
 319static int eadm_subchannel_sch_event(struct subchannel *sch, int process)
 320{
 321        struct eadm_private *private;
 322        unsigned long flags;
 323
 324        spin_lock_irqsave(sch->lock, flags);
 325        if (!device_is_registered(&sch->dev))
 326                goto out_unlock;
 327
 328        if (work_pending(&sch->todo_work))
 329                goto out_unlock;
 330
 331        if (cio_update_schib(sch)) {
 332                css_sched_sch_todo(sch, SCH_TODO_UNREG);
 333                goto out_unlock;
 334        }
 335        private = get_eadm_private(sch);
 336        if (private->state == EADM_NOT_OPER)
 337                private->state = EADM_IDLE;
 338
 339out_unlock:
 340        spin_unlock_irqrestore(sch->lock, flags);
 341
 342        return 0;
 343}
 344
 345static struct css_device_id eadm_subchannel_ids[] = {
 346        { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_ADM, },
 347        { /* end of list */ },
 348};
 349MODULE_DEVICE_TABLE(css, eadm_subchannel_ids);
 350
 351static struct css_driver eadm_subchannel_driver = {
 352        .drv = {
 353                .name = "eadm_subchannel",
 354                .owner = THIS_MODULE,
 355        },
 356        .subchannel_type = eadm_subchannel_ids,
 357        .irq = eadm_subchannel_irq,
 358        .probe = eadm_subchannel_probe,
 359        .remove = eadm_subchannel_remove,
 360        .shutdown = eadm_subchannel_shutdown,
 361        .sch_event = eadm_subchannel_sch_event,
 362};
 363
 364static int __init eadm_sch_init(void)
 365{
 366        int ret;
 367
 368        if (!css_general_characteristics.eadm)
 369                return -ENXIO;
 370
 371        eadm_debug = debug_register("eadm_log", 16, 1, 16);
 372        if (!eadm_debug)
 373                return -ENOMEM;
 374
 375        debug_register_view(eadm_debug, &debug_hex_ascii_view);
 376        debug_set_level(eadm_debug, 2);
 377
 378        isc_register(EADM_SCH_ISC);
 379        ret = css_driver_register(&eadm_subchannel_driver);
 380        if (ret)
 381                goto cleanup;
 382
 383        return ret;
 384
 385cleanup:
 386        isc_unregister(EADM_SCH_ISC);
 387        debug_unregister(eadm_debug);
 388        return ret;
 389}
 390
 391static void __exit eadm_sch_exit(void)
 392{
 393        css_driver_unregister(&eadm_subchannel_driver);
 394        isc_unregister(EADM_SCH_ISC);
 395        debug_unregister(eadm_debug);
 396}
 397module_init(eadm_sch_init);
 398module_exit(eadm_sch_exit);
 399