Messages in this thread Patch in this message | | | From | Martin Schwidefsky <> | Subject | [PATCH] s390 (2/13): common i/o layer. | Date | Mon, 24 Feb 2003 19:07:54 +0100 |
| |
updates for the channel subsystem and qdio driver
This adds the missing support for chp machine checks, i.e. enabling or disabling a set of devices from the service element. Some minor bugs in the driver are fixed as well.
diff -urN linux-2.5.62/drivers/s390/cio/ccwgroup.c linux-2.5.62-s390/drivers/s390/cio/ccwgroup.c --- linux-2.5.62/drivers/s390/cio/ccwgroup.c Mon Feb 17 23:56:16 2003 +++ linux-2.5.62-s390/drivers/s390/cio/ccwgroup.c Mon Feb 24 18:18:38 2003 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/ccwgroup.c * bus driver for ccwgroup - * $Revision: 1.5 $ + * $Revision: 1.6 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation diff -urN linux-2.5.62/drivers/s390/cio/chsc.c linux-2.5.62-s390/drivers/s390/cio/chsc.c --- linux-2.5.62/drivers/s390/cio/chsc.c Mon Feb 24 18:17:44 2003 +++ linux-2.5.62-s390/drivers/s390/cio/chsc.c Mon Feb 24 18:23:32 2003 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/chsc.c * S/390 common I/O routines -- channel subsystem call - * $Revision: 1.46 $ + * $Revision: 1.57 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -53,12 +53,6 @@ return test_bit (sch->schib.pmcw.chpid[chp], chpids_logical); } -static inline void -chsc_clear_chpid(struct subchannel *sch, int chp) -{ - clear_bit(sch->schib.pmcw.chpid[chp], chpids); -} - void chsc_validate_chpids(struct subchannel *sch) { @@ -69,17 +63,10 @@ for (chp = 0; chp <= 7; chp++) { mask = 0x80 >> chp; - if (sch->lpm & mask) { + if (sch->lpm & mask) if (!chsc_chpid_logical(sch, chp)) /* disable using this path */ sch->lpm &= ~mask; - } else { - /* This chpid is not - * available to us */ - chsc_clear_chpid(sch, chp); - if (test_bit(chp, chpids_known)) - set_chp_status(chp, CHP_STANDBY); - } } } @@ -278,6 +265,7 @@ sch = ioinfo[irq]; if (sch == NULL) continue; /* we don't know the device anyway */ + /* FIXME: Kill pending I/O. */ s390_subchannel_remove_chpid(sch, chpid); } #endif @@ -381,6 +369,7 @@ continue; } + /* FIXME: Kill pending I/O. */ spin_lock_irq(&sch->lock); chp_mask = s390_process_res_acc_sch(chpid, fla, fla_mask, sch); @@ -413,7 +402,7 @@ static void do_process_crw(void *ignore) { - int ccode; + int do_sei; /* * build the chsc request block for store event information @@ -438,94 +427,212 @@ CIO_TRACE_EVENT( 2, "prcss"); - ccode = chsc(&chsc_area_sei); - if (ccode > 0) - return; + do_sei = 1; - switch (chsc_area_sei.response_block.response_code) { - /* for debug purposes, check for problems */ - case 0x0001: - break; /* everything ok */ - case 0x0002: - CIO_CRW_EVENT(2, "chsc_process_crw:invalid command!\n"); - case 0x0003: - CIO_CRW_EVENT(2, "chsc_process_crw: error in chsc " - "request block!\n"); - return; - case 0x0005: - CIO_CRW_EVENT(2, "chsc_process_crw: no event information " - "stored\n"); - return; - default: - CIO_CRW_EVENT(2, "chsc_process_crw: chsc response %d\n", - chsc_area_sei.response_block.response_code); - return; - } + while (do_sei) { + int ccode; - CIO_CRW_EVENT(4, "chsc_process_crw: event information successfully " - "stored\n"); + ccode = chsc(&chsc_area_sei); + if (ccode > 0) + return; + + switch (sei_res->response_code) { + /* for debug purposes, check for problems */ + case 0x0001: + break; /* everything ok */ + case 0x0002: + CIO_CRW_EVENT(2, + "chsc_process_crw: invalid command!\n"); + return; + case 0x0003: + CIO_CRW_EVENT(2, "chsc_process_crw: error in chsc " + "request block!\n"); + return; + case 0x0005: + CIO_CRW_EVENT(2, "chsc_process_crw: no event " + "information stored\n"); + return; + default: + CIO_CRW_EVENT(2, "chsc_process_crw: chsc response %d\n", + sei_res->response_code); + return; + } + + CIO_CRW_EVENT(4, "chsc_process_crw: event information " + "successfully stored\n"); + + /* Check if there is more event information pending. */ + if (sei_res->flags & 0x80) + CIO_CRW_EVENT( 2, "chsc_process_crw: " + "further event information pending\n"); + else + do_sei = 0; - if (sei_res->rs != 4) { - CIO_CRW_EVENT(2, "chsc_process_crw: " - "reporting source (%04X) isn't a chpid!" - "Aborting processing of machine check...\n", - sei_res->rsid); - return; + /* Check if we might have lost some information. */ + if (sei_res->flags & 0x40) + CIO_CRW_EVENT( 2, "chsc_process_crw: Event information " + "has been lost due to overflow!\n"); + + if (sei_res->rs != 4) { + CIO_CRW_EVENT(2, "chsc_process_crw: reporting source " + "(%04X) isn't a chpid!\n", + sei_res->rsid); + continue; + } + + /* which kind of information was stored? */ + switch (sei_res->cc) { + case 1: /* link incident*/ + CIO_CRW_EVENT(4, "chsc_process_crw: " + "channel subsystem reports link incident," + " source is chpid %x\n", sei_res->rsid); + + s390_set_chpid_offline(sei_res->rsid); + break; + + case 2: /* i/o resource accessibiliy */ + CIO_CRW_EVENT(4, "chsc_process_crw: " + "channel subsystem reports some I/O " + "devices may have become accessible\n"); + pr_debug("Data received after sei: \n"); + pr_debug("Validity flags: %x\n", sei_res->vf); + + /* allocate a new channel path structure, if needed */ + if (chps[sei_res->rsid] == NULL) + new_channel_path(sei_res->rsid, CHP_ONLINE); + else + set_chp_status(sei_res->rsid, CHP_ONLINE); + + if ((sei_res->vf & 0x80) == 0) { + pr_debug("chpid: %x\n", sei_res->rsid); + s390_process_res_acc(sei_res->rsid, 0, 0); + } else if ((sei_res->vf & 0xc0) == 0x80) { + pr_debug("chpid: %x link addr: %x\n", + sei_res->rsid, sei_res->fla); + s390_process_res_acc(sei_res->rsid, + sei_res->fla, 0xff00); + } else if ((sei_res->vf & 0xc0) == 0xc0) { + pr_debug("chpid: %x full link addr: %x\n", + sei_res->rsid, sei_res->fla); + s390_process_res_acc(sei_res->rsid, + sei_res->fla, 0xffff); + } + pr_debug("\n"); + + break; + + default: /* other stuff */ + CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n", + sei_res->cc); + break; + } + if (do_sei) { + memset(&chsc_area_sei, 0, sizeof(struct sei_area)); + chsc_area_sei.request_block.command_code1 = 0x0010; + chsc_area_sei.request_block.command_code2 = 0x000e; + } } +} - /* which kind of information was stored? */ - switch (sei_res->cc) { - case 1: /* link incident*/ - CIO_CRW_EVENT(4, "chsc_process_crw: " - "channel subsystem reports link incident," - " source is chpid %x\n", sei_res->rsid); +void +chsc_process_crw(void) +{ + static DECLARE_WORK(work, do_process_crw, 0); - s390_set_chpid_offline(sei_res->rsid); - break; + schedule_work(&work); +} - case 2: /* i/o resource accessibiliy */ - CIO_CRW_EVENT(4, "chsc_process_crw: " - "channel subsystem reports some I/O " - "devices may have become accessible\n"); - pr_debug( KERN_DEBUG "Data received after sei: \n"); - pr_debug( KERN_DEBUG "Validity flags: %x\n", sei_res->vf); - - /* allocate a new channel path structure, if needed */ - if (chps[sei_res->rsid] == NULL) - new_channel_path(sei_res->rsid, CHP_ONLINE); - else - set_chp_status(sei_res->rsid, CHP_ONLINE); +static void +chp_add(int chpid) +{ + struct subchannel *sch; + int irq, ret; + char dbf_txt[15]; + + if (!test_bit(chpid, chpids_logical)) + return; /* no need to do the rest */ + + sprintf(dbf_txt, "cadd%x", chpid); + CIO_TRACE_EVENT(2, dbf_txt); + + for (irq = 0; irq <= __MAX_SUBCHANNELS; irq++) { + int i; - if ((sei_res->vf & 0x80) == 0) { - pr_debug( KERN_DEBUG "chpid: %x\n", sei_res->rsid); - s390_process_res_acc(sei_res->rsid, 0, 0); - } else if ((sei_res->vf & 0xc0) == 0x80) { - pr_debug( KERN_DEBUG "chpid: %x link addr: %x\n", - sei_res->rsid, sei_res->fla); - s390_process_res_acc(sei_res->rsid, sei_res->fla, - 0xff00); - } else if ((sei_res->vf & 0xc0) == 0xc0) { - pr_debug( KERN_DEBUG "chpid: %x full link addr: %x\n", - sei_res->rsid, sei_res->fla); - s390_process_res_acc(sei_res->rsid, sei_res->fla, - 0xffff); + sch = ioinfo[irq]; + if (!sch) { + ret = css_probe_device(irq); + if (ret == -ENXIO) + /* We're through */ + return; + continue; } - pr_debug( KERN_DEBUG "\n"); + + /* FIXME: Kill pending I/O. */ + spin_lock(&sch->lock); + for (i=0; i<8; i++) + if (sch->schib.pmcw.chpid[i] == chpid) { + if (stsch(sch->irq, &sch->schib) != 0) { + /* Endgame. */ + spin_unlock(&sch->lock); + return; + } + break; + } + if (i==8) { + spin_unlock(&sch->lock); + return; + } + sch->lpm = (sch->schib.pmcw.pim & + sch->schib.pmcw.pam & + sch->schib.pmcw.pom) + | 0x80 >> i; - break; + chsc_validate_chpids(sch); - default: /* other stuff */ - CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n", sei_res->cc); - break; + dev_fsm_event(sch->dev.driver_data, DEV_EVENT_VERIFY); + + spin_unlock(&sch->lock); } } +/* + * Handling of crw machine checks with channel path source. + */ void -chsc_process_crw(void) +chp_process_crw(int chpid) { - static DECLARE_WORK(work, do_process_crw, 0); + /* + * Update our descriptions. We need this since we don't always + * get machine checks for path come and can't rely on our information + * being consistent otherwise. + */ + chsc_get_sch_descriptions(); + if (!cio_chsc_desc_avail) { + /* + * Something went wrong... + * We can't reliably say whether a path was there before. + */ + CIO_CRW_EVENT(0, "Error: Could not retrieve " + "subchannel descriptions, will not process chp" + "machine check...\n"); + return; + } - schedule_work(&work); + if (!test_bit(chpid, chpids)) { + /* Path has gone. We use the link incident routine.*/ + s390_set_chpid_offline(chpid); + } else { + /* + * Path has come. Allocate a new channel path structure, + * if needed. + */ + if (chps[chpid] == NULL) + new_channel_path(chpid, CHP_ONLINE); + else + set_chp_status(chpid, CHP_ONLINE); + /* Avoid the extra overhead in process_rec_acc. */ + chp_add(chpid); + } } /* @@ -608,8 +715,7 @@ static ssize_t chp_status_show(struct device *dev, char *buf) { - struct sys_device *sdev = container_of(dev, struct sys_device, dev); - struct channel_path *chp = container_of(sdev, struct channel_path, sdev); + struct channel_path *chp = container_of(dev, struct channel_path, dev); if (!chp) return 0; @@ -631,8 +737,7 @@ static ssize_t chp_status_write(struct device *dev, const char *buf, size_t count) { - struct sys_device *sdev = container_of(dev, struct sys_device, dev); - struct channel_path *cp = container_of(sdev, struct channel_path, sdev); + struct channel_path *cp = container_of(dev, struct channel_path, dev); char cmd[10]; int num_args; int error; @@ -667,29 +772,29 @@ chp = kmalloc(sizeof(struct channel_path), GFP_KERNEL); if (!chp) return -ENOMEM; + memset(chp, 0, sizeof(struct channel_path)); chps[chpid] = chp; /* fill in status, etc. */ chp->id = chpid; chp->state = status; + chp->dev.parent = &css_bus_device; - snprintf(chp->sdev.dev.name, DEVICE_NAME_SIZE, + snprintf(chp->dev.name, DEVICE_NAME_SIZE, "channel path %x", chpid); - chp->sdev.name = "channel_path"; - - chp->sdev.id = chpid; + snprintf(chp->dev.bus_id, DEVICE_ID_SIZE, "chp%x", chpid); /* make it known to the system */ - ret = sys_device_register(&chp->sdev); + ret = device_register(&chp->dev); if (ret) { printk(KERN_WARNING "%s: could not register %02x\n", __func__, chpid); return ret; } - ret = device_create_file(&chp->sdev.dev, &dev_attr_status); + ret = device_create_file(&chp->dev, &dev_attr_status); if (ret) - sys_device_unregister(&chp->sdev); + device_unregister(&chp->dev); return ret; } diff -urN linux-2.5.62/drivers/s390/cio/chsc.h linux-2.5.62-s390/drivers/s390/cio/chsc.h --- linux-2.5.62/drivers/s390/cio/chsc.h Mon Feb 17 23:56:48 2003 +++ linux-2.5.62-s390/drivers/s390/cio/chsc.h Mon Feb 24 18:18:38 2003 @@ -95,7 +95,7 @@ struct channel_path { int id; int state; - struct sys_device sdev; + struct device dev; }; extern struct channel_path *chps[]; diff -urN linux-2.5.62/drivers/s390/cio/cio.c linux-2.5.62-s390/drivers/s390/cio/cio.c --- linux-2.5.62/drivers/s390/cio/cio.c Mon Feb 17 23:57:18 2003 +++ linux-2.5.62-s390/drivers/s390/cio/cio.c Mon Feb 24 18:18:38 2003 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls - * $Revision: 1.90 $ + * $Revision: 1.91 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -197,8 +197,7 @@ sch->orb.pfch = sch->options.prefetch == 0; sch->orb.spnd = sch->options.suspend; sch->orb.ssic = sch->options.suspend && sch->options.inter; - sch->orb.lpm = (lpm != 0) ? (lpm & sch->lpm) : sch->lpm; - + sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm; #ifdef CONFIG_ARCH_S390X /* * for 64 bit we always support 64 bit IDAWs with 4k page size only diff -urN linux-2.5.62/drivers/s390/cio/device.c linux-2.5.62-s390/drivers/s390/cio/device.c --- linux-2.5.62/drivers/s390/cio/device.c Mon Feb 17 23:56:43 2003 +++ linux-2.5.62-s390/drivers/s390/cio/device.c Mon Feb 24 18:18:38 2003 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/device.c * bus driver for ccw devices - * $Revision: 1.45 $ + * $Revision: 1.50 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -215,6 +215,8 @@ void ccw_device_set_offline(struct ccw_device *cdev) { + int ret; + if (!cdev) return; if (!cdev->online || !cdev->drv) @@ -226,23 +228,36 @@ cdev->online = 0; spin_lock_irq(cdev->ccwlock); - ccw_device_offline(cdev); + ret = ccw_device_offline(cdev); spin_unlock_irq(cdev->ccwlock); - wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); + if (ret == 0) + wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); + else + //FIXME: we can't fail! + pr_debug("ccw_device_offline returned %d, device %s\n", + ret, cdev->dev.bus_id); } void ccw_device_set_online(struct ccw_device *cdev) { - if (!cdev || !cdev->handler) + int ret; + + if (!cdev) return; if (cdev->online || !cdev->drv) return; spin_lock_irq(cdev->ccwlock); - ccw_device_online(cdev); + ret = ccw_device_online(cdev); spin_unlock_irq(cdev->ccwlock); - wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); + if (ret == 0) + wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); + else { + pr_debug("ccw_device_online returned %d, device %s\n", + ret, cdev->dev.bus_id); + return; + } if (cdev->private->state != DEV_STATE_ONLINE) return; if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) { @@ -250,9 +265,13 @@ return; } spin_lock_irq(cdev->ccwlock); - ccw_device_offline(cdev); + ret = ccw_device_offline(cdev); spin_unlock_irq(cdev->ccwlock); - wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); + if (ret == 0) + wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); + else + pr_debug("ccw_device_offline returned %d, device %s\n", + ret, cdev->dev.bus_id); } static ssize_t @@ -574,7 +593,7 @@ * doubled code. * This is safe because of the checks in ccw_device_set_offline. */ - pr_debug(KERN_INFO "removing device %s, sch %d, devno %x\n", + pr_debug("removing device %s, sch %d, devno %x\n", cdev->dev.name, cdev->private->irq, cdev->private->devno); diff -urN linux-2.5.62/drivers/s390/cio/device_id.c linux-2.5.62-s390/drivers/s390/cio/device_id.c --- linux-2.5.62/drivers/s390/cio/device_id.c Mon Feb 17 23:55:48 2003 +++ linux-2.5.62-s390/drivers/s390/cio/device_id.c Mon Feb 24 18:18:38 2003 @@ -136,7 +136,7 @@ ccode = diag210 (&diag_data); ps->reserved = 0xff; - /* Special case for bloddy osa devices. */ + /* Special case for bloody osa devices. */ if (diag_data.vrdcvcla == 0x02 && diag_data.vrdcvtyp == 0x20) { ps->cu_type = 0x3088; diff -urN linux-2.5.62/drivers/s390/cio/device_ops.c linux-2.5.62-s390/drivers/s390/cio/device_ops.c --- linux-2.5.62/drivers/s390/cio/device_ops.c Mon Feb 17 23:56:43 2003 +++ linux-2.5.62-s390/drivers/s390/cio/device_ops.c Mon Feb 24 18:18:38 2003 @@ -48,7 +48,8 @@ if (!cdev) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE && - cdev->private->state != DEV_STATE_W4SENSE) + cdev->private->state != DEV_STATE_W4SENSE && + cdev->private->state != DEV_STATE_QDIO_ACTIVE) return -EINVAL; sch = to_subchannel(cdev->dev.parent); if (!sch) @@ -122,6 +123,15 @@ { struct subchannel *sch; unsigned int stctl; + void (*handler)(struct ccw_device *, unsigned long, struct irb *); + + if (cdev->private->state == DEV_STATE_QDIO_ACTIVE) { + if (cdev->private->qdio_data) + handler = cdev->private->qdio_data->handler; + else + handler = NULL; + } else + handler = cdev->handler; sch = to_subchannel(cdev->dev.parent); @@ -144,13 +154,9 @@ /* * Now we are ready to call the device driver interrupt handler. */ - if (cdev->private->state == DEV_STATE_QDIO_ACTIVE) { - if (cdev->private->qdio_data && - cdev->private->qdio_data->handler) - cdev->private->qdio_data->handler(cdev, sch->u_intparm, - &cdev->private->irb); - } else - cdev->handler (cdev, sch->u_intparm, &cdev->private->irb); + if (handler) + handler(cdev, sch->u_intparm, &cdev->private->irb); + /* * Clear the old and now useless interrupt response block. */ @@ -245,6 +251,8 @@ wait_event(cdev->private->wait_q, sch->schib.scsw.actl == 0); spin_lock_irqsave(&sch->lock, flags); + /* FIXME: Check if we got sensible stuff. */ + break; } } /* Restore interrupt handler. */ @@ -317,6 +325,8 @@ spin_unlock_irqrestore(&sch->lock, flags); wait_event(cdev->private->wait_q, sch->schib.scsw.actl == 0); spin_lock_irqsave(&sch->lock, flags); + /* FIXME: Check if we got sensible stuff. */ + break; } /* Restore interrupt handler. */ cdev->handler = handler; diff -urN linux-2.5.62/drivers/s390/cio/device_pgid.c linux-2.5.62-s390/drivers/s390/cio/device_pgid.c --- linux-2.5.62/drivers/s390/cio/device_pgid.c Mon Feb 17 23:56:16 2003 +++ linux-2.5.62-s390/drivers/s390/cio/device_pgid.c Mon Feb 24 18:18:38 2003 @@ -141,6 +141,8 @@ struct subchannel *sch; struct irb *irb; int ret; + int opm; + int i; irb = (struct irb *) __LC_IRB; /* Ignore unsolicited interrupts. */ @@ -154,6 +156,16 @@ /* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */ case 0: /* Sense Path Group ID successful. */ cdev->private->flags.pgid_supp = 1; + opm = sch->schib.pmcw.pim & + sch->schib.pmcw.pam & + sch->schib.pmcw.pom; + for (i=0;i<8;i++) { + if (opm == (0x80 << i)) { + /* Don't group single path devices. */ + cdev->private->flags.pgid_supp = 0; + break; + } + } if (cdev->private->pgid.inf.ps.state1 == SNID_STATE1_RESET) memcpy(&cdev->private->pgid, &global_pgid, sizeof(struct pgid)); diff -urN linux-2.5.62/drivers/s390/cio/device_status.c linux-2.5.62-s390/drivers/s390/cio/device_status.c --- linux-2.5.62/drivers/s390/cio/device_status.c Mon Feb 17 23:56:14 2003 +++ linux-2.5.62-s390/drivers/s390/cio/device_status.c Mon Feb 24 18:18:38 2003 @@ -62,8 +62,9 @@ sch = to_subchannel(cdev->dev.parent); stsch (sch->irq, &sch->schib); - CIO_MSG_EVENT(0, "cio_process_irq(%04X) - path(s) %02x are " - "not operational ", sch->irq, sch->schib.pmcw.pnom); + CIO_MSG_EVENT(0, "%s(%04X) - path(s) %02x are " + "not operational \n", __FUNCTION__, sch->irq, + sch->schib.pmcw.pnom); sch->lpm &= ~sch->schib.pmcw.pnom; dev_fsm_event(cdev, DEV_EVENT_VERIFY); @@ -289,7 +290,7 @@ sch = to_subchannel(cdev->dev.parent); /* A sense is required, can we do it now ? */ - if (irb->scsw.actl != 0) + if ((irb->scsw.actl & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0) /* * we received an Unit Check but we have no final * status yet, therefore we must delay the SENSE @@ -348,7 +349,7 @@ ccw_device_accumulate_and_sense(struct ccw_device *cdev, struct irb *irb) { ccw_device_accumulate_irb(cdev, irb); - if (irb->scsw.actl != 0) + if ((irb->scsw.actl & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0) return -EBUSY; /* Check for basic sense. */ if (cdev->private->flags.dosense && diff -urN linux-2.5.62/drivers/s390/cio/ioasm.h linux-2.5.62-s390/drivers/s390/cio/ioasm.h --- linux-2.5.62/drivers/s390/cio/ioasm.h Mon Feb 17 23:57:22 2003 +++ linux-2.5.62-s390/drivers/s390/cio/ioasm.h Mon Feb 24 18:18:38 2003 @@ -2,83 +2,6 @@ #define S390_CIO_IOASM_H /* - * area for channel subsystem call - */ -struct chsc_area { - struct { - /* word 0 */ - __u16 command_code1; - __u16 command_code2; - union { - struct { - /* word 1 */ - __u32 reserved1; - /* word 2 */ - __u32 reserved2; - } __attribute__ ((packed,aligned(8))) sei_req; - struct { - /* word 1 */ - __u16 reserved1; - __u16 f_sch; /* first subchannel */ - /* word 2 */ - __u16 reserved2; - __u16 l_sch; /* last subchannel */ - } __attribute__ ((packed,aligned(8))) ssd_req; - } request_block_data; - /* word 3 */ - __u32 reserved3; - } __attribute__ ((packed,aligned(8))) request_block; - struct { - /* word 0 */ - __u16 length; - __u16 response_code; - /* word 1 */ - __u32 reserved1; - union { - struct { - /* word 2 */ - __u8 flags; - __u8 vf; /* validity flags */ - __u8 rs; /* reporting source */ - __u8 cc; /* content code */ - /* word 3 */ - __u16 fla; /* full link address */ - __u16 rsid; /* reporting source id */ - /* word 4 */ - __u32 reserved2; - /* word 5 */ - __u32 reserved3; - /* word 6 */ - __u32 ccdf; /* content-code dependent field */ - /* word 7 */ - __u32 reserved4; - /* word 8 */ - __u32 reserved5; - /* word 9 */ - __u32 reserved6; - } __attribute__ ((packed,aligned(8))) sei_res; - struct { - /* word 2 */ - __u8 sch_valid : 1; - __u8 dev_valid : 1; - __u8 st : 3; /* subchannel type */ - __u8 zeroes : 3; - __u8 unit_addr; /* unit address */ - __u16 devno; /* device number */ - /* word 3 */ - __u8 path_mask; - __u8 fla_valid_mask; - __u16 sch; /* subchannel */ - /* words 4-5 */ - __u8 chpid[8]; /* chpids 0-7 */ - /* words 6-9 */ - __u16 fla[8]; /* full link addresses 0-7 */ - } __attribute__ ((packed,aligned(8))) ssd_res; - } response_block_data; - } __attribute__ ((packed,aligned(8))) response_block; -} __attribute__ ((packed,aligned(PAGE_SIZE))); - -/* * TPI info structure */ struct tpi_info { diff -urN linux-2.5.62/drivers/s390/cio/qdio.c linux-2.5.62-s390/drivers/s390/cio/qdio.c --- linux-2.5.62/drivers/s390/cio/qdio.c Mon Feb 17 23:56:19 2003 +++ linux-2.5.62-s390/drivers/s390/cio/qdio.c Mon Feb 24 18:18:38 2003 @@ -55,7 +55,7 @@ #include "qdio.h" #include "ioasm.h" -#define VERSION_QDIO_C "$Revision: 1.18 $" +#define VERSION_QDIO_C "$Revision: 1.34 $" /****************** MODULE PARAMETER VARIABLES ********************/ MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>"); @@ -87,8 +87,6 @@ static debug_info_t *qdio_dbf_slsb_in; #endif /* QDIO_DBF_LIKE_HELL */ -static struct semaphore init_sema; - static struct qdio_chsc_area *chsc_area; /* iQDIO stuff: */ static volatile struct qdio_q *iq_list=NULL; /* volatile as it could change @@ -752,7 +750,7 @@ #endif /* QDIO_DBF_LIKE_HELL */ if (q->state==QDIO_IRQ_STATE_ACTIVE) - q->handler(q->irq, + q->handler(q->cdev, QDIO_STATUS_INBOUND_INT|q->error_status_flags, q->qdio_error,q->siga_error,q->q_no,start,count, q->int_parm); @@ -1039,7 +1037,7 @@ #endif /* QDIO_DBF_LIKE_HELL */ if (q->state==QDIO_IRQ_STATE_ACTIVE) - q->handler(q->irq,QDIO_STATUS_OUTBOUND_INT| + q->handler(q->cdev,QDIO_STATUS_OUTBOUND_INT| q->error_status_flags, q->qdio_error,q->siga_error,q->q_no,start,count, q->int_parm); @@ -1283,7 +1281,8 @@ } static int -qdio_alloc_qs(struct qdio_irq *irq_ptr, int no_input_qs, int no_output_qs, +qdio_alloc_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, + int no_input_qs, int no_output_qs, qdio_handler_t *input_handler, qdio_handler_t *output_handler, unsigned long int_parm,int q_format, @@ -1327,6 +1326,7 @@ q->int_parm=int_parm; irq_ptr->input_qs[i]=q; q->irq=irq_ptr->irq; + q->cdev = cdev; q->mask=1<<(31-i); q->q_no=i; q->is_input_q=1; @@ -1403,6 +1403,7 @@ irq_ptr->output_qs[i]=q; q->is_input_q=0; q->irq=irq_ptr->irq; + q->cdev = cdev; q->mask=1<<(31-i); q->q_no=i; q->first_to_check=0; @@ -1626,7 +1627,7 @@ "device %s!?\n", cdev->dev.bus_id); goto omit_handler_call; } - q->handler(q->irq,QDIO_STATUS_ACTIVATE_CHECK_CONDITION| + q->handler(q->cdev,QDIO_STATUS_ACTIVATE_CHECK_CONDITION| QDIO_STATUS_LOOK_FOR_ERROR, 0,0,0,-1,-1,q->int_parm); omit_handler_call: @@ -1636,7 +1637,6 @@ } -/* this is for mp3 */ int qdio_synchronize(struct ccw_device *cdev, unsigned int flags, unsigned int queue_number) @@ -1882,10 +1882,8 @@ qdio_cleanup(struct ccw_device *cdev, int how) { struct qdio_irq *irq_ptr; - int i,result; - unsigned long flags; - int timeout; - char dbf_text[15]="12345678"; + char dbf_text[15]; + int rc; irq_ptr = cdev->private->qdio_data; if (!irq_ptr) @@ -1895,9 +1893,31 @@ QDIO_DBF_TEXT1(0,trace,dbf_text); QDIO_DBF_TEXT0(0,setup,dbf_text); - spin_lock(&irq_ptr->setting_up_lock); + rc = qdio_shutdown(cdev, how); + if (rc == 0) + rc = qdio_free(cdev); + return rc; +} - result=0; +int +qdio_shutdown(struct ccw_device *cdev, int how) +{ + struct qdio_irq *irq_ptr; + int i; + int result = 0; + unsigned long flags; + int timeout; + char dbf_text[15]="12345678"; + + irq_ptr = cdev->private->qdio_data; + if (!irq_ptr) + return -ENODEV; + + down(&irq_ptr->setting_up_sema); + + sprintf(dbf_text,"qsqs%4x",irq_ptr->irq); + QDIO_DBF_TEXT1(0,trace,dbf_text); + QDIO_DBF_TEXT0(0,setup,dbf_text); /* mark all qs as uninteresting */ for (i=0;i<irq_ptr->no_input_qs;i++) @@ -1913,6 +1933,13 @@ tasklet_kill(&irq_ptr->input_qs[i]->tasklet); if (qdio_wait_for_no_use_count(&irq_ptr->input_qs[i]-> use_count)) + /* + * FIXME: + * nobody cares about such retval, + * does a timeout make sense at all? + * can this case be eliminated? + * mutex should be released anyway, shouldn't it? + */ result=-EINPROGRESS; } @@ -1920,9 +1947,19 @@ tasklet_kill(&irq_ptr->output_qs[i]->tasklet); if (qdio_wait_for_no_use_count(&irq_ptr->output_qs[i]-> use_count)) + /* + * FIXME: + * nobody cares about such retval, + * does a timeout make sense at all? + * can this case be eliminated? + * mutex should be released anyway, shouldn't it? + */ result=-EINPROGRESS; } + if (result) + goto out; + /* cleanup subchannel */ spin_lock_irqsave(get_ccwdev_lock(cdev),flags); if (how&QDIO_FLAG_CLEANUP_USING_CLEAR) { @@ -1940,7 +1977,10 @@ spin_unlock_irqrestore(get_ccwdev_lock(cdev),flags); wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); - return 0; + +out: + up(&irq_ptr->setting_up_sema); + return result; } static inline void @@ -1955,6 +1995,34 @@ qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE); } +int +qdio_free(struct ccw_device *cdev) +{ + struct qdio_irq *irq_ptr; + char dbf_text[15]; + + irq_ptr = cdev->private->qdio_data; + if (!irq_ptr) + return -ENODEV; + + down(&irq_ptr->setting_up_sema); + + sprintf(dbf_text,"qfqs%4x",irq_ptr->irq); + QDIO_DBF_TEXT1(0,trace,dbf_text); + QDIO_DBF_TEXT0(0,setup,dbf_text); + + if (cdev->private->state != DEV_STATE_ONLINE) + return -EINVAL; + + qdio_cleanup_finish(irq_ptr); + cdev->private->qdio_data = 0; + + up(&irq_ptr->setting_up_sema); + + qdio_release_irq_memory(irq_ptr); + return 0; +} + static void qdio_cleanup_handle_timeout(struct ccw_device *cdev) { @@ -1967,14 +2035,8 @@ QDIO_PRINT_INFO("Did not get interrupt on cleanup, irq=0x%x.\n", irq_ptr->irq); - qdio_cleanup_finish(irq_ptr); - spin_unlock_irqrestore(get_ccwdev_lock(cdev),flags); - spin_unlock(&irq_ptr->setting_up_lock); - - cdev->private->qdio_data = 0; - qdio_release_irq_memory(irq_ptr); cdev->private->state = DEV_STATE_ONLINE; wake_up(&cdev->private->wait_q); } @@ -1984,10 +2046,6 @@ struct irb *irb) { struct qdio_irq *irq_ptr; - int cstat,dstat; - - cstat = irb->scsw.cstat; - dstat = irb->scsw.dstat; if (intparm == 0) QDIO_PRINT_WARN("Got unsolicited interrupt on cleanup " @@ -1997,22 +2055,16 @@ qdio_irq_check_sense(irq_ptr->irq, irb); - qdio_cleanup_finish(irq_ptr); - - spin_unlock(&irq_ptr->setting_up_lock); - - cdev->private->qdio_data = 0; - qdio_release_irq_memory(irq_ptr); cdev->private->state = DEV_STATE_ONLINE; wake_up(&cdev->private->wait_q); } static inline void -qdio_initialize_do_dbf(struct qdio_initialize *init_data) +qdio_allocate_do_dbf(struct qdio_initialize *init_data) { char dbf_text[20]; /* if a printf would print out more than 8 chars */ - sprintf(dbf_text,"qini%4x",init_data->cdev->private->irq); + sprintf(dbf_text,"qalc%4x",init_data->cdev->private->irq); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,trace,dbf_text); sprintf(dbf_text,"qfmt:%x",init_data->q_format); @@ -2045,7 +2097,7 @@ } static inline void -qdio_initialize_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt) +qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt) { irq_ptr->input_qs[i]->is_iqdio_q = iqfmt; @@ -2063,8 +2115,8 @@ } static inline void -qdio_initialize_fill_output_desc(struct qdio_irq *irq_ptr, int i, - int j, int iqfmt) +qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i, + int j, int iqfmt) { irq_ptr->output_qs[i]->is_iqdio_q = iqfmt; @@ -2092,10 +2144,13 @@ QDIO_PRINT_ERR("establish queues on irq %04x: timed out\n", irq_ptr->irq); QDIO_DBF_TEXT2(1,setup,"eq:timeo"); - spin_unlock(&irq_ptr->setting_up_lock); - qdio_cleanup(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR); - - up(&init_sema); + /* + * FIXME: + * this is broken, + * we are in the context of a timer interrupt and + * qdio_shutdown calls schedule + */ + qdio_shutdown(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR); } static inline void @@ -2163,9 +2218,13 @@ QDIO_PRINT_ERR("establish queues on irq %04x: didn't get " "device end: dstat=%02x, cstat=%02x\n", irq_ptr->irq, dstat, cstat); - spin_unlock(&irq_ptr->setting_up_lock); - qdio_cleanup(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR); - up(&init_sema); + /* + * FIXME: + * this is broken, + * we are probably in the context of an i/o interrupt and + * qdio_shutdown calls schedule + */ + qdio_shutdown(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR); return 1; } @@ -2178,9 +2237,6 @@ "cstat=%02x\n", irq_ptr->irq, dstat, cstat); cdev->private->state = DEV_STATE_ONLINE; - spin_unlock(&irq_ptr->setting_up_lock); - - up(&init_sema); return 1; } return 0; @@ -2202,7 +2258,7 @@ if (intparm == 0) { QDIO_PRINT_WARN("Got unsolicited interrupt on establish " "queues (irq 0x%x).\n", cdev->private->irq); - goto out; + return; } qdio_irq_check_sense(irq_ptr->irq, irb); @@ -2231,46 +2287,51 @@ qdio_initialize_set_siga_flags_output(irq_ptr); qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ESTABLISHED); +} - out: - if (irq_ptr) - spin_unlock(&irq_ptr->setting_up_lock); +int +qdio_initialize(struct qdio_initialize *init_data) +{ + int rc; + char dbf_text[15]; + + sprintf(dbf_text,"qini%4x",init_data->cdev->private->irq); + QDIO_DBF_TEXT0(0,setup,dbf_text); + QDIO_DBF_TEXT0(0,trace,dbf_text); - up(&init_sema); + rc = qdio_allocate(init_data); + if (rc == 0) { + rc = qdio_establish(init_data->cdev); + if (rc != 0) + qdio_free(init_data->cdev); + } + return rc; } + int -qdio_initialize(struct qdio_initialize *init_data) +qdio_allocate(struct qdio_initialize *init_data) { int i; - unsigned long saveflags; struct qdio_irq *irq_ptr; struct ciw *ciw; - int result,result2; + int result; int is_iqdio; - char dbf_text[20]; /* if a printf would print out more than 8 chars */ - - down_interruptible(&init_sema); if ( (init_data->no_input_qs>QDIO_MAX_QUEUES_PER_IRQ) || (init_data->no_output_qs>QDIO_MAX_QUEUES_PER_IRQ) || ((init_data->no_input_qs) && (!init_data->input_handler)) || - ((init_data->no_output_qs) && (!init_data->output_handler)) ) { - result=-EINVAL; - goto out; - } + ((init_data->no_output_qs) && (!init_data->output_handler)) ) + return -EINVAL; - if (!init_data->input_sbal_addr_array) { - result=-EINVAL; - goto out; - } - if (!init_data->output_sbal_addr_array) { - result=-EINVAL; - goto out; - } + if (!init_data->input_sbal_addr_array) + return -EINVAL; + + if (!init_data->output_sbal_addr_array) + return -EINVAL; - qdio_initialize_do_dbf(init_data); + qdio_allocate_do_dbf(init_data); /* create irq */ irq_ptr=kmalloc(sizeof(struct qdio_irq),GFP_DMA); @@ -2280,8 +2341,7 @@ if (!irq_ptr) { QDIO_PRINT_ERR("kmalloc of irq_ptr failed!\n"); - result=-ENOMEM; - goto out; + return -ENOMEM; } memset(irq_ptr,0,sizeof(struct qdio_irq)); @@ -2292,8 +2352,7 @@ kfree(irq_ptr->qdr); kfree(irq_ptr); QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n"); - result=-ENOMEM; - goto out; + return -ENOMEM; } memset(irq_ptr->qdr,0,sizeof(struct qdr)); QDIO_DBF_TEXT0(0,setup,"qdr:"); @@ -2313,9 +2372,13 @@ if (!irq_ptr->dev_st_chg_ind) { QDIO_PRINT_WARN("no indicator location available " \ "for irq 0x%x\n",irq_ptr->irq); + /* + * FIXME: + * qdio_release_irq_memory does MOD_DEC_USE_COUNT + * in an unbalanced fashion (see 30 lines farther down) + */ qdio_release_irq_memory(irq_ptr); - result=-ENOBUFS; - goto out; + return -ENOBUFS; } } @@ -2325,26 +2388,29 @@ irq_ptr->aqueue.cmd=DEFAULT_ACTIVATE_QS_CMD; irq_ptr->aqueue.count=DEFAULT_ACTIVATE_QS_COUNT; - if (!qdio_alloc_qs(irq_ptr,init_data->no_input_qs, + if (!qdio_alloc_qs(irq_ptr, init_data->cdev, + init_data->no_input_qs, init_data->no_output_qs, init_data->input_handler, init_data->output_handler,init_data->int_parm, init_data->q_format,init_data->flags, init_data->input_sbal_addr_array, init_data->output_sbal_addr_array)) { + /* + * FIXME: + * qdio_release_irq_memory does MOD_DEC_USE_COUNT + * in an unbalanced fashion (see 10 lines farther down) + */ qdio_release_irq_memory(irq_ptr); - result=-ENOMEM; - goto out; + return -ENOMEM; } qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE); - irq_ptr->setting_up_lock=SPIN_LOCK_UNLOCKED; - MOD_INC_USE_COUNT; QDIO_DBF_TEXT3(0,setup,"MOD_INC_"); - spin_lock(&irq_ptr->setting_up_lock); + init_MUTEX_LOCKED(&irq_ptr->setting_up_sema); init_data->cdev->private->qdio_data = irq_ptr; @@ -2383,12 +2449,12 @@ /* first input descriptors, then output descriptors */ is_iqdio = (init_data->q_format == QDIO_IQDIO_QFMT) ? 1 : 0; for (i=0;i<init_data->no_input_qs;i++) - qdio_initialize_fill_input_desc(irq_ptr, i, is_iqdio); + qdio_allocate_fill_input_desc(irq_ptr, i, is_iqdio); for (i=0;i<init_data->no_output_qs;i++) - qdio_initialize_fill_output_desc(irq_ptr, i, - init_data->no_input_qs, - is_iqdio); + qdio_allocate_fill_output_desc(irq_ptr, i, + init_data->no_input_qs, + is_iqdio); /* qdr, qib, sls, slsbs, slibs, sbales filled. */ @@ -2418,9 +2484,15 @@ } result=iqdio_set_subchannel_ind(irq_ptr,0); if (result) { - spin_unlock(&irq_ptr->setting_up_lock); + up(&irq_ptr->setting_up_sema); + /* + * FIXME: + * need some callback pointers to be set already, + * i.e. irq_ptr->cleanup_irq and irq_ptr->cleanup_timeout? + * (see 10 lines farther down) + */ qdio_cleanup(init_data->cdev, QDIO_FLAG_CLEANUP_USING_CLEAR); - goto out2; + return result; } iqdio_set_delay_target(irq_ptr,IQDIO_DELAY_TARGET); } @@ -2432,20 +2504,46 @@ irq_ptr->establish_timeout = qdio_establish_handle_timeout; irq_ptr->handler = qdio_handler; + up(&irq_ptr->setting_up_sema); + + return 0; +} + +int +qdio_establish(struct ccw_device *cdev) +{ + struct qdio_irq *irq_ptr; + unsigned long saveflags; + int result, result2; + char dbf_text[20]; + + irq_ptr = cdev->private->qdio_data; + if (!irq_ptr) + return -EINVAL; + + if (cdev->private->state != DEV_STATE_ONLINE) + return -EINVAL; + + down(&irq_ptr->setting_up_sema); + + sprintf(dbf_text,"qest%4x",cdev->private->irq); + QDIO_DBF_TEXT0(0,setup,dbf_text); + QDIO_DBF_TEXT0(0,trace,dbf_text); + /* establish q */ irq_ptr->ccw.cmd_code=irq_ptr->equeue.cmd; irq_ptr->ccw.flags=CCW_FLAG_SLI; irq_ptr->ccw.count=irq_ptr->equeue.count; irq_ptr->ccw.cda=QDIO_GET_ADDR(irq_ptr->qdr); - spin_lock_irqsave(get_ccwdev_lock(init_data->cdev),saveflags); + spin_lock_irqsave(get_ccwdev_lock(cdev),saveflags); - ccw_device_set_timeout(init_data->cdev, QDIO_ESTABLISH_TIMEOUT); - ccw_device_set_options(init_data->cdev, 0); - result=ccw_device_start(init_data->cdev,&irq_ptr->ccw, + ccw_device_set_timeout(cdev, QDIO_ESTABLISH_TIMEOUT); + ccw_device_set_options(cdev, 0); + result=ccw_device_start(cdev,&irq_ptr->ccw, QDIO_DOING_ESTABLISH,0,0); if (result) { - result2=ccw_device_start(init_data->cdev,&irq_ptr->ccw, + result2=ccw_device_start(cdev,&irq_ptr->ccw, QDIO_DOING_ESTABLISH,0,0); sprintf(dbf_text,"eq:io%4x",result); QDIO_DBF_TEXT2(1,setup,dbf_text); @@ -2459,28 +2557,25 @@ result=result2; } if (result == 0) - init_data->cdev->private->state = DEV_STATE_QDIO_INIT; - spin_unlock_irqrestore(get_ccwdev_lock(init_data->cdev),saveflags); + cdev->private->state = DEV_STATE_QDIO_INIT; + spin_unlock_irqrestore(get_ccwdev_lock(cdev),saveflags); if (result) { - spin_unlock(&irq_ptr->setting_up_lock); - qdio_cleanup(init_data->cdev,QDIO_FLAG_CLEANUP_USING_CLEAR); - goto out2; + up(&irq_ptr->setting_up_sema); + qdio_shutdown(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR); + return result; } - wait_event(init_data->cdev->private->wait_q, - dev_fsm_final_state(init_data->cdev) || + wait_event(cdev->private->wait_q, + dev_fsm_final_state(cdev) || (irq_ptr->state == QDIO_IRQ_STATE_ESTABLISHED)); - if (init_data->cdev->private->state == DEV_STATE_QDIO_INIT) - return 0; + if (cdev->private->state == DEV_STATE_QDIO_INIT) + result = 0; + else + result = -EIO; - result = -EIO; - out: - if (irq_ptr) - spin_unlock(&irq_ptr->setting_up_lock); - out2: - up(&init_sema); + up(&irq_ptr->setting_up_sema); return result; @@ -2501,7 +2596,7 @@ if (cdev->private->state != DEV_STATE_QDIO_INIT) return -EINVAL; - spin_lock(&irq_ptr->setting_up_lock); + down(&irq_ptr->setting_up_sema); if (irq_ptr->state==QDIO_IRQ_STATE_INACTIVE) { result=-EBUSY; goto out; @@ -2564,10 +2659,12 @@ } } + qdio_wait_nonbusy(QDIO_ACTIVATE_DELAY); + qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ACTIVE); out: - spin_unlock(&irq_ptr->setting_up_lock); + up(&irq_ptr->setting_up_sema); return result; } @@ -3016,8 +3113,6 @@ if (res) return res; - sema_init(&init_sema,1); - res = qdio_register_dbf_views(); if (res) return res; @@ -3051,8 +3146,12 @@ module_init(init_QDIO); module_exit(cleanup_QDIO); +EXPORT_SYMBOL(qdio_allocate); +EXPORT_SYMBOL(qdio_establish); EXPORT_SYMBOL(qdio_initialize); EXPORT_SYMBOL(qdio_activate); EXPORT_SYMBOL(do_QDIO); +EXPORT_SYMBOL(qdio_shutdown); +EXPORT_SYMBOL(qdio_free); EXPORT_SYMBOL(qdio_cleanup); EXPORT_SYMBOL(qdio_synchronize); diff -urN linux-2.5.62/drivers/s390/cio/qdio.h linux-2.5.62-s390/drivers/s390/cio/qdio.h --- linux-2.5.62/drivers/s390/cio/qdio.h Mon Feb 17 23:56:01 2003 +++ linux-2.5.62-s390/drivers/s390/cio/qdio.h Mon Feb 24 18:18:38 2003 @@ -1,7 +1,7 @@ #ifndef _CIO_QDIO_H #define _CIO_QDIO_H -#define VERSION_CIO_QDIO_H "$Revision: 1.8 $" +#define VERSION_CIO_QDIO_H "$Revision: 1.11 $" //#define QDIO_DBF_LIKE_HELL @@ -48,6 +48,10 @@ #define QDIO_STATS_CLASSES 2 #define QDIO_STATS_COUNT_NEEDED 2*/ +#define QDIO_ACTIVATE_DELAY 5 /* according to brenton belmar and paul + gioquindo it can take up to 5ms before + queues are really active */ + #define QDIO_NO_USE_COUNT_TIME 10 #define QDIO_NO_USE_COUNT_TIMEOUT 1000 /* wait for 1 sec on each q before exiting without having use_count @@ -579,6 +583,7 @@ int is_input_q; int irq; + struct ccw_device *cdev; unsigned int is_iqdio_q; @@ -670,7 +675,7 @@ unsigned int sync_done_on_outb_pcis; unsigned int state; - spinlock_t setting_up_lock; + struct semaphore setting_up_sema; unsigned int no_input_qs; unsigned int no_output_qs; diff -urN linux-2.5.62/drivers/s390/s390mach.c linux-2.5.62-s390/drivers/s390/s390mach.c --- linux-2.5.62/drivers/s390/s390mach.c Mon Feb 17 23:57:19 2003 +++ linux-2.5.62-s390/drivers/s390/s390mach.c Mon Feb 24 18:18:38 2003 @@ -21,6 +21,7 @@ extern void css_process_crw(int); extern void chsc_process_crw(void); +extern void chp_process_crw(int); static void s390_handle_damage(char *msg) @@ -53,29 +54,25 @@ crw.erc, crw.rsid); switch (crw.rsc) { case CRW_RSC_SCH: - pr_debug(KERN_NOTICE, "source is subchannel %04X\n", - crw.rsid); + pr_debug("source is subchannel %04X\n", crw.rsid); css_process_crw (crw.rsid); break; case CRW_RSC_MONITOR: - pr_debug(KERN_NOTICE, - "source is monitoring facility\n"); + pr_debug("source is monitoring facility\n"); break; case CRW_RSC_CPATH: - pr_debug(KERN_NOTICE, - "source is channel path %02X\n", - pcrwe->crw.rsid); + pr_debug("source is channel path %02X\n", crw.rsid); + chp_process_crw(crw.rsid); break; case CRW_RSC_CONFIG: - pr_debug(KERN_NOTICE, - "source is configuration-alert facility\n"); + pr_debug("source is configuration-alert facility\n"); break; case CRW_RSC_CSS: - pr_debug(KERN_NOTICE, "source is channel subsystem\n"); + pr_debug("source is channel subsystem\n"); chsc_process_crw(); break; default: - pr_debug(KERN_NOTICE, "unknown source\n"); + pr_debug("unknown source\n"); break; } } while (crw.chn); diff -urN linux-2.5.62/include/asm-s390/qdio.h linux-2.5.62-s390/include/asm-s390/qdio.h --- linux-2.5.62/include/asm-s390/qdio.h Mon Feb 17 23:56:00 2003 +++ linux-2.5.62-s390/include/asm-s390/qdio.h Mon Feb 24 18:18:38 2003 @@ -50,11 +50,11 @@ } __attribute__ ((packed,aligned(256))); -/* params are: irq, status, qdio_error, siga_error, +/* params are: ccw_device, status, qdio_error, siga_error, queue_number, first element processed, number of elements processed, int_parm */ -typedef void qdio_handler_t(int,unsigned int,unsigned int,unsigned int, - unsigned int,int,int,unsigned long); +typedef void qdio_handler_t(struct ccw_device *,unsigned int,unsigned int, + unsigned int,unsigned int,int,int,unsigned long); #define QDIO_STATUS_INBOUND_INT 0x01 @@ -100,6 +100,8 @@ void **output_sbal_addr_array; /* addr of n*128 void ptrs */ }; extern int qdio_initialize(struct qdio_initialize *init_data); +extern int qdio_allocate(struct qdio_initialize *init_data); +extern int qdio_establish(struct ccw_device *); extern int qdio_activate(struct ccw_device *,int flags); @@ -127,6 +129,8 @@ unsigned int queue_number); extern int qdio_cleanup(struct ccw_device*, int how); +extern int qdio_shutdown(struct ccw_device*, int how); +extern int qdio_free(struct ccw_device*); unsigned char qdio_get_slsb_state(struct ccw_device*, unsigned int flag, unsigned int queue_number, diff -urN linux-2.5.62/include/asm-s390x/qdio.h linux-2.5.62-s390/include/asm-s390x/qdio.h --- linux-2.5.62/include/asm-s390x/qdio.h Mon Feb 17 23:56:14 2003 +++ linux-2.5.62-s390/include/asm-s390x/qdio.h Mon Feb 24 18:18:38 2003 @@ -50,11 +50,11 @@ } __attribute__ ((packed,aligned(256))); -/* params are: irq, status, qdio_error, siga_error, +/* params are: ccw_device, status, qdio_error, siga_error, queue_number, first element processed, number of elements processed, int_parm */ -typedef void qdio_handler_t(int,unsigned int,unsigned int,unsigned int, - unsigned int,int,int,unsigned long); +typedef void qdio_handler_t(struct ccw_device *,unsigned int,unsigned int, + unsigned int,unsigned int,int,int,unsigned long); #define QDIO_STATUS_INBOUND_INT 0x01 @@ -100,6 +100,8 @@ void **output_sbal_addr_array; /* addr of n*128 void ptrs */ }; extern int qdio_initialize(struct qdio_initialize *init_data); +extern int qdio_allocate(struct qdio_initialize *init_data); +extern int qdio_establish(struct ccw_device *); extern int qdio_activate(struct ccw_device *,int flags); @@ -127,6 +129,8 @@ unsigned int queue_number); extern int qdio_cleanup(struct ccw_device*, int how); +extern int qdio_shutdown(struct ccw_device*, int how); +extern int qdio_free(struct ccw_device*); unsigned char qdio_get_slsb_state(struct ccw_device*, unsigned int flag, unsigned int queue_number, - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |