patch-2.4.4 linux/drivers/s390/char/hwc_rw.c
Next file: linux/drivers/s390/char/hwc_tty.c
Previous file: linux/drivers/s390/char/hwc_con.c
Back to the patch index
Back to the overall index
- Lines: 561
- Date:
Wed Apr 11 19:02:29 2001
- Orig file:
v2.4.3/linux/drivers/s390/char/hwc_rw.c
- Orig date:
Tue Feb 13 14:13:44 2001
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/hwc_rw.c linux/drivers/s390/char/hwc_rw.c
@@ -30,9 +30,13 @@
#include <asm/s390_ext.h>
#ifndef MIN
-#define MIN(a,b) ((a<b) ? a : b)
+#define MIN(a,b) (((a<b) ? a : b))
#endif
+#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x]))
+
+#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c)))
+
#define HWC_RW_PRINT_HEADER "hwc low level driver: "
#define USE_VM_DETECTION
@@ -118,16 +122,16 @@
static unsigned char
_page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE)));
-/* pedantic: long because we use set_bit on it --RR */
-typedef long kmem_pages_t;
+typedef unsigned long kmem_pages_t;
#define MAX_KMEM_PAGES (sizeof(kmem_pages_t) << 3)
-#define HWC_TIMER_RUNS 1
-#define HWC_FLUSH 2
-#define HWC_INIT 4
-#define HWC_BROKEN 8
-#define HWC_INTERRUPT 16
+#define HWC_WTIMER_RUNS 1
+#define HWC_FLUSH 2
+#define HWC_INIT 4
+#define HWC_BROKEN 8
+#define HWC_INTERRUPT 16
+#define HWC_PTIMER_RUNS 32
static struct {
@@ -169,6 +173,7 @@
unsigned char write_prio:1;
unsigned char read_nonprio:1;
unsigned char read_prio:1;
+ unsigned char read_statechange:1;
unsigned char flags;
@@ -177,6 +182,8 @@
spinlock_t lock;
struct timer_list write_timer;
+
+ struct timer_list poll_timer;
} hwc_data =
{
{
@@ -186,7 +193,7 @@
0,
80,
1,
- 50,
+ MAX_KMEM_PAGES,
MAX_KMEM_PAGES,
0,
@@ -214,6 +221,7 @@
0,
0,
0,
+ 0,
NULL
};
@@ -345,9 +353,6 @@
memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t));
- if (!hwc_data.write_nonprio && hwc_data.write_prio)
- hwcb->msgbuf.type = ET_PMsgCmd;
-
return 0;
}
@@ -647,25 +652,58 @@
return count;
}
+static int write_event_data_1 (void);
+
+static void
+do_poll_hwc (unsigned long data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave (&hwc_data.lock, flags);
+
+ write_event_data_1 ();
+
+ spin_unlock_irqrestore (&hwc_data.lock, flags);
+}
+
+void
+start_poll_hwc (void)
+{
+ init_timer (&hwc_data.poll_timer);
+ hwc_data.poll_timer.function = do_poll_hwc;
+ hwc_data.poll_timer.data = (unsigned long) NULL;
+ hwc_data.poll_timer.expires = jiffies + 2 * HZ;
+ add_timer (&hwc_data.poll_timer);
+ hwc_data.flags |= HWC_PTIMER_RUNS;
+}
+
static int
write_event_data_1 (void)
{
unsigned short int condition_code;
int retval;
+ write_hwcb_t *hwcb = (write_hwcb_t *) OUT_HWCB;
- if ((!hwc_data.write_prio) && (!hwc_data.write_nonprio))
- return -EPERM;
+ if ((!hwc_data.write_prio) &&
+ (!hwc_data.write_nonprio) &&
+ hwc_data.read_statechange)
+ return -EOPNOTSUPP;
if (hwc_data.current_servc)
return -EBUSY;
retval = sane_write_hwcb ();
if (retval < 0)
- return retval;
+ return -EIO;
if (!OUT_HWCB_MTO)
return -ENODATA;
+ if (!hwc_data.write_nonprio && hwc_data.write_prio)
+ hwcb->msgbuf.type = ET_PMsgCmd;
+ else
+ hwcb->msgbuf.type = ET_Msg;
+
condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB);
#ifdef DUMP_HWC_WRITE_ERROR
@@ -688,6 +726,8 @@
case HWC_BUSY:
retval = -EBUSY;
break;
+ case HWC_NOT_OPERATIONAL:
+ start_poll_hwc ();
default:
retval = -EIO;
}
@@ -710,7 +750,7 @@
write_event_data_2 (void)
{
write_hwcb_t *hwcb;
- int retval;
+ int retval = 0;
#ifdef DUMP_HWC_WRITE_ERROR
unsigned char *param;
@@ -765,11 +805,22 @@
}
#endif
- if (hwcb->response_code == 0x0020) {
+ switch (hwcb->response_code) {
+ case 0x0020:
retval = OUT_HWCB_CHAR;
release_write_hwcb ();
- } else {
+ break;
+ case 0x0040:
+ case 0x0340:
+ case 0x40F0:
+ if (!hwc_data.read_statechange) {
+ hwcb->response_code = 0;
+ start_poll_hwc ();
+ }
+ retval = -EIO;
+ break;
+ default:
internal_print (
DELAYED_WRITE,
HWC_RW_PRINT_HEADER
@@ -782,6 +833,13 @@
retval = -EIO;
}
+ if (retval == -EIO) {
+
+ hwcb->control_mask[0] = 0;
+ hwcb->control_mask[1] = 0;
+ hwcb->control_mask[2] = 0;
+ hwcb->response_code = 0;
+ }
hwc_data.current_servc = 0;
hwc_data.current_hwcb = NULL;
@@ -826,9 +884,9 @@
unsigned short count)
{
- if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_TIMER_RUNS)) {
+ if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_WTIMER_RUNS)) {
del_timer (&hwc_data.write_timer);
- hwc_data.flags &= ~HWC_TIMER_RUNS;
+ hwc_data.flags &= ~HWC_WTIMER_RUNS;
}
hwc_data.obuf_start += count;
@@ -937,7 +995,7 @@
if (obuf_cursor < obuf_columns) {
hwc_data.obuf[hwc_data.obuf_start +
obuf_cursor]
- = 0x20;
+ = HWC_ASCEBC (' ');
obuf_cursor++;
} else
break;
@@ -955,7 +1013,7 @@
while (spaces) {
hwc_data.obuf[hwc_data.obuf_start +
obuf_cursor - spaces]
- = 0x20;
+ = HWC_ASCEBC (' ');
spaces--;
}
@@ -985,9 +1043,7 @@
if (isprint (ch))
hwc_data.obuf[hwc_data.obuf_start +
obuf_cursor++]
- = (MACHINE_IS_VM) ?
- _ascebc[ch] :
- _ascebc_500[ch];
+ = HWC_ASCEBC (ch);
}
if (obuf_cursor > obuf_count)
obuf_count = obuf_cursor;
@@ -1006,11 +1062,10 @@
if (hwc_data.ioctls.final_nl > 0) {
- if (hwc_data.flags & HWC_TIMER_RUNS) {
+ if (hwc_data.flags & HWC_WTIMER_RUNS) {
- hwc_data.write_timer.expires =
- jiffies +
- hwc_data.ioctls.final_nl * HZ / 10;
+ mod_timer (&hwc_data.write_timer,
+ jiffies + hwc_data.ioctls.final_nl * HZ / 10);
} else {
init_timer (&hwc_data.write_timer);
@@ -1022,7 +1077,7 @@
jiffies +
hwc_data.ioctls.final_nl * HZ / 10;
add_timer (&hwc_data.write_timer);
- hwc_data.flags |= HWC_TIMER_RUNS;
+ hwc_data.flags |= HWC_WTIMER_RUNS;
}
} else;
@@ -1306,14 +1361,11 @@
if (hwc_data.ioctls.delim)
count = seperate_cases (start, count);
- if (MACHINE_IS_VM)
- EBCASC (start, count);
- else
- EBCASC_500 (start, count);
+ HWC_EBCASC_STR (start, count);
- if (hwc_data.ioctls.echo) {
+ if (hwc_data.ioctls.echo)
do_hwc_write (0, start, count, IMMEDIATE_WRITE);
- }
+
if (hwc_data.calls != NULL)
if (hwc_data.calls->move_input != NULL)
(hwc_data.calls->move_input) (start, count);
@@ -1416,7 +1468,7 @@
return retval;
}
-inline static int
+static int
eval_evbuf (gds_vector_t * start, void *end)
{
gds_vector_t *vec;
@@ -1434,6 +1486,128 @@
return retval;
}
+static inline int
+eval_hwc_receive_mask (_hwcb_mask_t mask)
+{
+
+ hwc_data.write_nonprio
+ = ((mask & ET_Msg_Mask) == ET_Msg_Mask);
+
+ hwc_data.write_prio
+ = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
+
+ if (hwc_data.write_prio || hwc_data.write_nonprio) {
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "can write messages\n");
+ return 0;
+ } else {
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "can not write messages\n");
+ return -1;
+ }
+}
+
+static inline int
+eval_hwc_send_mask (_hwcb_mask_t mask)
+{
+
+ hwc_data.read_statechange
+ = ((mask & ET_StateChange_Mask) == ET_StateChange_Mask);
+ if (hwc_data.read_statechange)
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "can read state change notifications\n");
+ else
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "can not read state change notifications\n");
+
+ hwc_data.read_nonprio
+ = ((mask & ET_OpCmd_Mask) == ET_OpCmd_Mask);
+ if (hwc_data.read_nonprio)
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "can read commands\n");
+
+ hwc_data.read_prio
+ = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
+ if (hwc_data.read_prio)
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "can read priority commands\n");
+
+ if (hwc_data.read_prio || hwc_data.read_nonprio) {
+ return 0;
+ } else {
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "can not read commands from operator\n");
+ return -1;
+ }
+}
+
+static int
+eval_statechangebuf (statechangebuf_t * scbuf)
+{
+ int retval = 0;
+
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "HWC state change detected\n");
+
+ if (scbuf->validity_hwc_active_facility_mask) {
+
+ }
+ if (scbuf->validity_hwc_receive_mask) {
+
+ if (scbuf->mask_length != 4) {
+#ifdef DUMP_HWC_INIT_ERROR
+ __asm__ ("LHI 1,0xe50\n\t"
+ "LRA 2,0(%0)\n\t"
+ "J .+0 \n\t"
+ :
+ : "a" (scbuf)
+ : "1", "2");
+#endif
+ } else {
+
+ retval += eval_hwc_receive_mask
+ (scbuf->hwc_receive_mask);
+ }
+ }
+ if (scbuf->validity_hwc_send_mask) {
+
+ if (scbuf->mask_length != 4) {
+#ifdef DUMP_HWC_INIT_ERROR
+ __asm__ ("LHI 1,0xe51\n\t"
+ "LRA 2,0(%0)\n\t"
+ "J .+0 \n\t"
+ :
+ : "a" (scbuf)
+ : "1", "2");
+#endif
+ } else {
+
+ retval += eval_hwc_send_mask
+ (scbuf->hwc_send_mask);
+ }
+ }
+ if (scbuf->validity_read_data_function_mask) {
+
+ }
+ return retval;
+}
+
static int
process_evbufs (void *start, void *end)
{
@@ -1466,17 +1640,17 @@
retval += eval_evbuf (evbuf_data, evbuf_end);
break;
case ET_StateChange:
-
- retval = -ENOSYS;
+ retval += eval_statechangebuf
+ ((statechangebuf_t *) evbuf);
break;
default:
- printk (
- KERN_WARNING
- HWC_RW_PRINT_HEADER
- "unconditional read: "
- "unknown event buffer found, "
- "type 0x%x",
- evbuf->type);
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "unconditional read: "
+ "unknown event buffer found, "
+ "type 0x%x",
+ evbuf->type);
retval = -ENOSYS;
}
evbuf = (evbuf_t *) evbuf_end;
@@ -1491,11 +1665,14 @@
read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
int retval;
+#if 0
+
if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio))
return -EOPNOTSUPP;
if (hwc_data.current_servc)
return -EBUSY;
+#endif
memset (hwcb, 0x00, PAGE_SIZE);
memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t));
@@ -1601,26 +1778,21 @@
internal_print (
IMMEDIATE_WRITE,
HWC_RW_PRINT_HEADER
- "unconditional read: invalid function code - this "
- "must not occur in a correct driver, please contact "
- "author\n");
+ "unconditional read: invalid function code\n");
return -EIO;
case 0x70F0:
internal_print (
IMMEDIATE_WRITE,
HWC_RW_PRINT_HEADER
- "unconditional read: invalid selection mask - this "
- "must not occur in a correct driver, please contact "
- "author\n");
+ "unconditional read: invalid selection mask\n");
return -EIO;
case 0x0040:
internal_print (
IMMEDIATE_WRITE,
HWC_RW_PRINT_HEADER
- "unconditional read: HWC equipment check - don't "
- "know how to handle this case\n");
+ "unconditional read: HWC equipment check\n");
return -EIO;
default:
@@ -1677,27 +1849,7 @@
init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page;
int retval = 0;
- if (hwcb->hwc_receive_mask & ET_Msg_Mask)
- hwc_data.write_nonprio = 1;
-
- if (hwcb->hwc_receive_mask & ET_PMsgCmd_Mask)
- hwc_data.write_prio = 1;
-
- if (hwcb->hwc_send_mask & ET_OpCmd_Mask) {
- internal_print (DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "capable of receipt of commands\n");
- hwc_data.read_nonprio = 1;
- }
- if (hwcb->hwc_send_mask & ET_PMsgCmd_Mask) {
- internal_print (DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "capable of receipt of priority commands\n");
- hwc_data.read_nonprio = 1;
- }
- if ((hwcb->response_code != 0x0020) ||
- (!hwc_data.write_nonprio) ||
- ((!hwc_data.read_nonprio) && (!hwc_data.read_prio)))
+ if (hwcb->response_code != 0x0020) {
#ifdef DUMP_HWC_INIT_ERROR
__asm__ ("LHI 1,0xe11\n\t"
"LRA 2,0(%0)\n\t"
@@ -1707,8 +1859,24 @@
: "a" (hwcb), "a" (&(hwcb->response_code))
: "1", "2", "3");
#else
- retval = -EIO;
+ retval = -1;
#endif
+ } else {
+ if (hwcb->mask_length != 4) {
+#ifdef DUMP_HWC_INIT_ERROR
+ __asm__ ("LHI 1,0xe52\n\t"
+ "LRA 2,0(%0)\n\t"
+ "J .+0 \n\t"
+ :
+ : "a" (hwcb)
+ : "1", "2");
+#endif
+ } else {
+ retval += eval_hwc_receive_mask
+ (hwcb->hwc_receive_mask);
+ retval += eval_hwc_send_mask (hwcb->hwc_send_mask);
+ }
+ }
hwc_data.current_servc = 0;
hwc_data.current_hwcb = NULL;
@@ -1934,6 +2102,10 @@
} else {
spin_lock (&hwc_data.lock);
+ if (hwc_data.flags & HWC_PTIMER_RUNS) {
+ del_timer (&hwc_data.poll_timer);
+ hwc_data.flags &= ~HWC_PTIMER_RUNS;
+ }
if (!hwc_data.current_servc) {
unconditional_read_1 ();
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)