#include <asm/ipl.h>
#include <asm/chpid.h>
#include <asm/airq.h>
+#include <asm/isc.h>
#include <asm/cpu.h>
+#include <asm/fcx.h>
#include "cio.h"
#include "css.h"
#include "chsc.h"
debug_unregister(cio_debug_trace_id);
if (cio_debug_crw_id)
debug_unregister(cio_debug_crw_id);
- printk(KERN_WARNING"cio: could not initialize debugging\n");
return -1;
}
local_bh_disable();
irq_enter ();
spin_lock(sch->lock);
- memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw));
+ memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
if (sch->driver && sch->driver->irq)
sch->driver->irq(sch);
spin_unlock(sch->lock);
{
char dbf_txt[15];
int ccode;
- struct orb *orb;
+ union orb *orb;
CIO_TRACE_EVENT(4, "stIO");
CIO_TRACE_EVENT(4, sch->dev.bus_id);
orb = &to_io_private(sch)->orb;
/* sch is always under 2G. */
- orb->intparm = (u32)(addr_t)sch;
- orb->fmt = 1;
+ orb->cmd.intparm = (u32)(addr_t)sch;
+ orb->cmd.fmt = 1;
- orb->pfch = sch->options.prefetch == 0;
- orb->spnd = sch->options.suspend;
- orb->ssic = sch->options.suspend && sch->options.inter;
- orb->lpm = (lpm != 0) ? lpm : sch->lpm;
+ orb->cmd.pfch = sch->options.prefetch == 0;
+ orb->cmd.spnd = sch->options.suspend;
+ orb->cmd.ssic = sch->options.suspend && sch->options.inter;
+ orb->cmd.lpm = (lpm != 0) ? lpm : sch->lpm;
#ifdef CONFIG_64BIT
/*
* for 64 bit we always support 64 bit IDAWs with 4k page size only
*/
- orb->c64 = 1;
- orb->i2k = 0;
+ orb->cmd.c64 = 1;
+ orb->cmd.i2k = 0;
#endif
- orb->key = key >> 4;
+ orb->cmd.key = key >> 4;
/* issue "Start Subchannel" */
- orb->cpa = (__u32) __pa(cpa);
+ orb->cmd.cpa = (__u32) __pa(cpa);
ccode = ssch(sch->schid, orb);
/* process condition code */
/*
* initialize device status information
*/
- sch->schib.scsw.actl |= SCSW_ACTL_START_PEND;
+ sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND;
return 0;
case 1: /* status pending */
case 2: /* busy */
switch (ccode) {
case 0:
- sch->schib.scsw.actl |= SCSW_ACTL_RESUME_PEND;
+ sch->schib.scsw.cmd.actl |= SCSW_ACTL_RESUME_PEND;
return 0;
case 1:
return -EBUSY;
switch (ccode) {
case 0:
- sch->schib.scsw.actl |= SCSW_ACTL_HALT_PEND;
+ sch->schib.scsw.cmd.actl |= SCSW_ACTL_HALT_PEND;
return 0;
case 1: /* status pending */
case 2: /* busy */
switch (ccode) {
case 0:
- sch->schib.scsw.actl |= SCSW_ACTL_CLEAR_PEND;
+ sch->schib.scsw.cmd.actl |= SCSW_ACTL_CLEAR_PEND;
return 0;
default: /* device not operational */
return -ENODEV;
if (ccode == 3) /* Not operational. */
return -ENODEV;
- if (sch->schib.scsw.actl != 0)
+ if (scsw_actl(&sch->schib.scsw) != 0)
/*
* the disable function must not be called while there are
* requests pending for completion !
return 0;
}
-static int cio_validate_io_subchannel(struct subchannel *sch)
+static int cio_check_devno_blacklisted(struct subchannel *sch)
{
- /* Initialization for io subchannels. */
- if (!css_sch_is_valid(&sch->schib))
- return -ENODEV;
-
- /* Devno is valid. */
if (is_blacklisted(sch->schid.ssid, sch->schib.pmcw.dev)) {
/*
* This device must not be known to Linux. So we simply
return 0;
}
+static int cio_validate_io_subchannel(struct subchannel *sch)
+{
+ /* Initialization for io subchannels. */
+ if (!css_sch_is_valid(&sch->schib))
+ return -ENODEV;
+
+ /* Devno is valid. */
+ return cio_check_devno_blacklisted(sch);
+}
+
+static int cio_validate_msg_subchannel(struct subchannel *sch)
+{
+ /* Initialization for message subchannels. */
+ if (!css_sch_is_valid(&sch->schib))
+ return -ENODEV;
+
+ /* Devno is valid. */
+ return cio_check_devno_blacklisted(sch);
+}
+
/**
* cio_validate_subchannel - basic validation of subchannel
* @sch: subchannel structure to be filled out
case SUBCHANNEL_TYPE_IO:
err = cio_validate_io_subchannel(sch);
break;
+ case SUBCHANNEL_TYPE_MSG:
+ err = cio_validate_msg_subchannel(sch);
+ break;
default:
err = 0;
}
*/
if (tpi_info->adapter_IO == 1 &&
tpi_info->int_type == IO_INTERRUPT_TYPE) {
- do_adapter_IO();
+ do_adapter_IO(tpi_info->isc);
continue;
}
sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
if (!console_subchannel_in_use)
return;
- /* disable all but isc 1 (console device) */
+ /* disable all but the console isc */
__ctl_store (save_cr6, 6, 6);
- cr6 = 0x40000000;
+ cr6 = 1UL << (31 - CONSOLE_ISC);
__ctl_load (cr6, 6, 6);
do {
if (!cio_tpi())
cpu_relax();
spin_lock(console_subchannel.lock);
- } while (console_subchannel.schib.scsw.actl != 0);
+ } while (console_subchannel.schib.scsw.cmd.actl != 0);
/*
* restore previous isc value
*/
/* unlike in 2.4, we cannot autoprobe here, since
* the channel subsystem is not fully initialized.
* With some luck, the HWC console can take over */
- printk(KERN_WARNING "cio: No ccw console found!\n");
return -1;
}
return console_irq;
sch_no = cio_get_console_sch_no();
if (sch_no == -1) {
console_subchannel_in_use = 0;
+ printk(KERN_WARNING "cio: No ccw console found!\n");
return ERR_PTR(-ENODEV);
}
memset(&console_subchannel, 0, sizeof(struct subchannel));
}
/*
- * enable console I/O-interrupt subclass 1
+ * enable console I/O-interrupt subclass
*/
- ctl_set_bit(6, 30);
- console_subchannel.schib.pmcw.isc = 1;
+ isc_register(CONSOLE_ISC);
+ console_subchannel.schib.pmcw.isc = CONSOLE_ISC;
console_subchannel.schib.pmcw.intparm =
(u32)(addr_t)&console_subchannel;
ret = cio_modify(&console_subchannel);
if (ret) {
+ isc_unregister(CONSOLE_ISC);
console_subchannel_in_use = 0;
return ERR_PTR(ret);
}
{
console_subchannel.schib.pmcw.intparm = 0;
cio_modify(&console_subchannel);
- ctl_clear_bit(6, 30);
+ isc_unregister(CONSOLE_ISC);
console_subchannel_in_use = 0;
}
return -EBUSY;
}
+static void __clear_chsc_subchannel_easy(void)
+{
+ /* It seems we can only wait for a bit here :/ */
+ udelay_reset(100);
+}
+
static int pgm_check_occured;
static void cio_reset_pgm_check_handler(void)
if (__clear_io_subchannel_easy(schid))
goto out; /* give up... */
break;
+ case SUBCHANNEL_TYPE_CHSC:
+ __clear_chsc_subchannel_easy();
+ break;
default:
/* No default clear strategy */
break;
iplinfo->is_qdio = schib.pmcw.qf;
return 0;
}
+
+/**
+ * cio_tm_start_key - perform start function
+ * @sch: subchannel on which to perform the start function
+ * @tcw: transport-command word to be started
+ * @lpm: mask of paths to use
+ * @key: storage key to use for storage access
+ *
+ * Start the tcw on the given subchannel. Return zero on success, non-zero
+ * otherwise.
+ */
+int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key)
+{
+ int cc;
+ union orb *orb = &to_io_private(sch)->orb;
+
+ memset(orb, 0, sizeof(union orb));
+ orb->tm.intparm = (u32) (addr_t) sch;
+ orb->tm.key = key >> 4;
+ orb->tm.b = 1;
+ orb->tm.lpm = lpm ? lpm : sch->lpm;
+ orb->tm.tcw = (u32) (addr_t) tcw;
+ cc = ssch(sch->schid, orb);
+ switch (cc) {
+ case 0:
+ return 0;
+ case 1:
+ case 2:
+ return -EBUSY;
+ default:
+ return cio_start_handle_notoper(sch, lpm);
+ }
+}
+
+/**
+ * cio_tm_intrg - perform interrogate function
+ * @sch - subchannel on which to perform the interrogate function
+ *
+ * If the specified subchannel is running in transport-mode, perform the
+ * interrogate function. Return zero on success, non-zero otherwie.
+ */
+int cio_tm_intrg(struct subchannel *sch)
+{
+ int cc;
+
+ if (!to_io_private(sch)->orb.tm.b)
+ return -EINVAL;
+ cc = xsch(sch->schid);
+ switch (cc) {
+ case 0:
+ case 2:
+ return 0;
+ case 1:
+ return -EBUSY;
+ default:
+ return -ENODEV;
+ }
+}