/*
* drivers/s390/cio/chsc.c
* S/390 common I/O routines -- channel subsystem call
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
* Author(s): Ingo Adlung (adlung@de.ibm.com)
* Cornelia Huck (cornelia.huck@de.ibm.com)
* Arnd Bergmann (arndb@de.ibm.com)
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/device.h>
#include <asm/cio.h>
#include "css.h"
#include "cio.h"
#include "cio_debug.h"
#include "ioasm.h"
#include "chsc.h"
static void *sei_page;
static int new_channel_path(int chpid);
static inline void
set_chp_logically_online(int chp, int onoff)
{
css[0]->chps[chp]->state = onoff;
}
static int
get_chp_status(int chp)
{
return (css[0]->chps[chp] ? css[0]->chps[chp]->state : -ENODEV);
}
void
chsc_validate_chpids(struct subchannel *sch)
{
int mask, chp;
for (chp = 0; chp <= 7; chp++) {
mask = 0x80 >> chp;
if (!get_chp_status(sch->schib.pmcw.chpid[chp]))
/* disable using this path */
sch->opm &= ~mask;
}
}
void
chpid_is_actually_online(int chp)
{
int state;
state = get_chp_status(chp);
if (state < 0) {
need_rescan = 1;
queue_work(slow_path_wq, &slow_path_work);
} else
WARN_ON(!state);
}
/* FIXME: this is _always_ called for every subchannel. shouldn't we
* process more than one at a time? */
static int
chsc_get_sch_desc_irq(struct subchannel *sch, void *page)
{
int ccode, j;
struct {
struct chsc_header request;
u16 reserved1a:10;
u16 ssid:2;
u16 reserved1b:4;
u16 f_sch; /* first subchannel */
u16 reserved2;
u16 l_sch; /* last subchannel */
u32 reserved3;
struct chsc_header response;
u32 reserved4;
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 */
u8 path_mask;
u8 fla_valid_mask;
u16 sch; /* subchannel */
u8 chpid[8]; /* chpids 0-7 */
u16 fla[8]; /* full link addresses 0-7 */
} *ssd_area;
ssd_area = page;
ssd_area->request = (struct chsc_header) {
.length = 0x0010,
.code = 0x0004,
};
ssd_area->ssid = sch->schid.ssid;
ssd_area->f_sch = sch->schid.sch_no;
ssd_area->l_sch = sch->schid.sch_no;
ccode = chsc(ssd_area);
if (ccode > 0) {
pr_debug("chsc returned with ccode = %d\n&quo