aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Oberparleiter <peter.oberparleiter@de.ibm.com>2008-02-05 10:50:33 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-02-05 10:50:52 -0500
commit6f52ac29712f3eec192599249b12612360948646 (patch)
tree969f70f233860c35f676d7c457dd28a39a8dde1b
parent9ef9dc69d4167276c04590d67ee55de8380bc1ad (diff)
[S390] cio: make sense id procedure work with partial hardware response
In some cases the current sense id procedure trips over incomplete hardware responses. In these cases, checking against the preset value of 0xFFFF is not enough. More critically, the VM DIAG call will always be considered to have provided data after such an incident, even if it was not successful at all. The solution is to always initialize the control unit data before doing a sense id call. Check the condition code before considering the control unit data. And initialize again, before evaluating the VM data. Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--drivers/s390/cio/device_id.c107
1 files changed, 64 insertions, 43 deletions
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index 918b8b89cf9a..dc4d87f77f6c 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -26,17 +26,18 @@
26#include "ioasm.h" 26#include "ioasm.h"
27#include "io_sch.h" 27#include "io_sch.h"
28 28
29/* 29/**
30 * Input : 30 * vm_vdev_to_cu_type - Convert vm virtual device into control unit type
31 * devno - device number 31 * for certain devices.
32 * ps - pointer to sense ID data area 32 * @class: virtual device class
33 * Output : none 33 * @type: virtual device type
34 *
35 * Returns control unit type if a match was made or %0xffff otherwise.
34 */ 36 */
35static void 37static int vm_vdev_to_cu_type(int class, int type)
36VM_virtual_device_info (__u16 devno, struct senseid *ps)
37{ 38{
38 static struct { 39 static struct {
39 int vrdcvcla, vrdcvtyp, cu_type; 40 int class, type, cu_type;
40 } vm_devices[] = { 41 } vm_devices[] = {
41 { 0x08, 0x01, 0x3480 }, 42 { 0x08, 0x01, 0x3480 },
42 { 0x08, 0x02, 0x3430 }, 43 { 0x08, 0x02, 0x3430 },
@@ -68,8 +69,26 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps)
68 { 0x40, 0xc0, 0x5080 }, 69 { 0x40, 0xc0, 0x5080 },
69 { 0x80, 0x00, 0x3215 }, 70 { 0x80, 0x00, 0x3215 },
70 }; 71 };
72 int i;
73
74 for (i = 0; i < ARRAY_SIZE(vm_devices); i++)
75 if (class == vm_devices[i].class && type == vm_devices[i].type)
76 return vm_devices[i].cu_type;
77
78 return 0xffff;
79}
80
81/**
82 * diag_get_dev_info - retrieve device information via DIAG X'210'
83 * @devno: device number
84 * @ps: pointer to sense ID data area
85 *
86 * Returns zero on success, non-zero otherwise.
87 */
88static int diag_get_dev_info(u16 devno, struct senseid *ps)
89{
71 struct diag210 diag_data; 90 struct diag210 diag_data;
72 int ccode, i; 91 int ccode;
73 92
74 CIO_TRACE_EVENT (4, "VMvdinf"); 93 CIO_TRACE_EVENT (4, "VMvdinf");
75 94
@@ -79,21 +98,21 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps)
79 }; 98 };
80 99
81 ccode = diag210 (&diag_data); 100 ccode = diag210 (&diag_data);
82 ps->reserved = 0xff; 101 if ((ccode == 0) || (ccode == 2)) {
102 ps->reserved = 0xff;
83 103
84 /* Special case for bloody osa devices. */ 104 /* Special case for osa devices. */
85 if (diag_data.vrdcvcla == 0x02 && 105 if (diag_data.vrdcvcla == 0x02 && diag_data.vrdcvtyp == 0x20) {
86 diag_data.vrdcvtyp == 0x20) { 106 ps->cu_type = 0x3088;
87 ps->cu_type = 0x3088; 107 ps->cu_model = 0x60;
88 ps->cu_model = 0x60; 108 return 0;
89 return;
90 }
91 for (i = 0; i < ARRAY_SIZE(vm_devices); i++)
92 if (diag_data.vrdcvcla == vm_devices[i].vrdcvcla &&
93 diag_data.vrdcvtyp == vm_devices[i].vrdcvtyp) {
94 ps->cu_type = vm_devices[i].cu_type;
95 return;
96 } 109 }
110 ps->cu_type = vm_vdev_to_cu_type(diag_data.vrdcvcla,
111 diag_data.vrdcvtyp);
112 if (ps->cu_type != 0xffff)
113 return 0;
114 }
115
97 CIO_MSG_EVENT(0, "DIAG X'210' for device %04X returned (cc = %d):" 116 CIO_MSG_EVENT(0, "DIAG X'210' for device %04X returned (cc = %d):"
98 "vdev class : %02X, vdev type : %04X \n ... " 117 "vdev class : %02X, vdev type : %04X \n ... "
99 "rdev class : %02X, rdev type : %04X, " 118 "rdev class : %02X, rdev type : %04X, "
@@ -102,6 +121,8 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps)
102 diag_data.vrdcvcla, diag_data.vrdcvtyp, 121 diag_data.vrdcvcla, diag_data.vrdcvtyp,
103 diag_data.vrdcrccl, diag_data.vrdccrty, 122 diag_data.vrdcrccl, diag_data.vrdccrty,
104 diag_data.vrdccrmd); 123 diag_data.vrdccrmd);
124
125 return -ENODEV;
105} 126}
106 127
107/* 128/*
@@ -130,6 +151,7 @@ __ccw_device_sense_id_start(struct ccw_device *cdev)
130 /* Try on every path. */ 151 /* Try on every path. */
131 ret = -ENODEV; 152 ret = -ENODEV;
132 while (cdev->private->imask != 0) { 153 while (cdev->private->imask != 0) {
154 cdev->private->senseid.cu_type = 0xFFFF;
133 if ((sch->opm & cdev->private->imask) != 0 && 155 if ((sch->opm & cdev->private->imask) != 0 &&
134 cdev->private->iretry > 0) { 156 cdev->private->iretry > 0) {
135 cdev->private->iretry--; 157 cdev->private->iretry--;
@@ -153,7 +175,6 @@ ccw_device_sense_id_start(struct ccw_device *cdev)
153 int ret; 175 int ret;
154 176
155 memset (&cdev->private->senseid, 0, sizeof (struct senseid)); 177 memset (&cdev->private->senseid, 0, sizeof (struct senseid));
156 cdev->private->senseid.cu_type = 0xFFFF;
157 cdev->private->imask = 0x80; 178 cdev->private->imask = 0x80;
158 cdev->private->iretry = 5; 179 cdev->private->iretry = 5;
159 ret = __ccw_device_sense_id_start(cdev); 180 ret = __ccw_device_sense_id_start(cdev);
@@ -173,13 +194,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
173 194
174 sch = to_subchannel(cdev->dev.parent); 195 sch = to_subchannel(cdev->dev.parent);
175 irb = &cdev->private->irb; 196 irb = &cdev->private->irb;
176 /* Did we get a proper answer ? */ 197
177 if (cdev->private->senseid.cu_type != 0xFFFF &&
178 cdev->private->senseid.reserved == 0xFF) {
179 if (irb->scsw.count < sizeof (struct senseid) - 8)
180 cdev->private->flags.esid = 1;
181 return 0; /* Success */
182 }
183 /* Check the error cases. */ 198 /* Check the error cases. */
184 if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { 199 if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
185 /* Retry Sense ID if requested. */ 200 /* Retry Sense ID if requested. */
@@ -231,6 +246,15 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
231 sch->schid.ssid, sch->schid.sch_no); 246 sch->schid.ssid, sch->schid.sch_no);
232 return -EACCES; 247 return -EACCES;
233 } 248 }
249
250 /* Did we get a proper answer ? */
251 if (irb->scsw.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF &&
252 cdev->private->senseid.reserved == 0xFF) {
253 if (irb->scsw.count < sizeof(struct senseid) - 8)
254 cdev->private->flags.esid = 1;
255 return 0; /* Success */
256 }
257
234 /* Hmm, whatever happened, try again. */ 258 /* Hmm, whatever happened, try again. */
235 CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on " 259 CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on "
236 "subchannel 0.%x.%04x returns status %02X%02X\n", 260 "subchannel 0.%x.%04x returns status %02X%02X\n",
@@ -283,20 +307,17 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
283 break; 307 break;
284 /* fall through. */ 308 /* fall through. */
285 default: /* Sense ID failed. Try asking VM. */ 309 default: /* Sense ID failed. Try asking VM. */
286 if (MACHINE_IS_VM) { 310 if (MACHINE_IS_VM)
287 VM_virtual_device_info (cdev->private->dev_id.devno, 311 ret = diag_get_dev_info(cdev->private->dev_id.devno,
288 &cdev->private->senseid); 312 &cdev->private->senseid);
289 if (cdev->private->senseid.cu_type != 0xFFFF) { 313 else
290 /* Got the device information from VM. */ 314 /*
291 ccw_device_sense_id_done(cdev, 0); 315 * If we can't couldn't identify the device type we
292 return; 316 * consider the device "not operational".
293 } 317 */
294 } 318 ret = -ENODEV;
295 /* 319
296 * If we can't couldn't identify the device type we 320 ccw_device_sense_id_done(cdev, ret);
297 * consider the device "not operational".
298 */
299 ccw_device_sense_id_done(cdev, -ENODEV);
300 break; 321 break;
301 } 322 }
302} 323}