Commit a8237fc4 authored by Cornelia Huck's avatar Cornelia Huck Committed by Linus Torvalds
Browse files

[PATCH] s390: introduce struct subchannel_id



This patch introduces a struct subchannel_id containing the subchannel number
(formerly referred to as "irq") and switches code formerly relying on the
subchannel number over to it.

While we're touching inline assemblies anyway, make sure they have correct
memory constraints.
Signed-off-by: default avatarCornelia Huck <cohuck@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 8129ee16
......@@ -35,7 +35,7 @@
*/
/* 65536 bits to indicate if a devno is blacklisted or not */
#define __BL_DEV_WORDS ((__MAX_SUBCHANNELS + (8*sizeof(long) - 1)) / \
#define __BL_DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \
(8*sizeof(long)))
static unsigned long bl_dev[__BL_DEV_WORDS];
typedef enum {add, free} range_action;
......@@ -50,7 +50,7 @@ blacklist_range (range_action action, unsigned int from, unsigned int to)
if (!to)
to = from;
if (from > to || to > __MAX_SUBCHANNELS) {
if (from > to || to > __MAX_SUBCHANNEL) {
printk (KERN_WARNING "Invalid blacklist range "
"0x%04x to 0x%04x, skipping\n", from, to);
return;
......@@ -143,7 +143,7 @@ blacklist_parse_parameters (char *str, range_action action)
if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 ||
strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) {
from = 0;
to = __MAX_SUBCHANNELS;
to = __MAX_SUBCHANNEL;
str += 3;
} else {
int rc;
......@@ -226,20 +226,21 @@ is_blacklisted (int devno)
static inline void
s390_redo_validation (void)
{
unsigned int irq;
struct subchannel_id schid;
CIO_TRACE_EVENT (0, "redoval");
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
init_subchannel_id(&schid);
do {
int ret;
struct subchannel *sch;
sch = get_subchannel_by_schid(irq);
sch = get_subchannel_by_schid(schid);
if (sch) {
/* Already known. */
put_device(&sch->dev);
continue;
}
ret = css_probe_device(irq);
ret = css_probe_device(schid);
if (ret == -ENXIO)
break; /* We're through. */
if (ret == -ENOMEM)
......@@ -248,7 +249,7 @@ s390_redo_validation (void)
* panic.
*/
break;
}
} while (schid.sch_no++ < __MAX_SUBCHANNEL);
}
/*
......@@ -289,12 +290,12 @@ static int cio_ignore_read (char *page, char **start, off_t off,
len = 0;
for (devno = off; /* abuse the page variable
* as counter, see fs/proc/generic.c */
devno < __MAX_SUBCHANNELS && len + entry_size < count; devno++) {
devno < __MAX_SUBCHANNEL && len + entry_size < count; devno++) {
if (!test_bit(devno, bl_dev))
continue;
len += sprintf(page + len, "0.0.%04lx", devno);
if (test_bit(devno + 1, bl_dev)) { /* print range */
while (++devno < __MAX_SUBCHANNELS)
while (++devno < __MAX_SUBCHANNEL)
if (!test_bit(devno, bl_dev))
break;
len += sprintf(page + len, "-0.0.%04lx", --devno);
......@@ -302,7 +303,7 @@ static int cio_ignore_read (char *page, char **start, off_t off,
len += sprintf(page + len, "\n");
}
if (devno < __MAX_SUBCHANNELS)
if (devno < __MAX_SUBCHANNEL)
*eof = 1;
*start = (char *) (devno - off); /* number of checked entries */
return len;
......
......@@ -104,8 +104,8 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page)
.code = 0x0004,
};
ssd_area->f_sch = sch->irq;
ssd_area->l_sch = sch->irq;
ssd_area->f_sch = sch->schid.sch_no;
ssd_area->l_sch = sch->schid.sch_no;
ccode = chsc(ssd_area);
if (ccode > 0) {
......@@ -147,7 +147,8 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page)
*/
if (ssd_area->st > 3) { /* uhm, that looks strange... */
CIO_CRW_EVENT(0, "Strange subchannel type %d"
" for sch %04x\n", ssd_area->st, sch->irq);
" for sch %04x\n", ssd_area->st,
sch->schid.sch_no);
/*
* There may have been a new subchannel type defined in the
* time since this code was written; since we don't know which
......@@ -157,7 +158,7 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page)
} else {
const char *type[4] = {"I/O", "chsc", "message", "ADM"};
CIO_CRW_EVENT(6, "ssd: sch %04x is %s subchannel\n",
sch->irq, type[ssd_area->st]);
sch->schid.sch_no, type[ssd_area->st]);
sch->ssd_info.valid = 1;
sch->ssd_info.type = ssd_area->st;
......@@ -232,7 +233,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
mask = 0x80 >> j;
spin_lock(&sch->lock);
stsch(sch->irq, &schib);
stsch(sch->schid, &schib);
if (!schib.pmcw.dnv)
goto out_unreg;
memcpy(&sch->schib, &schib, sizeof(struct schib));
......@@ -284,7 +285,7 @@ out_unlock:
out_unreg:
spin_unlock(&sch->lock);
sch->lpm = 0;
if (css_enqueue_subchannel_slow(sch->irq)) {
if (css_enqueue_subchannel_slow(sch->schid)) {
css_clear_subchannel_slow_list();
need_rescan = 1;
}
......@@ -337,7 +338,7 @@ s390_process_res_acc_sch(u8 chpid, __u16 fla, u32 fla_mask,
* new path information and eventually check for logically
* offline chpids.
*/
ccode = stsch(sch->irq, &sch->schib);
ccode = stsch(sch->schid, &sch->schib);
if (ccode > 0)
return 0;
......@@ -348,7 +349,8 @@ static int
s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
{
struct subchannel *sch;
int irq, rc;
int rc;
struct subchannel_id schid;
char dbf_txt[15];
sprintf(dbf_txt, "accpr%x", chpid);
......@@ -370,10 +372,11 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
return 0; /* no need to do the rest */
rc = 0;
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
init_subchannel_id(&schid);
do {
int chp_mask, old_lpm;
sch = get_subchannel_by_schid(irq);
sch = get_subchannel_by_schid(schid);
if (!sch) {
struct schib schib;
int ret;
......@@ -385,7 +388,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
* that beast may be on we'll have to do a stsch
* on all devices, grr...
*/
if (stsch(irq, &schib)) {
if (stsch(schid, &schib)) {
/* We're through */
if (need_rescan)
rc = -EAGAIN;
......@@ -396,7 +399,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
continue;
}
/* Put it on the slow path. */
ret = css_enqueue_subchannel_slow(irq);
ret = css_enqueue_subchannel_slow(schid);
if (ret) {
css_clear_subchannel_slow_list();
need_rescan = 1;
......@@ -428,7 +431,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
put_device(&sch->dev);
if (fla_mask == 0xffff)
break;
}
} while (schid.sch_no++ < __MAX_SUBCHANNEL);
return rc;
}
......@@ -608,7 +611,8 @@ static int
chp_add(int chpid)
{
struct subchannel *sch;
int irq, ret, rc;
int ret, rc;
struct subchannel_id schid;
char dbf_txt[15];
if (!get_chp_status(chpid))
......@@ -618,14 +622,15 @@ chp_add(int chpid)
CIO_TRACE_EVENT(2, dbf_txt);
rc = 0;
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
init_subchannel_id(&schid);
do {
int i;
sch = get_subchannel_by_schid(irq);
sch = get_subchannel_by_schid(schid);
if (!sch) {
struct schib schib;
if (stsch(irq, &schib)) {
if (stsch(schid, &schib)) {
/* We're through */
if (need_rescan)
rc = -EAGAIN;
......@@ -636,7 +641,7 @@ chp_add(int chpid)
continue;
}
/* Put it on the slow path. */
ret = css_enqueue_subchannel_slow(irq);
ret = css_enqueue_subchannel_slow(schid);
if (ret) {
css_clear_subchannel_slow_list();
need_rescan = 1;
......@@ -648,7 +653,7 @@ chp_add(int chpid)
spin_lock(&sch->lock);
for (i=0; i<8; i++)
if (sch->schib.pmcw.chpid[i] == chpid) {
if (stsch(sch->irq, &sch->schib) != 0) {
if (stsch(sch->schid, &sch->schib) != 0) {
/* Endgame. */
spin_unlock(&sch->lock);
return rc;
......@@ -669,7 +674,7 @@ chp_add(int chpid)
spin_unlock(&sch->lock);
put_device(&sch->dev);
}
} while (schid.sch_no++ < __MAX_SUBCHANNEL);
return rc;
}
......@@ -702,7 +707,7 @@ __check_for_io_and_kill(struct subchannel *sch, int index)
if (!device_is_online(sch))
/* cio could be doing I/O. */
return 0;
cc = stsch(sch->irq, &sch->schib);
cc = stsch(sch->schid, &sch->schib);
if (cc)
return 0;
if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) {
......@@ -743,7 +748,7 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
* just varied off path. Then kill it.
*/
if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) {
if (css_enqueue_subchannel_slow(sch->irq)) {
if (css_enqueue_subchannel_slow(sch->schid)) {
css_clear_subchannel_slow_list();
need_rescan = 1;
}
......@@ -789,7 +794,8 @@ static int
s390_vary_chpid( __u8 chpid, int on)
{
char dbf_text[15];
int status, irq, ret;
int status, ret;
struct subchannel_id schid;
struct subchannel *sch;
sprintf(dbf_text, on?"varyon%x":"varyoff%x", chpid);
......@@ -818,26 +824,27 @@ s390_vary_chpid( __u8 chpid, int on)
if (!on)
goto out;
/* Scan for new devices on varied on path. */
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
init_subchannel_id(&schid);
do {
struct schib schib;
if (need_rescan)
break;
sch = get_subchannel_by_schid(irq);
sch = get_subchannel_by_schid(schid);
if (sch) {
put_device(&sch->dev);
continue;
}
if (stsch(irq, &schib))
if (stsch(schid, &schib))
/* We're through */
break;
/* Put it on the slow path. */
ret = css_enqueue_subchannel_slow(irq);
ret = css_enqueue_subchannel_slow(schid);
if (ret) {
css_clear_subchannel_slow_list();
need_rescan = 1;
}
}
} while (schid.sch_no++ < __MAX_SUBCHANNEL);
out:
if (need_rescan || css_slow_subchannels_exist())
queue_work(slow_path_wq, &slow_path_work);
......
......@@ -135,7 +135,7 @@ cio_tpi(void)
return 0;
irb = (struct irb *) __LC_IRB;
/* Store interrupt response block to lowcore. */
if (tsch (tpi_info->irq, irb) != 0)
if (tsch (tpi_info->schid, irb) != 0)
/* Not status pending or not operational. */
return 1;
sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
......@@ -163,10 +163,10 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
else
sch->lpm = 0;
stsch (sch->irq, &sch->schib);
stsch (sch->schid, &sch->schib);
CIO_MSG_EVENT(0, "cio_start: 'not oper' status for "
"subchannel %04x!\n", sch->irq);
"subchannel %04x!\n", sch->schid.sch_no);
sprintf(dbf_text, "no%s", sch->dev.bus_id);
CIO_TRACE_EVENT(0, dbf_text);
CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));
......@@ -204,7 +204,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */
sch->orb.key = key >> 4;
/* issue "Start Subchannel" */
sch->orb.cpa = (__u32) __pa (cpa);
ccode = ssch (sch->irq, &sch->orb);
ccode = ssch (sch->schid, &sch->orb);
/* process condition code */
sprintf (dbf_txt, "ccode:%d", ccode);
......@@ -243,7 +243,7 @@ cio_resume (struct subchannel *sch)
CIO_TRACE_EVENT (4, "resIO");
CIO_TRACE_EVENT (4, sch->dev.bus_id);
ccode = rsch (sch->irq);
ccode = rsch (sch->schid);
sprintf (dbf_txt, "ccode:%d", ccode);
CIO_TRACE_EVENT (4, dbf_txt);
......@@ -283,7 +283,7 @@ cio_halt(struct subchannel *sch)
/*
* Issue "Halt subchannel" and process condition code
*/
ccode = hsch (sch->irq);
ccode = hsch (sch->schid);
sprintf (dbf_txt, "ccode:%d", ccode);
CIO_TRACE_EVENT (2, dbf_txt);
......@@ -318,7 +318,7 @@ cio_clear(struct subchannel *sch)
/*
* Issue "Clear subchannel" and process condition code
*/
ccode = csch (sch->irq);
ccode = csch (sch->schid);
sprintf (dbf_txt, "ccode:%d", ccode);
CIO_TRACE_EVENT (2, dbf_txt);
......@@ -351,7 +351,7 @@ cio_cancel (struct subchannel *sch)
CIO_TRACE_EVENT (2, "cancelIO");
CIO_TRACE_EVENT (2, sch->dev.bus_id);
ccode = xsch (sch->irq);
ccode = xsch (sch->schid);
sprintf (dbf_txt, "ccode:%d", ccode);
CIO_TRACE_EVENT (2, dbf_txt);
......@@ -359,7 +359,7 @@ cio_cancel (struct subchannel *sch)
switch (ccode) {
case 0: /* success */
/* Update information in scsw. */
stsch (sch->irq, &sch->schib);
stsch (sch->schid, &sch->schib);
return 0;
case 1: /* status pending */
return -EBUSY;
......@@ -381,7 +381,7 @@ cio_modify (struct subchannel *sch)
ret = 0;
for (retry = 0; retry < 5; retry++) {
ccode = msch_err (sch->irq, &sch->schib);
ccode = msch_err (sch->schid, &sch->schib);
if (ccode < 0) /* -EIO if msch gets a program check. */
return ccode;
switch (ccode) {
......@@ -414,7 +414,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
CIO_TRACE_EVENT (2, "ensch");
CIO_TRACE_EVENT (2, sch->dev.bus_id);
ccode = stsch (sch->irq, &sch->schib);
ccode = stsch (sch->schid, &sch->schib);
if (ccode)
return -ENODEV;
......@@ -432,13 +432,13 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
*/
sch->schib.pmcw.csense = 0;
if (ret == 0) {
stsch (sch->irq, &sch->schib);
stsch (sch->schid, &sch->schib);
if (sch->schib.pmcw.ena)
break;
}
if (ret == -EBUSY) {
struct irb irb;
if (tsch(sch->irq, &irb) != 0)
if (tsch(sch->schid, &irb) != 0)
break;
}
}
......@@ -461,7 +461,7 @@ cio_disable_subchannel (struct subchannel *sch)
CIO_TRACE_EVENT (2, "dissch");
CIO_TRACE_EVENT (2, sch->dev.bus_id);
ccode = stsch (sch->irq, &sch->schib);
ccode = stsch (sch->schid, &sch->schib);
if (ccode == 3) /* Not operational. */
return -ENODEV;
......@@ -485,7 +485,7 @@ cio_disable_subchannel (struct subchannel *sch)
*/
break;
if (ret == 0) {
stsch (sch->irq, &sch->schib);
stsch (sch->schid, &sch->schib);
if (!sch->schib.pmcw.ena)
break;
}
......@@ -508,12 +508,12 @@ cio_disable_subchannel (struct subchannel *sch)
* -ENODEV for subchannels with invalid device number or blacklisted devices
*/
int
cio_validate_subchannel (struct subchannel *sch, unsigned int irq)
cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
{
char dbf_txt[15];
int ccode;
sprintf (dbf_txt, "valsch%x", irq);
sprintf (dbf_txt, "valsch%x", schid.sch_no);
CIO_TRACE_EVENT (4, dbf_txt);
/* Nuke all fields. */
......@@ -522,17 +522,17 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq)
spin_lock_init(&sch->lock);
/* Set a name for the subchannel */
snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", irq);
snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", schid.sch_no);
/*
* The first subchannel that is not-operational (ccode==3)
* indicates that there aren't any more devices available.
*/
sch->irq = irq;
ccode = stsch (irq, &sch->schib);
ccode = stsch (schid, &sch->schib);
if (ccode)
return -ENXIO;
sch->schid = schid;
/* Copy subchannel type from path management control word. */
sch->st = sch->schib.pmcw.st;
......@@ -543,7 +543,7 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq)
CIO_DEBUG(KERN_INFO, 0,
"Subchannel %04X reports "
"non-I/O subchannel type %04X\n",
sch->irq, sch->st);
sch->schid.sch_no, sch->st);
/* We stop here for non-io subchannels. */
return sch->st;
}
......@@ -573,7 +573,7 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq)
CIO_DEBUG(KERN_INFO, 0,
"Detected device %04X on subchannel %04X"
" - PIM = %02X, PAM = %02X, POM = %02X\n",
sch->schib.pmcw.dev, sch->irq, sch->schib.pmcw.pim,
sch->schib.pmcw.dev, sch->schid.sch_no, sch->schib.pmcw.pim,
sch->schib.pmcw.pam, sch->schib.pmcw.pom);
/*
......@@ -632,7 +632,7 @@ do_IRQ (struct pt_regs *regs)
if (sch)
spin_lock(&sch->lock);
/* Store interrupt response block to lowcore. */
if (tsch (tpi_info->irq, irb) == 0 && sch) {
if (tsch (tpi_info->schid, irb) == 0 && sch) {
/* Keep subchannel information word up to date. */
memcpy (&sch->schib.scsw, &irb->scsw,
sizeof (irb->scsw));
......@@ -693,26 +693,28 @@ wait_cons_dev (void)
static int
cio_console_irq(void)
{
int irq;
struct subchannel_id schid;
init_subchannel_id(&schid);
if (console_irq != -1) {
/* VM provided us with the irq number of the console. */
if (stsch(console_irq, &console_subchannel.schib) != 0 ||
schid.sch_no = console_irq;
if (stsch(schid, &console_subchannel.schib) != 0 ||
!console_subchannel.schib.pmcw.dnv)
return -1;
console_devno = console_subchannel.schib.pmcw.dev;
} else if (console_devno != -1) {
/* At least the console device number is known. */
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
if (stsch(irq, &console_subchannel.schib) != 0)
do {
if (stsch(schid, &console_subchannel.schib) != 0)
break;
if (console_subchannel.schib.pmcw.dnv &&
console_subchannel.schib.pmcw.dev ==
console_devno) {
console_irq = irq;
console_irq = schid.sch_no;
break;
}
}
} while (schid.sch_no++ < __MAX_SUBCHANNEL);
if (console_irq == -1)
return -1;
} else {
......@@ -729,6 +731,7 @@ struct subchannel *
cio_probe_console(void)
{
int irq, ret;
struct subchannel_id schid;
if (xchg(&console_subchannel_in_use, 1) != 0)
return ERR_PTR(-EBUSY);
......@@ -738,7 +741,9 @@ cio_probe_console(void)
return ERR_PTR(-ENODEV);
}
memset(&console_subchannel, 0, sizeof(struct subchannel));
ret = cio_validate_subchannel(&console_subchannel, irq);
init_subchannel_id(&schid);
schid.sch_no = irq;
ret = cio_validate_subchannel(&console_subchannel, schid);
if (ret) {
console_subchannel_in_use = 0;
return ERR_PTR(-ENODEV);
......@@ -770,11 +775,11 @@ cio_release_console(void)
/* Bah... hack to catch console special sausages. */
int
cio_is_console(int irq)
cio_is_console(struct subchannel_id schid)
{
if (!console_subchannel_in_use)
return 0;
return (irq == console_subchannel.irq);
return schid_equal(&schid, &console_subchannel.schid);
}
struct subchannel *
......@@ -787,7 +792,7 @@ cio_get_console_subchannel(void)
#endif
static inline int
__disable_subchannel_easy(unsigned int schid, struct schib *schib)
__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
{
int retry, cc;
......@@ -805,7 +810,7 @@ __disable_subchannel_easy(unsigned int schid, struct schib *schib)
}
static inline int
__clear_subchannel_easy(unsigned int schid)
__clear_subchannel_easy(struct subchannel_id schid)
{
int retry;
......@@ -815,8 +820,8 @@ __clear_subchannel_easy(unsigned int schid)
struct tpi_info ti;
if (tpi(&ti)) {
tsch(ti.irq, (struct irb *)__LC_IRB);
if (ti.irq == schid)
tsch(ti.schid, (struct irb *)__LC_IRB);
if (schid_equal(&ti.schid, &schid))
return 0;
}
udelay(100);
......@@ -830,10 +835,11 @@ extern void do_reipl(unsigned long devno);
void
clear_all_subchannels(void)
{
unsigned int schid;
struct subchannel_id schid;
local_irq_disable();
for (schid=0;schid<=highest_subchannel;schid++) {
init_subchannel_id(&schid);
do {
struct schib schib;
if (stsch(schid, &schib))
break; /* break out of the loop */
......@@ -849,7 +855,7 @@ clear_all_subchannels(void)
stsch(schid, &schib);
__disable_subchannel_easy(schid, &schib);
}
}
} while (schid.sch_no++ < __MAX_SUBCHANNEL);
}
/* Make sure all subchannels are quiet before we re-ipl an lpar. */
......
#ifndef S390_CIO_H
#define S390_CIO_H
#include "schid.h"
/*
* where we put the ssd info
*/
......@@ -83,7 +85,7 @@ struct orb {
/* subchannel data structure used by I/O subroutines */
struct subchannel {
unsigned int irq; /* aka. subchannel number */
struct subchannel_id schid;
spinlock_t lock; /* subchannel lock */
enum {
......@@ -114,7 +116,7 @@ struct subchannel {