--- /dev/null
+From: Gerald Schaefer <geraldsc@de.ibm.com>
+Subject: cio: notify ccw driver for boxed devices
+References: bnc#487755,LTC#52560
+
+Symptom: Dasd driver keeps trying to start io on not accessible device.
+Problem: Missing notification for ccw device drivers.
+Solution: Add proper notification if a device goes into boxed state.
+
+Acked-by: John Jolly <jjolly@suse.de>
+---
+ Documentation/kmsg/s390/zfcp | 15 +++++++++++++++
+ arch/s390/include/asm/cio.h | 2 ++
+ drivers/s390/block/dasd.c | 1 +
+ drivers/s390/cio/device.c | 26 +++++++++++++++++---------
+ drivers/s390/cio/device.h | 1 +
+ drivers/s390/cio/device_fsm.c | 29 ++++++++++++++++++-----------
+ drivers/s390/scsi/zfcp_ccw.c | 5 +++++
+ 7 files changed, 59 insertions(+), 20 deletions(-)
+
+--- a/Documentation/kmsg/s390/zfcp
++++ b/Documentation/kmsg/s390/zfcp
+@@ -100,6 +100,21 @@
+ */
+
+ /*?
++ * Text: "%s: The FCP device did not respond within the specified time\n"
++ * Severity: Warning
++ * Parameter:
++ * @1: bus ID of the zfcp device
++ * Description:
++ * The common I/O layer waited for a response from the FCP adapter but
++ * no response was received within the specified time limit. This might
++ * indicate a hardware problem.
++ * User action:
++ * Consult your hardware administrator. If this problem persists,
++ * gather Linux debug data, collect the FCP adapter hardware logs, and
++ * report the problem to your support organization.
++ */
++
++/*?
+ * Text: "%s: Registering the FCP device with the SCSI stack failed\n"
+ * Severity: Error
+ * Parameter:
+--- a/arch/s390/include/asm/cio.h
++++ b/arch/s390/include/asm/cio.h
+@@ -456,6 +456,8 @@ struct ciw {
+ #define CIO_OPER 0x0004
+ /* Sick revalidation of device. */
+ #define CIO_REVALIDATE 0x0008
++/* Device did not respond in time. */
++#define CIO_BOXED 0x0010
+
+ /**
+ * struct ccw_dev_id - unique identifier for ccw devices
+--- a/drivers/s390/block/dasd.c
++++ b/drivers/s390/block/dasd.c
+@@ -2359,6 +2359,7 @@ int dasd_generic_notify(struct ccw_devic
+ ret = 0;
+ switch (event) {
+ case CIO_GONE:
++ case CIO_BOXED:
+ case CIO_NO_PATH:
+ /* First of all call extended error reporting. */
+ dasd_eer_write(device, NULL, DASD_EER_NOPATH);
+--- a/drivers/s390/cio/device.c
++++ b/drivers/s390/cio/device.c
+@@ -479,11 +479,15 @@ static int online_store_recog_and_online
+ }
+ wait_event(cdev->private->wait_q,
+ cdev->private->flags.recog_done);
++ if (cdev->private->state != DEV_STATE_OFFLINE)
++ /* recognition failed */
++ return -EAGAIN;
+ }
+ if (cdev->drv && cdev->drv->set_online)
+ ccw_device_set_online(cdev);
+ return 0;
+ }
++
+ static int online_store_handle_online(struct ccw_device *cdev, int force)
+ {
+ int ret;
+@@ -497,7 +501,9 @@ static int online_store_handle_online(st
+ return ret;
+ if (cdev->id.cu_type == 0)
+ cdev->private->state = DEV_STATE_NOT_OPER;
+- online_store_recog_and_online(cdev);
++ ret = online_store_recog_and_online(cdev);
++ if (ret)
++ return ret;
+ }
+ return 0;
+ }
+@@ -1017,33 +1023,35 @@ static void ccw_device_call_sch_unregist
+ put_device(&sch->dev);
+ }
+
++void ccw_device_schedule_sch_unregister(struct ccw_device *cdev)
++{
++ PREPARE_WORK(&cdev->private->kick_work,
++ ccw_device_call_sch_unregister);
++ queue_work(slow_path_wq, &cdev->private->kick_work);
++}
++
+ /*
+ * subchannel recognition done. Called from the state machine.
+ */
+ void
+ io_subchannel_recog_done(struct ccw_device *cdev)
+ {
+- struct subchannel *sch;
+-
+ if (css_init_done == 0) {
+ cdev->private->flags.recog_done = 1;
+ return;
+ }
+ switch (cdev->private->state) {
++ case DEV_STATE_BOXED:
++ /* Device did not respond in time. */
+ case DEV_STATE_NOT_OPER:
+ cdev->private->flags.recog_done = 1;
+ /* Remove device found not operational. */
+ if (!get_device(&cdev->dev))
+ break;
+- sch = to_subchannel(cdev->dev.parent);
+- PREPARE_WORK(&cdev->private->kick_work,
+- ccw_device_call_sch_unregister);
+- queue_work(slow_path_wq, &cdev->private->kick_work);
++ ccw_device_schedule_sch_unregister(cdev);
+ if (atomic_dec_and_test(&ccw_device_init_count))
+ wake_up(&ccw_device_init_wq);
+ break;
+- case DEV_STATE_BOXED:
+- /* Device did not respond in time. */
+ case DEV_STATE_OFFLINE:
+ /*
+ * We can't register the device in interrupt context so
+--- a/drivers/s390/cio/device.h
++++ b/drivers/s390/cio/device.h
+@@ -86,6 +86,7 @@ int ccw_device_is_orphan(struct ccw_devi
+ int ccw_device_recognition(struct ccw_device *);
+ int ccw_device_online(struct ccw_device *);
+ int ccw_device_offline(struct ccw_device *);
++void ccw_device_schedule_sch_unregister(struct ccw_device *);
+
+ /* Function prototypes for device status and basic sense stuff. */
+ void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);
+--- a/drivers/s390/cio/device_fsm.c
++++ b/drivers/s390/cio/device_fsm.c
+@@ -253,13 +253,12 @@ ccw_device_recog_done(struct ccw_device
+ old_lpm = 0;
+ if (sch->lpm != old_lpm)
+ __recover_lost_chpids(sch, old_lpm);
+- if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) {
+- if (state == DEV_STATE_NOT_OPER) {
+- cdev->private->flags.recog_done = 1;
+- cdev->private->state = DEV_STATE_DISCONNECTED;
+- return;
+- }
+- /* Boxed devices don't need extra treatment. */
++ if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID &&
++ (state == DEV_STATE_NOT_OPER || state == DEV_STATE_BOXED)) {
++ cdev->private->flags.recog_done = 1;
++ cdev->private->state = DEV_STATE_DISCONNECTED;
++ wake_up(&cdev->private->wait_q);
++ return;
+ }
+ notify = 0;
+ same_dev = 0; /* Keep the compiler quiet... */
+@@ -304,12 +303,17 @@ ccw_device_recog_done(struct ccw_device
+ " subchannel 0.%x.%04x\n",
+ cdev->private->dev_id.devno,
+ sch->schid.ssid, sch->schid.sch_no);
++ if (cdev->id.cu_type != 0) { /* device was recognized before */
++ cdev->private->flags.recog_done = 1;
++ cdev->private->state = DEV_STATE_BOXED;
++ wake_up(&cdev->private->wait_q);
++ return;
++ }
+ break;
+ }
+ cdev->private->state = state;
+ io_subchannel_recog_done(cdev);
+- if (state != DEV_STATE_NOT_OPER)
+- wake_up(&cdev->private->wait_q);
++ wake_up(&cdev->private->wait_q);
+ }
+
+ /*
+@@ -387,10 +391,13 @@ ccw_device_done(struct ccw_device *cdev,
+
+ cdev->private->state = state;
+
+-
+- if (state == DEV_STATE_BOXED)
++ if (state == DEV_STATE_BOXED) {
+ CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n",
+ cdev->private->dev_id.devno, sch->schid.sch_no);
++ if (cdev->online && !ccw_device_notify(cdev, CIO_BOXED))
++ ccw_device_schedule_sch_unregister(cdev);
++ cdev->private->flags.donotify = 0;
++ }
+
+ if (cdev->private->flags.donotify) {
+ cdev->private->flags.donotify = 0;
+--- a/drivers/s390/scsi/zfcp_ccw.c
++++ b/drivers/s390/scsi/zfcp_ccw.c
+@@ -181,6 +181,11 @@ static int zfcp_ccw_notify(struct ccw_de
+ zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
+ 89, NULL);
+ break;
++ case CIO_BOXED:
++ dev_warn(&adapter->ccw_device->dev, "The FCP device "
++ "did not respond within the specified time\n");
++ zfcp_erp_adapter_shutdown(adapter, 0, 91, NULL);
++ break;
+ }
+ return 1;
+ }