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