diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/cio/device_id.c | 107 |
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 | */ |
35 | static void | 37 | static int vm_vdev_to_cu_type(int class, int type) |
36 | VM_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 | */ | ||
88 | static 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 | } |