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