aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sr.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/sr.c')
-rw-r--r--drivers/scsi/sr.c46
1 files changed, 42 insertions, 4 deletions
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 4778e2707168..5fc97d2ba2fd 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -221,14 +221,33 @@ static unsigned int sr_check_events(struct cdrom_device_info *cdi,
221 return 0; 221 return 0;
222 222
223 events = sr_get_events(cd->device); 223 events = sr_get_events(cd->device);
224 cd->get_event_changed |= events & DISK_EVENT_MEDIA_CHANGE;
225
226 /*
227 * If earlier GET_EVENT_STATUS_NOTIFICATION and TUR did not agree
228 * for several times in a row. We rely on TUR only for this likely
229 * broken device, to prevent generating incorrect media changed
230 * events for every open().
231 */
232 if (cd->ignore_get_event) {
233 events &= ~DISK_EVENT_MEDIA_CHANGE;
234 goto do_tur;
235 }
236
224 /* 237 /*
225 * GET_EVENT_STATUS_NOTIFICATION is enough unless MEDIA_CHANGE 238 * GET_EVENT_STATUS_NOTIFICATION is enough unless MEDIA_CHANGE
226 * is being cleared. Note that there are devices which hang 239 * is being cleared. Note that there are devices which hang
227 * if asked to execute TUR repeatedly. 240 * if asked to execute TUR repeatedly.
228 */ 241 */
229 if (!(clearing & DISK_EVENT_MEDIA_CHANGE)) 242 if (cd->device->changed) {
230 goto skip_tur; 243 events |= DISK_EVENT_MEDIA_CHANGE;
244 cd->device->changed = 0;
245 cd->tur_changed = true;
246 }
231 247
248 if (!(clearing & DISK_EVENT_MEDIA_CHANGE))
249 return events;
250do_tur:
232 /* let's see whether the media is there with TUR */ 251 /* let's see whether the media is there with TUR */
233 last_present = cd->media_present; 252 last_present = cd->media_present;
234 ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); 253 ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr);
@@ -242,12 +261,31 @@ static unsigned int sr_check_events(struct cdrom_device_info *cdi,
242 (scsi_sense_valid(&sshdr) && sshdr.asc != 0x3a); 261 (scsi_sense_valid(&sshdr) && sshdr.asc != 0x3a);
243 262
244 if (last_present != cd->media_present) 263 if (last_present != cd->media_present)
245 events |= DISK_EVENT_MEDIA_CHANGE; 264 cd->device->changed = 1;
246skip_tur: 265
247 if (cd->device->changed) { 266 if (cd->device->changed) {
248 events |= DISK_EVENT_MEDIA_CHANGE; 267 events |= DISK_EVENT_MEDIA_CHANGE;
249 cd->device->changed = 0; 268 cd->device->changed = 0;
269 cd->tur_changed = true;
270 }
271
272 if (cd->ignore_get_event)
273 return events;
274
275 /* check whether GET_EVENT is reporting spurious MEDIA_CHANGE */
276 if (!cd->tur_changed) {
277 if (cd->get_event_changed) {
278 if (cd->tur_mismatch++ > 8) {
279 sdev_printk(KERN_WARNING, cd->device,
280 "GET_EVENT and TUR disagree continuously, suppress GET_EVENT events\n");
281 cd->ignore_get_event = true;
282 }
283 } else {
284 cd->tur_mismatch = 0;
285 }
250 } 286 }
287 cd->tur_changed = false;
288 cd->get_event_changed = false;
251 289
252 return events; 290 return events;
253} 291}