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

[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 @@ ...@@ -35,7 +35,7 @@
*/ */
/* 65536 bits to indicate if a devno is blacklisted or not */ /* 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))) (8*sizeof(long)))
static unsigned long bl_dev[__BL_DEV_WORDS]; static unsigned long bl_dev[__BL_DEV_WORDS];
typedef enum {add, free} range_action; typedef enum {add, free} range_action;
...@@ -50,7 +50,7 @@ blacklist_range (range_action action, unsigned int from, unsigned int to) ...@@ -50,7 +50,7 @@ blacklist_range (range_action action, unsigned int from, unsigned int to)
if (!to) if (!to)
to = from; to = from;
if (from > to || to > __MAX_SUBCHANNELS) { if (from > to || to > __MAX_SUBCHANNEL) {
printk (KERN_WARNING "Invalid blacklist range " printk (KERN_WARNING "Invalid blacklist range "
"0x%04x to 0x%04x, skipping\n", from, to); "0x%04x to 0x%04x, skipping\n", from, to);
return; return;
...@@ -143,7 +143,7 @@ blacklist_parse_parameters (char *str, range_action action) ...@@ -143,7 +143,7 @@ blacklist_parse_parameters (char *str, range_action action)
if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 || if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 ||
strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) { strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) {
from = 0; from = 0;
to = __MAX_SUBCHANNELS; to = __MAX_SUBCHANNEL;
str += 3; str += 3;
} else { } else {
int rc; int rc;
...@@ -226,20 +226,21 @@ is_blacklisted (int devno) ...@@ -226,20 +226,21 @@ is_blacklisted (int devno)
static inline void static inline void
s390_redo_validation (void) s390_redo_validation (void)
{ {
unsigned int irq; struct subchannel_id schid;
CIO_TRACE_EVENT (0, "redoval"); CIO_TRACE_EVENT (0, "redoval");
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { init_subchannel_id(&schid);
do {
int ret; int ret;
struct subchannel *sch; struct subchannel *sch;
sch = get_subchannel_by_schid(irq); sch = get_subchannel_by_schid(schid);
if (sch) { if (sch) {
/* Already known. */ /* Already known. */
put_device(&sch->dev); put_device(&sch->dev);
continue; continue;
} }
ret = css_probe_device(irq); ret = css_probe_device(schid);
if (ret == -ENXIO) if (ret == -ENXIO)
break; /* We're through. */ break; /* We're through. */
if (ret == -ENOMEM) if (ret == -ENOMEM)
...@@ -248,7 +249,7 @@ s390_redo_validation (void) ...@@ -248,7 +249,7 @@ s390_redo_validation (void)
* panic. * panic.
*/ */
break; break;
} } while (schid.sch_no++ < __MAX_SUBCHANNEL);
} }
/* /*
...@@ -289,12 +290,12 @@ static int cio_ignore_read (char *page, char **start, off_t off, ...@@ -289,12 +290,12 @@ static int cio_ignore_read (char *page, char **start, off_t off,
len = 0; len = 0;
for (devno = off; /* abuse the page variable for (devno = off; /* abuse the page variable
* as counter, see fs/proc/generic.c */ * 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)) if (!test_bit(devno, bl_dev))
continue; continue;
len += sprintf(page + len, "0.0.%04lx", devno); len += sprintf(page + len, "0.0.%04lx", devno);
if (test_bit(devno + 1, bl_dev)) { /* print range */ if (test_bit(devno + 1, bl_dev)) { /* print range */
while (++devno < __MAX_SUBCHANNELS) while (++devno < __MAX_SUBCHANNEL)
if (!test_bit(devno, bl_dev)) if (!test_bit(devno, bl_dev))
break; break;
len += sprintf(page + len, "-0.0.%04lx", --devno); len += sprintf(page + len, "-0.0.%04lx", --devno);
...@@ -302,7 +303,7 @@ static int cio_ignore_read (char *page, char **start, off_t off, ...@@ -302,7 +303,7 @@ static int cio_ignore_read (char *page, char **start, off_t off,
len += sprintf(page + len, "\n"); len += sprintf(page + len, "\n");
} }
if (devno < __MAX_SUBCHANNELS) if (devno < __MAX_SUBCHANNEL)
*eof = 1; *eof = 1;
*start = (char *) (devno - off); /* number of checked entries */ *start = (char *) (devno - off); /* number of checked entries */
return len; return len;
......
...@@ -104,8 +104,8 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page) ...@@ -104,8 +104,8 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page)
.code = 0x0004, .code = 0x0004,
}; };
ssd_area->f_sch = sch->irq; ssd_area->f_sch = sch->schid.sch_no;
ssd_area->l_sch = sch->irq; ssd_area->l_sch = sch->schid.sch_no;
ccode = chsc(ssd_area); ccode = chsc(ssd_area);
if (ccode > 0) { if (ccode > 0) {
...@@ -147,7 +147,8 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page) ...@@ -147,7 +147,8 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page)
*/ */
if (ssd_area->st > 3) { /* uhm, that looks strange... */ if (ssd_area->st > 3) { /* uhm, that looks strange... */
CIO_CRW_EVENT(0, "Strange subchannel type %d" 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 * There may have been a new subchannel type defined in the
* time since this code was written; since we don't know which * 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) ...@@ -157,7 +158,7 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page)
} else { } else {
const char *type[4] = {"I/O", "chsc", "message", "ADM"}; const char *type[4] = {"I/O", "chsc", "message", "ADM"};
CIO_CRW_EVENT(6, "ssd: sch %04x is %s subchannel\n", 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.valid = 1;
sch->ssd_info.type = ssd_area->st; sch->ssd_info.type = ssd_area->st;
...@@ -232,7 +233,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) ...@@ -232,7 +233,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
mask = 0x80 >> j; mask = 0x80 >> j;
spin_lock(&sch->lock); spin_lock(&sch->lock);
stsch(sch->irq, &schib); stsch(sch->schid, &schib);
if (!schib.pmcw.dnv) if (!schib.pmcw.dnv)
goto out_unreg; goto out_unreg;
memcpy(&sch->schib, &schib, sizeof(struct schib)); memcpy(&sch->schib, &schib, sizeof(struct schib));
...@@ -284,7 +285,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) ...@@ -284,7 +285,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
out_unreg: out_unreg:
spin_unlock(&sch->lock); spin_unlock(&sch->lock);
sch->lpm = 0; sch->lpm = 0;
if (css_enqueue_subchannel_slow(sch->irq)) { if (css_enqueue_subchannel_slow(sch->schid)) {
css_clear_subchannel_slow_list(); css_clear_subchannel_slow_list();
need_rescan = 1; need_rescan = 1;
} }
...@@ -337,7 +338,7 @@ s390_process_res_acc_sch(u8 chpid, __u16 fla, u32 fla_mask, ...@@ -337,7 +338,7 @@ s390_process_res_acc_sch(u8 chpid, __u16 fla, u32 fla_mask,
* new path information and eventually check for logically * new path information and eventually check for logically
* offline chpids. * offline chpids.
*/ */
ccode = stsch(sch->irq, &sch->schib); ccode = stsch(sch->schid, &sch->schib);
if (ccode > 0) if (ccode > 0)
return 0; return 0;
...@@ -348,7 +349,8 @@ static int ...@@ -348,7 +349,8 @@ static int
s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask) s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
{ {
struct subchannel *sch; struct subchannel *sch;
int irq, rc; int rc;
struct subchannel_id schid;
char dbf_txt[15]; char dbf_txt[15];
sprintf(dbf_txt, "accpr%x", chpid); sprintf(dbf_txt, "accpr%x", chpid);
...@@ -370,10 +372,11 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask) ...@@ -370,10 +372,11 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
return 0; /* no need to do the rest */ return 0; /* no need to do the rest */
rc = 0; rc = 0;
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { init_subchannel_id(&schid);
do {
int chp_mask, old_lpm; int chp_mask, old_lpm;
sch = get_subchannel_by_schid(irq); sch = get_subchannel_by_schid(schid);
if (!sch) { if (!sch) {
struct schib schib; struct schib schib;
int ret; int ret;
...@@ -385,7 +388,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask) ...@@ -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 * that beast may be on we'll have to do a stsch
* on all devices, grr... * on all devices, grr...
*/ */
if (stsch(irq, &schib)) { if (stsch(schid, &schib)) {
/* We're through */ /* We're through */
if (need_rescan) if (need_rescan)
rc = -EAGAIN; rc = -EAGAIN;
...@@ -396,7 +399,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask) ...@@ -396,7 +399,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
continue; continue;
} }
/* Put it on the slow path. */ /* Put it on the slow path. */
ret = css_enqueue_subchannel_slow(irq); ret = css_enqueue_subchannel_slow(schid);
if (ret) { if (ret) {
css_clear_subchannel_slow_list(); css_clear_subchannel_slow_list();
need_rescan = 1; need_rescan = 1;
...@@ -428,7 +431,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask) ...@@ -428,7 +431,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
put_device(&sch->dev); put_device(&sch->dev);
if (fla_mask == 0xffff) if (fla_mask == 0xffff)
break; break;
} } while (schid.sch_no++ < __MAX_SUBCHANNEL);
return rc; return rc;
} }
...@@ -608,7 +611,8 @@ static int ...@@ -608,7 +611,8 @@ static int
chp_add(int chpid) chp_add(int chpid)
{ {
struct subchannel *sch; struct subchannel *sch;
int irq, ret, rc; int ret, rc;
struct subchannel_id schid;
char dbf_txt[15]; char dbf_txt[15];
if (!get_chp_status(chpid)) if (!get_chp_status(chpid))
...@@ -618,14 +622,15 @@ chp_add(int chpid) ...@@ -618,14 +622,15 @@ chp_add(int chpid)
CIO_TRACE_EVENT(2, dbf_txt); CIO_TRACE_EVENT(2, dbf_txt);
rc = 0; rc = 0;
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { init_subchannel_id(&schid);
do {
int i; int i;
sch = get_subchannel_by_schid(irq); sch = get_subchannel_by_schid(schid);
if (!sch) { if (!sch) {
struct schib schib; struct schib schib;
if (stsch(irq, &schib)) { if (stsch(schid, &schib)) {
/* We're through */ /* We're through */
if (need_rescan) if (need_rescan)
rc = -EAGAIN; rc = -EAGAIN;
...@@ -636,7 +641,7 @@ chp_add(int chpid) ...@@ -636,7 +641,7 @@ chp_add(int chpid)
continue; continue;
} }
/* Put it on the slow path. */ /* Put it on the slow path. */
ret = css_enqueue_subchannel_slow(irq); ret = css_enqueue_subchannel_slow(schid);
if (ret) { if (ret) {
css_clear_subchannel_slow_list(); css_clear_subchannel_slow_list();
need_rescan = 1; need_rescan = 1;
...@@ -648,7 +653,7 @@ chp_add(int chpid) ...@@ -648,7 +653,7 @@ chp_add(int chpid)
spin_lock(&sch->lock); spin_lock(&sch->lock);
for (i=0; i<8; i++) for (i=0; i<8; i++)
if (sch->schib.pmcw.chpid[i] == chpid) { if (sch->schib.pmcw.chpid[i] == chpid) {
if (stsch(sch->irq, &sch->schib) != 0) { if (stsch(sch->schid, &sch->schib) != 0) {
/* Endgame. */ /* Endgame. */
spin_unlock(&sch->lock); spin_unlock(&sch->lock);
return rc; return rc;
...@@ -669,7 +674,7 @@ chp_add(int chpid) ...@@ -669,7 +674,7 @@ chp_add(int chpid)
spin_unlock(&sch->lock); spin_unlock(&sch->lock);
put_device(&sch->dev); put_device(&sch->dev);
} } while (schid.sch_no++ < __MAX_SUBCHANNEL);
return rc; return rc;
} }
...@@ -702,7 +707,7 @@ __check_for_io_and_kill(struct subchannel *sch, int index) ...@@ -702,7 +707,7 @@ __check_for_io_and_kill(struct subchannel *sch, int index)
if (!device_is_online(sch)) if (!device_is_online(sch))
/* cio could be doing I/O. */ /* cio could be doing I/O. */
return 0; return 0;
cc = stsch(sch->irq, &sch->schib); cc = stsch(sch->schid, &sch->schib);
if (cc) if (cc)
return 0; return 0;
if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) { 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) ...@@ -743,7 +748,7 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
* just varied off path. Then kill it. * just varied off path. Then kill it.
*/ */
if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) { 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(); css_clear_subchannel_slow_list();
need_rescan = 1; need_rescan = 1;
} }
...@@ -789,7 +794,8 @@ static int ...@@ -789,7 +794,8 @@ static int
s390_vary_chpid( __u8 chpid, int on) s390_vary_chpid( __u8 chpid, int on)
{ {
char dbf_text[15]; char dbf_text[15];
int status, irq, ret; int status, ret;
struct subchannel_id schid;
struct subchannel *sch; struct subchannel *sch;
sprintf(dbf_text, on?"varyon%x":"varyoff%x", chpid); sprintf(dbf_text, on?"varyon%x":"varyoff%x", chpid);
...@@ -818,26 +824,27 @@ s390_vary_chpid( __u8 chpid, int on) ...@@ -818,26 +824,27 @@ s390_vary_chpid( __u8 chpid, int on)
if (!on) if (!on)
goto out; goto out;
/* Scan for new devices on varied on path. */ /* Scan for new devices on varied on path. */
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { init_subchannel_id(&schid);
do {
struct schib schib; struct schib schib;
if (need_rescan) if (need_rescan)
break; break;
sch = get_subchannel_by_schid(irq); sch = get_subchannel_by_schid(schid);
if (sch) { if (sch) {
put_device(&sch->dev); put_device(&sch->dev);
continue; continue;
} }
if (stsch(irq, &schib)) if (stsch(schid, &schib))
/* We're through */ /* We're through */
break; break;
/* Put it on the slow path. */ /* Put it on the slow path. */
ret = css_enqueue_subchannel_slow(irq); ret = css_enqueue_subchannel_slow(schid);
if (ret) { if (ret) {
css_clear_subchannel_slow_list(); css_clear_subchannel_slow_list();
need_rescan = 1; need_rescan = 1;
} }
} } while (schid.sch_no++ < __MAX_SUBCHANNEL);
out: out:
if (need_rescan || css_slow_subchannels_exist()) if (need_rescan || css_slow_subchannels_exist())
queue_work(slow_path_wq, &slow_path_work); queue_work(slow_path_wq, &slow_path_work);
......
...@@ -135,7 +135,7 @@ cio_tpi(void) ...@@ -135,7 +135,7 @@ cio_tpi(void)
return 0; return 0;
irb = (struct irb *) __LC_IRB; irb = (struct irb *) __LC_IRB;
/* Store interrupt response block to lowcore. */ /* 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. */ /* Not status pending or not operational. */
return 1; return 1;
sch = (struct subchannel *)(unsigned long)tpi_info->intparm; sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
...@@ -163,10 +163,10 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) ...@@ -163,10 +163,10 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
else else
sch->lpm = 0; sch->lpm = 0;
stsch (sch->irq, &sch->schib); stsch (sch->schid, &sch->schib);
CIO_MSG_EVENT(0, "cio_start: 'not oper' status for " 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); sprintf(dbf_text, "no%s", sch->dev.bus_id);
CIO_TRACE_EVENT(0, dbf_text); CIO_TRACE_EVENT(0, dbf_text);
CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));
...@@ -204,7 +204,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ ...@@ -204,7 +204,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */
sch->orb.key = key >> 4; sch->orb.key = key >> 4;
/* issue "Start Subchannel" */ /* issue "Start Subchannel" */
sch->orb.cpa = (__u32) __pa (cpa); sch->orb.cpa = (__u32) __pa (cpa);
ccode = ssch (sch->irq, &sch->orb); ccode = ssch (sch->schid, &sch->orb);
/* process condition code */ /* process condition code */
sprintf (dbf_txt, "ccode:%d", ccode); sprintf (dbf_txt, "ccode:%d", ccode);
...@@ -243,7 +243,7 @@ cio_resume (struct subchannel *sch) ...@@ -243,7 +243,7 @@ cio_resume (struct subchannel *sch)
CIO_TRACE_EVENT (4, "resIO"); CIO_TRACE_EVENT (4, "resIO");
CIO_TRACE_EVENT (4, sch->dev.bus_id); CIO_TRACE_EVENT (4, sch->dev.bus_id);
ccode = rsch (sch->irq); ccode = rsch (sch->schid);
sprintf (dbf_txt, "ccode:%d", ccode); sprintf (dbf_txt, "ccode:%d", ccode);
CIO_TRACE_EVENT (4, dbf_txt); CIO_TRACE_EVENT (4, dbf_txt);
...@@ -283,7 +283,7 @@ cio_halt(struct subchannel *sch) ...@@ -283,7 +283,7 @@ cio_halt(struct subchannel *sch)
/* /*
* Issue "Halt subchannel" and process condition code * Issue "Halt subchannel" and process condition code
*/ */
ccode = hsch (sch->irq); ccode = hsch (sch->schid);
sprintf (dbf_txt, "ccode:%d", ccode); sprintf (dbf_txt, "ccode:%d", ccode);
CIO_TRACE_EVENT (2, dbf_txt); CIO_TRACE_EVENT (2, dbf_txt);
...@@ -318,7 +318,7 @@ cio_clear(struct subchannel *sch) ...@@ -318,7 +318,7 @@ cio_clear(struct subchannel *sch)
/* /*
* Issue "Clear subchannel" and process condition code * Issue "Clear subchannel" and process condition code
*/ */
ccode = csch (sch->irq); ccode = csch (sch->schid);
sprintf (dbf_txt, "ccode:%d", ccode); sprintf (dbf_txt, "ccode:%d", ccode);
CIO_TRACE_EVENT (2, dbf_txt); CIO_TRACE_EVENT (2, dbf_txt);
...@@ -351,7 +351,7 @@ cio_cancel (struct subchannel *sch) ...@@ -351,7 +351,7 @@ cio_cancel (struct subchannel *sch)
CIO_TRACE_EVENT (2, "cancelIO"); CIO_TRACE_EVENT (2, "cancelIO");
CIO_TRACE_EVENT (2, sch->dev.bus_id); CIO_TRACE_EVENT (2, sch->dev.bus_id);
ccode = xsch (sch->irq); ccode = xsch (sch->schid);
sprintf (dbf_txt, "ccode:%d", ccode); sprintf (dbf_txt, "ccode:%d", ccode);
CIO_TRACE_EVENT (2, dbf_txt); CIO_TRACE_EVENT (2, dbf_txt);
...@@ -359,7 +359,7 @@ cio_cancel (struct subchannel *sch) ...@@ -359,7 +359,7 @@ cio_cancel (struct subchannel *sch)
switch (ccode) { switch (ccode) {
case 0: /* success */ case 0: /* success */
/* Update information in scsw. */ /* Update information in scsw. */
stsch (sch->irq, &sch->schib); stsch (sch->schid, &sch->schib);
return 0; return 0;
case 1: /* status pending */ case 1: /* status pending */
return -EBUSY; return -EBUSY;
...@@ -381,7 +381,7 @@ cio_modify (struct subchannel *sch) ...@@ -381,7 +381,7 @@ cio_modify (struct subchannel *sch)
ret = 0; ret = 0;
for (retry = 0; retry < 5; retry++) { 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. */ if (ccode < 0) /* -EIO if msch gets a program check. */
return ccode; return ccode;
switch (ccode) { switch (ccode) {
...@@ -414,7 +414,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc) ...@@ -414,7 +414,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
CIO_TRACE_EVENT (2, "ensch"); CIO_TRACE_EVENT (2, "ensch");
CIO_TRACE_EVENT (2, sch->dev.bus_id); CIO_TRACE_EVENT (2, sch->dev.bus_id);
ccode = stsch (sch->irq, &sch->schib); ccode = stsch (sch->schid, &sch->schib);
if (ccode) if (ccode)
return -ENODEV; return -ENODEV;
...@@ -432,13 +432,13 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc) ...@@ -432,13 +432,13 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
*/ */
sch->schib.pmcw.csense = 0; sch->schib.pmcw.csense = 0;
if (ret == 0) { if (ret == 0) {
stsch (sch->irq, &sch->schib); stsch (sch->schid, &sch->schib);
if (sch->schib.pmcw.ena) if (sch->schib.pmcw.ena)
break; break;
} }
if (ret == -EBUSY) { if (ret == -EBUSY) {
struct irb irb; struct irb irb;
if (tsch(sch->irq, &irb) != 0) if (tsch(sch->schid, &irb) != 0)
break; break;
} }
} }
...@@ -461,7 +461,7 @@ cio_disable_subchannel (struct subchannel *sch) ...@@ -461,7 +461,7 @@ cio_disable_subchannel (struct subchannel *sch)
CIO_TRACE_EVENT (2, "dissch"); CIO_TRACE_EVENT (2, "dissch");
CIO_TRACE_EVENT (2, sch->dev.bus_id); 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. */ if (ccode == 3) /* Not operational. */
return -ENODEV; return -ENODEV;
...@@ -485,7 +485,7 @@ cio_disable_subchannel (struct subchannel *sch) ...@@ -485,7 +485,7 @@ cio_disable_subchannel (struct subchannel *sch)
*/ */
break; break;
if (ret == 0) { if (ret == 0) {
stsch (sch->irq, &sch->schib); stsch (sch->schid, &sch->schib);
if (!sch->schib.pmcw.ena) if (!sch->schib.pmcw.ena)
break; break;
} }
...@@ -508,12 +508,12 @@ cio_disable_subchannel (struct subchannel *sch) ...@@ -508,12 +508,12 @@ cio_disable_subchannel (struct subchannel *sch)
* -ENODEV for subchannels with invalid device number or blacklisted devices * -ENODEV for subchannels with invalid device number or blacklisted devices
*/ */
int int
cio_validate_subchannel (struct subchannel *sch, unsigned int irq) cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
{ {
char dbf_txt[15]; char dbf_txt[15];
int ccode; int ccode;
sprintf (dbf_txt, "valsch%x", irq); sprintf (dbf_txt, "valsch%x", schid.sch_no);
CIO_TRACE_EVENT (4, dbf_txt); CIO_TRACE_EVENT (4, dbf_txt);
/* Nuke all fields. */ /* Nuke all fields. */
...@@ -522,17 +522,17 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq) ...@@ -522,17 +522,17 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq)
spin_lock_init(&sch->lock); spin_lock_init(&sch->lock);
/* Set a name for the subchannel */ /* 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) * The first subchannel that is not-operational (ccode==3)
* indicates that there aren't any more devices available. * indicates that there aren't any more devices available.
*/ */
sch->irq = irq; ccode = stsch (schid, &sch->schib);
ccode = stsch (irq, &sch->schib);
if (ccode) if (ccode)
return -ENXIO; return -ENXIO;
sch->schid = schid;
/* Copy subchannel type from path management control word. */ /* Copy subchannel type from path management control word. */
sch->st = sch->schib.pmcw.st; sch->st = sch->schib.pmcw.st;
...@@ -543,7 +543,7 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq) ...@@ -543,7 +543,7 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq)
CIO_DEBUG(KERN_INFO, 0, CIO_DEBUG(KERN_INFO, 0,
"Subchannel %04X reports " "Subchannel %04X reports "
"non-I/O subchannel type %04X\n", "non-I/O subchannel type %04X\n",
sch->irq, sch->st); sch->schid.sch_no, sch->st);
/* We stop here for non-io subchannels. */ /* We stop here for non-io subchannels. */
return sch->st; return sch->st;
} }
...@@ -573,7 +573,7 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq) ...@@ -573,7 +573,7 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq)
CIO_DEBUG(KERN_INFO, 0, CIO_DEBUG(KERN_INFO, 0,
"Detected device %04X on subchannel %04X" "Detected device %04X on subchannel %04X"
" - PIM = %02X, PAM = %02X, POM = %02X\n", " - 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); sch->schib.pmcw.pam, sch->schib.pmcw.pom);
/* /*
...@@ -632,7 +632,7 @@ do_IRQ (struct pt_regs *regs) ...@@ -632,7 +632,7 @@ do_IRQ (struct pt_regs *regs)
if (sch) if (sch)
spin_lock(&sch->lock); spin_lock(&sch->lock);
/* Store interrupt response block to lowcore. */ /* 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. */ /* Keep subchannel information word up to date. */
memcpy (&sch->schib.scsw, &irb->scsw, memcpy (&sch->schib.scsw, &irb->scsw,
sizeof (irb->scsw)); sizeof (irb->scsw));
...@@ -693,26 +693,28 @@ wait_cons_dev (void) ...@@ -693,26 +693,28 @@ wait_cons_dev (void)
static int static int
cio_console_irq(void) cio_console_irq(void)
{ {
int irq; struct subchannel_id schid;
init_subchannel_id(&schid);
if (console_irq != -1) { if (console_irq != -1) {
/* VM provided us with the irq number of the console. */ /* 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) !console_subchannel.schib.pmcw.dnv)
return -1; return -1;
console_devno = console_subchannel.schib.pmcw.dev; console_devno = console_subchannel.schib.pmcw.dev;
} else if (console_devno != -1) { } else if (console_devno != -1) {
/* At least the console device number is known. */ /* At least the console device number is known. */
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { do {
if (stsch(irq, &console_subchannel.schib) != 0) if (stsch(schid, &console_subchannel.schib) != 0)
break; break;
if (console_subchannel.schib.pmcw.dnv && if (console_subchannel.schib.pmcw.dnv &&
console_subchannel.schib.pmcw.dev == console_subchannel.schib.pmcw.dev ==
console_devno) { console_devno) {
console_irq = irq; console_irq = schid.sch_no;
break; break;
} }
} } while (schid.sch_no++ < __MAX_SUBCHANNEL);
if (console_irq == -1) if (console_irq == -1)
return -1; return -1;
} else { } else {
...@@ -729,6 +731,7 @@ struct subchannel * ...@@ -729,6 +731,7 @@ struct subchannel *
cio_probe_console(void) cio_probe_console(void)
{ {
int irq, ret; int irq, ret;
struct subchannel_id schid;
if (xchg(&console_subchannel_in_use, 1) != 0) if (xchg(&console_subchannel_in_use, 1) != 0)
return ERR_PTR(-EBUSY); return ERR_PTR(-EBUSY);
...@@ -738,7 +741,9 @@ cio_probe_console(void) ...@@ -738,7 +741,9 @@ cio_probe_console(void)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
memset(&console_subchannel, 0, sizeof(struct subchannel)); 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) { if (ret) {
console_subchannel_in_use = 0; console_subchannel_in_use = 0;
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
...@@ -770,11 +775,11 @@ cio_release_console(void) ...@@ -770,11 +775,11 @@ cio_release_console(void)
/* Bah... hack to catch console special sausages. */ /* Bah... hack to catch console special sausages. */
int int
cio_is_console(int irq) cio_is_console(struct subchannel_id schid)
{ {
if (!console_subchannel_in_use) if (!console_subchannel_in_use)
return 0; return 0;
return (irq == console_subchannel.irq); return schid_equal(&schid, &console_subchannel.schid);
} }
struct subchannel * struct subchannel *
...@@ -787,7 +792,7 @@ cio_get_console_subchannel(void) ...@@ -787,7 +792,7 @@ cio_get_console_subchannel(void)
#endif #endif
static inline int 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; int retry, cc;
...@@ -805,7 +810,7 @@ __disable_subchannel_easy(unsigned int schid, struct schib *schib) ...@@ -805,7 +810,7 @@ __disable_subchannel_easy(unsigned int schid, struct schib *schib)
} }
static inline int static inline int
__clear_subchannel_easy(unsigned int schid) __clear_subchannel_easy(struct subchannel_id schid)
{ {
int retry; int retry;
...@@ -815,8 +820,8 @@ __clear_subchannel_easy(unsigned int schid) ...@@ -815,8 +820,8 @@ __clear_subchannel_easy(unsigned int schid)
struct tpi_info ti; struct tpi_info ti;
if (tpi(&ti)) { if (tpi(&ti)) {
tsch(ti.irq, (struct irb *)__LC_IRB); tsch(ti.schid, (struct irb *)__LC_IRB);
if (ti.irq == schid) if (schid_equal(&ti.schid, &schid))
return 0; return 0;
} }
udelay(100); udelay(100);
...@@ -830,10 +835,11 @@ extern void do_reipl(unsigned long devno); ...@@ -830,10 +835,11 @@ extern void do_reipl(unsigned long devno);
void void
clear_all_subchannels(void) clear_all_subchannels(void)
{ {
unsigned int schid; struct subchannel_id schid;
local_irq_disable(); local_irq_disable();
for (schid=0;schid<=highest_subchannel;schid++) { init_subchannel_id(&schid);
do {
struct schib schib; struct schib schib;
if (stsch(schid, &schib)) if (stsch(schid, &schib))
break; /* break out of the loop */ break; /* break out of the loop */
...@@ -849,7 +855,7 @@ clear_all_subchannels(void) ...@@ -849,7 +855,7 @@ clear_all_subchannels(void)
stsch(schid, &schib); stsch(schid, &schib);
__disable_subchannel_easy(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. */ /* Make sure all subchannels are quiet before we re-ipl an lpar. */
......
#ifndef S390_CIO_H #ifndef S390_CIO_H
#define S390_CIO_H #define S390_CIO_H
#include "schid.h"
/* /*
* where we put the ssd info * where we put the ssd info
*/ */
...@@ -83,7 +85,7 @@ struct orb { ...@@ -83,7 +85,7 @@ struct orb {
/* subchannel data structure used by I/O subroutines */ /* subchannel data structure used by I/O subroutines */
struct subchannel { struct subchannel {
unsigned int irq; /* aka. subchannel number */ struct subchannel_id schid;
spinlock_t lock; /* subchannel lock */ spinlock_t lock; /* subchannel lock */
enum { enum {
...@@ -114,7 +116,7 @@ struct subchannel { ...@@ -114,7 +116,7 @@ struct subchannel {
#define to_subchannel(n) container_of(n, struct subchannel, dev) #define to_subchannel(n) container_of(n, struct subchannel, dev)
extern int cio_validate_subchannel (struct subchannel *, unsigned int); extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id);
extern int cio_enable_subchannel (struct subchannel *, unsigned int); extern int cio_enable_subchannel (struct subchannel *, unsigned int);
extern int cio_disable_subchannel (struct subchannel *); extern int cio_disable_subchannel (struct subchannel *);
extern int cio_cancel (struct subchannel *); extern int cio_cancel (struct subchannel *);
...@@ -127,14 +129,15 @@ extern int cio_cancel (struct subchannel *); ...@@ -127,14 +129,15 @@ extern int cio_cancel (struct subchannel *);
extern int cio_set_options (struct subchannel *, int); extern int cio_set_options (struct subchannel *, int);
extern int cio_get_options (struct subchannel *); extern int cio_get_options (struct subchannel *);
extern int cio_modify (struct subchannel *); extern int cio_modify (struct subchannel *);
/* Use with care. */ /* Use with care. */
#ifdef CONFIG_CCW_CONSOLE #ifdef CONFIG_CCW_CONSOLE
extern struct subchannel *cio_probe_console(void); extern struct subchannel *cio_probe_console(void);
extern void cio_release_console(void); extern void cio_release_console(void);
extern int cio_is_console(int irq); extern int cio_is_console(struct subchannel_id);
extern struct subchannel *cio_get_console_subchannel(void); extern struct subchannel *cio_get_console_subchannel(void);
#else #else
#define cio_is_console(irq) 0 #define cio_is_console(schid) 0
#define cio_get_console_subchannel() NULL #define cio_get_console_subchannel() NULL
#endif #endif
......
/* /*
* linux/drivers/s390/cio/cmf.c ($Revision: 1.16 $) * linux/drivers/s390/cio/cmf.c ($Revision: 1.19 $)
* *
* Linux on zSeries Channel Measurement Facility support * Linux on zSeries Channel Measurement Facility support
* *
...@@ -178,7 +178,7 @@ set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address) ...@@ -178,7 +178,7 @@ set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address)
/* msch can silently fail, so do it again if necessary */ /* msch can silently fail, so do it again if necessary */
for (retry = 0; retry < 3; retry++) { for (retry = 0; retry < 3; retry++) {
/* prepare schib */ /* prepare schib */
stsch(sch->irq, schib); stsch(sch->schid, schib);
schib->pmcw.mme = mme; schib->pmcw.mme = mme;
schib->pmcw.mbfc = mbfc; schib->pmcw.mbfc = mbfc;
/* address can be either a block address or a block index */ /* address can be either a block address or a block index */
...@@ -188,7 +188,7 @@ set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address) ...@@ -188,7 +188,7 @@ set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address)
schib->pmcw.mbi = address; schib->pmcw.mbi = address;
/* try to submit it */ /* try to submit it */
switch(ret = msch_err(sch->irq, schib)) { switch(ret = msch_err(sch->schid, schib)) {
case 0: case 0:
break; break;
case 1: case 1:
...@@ -202,7 +202,7 @@ set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address) ...@@ -202,7 +202,7 @@ set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address)
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
stsch(sch->irq, schib); /* restore the schib */ stsch(sch->schid, schib); /* restore the schib */
if (ret) if (ret)
break; break;
......
...@@ -33,7 +33,7 @@ struct device css_bus_device = { ...@@ -33,7 +33,7 @@ struct device css_bus_device = {
}; };
static struct subchannel * static struct subchannel *
css_alloc_subchannel(int irq) css_alloc_subchannel(struct subchannel_id schid)
{ {
struct subchannel *sch; struct subchannel *sch;
int ret; int ret;
...@@ -41,13 +41,11 @@ css_alloc_subchannel(int irq) ...@@ -41,13 +41,11 @@ css_alloc_subchannel(int irq)
sch = kmalloc (sizeof (*sch), GFP_KERNEL | GFP_DMA); sch = kmalloc (sizeof (*sch), GFP_KERNEL | GFP_DMA);
if (sch == NULL) if (sch == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ret = cio_validate_subchannel (sch, irq); ret = cio_validate_subchannel (sch, schid);
if (ret < 0) { if (ret < 0) {
kfree(sch); kfree(sch);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
if (irq > highest_subchannel)
highest_subchannel = irq;
if (sch->st != SUBCHANNEL_TYPE_IO) { if (sch->st != SUBCHANNEL_TYPE_IO) {
/* For now we ignore all non-io subchannels. */ /* For now we ignore all non-io subchannels. */
...@@ -87,7 +85,7 @@ css_subchannel_release(struct device *dev) ...@@ -87,7 +85,7 @@ css_subchannel_release(struct device *dev)
struct subchannel *sch; struct subchannel *sch;
sch = to_subchannel(dev); sch = to_subchannel(dev);
if (!cio_is_console(sch->irq)) if (!cio_is_console(sch->schid))
kfree(sch); kfree(sch);
} }
...@@ -114,12 +112,12 @@ css_register_subchannel(struct subchannel *sch) ...@@ -114,12 +112,12 @@ css_register_subchannel(struct subchannel *sch)
} }
int int
css_probe_device(int irq) css_probe_device(struct subchannel_id schid)
{ {
int ret; int ret;
struct subchannel *sch; struct subchannel *sch;
sch = css_alloc_subchannel(irq); sch = css_alloc_subchannel(schid);
if (IS_ERR(sch)) if (IS_ERR(sch))
return PTR_ERR(sch); return PTR_ERR(sch);
ret = css_register_subchannel(sch); ret = css_register_subchannel(sch);
...@@ -132,26 +130,26 @@ static int ...@@ -132,26 +130,26 @@ static int
check_subchannel(struct device * dev, void * data) check_subchannel(struct device * dev, void * data)
{ {
struct subchannel *sch; struct subchannel *sch;
int irq = (unsigned long)data; struct subchannel_id *schid = data;
sch = to_subchannel(dev); sch = to_subchannel(dev);
return (sch->irq == irq); return schid_equal(&sch->schid, schid);
} }
struct subchannel * struct subchannel *
get_subchannel_by_schid(int irq) get_subchannel_by_schid(struct subchannel_id schid)
{ {
struct device *dev; struct device *dev;
dev = bus_find_device(&css_bus_type, NULL, dev = bus_find_device(&css_bus_type, NULL,
(void *)(unsigned long)irq, check_subchannel); (void *)&schid, check_subchannel);
return dev ? to_subchannel(dev) : NULL; return dev ? to_subchannel(dev) : NULL;
} }
static inline int static inline int
css_get_subchannel_status(struct subchannel *sch, int schid) css_get_subchannel_status(struct subchannel *sch, struct subchannel_id schid)
{ {
struct schib schib; struct schib schib;
int cc; int cc;
...@@ -170,13 +168,13 @@ css_get_subchannel_status(struct subchannel *sch, int schid) ...@@ -170,13 +168,13 @@ css_get_subchannel_status(struct subchannel *sch, int schid)
} }
static int static int
css_evaluate_subchannel(int irq, int slow) css_evaluate_subchannel(struct subchannel_id schid, int slow)
{ {
int event, ret, disc; int event, ret, disc;
struct subchannel *sch; struct subchannel *sch;
unsigned long flags; unsigned long flags;
sch = get_subchannel_by_schid(irq); sch = get_subchannel_by_schid(schid);
disc = sch ? device_is_disconnected(sch) : 0; disc = sch ? device_is_disconnected(sch) : 0;
if (disc && slow) { if (disc && slow) {
if (sch) if (sch)
...@@ -194,9 +192,10 @@ css_evaluate_subchannel(int irq, int slow) ...@@ -194,9 +192,10 @@ css_evaluate_subchannel(int irq, int slow)
put_device(&sch->dev); put_device(&sch->dev);
return -EAGAIN; /* Will be done on the slow path. */ return -EAGAIN; /* Will be done on the slow path. */
} }
event = css_get_subchannel_status(sch, irq); event = css_get_subchannel_status(sch, schid);
CIO_MSG_EVENT(4, "Evaluating schid %04x, event %d, %s, %s path.\n", CIO_MSG_EVENT(4, "Evaluating schid %04x, event %d, %s, %s path.\n",
irq, event, sch?(disc?"disconnected":"normal"):"unknown", schid.sch_no, event,
sch?(disc?"disconnected":"normal"):"unknown",
slow?"slow":"fast"); slow?"slow":"fast");
switch (event) { switch (event) {
case CIO_NO_PATH: case CIO_NO_PATH:
...@@ -253,7 +252,7 @@ css_evaluate_subchannel(int irq, int slow) ...@@ -253,7 +252,7 @@ css_evaluate_subchannel(int irq, int slow)
sch->schib.pmcw.intparm = 0; sch->schib.pmcw.intparm = 0;
cio_modify(sch); cio_modify(sch);
put_device(&sch->dev); put_device(&sch->dev);
ret = css_probe_device(irq); ret = css_probe_device(schid);
} else { } else {
/* /*
* We can't immediately deregister the disconnected * We can't immediately deregister the disconnected
...@@ -272,7 +271,7 @@ css_evaluate_subchannel(int irq, int slow) ...@@ -272,7 +271,7 @@ css_evaluate_subchannel(int irq, int slow)
device_trigger_reprobe(sch); device_trigger_reprobe(sch);
spin_unlock_irqrestore(&sch->lock, flags); spin_unlock_irqrestore(&sch->lock, flags);
} }
ret = sch ? 0 : css_probe_device(irq); ret = sch ? 0 : css_probe_device(schid);
break; break;
default: default:
BUG(); BUG();
...@@ -284,10 +283,12 @@ css_evaluate_subchannel(int irq, int slow) ...@@ -284,10 +283,12 @@ css_evaluate_subchannel(int irq, int slow)
static void static void
css_rescan_devices(void) css_rescan_devices(void)
{ {
int irq, ret; int ret;
struct subchannel_id schid;
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { init_subchannel_id(&schid);
ret = css_evaluate_subchannel(irq, 1); do {
ret = css_evaluate_subchannel(schid, 1);
/* No more memory. It doesn't make sense to continue. No /* No more memory. It doesn't make sense to continue. No
* panic because this can happen in midflight and just * panic because this can happen in midflight and just
* because we can't use a new device is no reason to crash * because we can't use a new device is no reason to crash
...@@ -297,12 +298,12 @@ css_rescan_devices(void) ...@@ -297,12 +298,12 @@ css_rescan_devices(void)
/* -ENXIO indicates that there are no more subchannels. */ /* -ENXIO indicates that there are no more subchannels. */
if (ret == -ENXIO) if (ret == -ENXIO)
break; break;
} } while (schid.sch_no++ < __MAX_SUBCHANNEL);
} }
struct slow_subchannel { struct slow_subchannel {
struct list_head slow_list; struct list_head slow_list;
unsigned long schid; struct subchannel_id schid;
}; };
static LIST_HEAD(slow_subchannels_head); static LIST_HEAD(slow_subchannels_head);
...@@ -357,20 +358,24 @@ int ...@@ -357,20 +358,24 @@ int
css_process_crw(int irq) css_process_crw(int irq)
{ {
int ret; int ret;
struct subchannel_id mchk_schid;
CIO_CRW_EVENT(2, "source is subchannel %04X\n", irq); CIO_CRW_EVENT(2, "source is subchannel %04X\n", irq);
if (need_rescan) if (need_rescan)
/* We need to iterate all subchannels anyway. */ /* We need to iterate all subchannels anyway. */
return -EAGAIN; return -EAGAIN;
init_subchannel_id(&mchk_schid);
mchk_schid.sch_no = irq;
/* /*
* Since we are always presented with IPI in the CRW, we have to * Since we are always presented with IPI in the CRW, we have to
* use stsch() to find out if the subchannel in question has come * use stsch() to find out if the subchannel in question has come
* or gone. * or gone.
*/ */
ret = css_evaluate_subchannel(irq, 0); ret = css_evaluate_subchannel(mchk_schid, 0);
if (ret == -EAGAIN) { if (ret == -EAGAIN) {
if (css_enqueue_subchannel_slow(irq)) { if (css_enqueue_subchannel_slow(mchk_schid)) {
css_clear_subchannel_slow_list(); css_clear_subchannel_slow_list();
need_rescan = 1; need_rescan = 1;
} }
...@@ -404,7 +409,8 @@ css_generate_pgid(void) ...@@ -404,7 +409,8 @@ css_generate_pgid(void)
static int __init static int __init
init_channel_subsystem (void) init_channel_subsystem (void)
{ {
int ret, irq; int ret;
struct subchannel_id schid;
if (chsc_determine_css_characteristics() == 0) if (chsc_determine_css_characteristics() == 0)
css_characteristics_avail = 1; css_characteristics_avail = 1;
...@@ -420,13 +426,14 @@ init_channel_subsystem (void) ...@@ -420,13 +426,14 @@ init_channel_subsystem (void)
ctl_set_bit(6, 28); ctl_set_bit(6, 28);
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { init_subchannel_id(&schid);
do {
struct subchannel *sch; struct subchannel *sch;
if (cio_is_console(irq)) if (cio_is_console(schid))
sch = cio_get_console_subchannel(); sch = cio_get_console_subchannel();
else { else {
sch = css_alloc_subchannel(irq); sch = css_alloc_subchannel(schid);
if (IS_ERR(sch)) if (IS_ERR(sch))
ret = PTR_ERR(sch); ret = PTR_ERR(sch);
else else
...@@ -448,7 +455,7 @@ init_channel_subsystem (void) ...@@ -448,7 +455,7 @@ init_channel_subsystem (void)
* console subchannel. * console subchannel.
*/ */
css_register_subchannel(sch); css_register_subchannel(sch);
} } while (schid.sch_no++ < __MAX_SUBCHANNEL);
return 0; return 0;
out_bus: out_bus:
...@@ -482,7 +489,7 @@ struct bus_type css_bus_type = { ...@@ -482,7 +489,7 @@ struct bus_type css_bus_type = {
subsys_initcall(init_channel_subsystem); subsys_initcall(init_channel_subsystem);
int int
css_enqueue_subchannel_slow(unsigned long schid) css_enqueue_subchannel_slow(struct subchannel_id schid)
{ {
struct slow_subchannel *new_slow_sch; struct slow_subchannel *new_slow_sch;
unsigned long flags; unsigned long flags;
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include <asm/cio.h> #include <asm/cio.h>
#include "schid.h"
/* /*
* path grouping stuff * path grouping stuff
*/ */
...@@ -68,7 +70,7 @@ struct ccw_device_private { ...@@ -68,7 +70,7 @@ struct ccw_device_private {
atomic_t onoff; atomic_t onoff;
unsigned long registered; unsigned long registered;
__u16 devno; /* device number */ __u16 devno; /* device number */
__u16 irq; /* subchannel number */ __u16 sch_no; /* subchannel number */
__u8 imask; /* lpm mask for SNID/SID/SPGID */ __u8 imask; /* lpm mask for SNID/SID/SPGID */
int iretry; /* retry counter SNID/SID/SPGID */ int iretry; /* retry counter SNID/SID/SPGID */
struct { struct {
...@@ -121,12 +123,11 @@ struct css_driver { ...@@ -121,12 +123,11 @@ struct css_driver {
extern struct bus_type css_bus_type; extern struct bus_type css_bus_type;
extern struct css_driver io_subchannel_driver; extern struct css_driver io_subchannel_driver;
int css_probe_device(int irq); extern int css_probe_device(struct subchannel_id);
extern struct subchannel * get_subchannel_by_schid(int irq); extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
extern unsigned int highest_subchannel;
extern int css_init_done; extern int css_init_done;
#define __MAX_SUBCHANNELS 65536 #define __MAX_SUBCHANNEL 65535
extern struct bus_type css_bus_type; extern struct bus_type css_bus_type;
extern struct device css_bus_device; extern struct device css_bus_device;
...@@ -144,7 +145,7 @@ void device_set_waiting(struct subchannel *); ...@@ -144,7 +145,7 @@ void device_set_waiting(struct subchannel *);
void device_kill_pending_timer(struct subchannel *); void device_kill_pending_timer(struct subchannel *);
/* Helper functions to build lists for the slow path. */ /* Helper functions to build lists for the slow path. */
int css_enqueue_subchannel_slow(unsigned long schid); extern int css_enqueue_subchannel_slow(struct subchannel_id schid);
void css_walk_subchannel_slow_list(void (*fn)(unsigned long)); void css_walk_subchannel_slow_list(void (*fn)(unsigned long));
void css_clear_subchannel_slow_list(void); void css_clear_subchannel_slow_list(void);
int css_slow_subchannels_exist(void); int css_slow_subchannels_exist(void);
......
...@@ -622,7 +622,7 @@ ccw_device_do_unreg_rereg(void *data) ...@@ -622,7 +622,7 @@ ccw_device_do_unreg_rereg(void *data)
other_sch = to_subchannel(other_cdev->dev.parent); other_sch = to_subchannel(other_cdev->dev.parent);
if (get_device(&other_sch->dev)) { if (get_device(&other_sch->dev)) {
stsch(other_sch->irq, &other_sch->schib); stsch(other_sch->schid, &other_sch->schib);
if (other_sch->schib.pmcw.dnv) { if (other_sch->schib.pmcw.dnv) {
other_sch->schib.pmcw.intparm = 0; other_sch->schib.pmcw.intparm = 0;
cio_modify(other_sch); cio_modify(other_sch);
...@@ -772,7 +772,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) ...@@ -772,7 +772,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
/* Init private data. */ /* Init private data. */
priv = cdev->private; priv = cdev->private;
priv->devno = sch->schib.pmcw.dev; priv->devno = sch->schib.pmcw.dev;
priv->irq = sch->irq; priv->sch_no = sch->schid.sch_no;
priv->state = DEV_STATE_NOT_OPER; priv->state = DEV_STATE_NOT_OPER;
INIT_LIST_HEAD(&priv->cmb_list); INIT_LIST_HEAD(&priv->cmb_list);
init_waitqueue_head(&priv->wait_q); init_waitqueue_head(&priv->wait_q);
...@@ -951,7 +951,7 @@ io_subchannel_shutdown(struct device *dev) ...@@ -951,7 +951,7 @@ io_subchannel_shutdown(struct device *dev)
sch = to_subchannel(dev); sch = to_subchannel(dev);
cdev = dev->driver_data; cdev = dev->driver_data;
if (cio_is_console(sch->irq)) if (cio_is_console(sch->schid))
return; return;
if (!sch->schib.pmcw.ena) if (!sch->schib.pmcw.ena)
/* Nothing to do. */ /* Nothing to do. */
...@@ -1146,6 +1146,16 @@ ccw_driver_unregister (struct ccw_driver *cdriver) ...@@ -1146,6 +1146,16 @@ ccw_driver_unregister (struct ccw_driver *cdriver)
driver_unregister(&cdriver->driver); driver_unregister(&cdriver->driver);
} }
/* Helper func for qdio. */
struct subchannel_id
ccw_device_get_subchannel_id(struct ccw_device *cdev)
{
struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent);
return sch->schid;
}
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccw_device_set_online); EXPORT_SYMBOL(ccw_device_set_online);
EXPORT_SYMBOL(ccw_device_set_offline); EXPORT_SYMBOL(ccw_device_set_offline);
...@@ -1155,3 +1165,4 @@ EXPORT_SYMBOL(get_ccwdev_by_busid); ...@@ -1155,3 +1165,4 @@ EXPORT_SYMBOL(get_ccwdev_by_busid);
EXPORT_SYMBOL(ccw_bus_type); EXPORT_SYMBOL(ccw_bus_type);
EXPORT_SYMBOL(ccw_device_work); EXPORT_SYMBOL(ccw_device_work);
EXPORT_SYMBOL(ccw_device_notify_work); EXPORT_SYMBOL(ccw_device_notify_work);
EXPORT_SYMBOL_GPL(ccw_device_get_subchannel_id);
...@@ -110,6 +110,7 @@ int ccw_device_stlck(struct ccw_device *); ...@@ -110,6 +110,7 @@ int ccw_device_stlck(struct ccw_device *);
/* qdio needs this. */ /* qdio needs this. */
void ccw_device_set_timeout(struct ccw_device *, int); void ccw_device_set_timeout(struct ccw_device *, int);
extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
void retry_set_schib(struct ccw_device *cdev); void retry_set_schib(struct ccw_device *cdev);
#endif #endif
...@@ -133,7 +133,7 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) ...@@ -133,7 +133,7 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
int ret; int ret;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
ret = stsch(sch->irq, &sch->schib); ret = stsch(sch->schid, &sch->schib);
if (ret || !sch->schib.pmcw.dnv) if (ret || !sch->schib.pmcw.dnv)
return -ENODEV; return -ENODEV;
if (!sch->schib.pmcw.ena || sch->schib.scsw.actl == 0) if (!sch->schib.pmcw.ena || sch->schib.scsw.actl == 0)
...@@ -231,7 +231,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) ...@@ -231,7 +231,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
* through ssch() and the path information is up to date. * through ssch() and the path information is up to date.
*/ */
old_lpm = sch->lpm; old_lpm = sch->lpm;
stsch(sch->irq, &sch->schib); stsch(sch->schid, &sch->schib);
sch->lpm = sch->schib.pmcw.pim & sch->lpm = sch->schib.pmcw.pim &
sch->schib.pmcw.pam & sch->schib.pmcw.pam &
sch->schib.pmcw.pom & sch->schib.pmcw.pom &
...@@ -258,7 +258,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) ...@@ -258,7 +258,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
case DEV_STATE_NOT_OPER: case DEV_STATE_NOT_OPER:
CIO_DEBUG(KERN_WARNING, 2, CIO_DEBUG(KERN_WARNING, 2,
"SenseID : unknown device %04x on subchannel %04x\n", "SenseID : unknown device %04x on subchannel %04x\n",
cdev->private->devno, sch->irq); cdev->private->devno, sch->schid.sch_no);
break; break;
case DEV_STATE_OFFLINE: case DEV_STATE_OFFLINE:
if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) { if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) {
...@@ -291,7 +291,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) ...@@ -291,7 +291,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
case DEV_STATE_BOXED: case DEV_STATE_BOXED:
CIO_DEBUG(KERN_WARNING, 2, CIO_DEBUG(KERN_WARNING, 2,
"SenseID : boxed device %04x on subchannel %04x\n", "SenseID : boxed device %04x on subchannel %04x\n",
cdev->private->devno, sch->irq); cdev->private->devno, sch->schid.sch_no);
break; break;
} }
cdev->private->state = state; cdev->private->state = state;
...@@ -359,7 +359,7 @@ ccw_device_done(struct ccw_device *cdev, int state) ...@@ -359,7 +359,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
if (state == DEV_STATE_BOXED) if (state == DEV_STATE_BOXED)
CIO_DEBUG(KERN_WARNING, 2, CIO_DEBUG(KERN_WARNING, 2,
"Boxed device %04x on subchannel %04x\n", "Boxed device %04x on subchannel %04x\n",
cdev->private->devno, sch->irq); cdev->private->devno, sch->schid.sch_no);
if (cdev->private->flags.donotify) { if (cdev->private->flags.donotify) {
cdev->private->flags.donotify = 0; cdev->private->flags.donotify = 0;
...@@ -592,7 +592,7 @@ ccw_device_offline(struct ccw_device *cdev) ...@@ -592,7 +592,7 @@ ccw_device_offline(struct ccw_device *cdev)
struct subchannel *sch; struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
if (stsch(sch->irq, &sch->schib) || !sch->schib.pmcw.dnv) if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv)
return -ENODEV; return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE) { if (cdev->private->state != DEV_STATE_ONLINE) {
if (sch->schib.scsw.actl != 0) if (sch->schib.scsw.actl != 0)
...@@ -711,7 +711,7 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -711,7 +711,7 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
* Since we might not just be coming from an interrupt from the * Since we might not just be coming from an interrupt from the
* subchannel we have to update the schib. * subchannel we have to update the schib.
*/ */
stsch(sch->irq, &sch->schib); stsch(sch->schid, &sch->schib);
if (sch->schib.scsw.actl != 0 || if (sch->schib.scsw.actl != 0 ||
(cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) { (cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) {
...@@ -923,7 +923,7 @@ ccw_device_wait4io_irq(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -923,7 +923,7 @@ ccw_device_wait4io_irq(struct ccw_device *cdev, enum dev_event dev_event)
/* Iff device is idle, reset timeout. */ /* Iff device is idle, reset timeout. */
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
if (!stsch(sch->irq, &sch->schib)) if (!stsch(sch->schid, &sch->schib))
if (sch->schib.scsw.actl == 0) if (sch->schib.scsw.actl == 0)
ccw_device_set_timeout(cdev, 0); ccw_device_set_timeout(cdev, 0);
/* Call the handler. */ /* Call the handler. */
...@@ -1035,7 +1035,7 @@ device_trigger_reprobe(struct subchannel *sch) ...@@ -1035,7 +1035,7 @@ device_trigger_reprobe(struct subchannel *sch)
return; return;
/* Update some values. */ /* Update some values. */
if (stsch(sch->irq, &sch->schib)) if (stsch(sch->schid, &sch->schib))
return; return;
/* /*
......
...@@ -258,7 +258,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev) ...@@ -258,7 +258,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
*/ */
CIO_MSG_EVENT(2, "SenseID : device %04x on Subchannel %04x " CIO_MSG_EVENT(2, "SenseID : device %04x on Subchannel %04x "
"reports cmd reject\n", "reports cmd reject\n",
cdev->private->devno, sch->irq); cdev->private->devno, sch->schid.sch_no);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
if (irb->esw.esw0.erw.cons) { if (irb->esw.esw0.erw.cons) {
...@@ -280,13 +280,13 @@ ccw_device_check_sense_id(struct ccw_device *cdev) ...@@ -280,13 +280,13 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x on" CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x on"
" subchannel %04x is 'not operational'\n", " subchannel %04x is 'not operational'\n",
sch->orb.lpm, cdev->private->devno, sch->orb.lpm, cdev->private->devno,
sch->irq); sch->schid.sch_no);
return -EACCES; return -EACCES;
} }
/* Hmm, whatever happened, try again. */ /* Hmm, whatever happened, try again. */
CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on " CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on "
"subchannel %04x returns status %02X%02X\n", "subchannel %04x returns status %02X%02X\n",
cdev->private->devno, sch->irq, cdev->private->devno, sch->schid.sch_no,
irb->scsw.dstat, irb->scsw.cstat); irb->scsw.dstat, irb->scsw.cstat);
return -EAGAIN; return -EAGAIN;
} }
......
/* /*
* drivers/s390/cio/device_ops.c * drivers/s390/cio/device_ops.c
* *
* $Revision: 1.57 $ * $Revision: 1.58 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -570,7 +570,7 @@ ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) ...@@ -570,7 +570,7 @@ ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
int int
_ccw_device_get_subchannel_number(struct ccw_device *cdev) _ccw_device_get_subchannel_number(struct ccw_device *cdev)
{ {
return cdev->private->irq; return cdev->private->sch_no;
} }
int int
......
...@@ -59,7 +59,7 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev) ...@@ -59,7 +59,7 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel " CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel "
"%04x, lpm %02X, became 'not " "%04x, lpm %02X, became 'not "
"operational'\n", "operational'\n",
cdev->private->devno, sch->irq, cdev->private->devno, sch->schid.sch_no,
cdev->private->imask); cdev->private->imask);
} }
...@@ -121,13 +121,14 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) ...@@ -121,13 +121,14 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
if (irb->scsw.cc == 3) { if (irb->scsw.cc == 3) {
CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel " CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel "
"%04x, lpm %02X, became 'not operational'\n", "%04x, lpm %02X, became 'not operational'\n",
cdev->private->devno, sch->irq, sch->orb.lpm); cdev->private->devno, sch->schid.sch_no,
sch->orb.lpm);
return -EACCES; return -EACCES;
} }
if (cdev->private->pgid.inf.ps.state2 == SNID_STATE2_RESVD_ELSE) { if (cdev->private->pgid.inf.ps.state2 == SNID_STATE2_RESVD_ELSE) {
CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel %04x " CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel %04x "
"is reserved by someone else\n", "is reserved by someone else\n",
cdev->private->devno, sch->irq); cdev->private->devno, sch->schid.sch_no);
return -EUSERS; return -EUSERS;
} }
return 0; return 0;
...@@ -237,7 +238,7 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func) ...@@ -237,7 +238,7 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
sch->vpm &= ~cdev->private->imask; sch->vpm &= ~cdev->private->imask;
CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel " CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel "
"%04x, lpm %02X, became 'not operational'\n", "%04x, lpm %02X, became 'not operational'\n",
cdev->private->devno, sch->irq, cdev->private->imask); cdev->private->devno, sch->schid.sch_no, cdev->private->imask);
return ret; return ret;
} }
...@@ -271,7 +272,7 @@ __ccw_device_check_pgid(struct ccw_device *cdev) ...@@ -271,7 +272,7 @@ __ccw_device_check_pgid(struct ccw_device *cdev)
if (irb->scsw.cc == 3) { if (irb->scsw.cc == 3) {
CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel " CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel "
"%04x, lpm %02X, became 'not operational'\n", "%04x, lpm %02X, became 'not operational'\n",
cdev->private->devno, sch->irq, cdev->private->devno, sch->schid.sch_no,
cdev->private->imask); cdev->private->imask);
return -EACCES; return -EACCES;
} }
...@@ -373,7 +374,7 @@ ccw_device_verify_start(struct ccw_device *cdev) ...@@ -373,7 +374,7 @@ ccw_device_verify_start(struct ccw_device *cdev)
* Update sch->lpm with current values to catch paths becoming * Update sch->lpm with current values to catch paths becoming
* available again. * available again.
*/ */
if (stsch(sch->irq, &sch->schib)) { if (stsch(sch->schid, &sch->schib)) {
ccw_device_verify_done(cdev, -ENODEV); ccw_device_verify_done(cdev, -ENODEV);
return; return;
} }
......
...@@ -38,13 +38,13 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) ...@@ -38,13 +38,13 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
"received" "received"
" ... device %04X on subchannel %04X, dev_stat " " ... device %04X on subchannel %04X, dev_stat "
": %02X sch_stat : %02X\n", ": %02X sch_stat : %02X\n",
cdev->private->devno, cdev->private->irq, cdev->private->devno, cdev->private->sch_no,
irb->scsw.dstat, irb->scsw.cstat); irb->scsw.dstat, irb->scsw.cstat);
if (irb->scsw.cc != 3) { if (irb->scsw.cc != 3) {
char dbf_text[15]; char dbf_text[15];
sprintf(dbf_text, "chk%x", cdev->private->irq); sprintf(dbf_text, "chk%x", cdev->private->sch_no);
CIO_TRACE_EVENT(0, dbf_text); CIO_TRACE_EVENT(0, dbf_text);
CIO_HEX_EVENT(0, irb, sizeof (struct irb)); CIO_HEX_EVENT(0, irb, sizeof (struct irb));
} }
...@@ -59,10 +59,10 @@ ccw_device_path_notoper(struct ccw_device *cdev) ...@@ -59,10 +59,10 @@ ccw_device_path_notoper(struct ccw_device *cdev)
struct subchannel *sch; struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
stsch (sch->irq, &sch->schib); stsch (sch->schid, &sch->schib);
CIO_MSG_EVENT(0, "%s(%04x) - path(s) %02x are " CIO_MSG_EVENT(0, "%s(%04x) - path(s) %02x are "
"not operational \n", __FUNCTION__, sch->irq, "not operational \n", __FUNCTION__, sch->schid.sch_no,
sch->schib.pmcw.pnom); sch->schib.pmcw.pnom);
sch->lpm &= ~sch->schib.pmcw.pnom; sch->lpm &= ~sch->schib.pmcw.pnom;
......
#ifndef S390_CIO_IOASM_H #ifndef S390_CIO_IOASM_H
#define S390_CIO_IOASM_H #define S390_CIO_IOASM_H
#include "schid.h"
/* /*
* TPI info structure * TPI info structure
*/ */
struct tpi_info { struct tpi_info {
__u32 reserved1 : 16; /* reserved 0x00000001 */ struct subchannel_id schid;
__u32 irq : 16; /* aka. subchannel number */
__u32 intparm; /* interruption parameter */ __u32 intparm; /* interruption parameter */
__u32 adapter_IO : 1; __u32 adapter_IO : 1;
__u32 reserved2 : 1; __u32 reserved2 : 1;
...@@ -21,7 +22,8 @@ struct tpi_info { ...@@ -21,7 +22,8 @@ struct tpi_info {
* Some S390 specific IO instructions as inline * Some S390 specific IO instructions as inline
*/ */
static inline int stsch(int irq, volatile struct schib *addr) static inline int stsch(struct subchannel_id schid,
volatile struct schib *addr)
{ {
int ccode; int ccode;
...@@ -31,12 +33,13 @@ static inline int stsch(int irq, volatile struct schib *addr) ...@@ -31,12 +33,13 @@ static inline int stsch(int irq, volatile struct schib *addr)
" ipm %0\n" " ipm %0\n"
" srl %0,28" " srl %0,28"
: "=d" (ccode) : "=d" (ccode)
: "d" (irq | 0x10000), "a" (addr) : "d" (schid), "a" (addr), "m" (*addr)
: "cc", "1" ); : "cc", "1" );
return ccode; return ccode;
} }
static inline int msch(int irq, volatile struct schib *addr) static inline int msch(struct subchannel_id schid,
volatile struct schib *addr)
{ {
int ccode; int ccode;
...@@ -46,12 +49,13 @@ static inline int msch(int irq, volatile struct schib *addr) ...@@ -46,12 +49,13 @@ static inline int msch(int irq, volatile struct schib *addr)
" ipm %0\n" " ipm %0\n"
" srl %0,28" " srl %0,28"
: "=d" (ccode) : "=d" (ccode)
: "d" (irq | 0x10000L), "a" (addr) : "d" (schid), "a" (addr), "m" (*addr)
: "cc", "1" ); : "cc", "1" );
return ccode; return ccode;
} }
static inline int msch_err(int irq, volatile struct schib *addr) static inline int msch_err(struct subchannel_id schid,
volatile struct schib *addr)
{ {
int ccode; int ccode;
...@@ -74,12 +78,13 @@ static inline int msch_err(int irq, volatile struct schib *addr) ...@@ -74,12 +78,13 @@ static inline int msch_err(int irq, volatile struct schib *addr)
".previous" ".previous"
#endif #endif
: "=&d" (ccode) : "=&d" (ccode)
: "d" (irq | 0x10000L), "a" (addr), "K" (-EIO) : "d" (schid), "a" (addr), "K" (-EIO), "m" (*addr)
: "cc", "1" ); : "cc", "1" );
return ccode; return ccode;
} }
static inline int tsch(int irq, volatile struct irb *addr) static inline int tsch(struct subchannel_id schid,
volatile struct irb *addr)
{ {
int ccode; int ccode;
...@@ -89,7 +94,7 @@ static inline int tsch(int irq, volatile struct irb *addr) ...@@ -89,7 +94,7 @@ static inline int tsch(int irq, volatile struct irb *addr)
" ipm %0\n" " ipm %0\n"
" srl %0,28" " srl %0,28"
: "=d" (ccode) : "=d" (ccode)
: "d" (irq | 0x10000L), "a" (addr) : "d" (schid), "a" (addr), "m" (*addr)
: "cc", "1" ); : "cc", "1" );
return ccode; return ccode;
} }
...@@ -103,12 +108,13 @@ static inline int tpi( volatile struct tpi_info *addr) ...@@ -103,12 +108,13 @@ static inline int tpi( volatile struct tpi_info *addr)
" ipm %0\n" " ipm %0\n"
" srl %0,28" " srl %0,28"
: "=d" (ccode) : "=d" (ccode)
: "a" (addr) : "a" (addr), "m" (*addr)
: "cc", "1" ); : "cc", "1" );
return ccode; return ccode;
} }
static inline int ssch(int irq, volatile struct orb *addr) static inline int ssch(struct subchannel_id schid,
volatile struct orb *addr)
{ {
int ccode; int ccode;
...@@ -118,12 +124,12 @@ static inline int ssch(int irq, volatile struct orb *addr) ...@@ -118,12 +124,12 @@ static inline int ssch(int irq, volatile struct orb *addr)
" ipm %0\n" " ipm %0\n"
" srl %0,28" " srl %0,28"
: "=d" (ccode) : "=d" (ccode)
: "d" (irq | 0x10000L), "a" (addr) : "d" (schid), "a" (addr), "m" (*addr)
: "cc", "1" ); : "cc", "1" );
return ccode; return ccode;
} }
static inline int rsch(int irq) static inline int rsch(struct subchannel_id schid)
{ {
int ccode; int ccode;
...@@ -133,12 +139,12 @@ static inline int rsch(int irq) ...@@ -133,12 +139,12 @@ static inline int rsch(int irq)
" ipm %0\n" " ipm %0\n"
" srl %0,28" " srl %0,28"
: "=d" (ccode) : "=d" (ccode)
: "d" (irq | 0x10000L) : "d" (schid)
: "cc", "1" ); : "cc", "1" );
return ccode; return ccode;
} }
static inline int csch(int irq) static inline int csch(struct subchannel_id schid)
{ {
int ccode; int ccode;
...@@ -148,12 +154,12 @@ static inline int csch(int irq) ...@@ -148,12 +154,12 @@ static inline int csch(int irq)
" ipm %0\n" " ipm %0\n"
" srl %0,28" " srl %0,28"
: "=d" (ccode) : "=d" (ccode)
: "d" (irq | 0x10000L) : "d" (schid)
: "cc", "1" ); : "cc", "1" );
return ccode; return ccode;
} }
static inline int hsch(int irq) static inline int hsch(struct subchannel_id schid)
{ {
int ccode; int ccode;
...@@ -163,12 +169,12 @@ static inline int hsch(int irq) ...@@ -163,12 +169,12 @@ static inline int hsch(int irq)
" ipm %0\n" " ipm %0\n"
" srl %0,28" " srl %0,28"
: "=d" (ccode) : "=d" (ccode)
: "d" (irq | 0x10000L) : "d" (schid)
: "cc", "1" ); : "cc", "1" );
return ccode; return ccode;
} }
static inline int xsch(int irq) static inline int xsch(struct subchannel_id schid)
{ {
int ccode; int ccode;
...@@ -178,21 +184,22 @@ static inline int xsch(int irq) ...@@ -178,21 +184,22 @@ static inline int xsch(int irq)
" ipm %0\n" " ipm %0\n"
" srl %0,28" " srl %0,28"
: "=d" (ccode) : "=d" (ccode)
: "d" (irq | 0x10000L) : "d" (schid)
: "cc", "1" ); : "cc", "1" );
return ccode; return ccode;
} }
static inline int chsc(void *chsc_area) static inline int chsc(void *chsc_area)
{ {
typedef struct { char _[4096]; } addr_type;
int cc; int cc;
__asm__ __volatile__ ( __asm__ __volatile__ (
".insn rre,0xb25f0000,%1,0 \n\t" ".insn rre,0xb25f0000,%2,0 \n\t"
"ipm %0 \n\t" "ipm %0 \n\t"
"srl %0,28 \n\t" "srl %0,28 \n\t"
: "=d" (cc) : "=d" (cc), "=m" (*(addr_type *) chsc_area)
: "d" (chsc_area) : "d" (chsc_area), "m" (*(addr_type *) chsc_area)
: "cc" ); : "cc" );
return cc; return cc;
......
This diff is collapsed.
...@@ -3,7 +3,9 @@ ...@@ -3,7 +3,9 @@
#include <asm/page.h> #include <asm/page.h>
#define VERSION_CIO_QDIO_H "$Revision: 1.37 $" #include "schid.h"
#define VERSION_CIO_QDIO_H "$Revision: 1.40 $"
#ifdef CONFIG_QDIO_DEBUG #ifdef CONFIG_QDIO_DEBUG
#define QDIO_VERBOSE_LEVEL 9 #define QDIO_VERBOSE_LEVEL 9
...@@ -317,7 +319,7 @@ do_eqbs(unsigned long sch, unsigned char *state, int queue, ...@@ -317,7 +319,7 @@ do_eqbs(unsigned long sch, unsigned char *state, int queue,
static inline int static inline int
do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2) do_siga_sync(struct subchannel_id schid, unsigned int mask1, unsigned int mask2)
{ {
int cc; int cc;
...@@ -331,7 +333,7 @@ do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2) ...@@ -331,7 +333,7 @@ do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2)
"ipm %0 \n\t" "ipm %0 \n\t"
"srl %0,28 \n\t" "srl %0,28 \n\t"
: "=d" (cc) : "=d" (cc)
: "d" (irq), "d" (mask1), "d" (mask2) : "d" (schid), "d" (mask1), "d" (mask2)
: "cc", "0", "1", "2", "3" : "cc", "0", "1", "2", "3"
); );
#else /* CONFIG_ARCH_S390X */ #else /* CONFIG_ARCH_S390X */
...@@ -344,7 +346,7 @@ do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2) ...@@ -344,7 +346,7 @@ do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2)
"ipm %0 \n\t" "ipm %0 \n\t"
"srl %0,28 \n\t" "srl %0,28 \n\t"
: "=d" (cc) : "=d" (cc)
: "d" (irq), "d" (mask1), "d" (mask2) : "d" (schid), "d" (mask1), "d" (mask2)
: "cc", "0", "1", "2", "3" : "cc", "0", "1", "2", "3"
); );
#endif /* CONFIG_ARCH_S390X */ #endif /* CONFIG_ARCH_S390X */
...@@ -352,7 +354,7 @@ do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2) ...@@ -352,7 +354,7 @@ do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2)
} }
static inline int static inline int
do_siga_input(unsigned int irq, unsigned int mask) do_siga_input(struct subchannel_id schid, unsigned int mask)
{ {
int cc; int cc;
...@@ -365,7 +367,7 @@ do_siga_input(unsigned int irq, unsigned int mask) ...@@ -365,7 +367,7 @@ do_siga_input(unsigned int irq, unsigned int mask)
"ipm %0 \n\t" "ipm %0 \n\t"
"srl %0,28 \n\t" "srl %0,28 \n\t"
: "=d" (cc) : "=d" (cc)
: "d" (irq), "d" (mask) : "d" (schid), "d" (mask)
: "cc", "0", "1", "2", "memory" : "cc", "0", "1", "2", "memory"
); );
#else /* CONFIG_ARCH_S390X */ #else /* CONFIG_ARCH_S390X */
...@@ -377,7 +379,7 @@ do_siga_input(unsigned int irq, unsigned int mask) ...@@ -377,7 +379,7 @@ do_siga_input(unsigned int irq, unsigned int mask)
"ipm %0 \n\t" "ipm %0 \n\t"
"srl %0,28 \n\t" "srl %0,28 \n\t"
: "=d" (cc) : "=d" (cc)
: "d" (irq), "d" (mask) : "d" (schid), "d" (mask)
: "cc", "0", "1", "2", "memory" : "cc", "0", "1", "2", "memory"
); );
#endif /* CONFIG_ARCH_S390X */ #endif /* CONFIG_ARCH_S390X */
...@@ -386,7 +388,7 @@ do_siga_input(unsigned int irq, unsigned int mask) ...@@ -386,7 +388,7 @@ do_siga_input(unsigned int irq, unsigned int mask)
} }
static inline int static inline int
do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb, do_siga_output(unsigned long schid, unsigned long mask, __u32 *bb,
unsigned int fc) unsigned int fc)
{ {
int cc; int cc;
...@@ -418,7 +420,7 @@ do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb, ...@@ -418,7 +420,7 @@ do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb,
".long 0b,2b \n\t" ".long 0b,2b \n\t"
".previous \n\t" ".previous \n\t"
: "=d" (cc), "=d" (busy_bit) : "=d" (cc), "=d" (busy_bit)
: "d" (irq), "d" (mask), : "d" (schid), "d" (mask),
"i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION) "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION)
: "cc", "0", "1", "2", "memory" : "cc", "0", "1", "2", "memory"
); );
...@@ -443,7 +445,7 @@ do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb, ...@@ -443,7 +445,7 @@ do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb,
".quad 0b,1b \n\t" ".quad 0b,1b \n\t"
".previous \n\t" ".previous \n\t"
: "=d" (cc), "=d" (busy_bit) : "=d" (cc), "=d" (busy_bit)
: "d" (irq), "d" (mask), : "d" (schid), "d" (mask),
"i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION), "d" (fc) "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION), "d" (fc)
: "cc", "0", "1", "2", "memory" : "cc", "0", "1", "2", "memory"
); );
...@@ -554,7 +556,7 @@ struct qdio_q { ...@@ -554,7 +556,7 @@ struct qdio_q {
__u32 * dev_st_chg_ind; __u32 * dev_st_chg_ind;
int is_input_q; int is_input_q;
int irq; struct subchannel_id schid;
struct ccw_device *cdev; struct ccw_device *cdev;
unsigned int is_iqdio_q; unsigned int is_iqdio_q;
...@@ -649,7 +651,7 @@ struct qdio_irq { ...@@ -649,7 +651,7 @@ struct qdio_irq {
__u32 * volatile dev_st_chg_ind; __u32 * volatile dev_st_chg_ind;
unsigned long int_parm; unsigned long int_parm;
int irq; struct subchannel_id schid;
unsigned int is_iqdio_irq; unsigned int is_iqdio_irq;
unsigned int is_thinint_irq; unsigned int is_thinint_irq;
......
#ifndef S390_SCHID_H
#define S390_SCHID_H
struct subchannel_id {
__u32 reserved:15;
__u32 one:1;
__u32 sch_no:16;
} __attribute__ ((packed,aligned(4)));
/* Helper function for sane state of pre-allocated subchannel_id. */
static inline void
init_subchannel_id(struct subchannel_id *schid)
{
memset(schid, 0, sizeof(struct subchannel_id));
schid->one = 1;
}
static inline int
schid_equal(struct subchannel_id *schid1, struct subchannel_id *schid2)
{
return !memcmp(schid1, schid2, sizeof(struct subchannel_id));
}
#endif /* S390_SCHID_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment