/* Suspend request */
 static DECLARE_COMPLETION(sclp_request_queue_flushed);
 
+/* Number of console pages to allocate, used by sclp_con.c and sclp_vt220.c */
+int sclp_console_pages = SCLP_CONSOLE_PAGES;
+/* Flag to indicate if buffer pages are dropped on buffer full condition */
+int sclp_console_drop = 0;
+/* Number of times the console dropped buffer pages */
+unsigned long sclp_console_full;
+
 static void sclp_suspend_req_cb(struct sclp_req *req, void *data)
 {
        complete(&sclp_request_queue_flushed);
 }
 
+static int __init sclp_setup_console_pages(char *str)
+{
+       int pages, rc;
+
+       rc = kstrtoint(str, 0, &pages);
+       if (!rc && pages >= SCLP_CONSOLE_PAGES)
+               sclp_console_pages = pages;
+       return 1;
+}
+
+__setup("sclp_con_pages=", sclp_setup_console_pages);
+
+static int __init sclp_setup_console_drop(char *str)
+{
+       int drop, rc;
+
+       rc = kstrtoint(str, 0, &drop);
+       if (!rc && drop)
+               sclp_console_drop = 1;
+       return 1;
+}
+
+__setup("sclp_con_drop=", sclp_setup_console_drop);
+
 static struct sclp_req sclp_suspend_req;
 
 /* Timer for request retries. */
        .restore        = sclp_restore,
 };
 
+static ssize_t sclp_show_console_pages(struct device_driver *dev, char *buf)
+{
+       return sprintf(buf, "%i\n", sclp_console_pages);
+}
+
+static DRIVER_ATTR(con_pages, S_IRUSR, sclp_show_console_pages, NULL);
+
+static ssize_t sclp_show_con_drop(struct device_driver *dev, char *buf)
+{
+       return sprintf(buf, "%i\n", sclp_console_drop);
+}
+
+static DRIVER_ATTR(con_drop, S_IRUSR, sclp_show_con_drop, NULL);
+
+static ssize_t sclp_show_console_full(struct device_driver *dev, char *buf)
+{
+       return sprintf(buf, "%lu\n", sclp_console_full);
+}
+
+static DRIVER_ATTR(con_full, S_IRUSR, sclp_show_console_full, NULL);
+
+static struct attribute *sclp_drv_attrs[] = {
+       &driver_attr_con_pages.attr,
+       &driver_attr_con_drop.attr,
+       &driver_attr_con_full.attr,
+       NULL,
+};
+static struct attribute_group sclp_drv_attr_group = {
+       .attrs = sclp_drv_attrs,
+};
+static const struct attribute_group *sclp_drv_attr_groups[] = {
+       &sclp_drv_attr_group,
+       NULL,
+};
+
 static struct platform_driver sclp_pdrv = {
        .driver = {
                .name   = "sclp",
                .owner  = THIS_MODULE,
                .pm     = &sclp_pm_ops,
+               .groups = sclp_drv_attr_groups,
        },
 };
 
        rc = platform_driver_register(&sclp_pdrv);
        if (rc)
                return rc;
+
        sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0);
        rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0;
        if (rc)
                goto fail_platform_driver_unregister;
+
        rc = atomic_notifier_chain_register(&panic_notifier_list,
                                            &sclp_on_panic_nb);
        if (rc)
 
 
 /* maximum number of pages concerning our own memory management */
 #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3)
-#define MAX_CONSOLE_PAGES      6
+#define SCLP_CONSOLE_PAGES     6
 
 #define EVTYP_OPCMD            0x01
 #define EVTYP_MSG              0x02
 int sclp_sdias_init(void);
 void sclp_sdias_exit(void);
 
+extern int sclp_console_pages;
+extern int sclp_console_drop;
+extern unsigned long sclp_console_full;
+
 /* useful inlines */
 
 /* VM uses EBCDIC 037, LPAR+native(SE+HMC) use EBCDIC 500 */
 
        sclp_conbuf_emit();
 }
 
+/*
+ * Drop oldest console buffer if sclp_con_drop is set
+ */
+static int
+sclp_console_drop_buffer(void)
+{
+       struct list_head *list;
+       struct sclp_buffer *buffer;
+       void *page;
+
+       if (!sclp_console_drop)
+               return 0;
+       list = sclp_con_outqueue.next;
+       if (sclp_con_queue_running)
+               /* The first element is in I/O */
+               list = list->next;
+       if (list == &sclp_con_outqueue)
+               return 0;
+       list_del(list);
+       buffer = list_entry(list, struct sclp_buffer, list);
+       page = sclp_unmake_buffer(buffer);
+       list_add_tail((struct list_head *) page, &sclp_con_pages);
+       return 1;
+}
+
 /*
  * Writes the given message to S390 system console
  */
        do {
                /* make sure we have a console output buffer */
                if (sclp_conbuf == NULL) {
+                       if (list_empty(&sclp_con_pages))
+                               sclp_console_full++;
                        while (list_empty(&sclp_con_pages)) {
                                if (sclp_con_suspended)
                                        goto out;
+                               if (sclp_console_drop_buffer())
+                                       break;
                                spin_unlock_irqrestore(&sclp_con_lock, flags);
                                sclp_sync_wait();
                                spin_lock_irqsave(&sclp_con_lock, flags);
                return rc;
        /* Allocate pages for output buffering */
        INIT_LIST_HEAD(&sclp_con_pages);
-       for (i = 0; i < MAX_CONSOLE_PAGES; i++) {
+       for (i = 0; i < sclp_console_pages; i++) {
                page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
                list_add_tail(page, &sclp_con_pages);
        }
 
 
 #define BUFFER_MAX_DELAY       HZ/20
 
+/*
+ * Drop oldest console buffer if sclp_con_drop is set
+ */
+static int
+sclp_vt220_drop_buffer(void)
+{
+       struct list_head *list;
+       struct sclp_vt220_request *request;
+       void *page;
+
+       if (!sclp_console_drop)
+               return 0;
+       list = sclp_vt220_outqueue.next;
+       if (sclp_vt220_queue_running)
+               /* The first element is in I/O */
+               list = list->next;
+       if (list == &sclp_vt220_outqueue)
+               return 0;
+       list_del(list);
+       request = list_entry(list, struct sclp_vt220_request, list);
+       page = request->sclp_req.sccb;
+       list_add_tail((struct list_head *) page, &sclp_vt220_empty);
+       return 1;
+}
+
 /* 
  * Internal implementation of the write function. Write COUNT bytes of data
  * from memory at BUF
        do {
                /* Create an sclp output buffer if none exists yet */
                if (sclp_vt220_current_request == NULL) {
+                       if (list_empty(&sclp_vt220_empty))
+                               sclp_console_full++;
                        while (list_empty(&sclp_vt220_empty)) {
-                               spin_unlock_irqrestore(&sclp_vt220_lock, flags);
                                if (may_fail || sclp_vt220_suspended)
                                        goto out;
-                               else
-                                       sclp_sync_wait();
+                               if (sclp_vt220_drop_buffer())
+                                       break;
+                               spin_unlock_irqrestore(&sclp_vt220_lock, flags);
+
+                               sclp_sync_wait();
                                spin_lock_irqsave(&sclp_vt220_lock, flags);
                        }
                        page = (void *) sclp_vt220_empty.next;
                sclp_vt220_timer.expires = jiffies + BUFFER_MAX_DELAY;
                add_timer(&sclp_vt220_timer);
        }
-       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
 out:
+       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
        return overall_written;
 }
 
 
        if (!CONSOLE_IS_SCLP)
                return 0;
-       rc = __sclp_vt220_init(MAX_CONSOLE_PAGES);
+       rc = __sclp_vt220_init(sclp_console_pages);
        if (rc)
                return rc;
        /* Attach linux console */