diff options
Diffstat (limited to 'drivers/s390/cio/device_id.c')
-rw-r--r-- | drivers/s390/cio/device_id.c | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 2f6bf462425e..156f3f9786b5 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c | |||
@@ -113,6 +113,7 @@ __ccw_device_sense_id_start(struct ccw_device *cdev) | |||
113 | { | 113 | { |
114 | struct subchannel *sch; | 114 | struct subchannel *sch; |
115 | struct ccw1 *ccw; | 115 | struct ccw1 *ccw; |
116 | int ret; | ||
116 | 117 | ||
117 | sch = to_subchannel(cdev->dev.parent); | 118 | sch = to_subchannel(cdev->dev.parent); |
118 | /* Setup sense channel program. */ | 119 | /* Setup sense channel program. */ |
@@ -124,9 +125,25 @@ __ccw_device_sense_id_start(struct ccw_device *cdev) | |||
124 | 125 | ||
125 | /* Reset device status. */ | 126 | /* Reset device status. */ |
126 | memset(&cdev->private->irb, 0, sizeof(struct irb)); | 127 | memset(&cdev->private->irb, 0, sizeof(struct irb)); |
127 | cdev->private->flags.intretry = 0; | ||
128 | 128 | ||
129 | return cio_start(sch, ccw, LPM_ANYPATH); | 129 | /* Try on every path. */ |
130 | ret = -ENODEV; | ||
131 | while (cdev->private->imask != 0) { | ||
132 | if ((sch->opm & cdev->private->imask) != 0 && | ||
133 | cdev->private->iretry > 0) { | ||
134 | cdev->private->iretry--; | ||
135 | /* Reset internal retry indication. */ | ||
136 | cdev->private->flags.intretry = 0; | ||
137 | ret = cio_start (sch, cdev->private->iccws, | ||
138 | cdev->private->imask); | ||
139 | /* ret is 0, -EBUSY, -EACCES or -ENODEV */ | ||
140 | if (ret != -EACCES) | ||
141 | return ret; | ||
142 | } | ||
143 | cdev->private->imask >>= 1; | ||
144 | cdev->private->iretry = 5; | ||
145 | } | ||
146 | return ret; | ||
130 | } | 147 | } |
131 | 148 | ||
132 | void | 149 | void |
@@ -136,7 +153,8 @@ ccw_device_sense_id_start(struct ccw_device *cdev) | |||
136 | 153 | ||
137 | memset (&cdev->private->senseid, 0, sizeof (struct senseid)); | 154 | memset (&cdev->private->senseid, 0, sizeof (struct senseid)); |
138 | cdev->private->senseid.cu_type = 0xFFFF; | 155 | cdev->private->senseid.cu_type = 0xFFFF; |
139 | cdev->private->iretry = 3; | 156 | cdev->private->imask = 0x80; |
157 | cdev->private->iretry = 5; | ||
140 | ret = __ccw_device_sense_id_start(cdev); | 158 | ret = __ccw_device_sense_id_start(cdev); |
141 | if (ret && ret != -EBUSY) | 159 | if (ret && ret != -EBUSY) |
142 | ccw_device_sense_id_done(cdev, ret); | 160 | ccw_device_sense_id_done(cdev, ret); |
@@ -252,13 +270,14 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event) | |||
252 | ccw_device_sense_id_done(cdev, ret); | 270 | ccw_device_sense_id_done(cdev, ret); |
253 | break; | 271 | break; |
254 | case -EACCES: /* channel is not operational. */ | 272 | case -EACCES: /* channel is not operational. */ |
273 | sch->lpm &= ~cdev->private->imask; | ||
274 | cdev->private->imask >>= 1; | ||
275 | cdev->private->iretry = 5; | ||
276 | /* fall through. */ | ||
255 | case -EAGAIN: /* try again. */ | 277 | case -EAGAIN: /* try again. */ |
256 | cdev->private->iretry--; | 278 | ret = __ccw_device_sense_id_start(cdev); |
257 | if (cdev->private->iretry > 0) { | 279 | if (ret == 0 || ret == -EBUSY) |
258 | ret = __ccw_device_sense_id_start(cdev); | 280 | break; |
259 | if (ret == 0 || ret == -EBUSY) | ||
260 | break; | ||
261 | } | ||
262 | /* fall through. */ | 281 | /* fall through. */ |
263 | default: /* Sense ID failed. Try asking VM. */ | 282 | default: /* Sense ID failed. Try asking VM. */ |
264 | if (MACHINE_IS_VM) { | 283 | if (MACHINE_IS_VM) { |