diff options
author | Jens Axboe <jaxboe@fusionio.com> | 2010-12-16 11:54:38 -0500 |
---|---|---|
committer | Jens Axboe <jaxboe@fusionio.com> | 2010-12-16 11:54:38 -0500 |
commit | 8ae47c1e7deda7fa959a1dd272ff67e8a1830490 (patch) | |
tree | f8c6f40b45b60c17a12015a1e94cac562c07b94f /drivers | |
parent | c4ffa146849099e9178d3fcfa48ba114d3d1e432 (diff) | |
parent | c8d2e937355d02db3055c2fc203e5f017297ee1f (diff) |
Merge branch 'for-2.6.38/event-handling' into for-next
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/cdrom/cdrom.c | 55 | ||||
-rw-r--r-- | drivers/scsi/scsi_lib.c | 13 | ||||
-rw-r--r-- | drivers/scsi/sd.c | 95 | ||||
-rw-r--r-- | drivers/scsi/sd.h | 1 | ||||
-rw-r--r-- | drivers/scsi/sr.c | 174 | ||||
-rw-r--r-- | drivers/scsi/sr.h | 3 | ||||
-rw-r--r-- | drivers/scsi/sr_ioctl.c | 2 |
7 files changed, 201 insertions, 142 deletions
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index af13c62dc473..1ea8f8d363c6 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c | |||
@@ -1348,7 +1348,10 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot) | |||
1348 | if (!CDROM_CAN(CDC_SELECT_DISC)) | 1348 | if (!CDROM_CAN(CDC_SELECT_DISC)) |
1349 | return -EDRIVE_CANT_DO_THIS; | 1349 | return -EDRIVE_CANT_DO_THIS; |
1350 | 1350 | ||
1351 | (void) cdi->ops->media_changed(cdi, slot); | 1351 | if (cdi->ops->check_events) |
1352 | cdi->ops->check_events(cdi, 0, slot); | ||
1353 | else | ||
1354 | cdi->ops->media_changed(cdi, slot); | ||
1352 | 1355 | ||
1353 | if (slot == CDSL_NONE) { | 1356 | if (slot == CDSL_NONE) { |
1354 | /* set media changed bits, on both queues */ | 1357 | /* set media changed bits, on both queues */ |
@@ -1392,6 +1395,41 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot) | |||
1392 | return slot; | 1395 | return slot; |
1393 | } | 1396 | } |
1394 | 1397 | ||
1398 | /* | ||
1399 | * As cdrom implements an extra ioctl consumer for media changed | ||
1400 | * event, it needs to buffer ->check_events() output, such that event | ||
1401 | * is not lost for both the usual VFS and ioctl paths. | ||
1402 | * cdi->{vfs|ioctl}_events are used to buffer pending events for each | ||
1403 | * path. | ||
1404 | * | ||
1405 | * XXX: Locking is non-existent. cdi->ops->check_events() can be | ||
1406 | * called in parallel and buffering fields are accessed without any | ||
1407 | * exclusion. The original media_changed code had the same problem. | ||
1408 | * It might be better to simply deprecate CDROM_MEDIA_CHANGED ioctl | ||
1409 | * and remove this cruft altogether. It doesn't have much usefulness | ||
1410 | * at this point. | ||
1411 | */ | ||
1412 | static void cdrom_update_events(struct cdrom_device_info *cdi, | ||
1413 | unsigned int clearing) | ||
1414 | { | ||
1415 | unsigned int events; | ||
1416 | |||
1417 | events = cdi->ops->check_events(cdi, clearing, CDSL_CURRENT); | ||
1418 | cdi->vfs_events |= events; | ||
1419 | cdi->ioctl_events |= events; | ||
1420 | } | ||
1421 | |||
1422 | unsigned int cdrom_check_events(struct cdrom_device_info *cdi, | ||
1423 | unsigned int clearing) | ||
1424 | { | ||
1425 | unsigned int events; | ||
1426 | |||
1427 | cdrom_update_events(cdi, clearing); | ||
1428 | events = cdi->vfs_events; | ||
1429 | cdi->vfs_events = 0; | ||
1430 | return events; | ||
1431 | } | ||
1432 | |||
1395 | /* We want to make media_changed accessible to the user through an | 1433 | /* We want to make media_changed accessible to the user through an |
1396 | * ioctl. The main problem now is that we must double-buffer the | 1434 | * ioctl. The main problem now is that we must double-buffer the |
1397 | * low-level implementation, to assure that the VFS and the user both | 1435 | * low-level implementation, to assure that the VFS and the user both |
@@ -1403,15 +1441,26 @@ int media_changed(struct cdrom_device_info *cdi, int queue) | |||
1403 | { | 1441 | { |
1404 | unsigned int mask = (1 << (queue & 1)); | 1442 | unsigned int mask = (1 << (queue & 1)); |
1405 | int ret = !!(cdi->mc_flags & mask); | 1443 | int ret = !!(cdi->mc_flags & mask); |
1444 | bool changed; | ||
1406 | 1445 | ||
1407 | if (!CDROM_CAN(CDC_MEDIA_CHANGED)) | 1446 | if (!CDROM_CAN(CDC_MEDIA_CHANGED)) |
1408 | return ret; | 1447 | return ret; |
1448 | |||
1409 | /* changed since last call? */ | 1449 | /* changed since last call? */ |
1410 | if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { | 1450 | if (cdi->ops->check_events) { |
1451 | BUG_ON(!queue); /* shouldn't be called from VFS path */ | ||
1452 | cdrom_update_events(cdi, DISK_EVENT_MEDIA_CHANGE); | ||
1453 | changed = cdi->ioctl_events & DISK_EVENT_MEDIA_CHANGE; | ||
1454 | cdi->ioctl_events = 0; | ||
1455 | } else | ||
1456 | changed = cdi->ops->media_changed(cdi, CDSL_CURRENT); | ||
1457 | |||
1458 | if (changed) { | ||
1411 | cdi->mc_flags = 0x3; /* set bit on both queues */ | 1459 | cdi->mc_flags = 0x3; /* set bit on both queues */ |
1412 | ret |= 1; | 1460 | ret |= 1; |
1413 | cdi->media_written = 0; | 1461 | cdi->media_written = 0; |
1414 | } | 1462 | } |
1463 | |||
1415 | cdi->mc_flags &= ~mask; /* clear bit */ | 1464 | cdi->mc_flags &= ~mask; /* clear bit */ |
1416 | return ret; | 1465 | return ret; |
1417 | } | 1466 | } |
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index eafeeda6e194..13bf89145b18 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -1984,8 +1984,7 @@ EXPORT_SYMBOL(scsi_mode_sense); | |||
1984 | * in. | 1984 | * in. |
1985 | * | 1985 | * |
1986 | * Returns zero if unsuccessful or an error if TUR failed. For | 1986 | * Returns zero if unsuccessful or an error if TUR failed. For |
1987 | * removable media, a return of NOT_READY or UNIT_ATTENTION is | 1987 | * removable media, UNIT_ATTENTION sets ->changed flag. |
1988 | * translated to success, with the ->changed flag updated. | ||
1989 | **/ | 1988 | **/ |
1990 | int | 1989 | int |
1991 | scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, | 1990 | scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, |
@@ -2012,16 +2011,6 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, | |||
2012 | } while (scsi_sense_valid(sshdr) && | 2011 | } while (scsi_sense_valid(sshdr) && |
2013 | sshdr->sense_key == UNIT_ATTENTION && --retries); | 2012 | sshdr->sense_key == UNIT_ATTENTION && --retries); |
2014 | 2013 | ||
2015 | if (!sshdr) | ||
2016 | /* could not allocate sense buffer, so can't process it */ | ||
2017 | return result; | ||
2018 | |||
2019 | if (sdev->removable && scsi_sense_valid(sshdr) && | ||
2020 | (sshdr->sense_key == UNIT_ATTENTION || | ||
2021 | sshdr->sense_key == NOT_READY)) { | ||
2022 | sdev->changed = 1; | ||
2023 | result = 0; | ||
2024 | } | ||
2025 | if (!sshdr_external) | 2014 | if (!sshdr_external) |
2026 | kfree(sshdr); | 2015 | kfree(sshdr); |
2027 | return result; | 2016 | return result; |
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index b9ab3a590e4b..b179b0e39a3b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -991,30 +991,50 @@ out: | |||
991 | 991 | ||
992 | static void set_media_not_present(struct scsi_disk *sdkp) | 992 | static void set_media_not_present(struct scsi_disk *sdkp) |
993 | { | 993 | { |
994 | if (sdkp->media_present) | ||
995 | sdkp->device->changed = 1; | ||
994 | sdkp->media_present = 0; | 996 | sdkp->media_present = 0; |
995 | sdkp->capacity = 0; | 997 | sdkp->capacity = 0; |
996 | sdkp->device->changed = 1; | 998 | } |
999 | |||
1000 | static int media_not_present(struct scsi_disk *sdkp, | ||
1001 | struct scsi_sense_hdr *sshdr) | ||
1002 | { | ||
1003 | if (!scsi_sense_valid(sshdr)) | ||
1004 | return 0; | ||
1005 | |||
1006 | /* not invoked for commands that could return deferred errors */ | ||
1007 | switch (sshdr->sense_key) { | ||
1008 | case UNIT_ATTENTION: | ||
1009 | sdkp->device->changed = 1; | ||
1010 | /* fall through */ | ||
1011 | case NOT_READY: | ||
1012 | /* medium not present */ | ||
1013 | if (sshdr->asc == 0x3A) { | ||
1014 | set_media_not_present(sdkp); | ||
1015 | return 1; | ||
1016 | } | ||
1017 | } | ||
1018 | return 0; | ||
997 | } | 1019 | } |
998 | 1020 | ||
999 | /** | 1021 | /** |
1000 | * sd_media_changed - check if our medium changed | 1022 | * sd_check_events - check media events |
1001 | * @disk: kernel device descriptor | 1023 | * @disk: kernel device descriptor |
1024 | * @clearing: disk events currently being cleared | ||
1002 | * | 1025 | * |
1003 | * Returns 0 if not applicable or no change; 1 if change | 1026 | * Returns mask of DISK_EVENT_*. |
1004 | * | 1027 | * |
1005 | * Note: this function is invoked from the block subsystem. | 1028 | * Note: this function is invoked from the block subsystem. |
1006 | **/ | 1029 | **/ |
1007 | static int sd_media_changed(struct gendisk *disk) | 1030 | static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing) |
1008 | { | 1031 | { |
1009 | struct scsi_disk *sdkp = scsi_disk(disk); | 1032 | struct scsi_disk *sdkp = scsi_disk(disk); |
1010 | struct scsi_device *sdp = sdkp->device; | 1033 | struct scsi_device *sdp = sdkp->device; |
1011 | struct scsi_sense_hdr *sshdr = NULL; | 1034 | struct scsi_sense_hdr *sshdr = NULL; |
1012 | int retval; | 1035 | int retval; |
1013 | 1036 | ||
1014 | SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n")); | 1037 | SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_check_events\n")); |
1015 | |||
1016 | if (!sdp->removable) | ||
1017 | return 0; | ||
1018 | 1038 | ||
1019 | /* | 1039 | /* |
1020 | * If the device is offline, don't send any commands - just pretend as | 1040 | * If the device is offline, don't send any commands - just pretend as |
@@ -1024,7 +1044,6 @@ static int sd_media_changed(struct gendisk *disk) | |||
1024 | */ | 1044 | */ |
1025 | if (!scsi_device_online(sdp)) { | 1045 | if (!scsi_device_online(sdp)) { |
1026 | set_media_not_present(sdkp); | 1046 | set_media_not_present(sdkp); |
1027 | retval = 1; | ||
1028 | goto out; | 1047 | goto out; |
1029 | } | 1048 | } |
1030 | 1049 | ||
@@ -1045,34 +1064,30 @@ static int sd_media_changed(struct gendisk *disk) | |||
1045 | sshdr); | 1064 | sshdr); |
1046 | } | 1065 | } |
1047 | 1066 | ||
1048 | /* | 1067 | /* failed to execute TUR, assume media not present */ |
1049 | * Unable to test, unit probably not ready. This usually | 1068 | if (host_byte(retval)) { |
1050 | * means there is no disc in the drive. Mark as changed, | ||
1051 | * and we will figure it out later once the drive is | ||
1052 | * available again. | ||
1053 | */ | ||
1054 | if (retval || (scsi_sense_valid(sshdr) && | ||
1055 | /* 0x3a is medium not present */ | ||
1056 | sshdr->asc == 0x3a)) { | ||
1057 | set_media_not_present(sdkp); | 1069 | set_media_not_present(sdkp); |
1058 | retval = 1; | ||
1059 | goto out; | 1070 | goto out; |
1060 | } | 1071 | } |
1061 | 1072 | ||
1073 | if (media_not_present(sdkp, sshdr)) | ||
1074 | goto out; | ||
1075 | |||
1062 | /* | 1076 | /* |
1063 | * For removable scsi disk we have to recognise the presence | 1077 | * For removable scsi disk we have to recognise the presence |
1064 | * of a disk in the drive. This is kept in the struct scsi_disk | 1078 | * of a disk in the drive. |
1065 | * struct and tested at open ! Daniel Roche (dan@lectra.fr) | ||
1066 | */ | 1079 | */ |
1080 | if (!sdkp->media_present) | ||
1081 | sdp->changed = 1; | ||
1067 | sdkp->media_present = 1; | 1082 | sdkp->media_present = 1; |
1068 | |||
1069 | retval = sdp->changed; | ||
1070 | sdp->changed = 0; | ||
1071 | out: | 1083 | out: |
1072 | if (retval != sdkp->previous_state) | 1084 | /* for backward compatibility */ |
1085 | if (sdp->changed) | ||
1073 | sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); | 1086 | sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); |
1074 | sdkp->previous_state = retval; | ||
1075 | kfree(sshdr); | 1087 | kfree(sshdr); |
1088 | |||
1089 | retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0; | ||
1090 | sdp->changed = 0; | ||
1076 | return retval; | 1091 | return retval; |
1077 | } | 1092 | } |
1078 | 1093 | ||
@@ -1165,7 +1180,7 @@ static const struct block_device_operations sd_fops = { | |||
1165 | #ifdef CONFIG_COMPAT | 1180 | #ifdef CONFIG_COMPAT |
1166 | .compat_ioctl = sd_compat_ioctl, | 1181 | .compat_ioctl = sd_compat_ioctl, |
1167 | #endif | 1182 | #endif |
1168 | .media_changed = sd_media_changed, | 1183 | .check_events = sd_check_events, |
1169 | .revalidate_disk = sd_revalidate_disk, | 1184 | .revalidate_disk = sd_revalidate_disk, |
1170 | .unlock_native_capacity = sd_unlock_native_capacity, | 1185 | .unlock_native_capacity = sd_unlock_native_capacity, |
1171 | }; | 1186 | }; |
@@ -1301,23 +1316,6 @@ static int sd_done(struct scsi_cmnd *SCpnt) | |||
1301 | return good_bytes; | 1316 | return good_bytes; |
1302 | } | 1317 | } |
1303 | 1318 | ||
1304 | static int media_not_present(struct scsi_disk *sdkp, | ||
1305 | struct scsi_sense_hdr *sshdr) | ||
1306 | { | ||
1307 | |||
1308 | if (!scsi_sense_valid(sshdr)) | ||
1309 | return 0; | ||
1310 | /* not invoked for commands that could return deferred errors */ | ||
1311 | if (sshdr->sense_key != NOT_READY && | ||
1312 | sshdr->sense_key != UNIT_ATTENTION) | ||
1313 | return 0; | ||
1314 | if (sshdr->asc != 0x3A) /* medium not present */ | ||
1315 | return 0; | ||
1316 | |||
1317 | set_media_not_present(sdkp); | ||
1318 | return 1; | ||
1319 | } | ||
1320 | |||
1321 | /* | 1319 | /* |
1322 | * spinup disk - called only in sd_revalidate_disk() | 1320 | * spinup disk - called only in sd_revalidate_disk() |
1323 | */ | 1321 | */ |
@@ -1492,7 +1490,7 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, | |||
1492 | */ | 1490 | */ |
1493 | if (sdp->removable && | 1491 | if (sdp->removable && |
1494 | sense_valid && sshdr->sense_key == NOT_READY) | 1492 | sense_valid && sshdr->sense_key == NOT_READY) |
1495 | sdp->changed = 1; | 1493 | set_media_not_present(sdkp); |
1496 | 1494 | ||
1497 | /* | 1495 | /* |
1498 | * We used to set media_present to 0 here to indicate no media | 1496 | * We used to set media_present to 0 here to indicate no media |
@@ -2347,8 +2345,10 @@ static void sd_probe_async(void *data, async_cookie_t cookie) | |||
2347 | 2345 | ||
2348 | gd->driverfs_dev = &sdp->sdev_gendev; | 2346 | gd->driverfs_dev = &sdp->sdev_gendev; |
2349 | gd->flags = GENHD_FL_EXT_DEVT; | 2347 | gd->flags = GENHD_FL_EXT_DEVT; |
2350 | if (sdp->removable) | 2348 | if (sdp->removable) { |
2351 | gd->flags |= GENHD_FL_REMOVABLE; | 2349 | gd->flags |= GENHD_FL_REMOVABLE; |
2350 | gd->events |= DISK_EVENT_MEDIA_CHANGE; | ||
2351 | } | ||
2352 | 2352 | ||
2353 | add_disk(gd); | 2353 | add_disk(gd); |
2354 | sd_dif_config_host(sdkp); | 2354 | sd_dif_config_host(sdkp); |
@@ -2430,7 +2430,6 @@ static int sd_probe(struct device *dev) | |||
2430 | sdkp->disk = gd; | 2430 | sdkp->disk = gd; |
2431 | sdkp->index = index; | 2431 | sdkp->index = index; |
2432 | atomic_set(&sdkp->openers, 0); | 2432 | atomic_set(&sdkp->openers, 0); |
2433 | sdkp->previous_state = 1; | ||
2434 | 2433 | ||
2435 | if (!sdp->request_queue->rq_timeout) { | 2434 | if (!sdp->request_queue->rq_timeout) { |
2436 | if (sdp->type != TYPE_MOD) | 2435 | if (sdp->type != TYPE_MOD) |
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 55488faf0815..c9d8f6ca49e2 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h | |||
@@ -55,7 +55,6 @@ struct scsi_disk { | |||
55 | u8 media_present; | 55 | u8 media_present; |
56 | u8 write_prot; | 56 | u8 write_prot; |
57 | u8 protection_type;/* Data Integrity Field */ | 57 | u8 protection_type;/* Data Integrity Field */ |
58 | unsigned previous_state : 1; | ||
59 | unsigned ATO : 1; /* state of disk ATO bit */ | 58 | unsigned ATO : 1; /* state of disk ATO bit */ |
60 | unsigned WCE : 1; /* state of disk WCE bit */ | 59 | unsigned WCE : 1; /* state of disk WCE bit */ |
61 | unsigned RCD : 1; /* state of disk RCD bit, unused */ | 60 | unsigned RCD : 1; /* state of disk RCD bit, unused */ |
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index d7b383c96d5d..be6baf8ad704 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c | |||
@@ -104,14 +104,15 @@ static void sr_release(struct cdrom_device_info *); | |||
104 | static void get_sectorsize(struct scsi_cd *); | 104 | static void get_sectorsize(struct scsi_cd *); |
105 | static void get_capabilities(struct scsi_cd *); | 105 | static void get_capabilities(struct scsi_cd *); |
106 | 106 | ||
107 | static int sr_media_change(struct cdrom_device_info *, int); | 107 | static unsigned int sr_check_events(struct cdrom_device_info *cdi, |
108 | unsigned int clearing, int slot); | ||
108 | static int sr_packet(struct cdrom_device_info *, struct packet_command *); | 109 | static int sr_packet(struct cdrom_device_info *, struct packet_command *); |
109 | 110 | ||
110 | static struct cdrom_device_ops sr_dops = { | 111 | static struct cdrom_device_ops sr_dops = { |
111 | .open = sr_open, | 112 | .open = sr_open, |
112 | .release = sr_release, | 113 | .release = sr_release, |
113 | .drive_status = sr_drive_status, | 114 | .drive_status = sr_drive_status, |
114 | .media_changed = sr_media_change, | 115 | .check_events = sr_check_events, |
115 | .tray_move = sr_tray_move, | 116 | .tray_move = sr_tray_move, |
116 | .lock_door = sr_lock_door, | 117 | .lock_door = sr_lock_door, |
117 | .select_speed = sr_select_speed, | 118 | .select_speed = sr_select_speed, |
@@ -165,90 +166,96 @@ static void scsi_cd_put(struct scsi_cd *cd) | |||
165 | mutex_unlock(&sr_ref_mutex); | 166 | mutex_unlock(&sr_ref_mutex); |
166 | } | 167 | } |
167 | 168 | ||
168 | /* identical to scsi_test_unit_ready except that it doesn't | 169 | static unsigned int sr_get_events(struct scsi_device *sdev) |
169 | * eat the NOT_READY returns for removable media */ | ||
170 | int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr) | ||
171 | { | 170 | { |
172 | int retries = MAX_RETRIES; | 171 | u8 buf[8]; |
173 | int the_result; | 172 | u8 cmd[] = { GET_EVENT_STATUS_NOTIFICATION, |
174 | u8 cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0 }; | 173 | 1, /* polled */ |
174 | 0, 0, /* reserved */ | ||
175 | 1 << 4, /* notification class: media */ | ||
176 | 0, 0, /* reserved */ | ||
177 | 0, sizeof(buf), /* allocation length */ | ||
178 | 0, /* control */ | ||
179 | }; | ||
180 | struct event_header *eh = (void *)buf; | ||
181 | struct media_event_desc *med = (void *)(buf + 4); | ||
182 | struct scsi_sense_hdr sshdr; | ||
183 | int result; | ||
175 | 184 | ||
176 | /* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION | 185 | result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, sizeof(buf), |
177 | * conditions are gone, or a timeout happens | 186 | &sshdr, SR_TIMEOUT, MAX_RETRIES, NULL); |
178 | */ | 187 | if (scsi_sense_valid(&sshdr) && sshdr.sense_key == UNIT_ATTENTION) |
179 | do { | 188 | return DISK_EVENT_MEDIA_CHANGE; |
180 | the_result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, | 189 | |
181 | 0, sshdr, SR_TIMEOUT, | 190 | if (result || be16_to_cpu(eh->data_len) < sizeof(*med)) |
182 | retries--, NULL); | 191 | return 0; |
183 | if (scsi_sense_valid(sshdr) && | 192 | |
184 | sshdr->sense_key == UNIT_ATTENTION) | 193 | if (eh->nea || eh->notification_class != 0x4) |
185 | sdev->changed = 1; | 194 | return 0; |
186 | 195 | ||
187 | } while (retries > 0 && | 196 | if (med->media_event_code == 1) |
188 | (!scsi_status_is_good(the_result) || | 197 | return DISK_EVENT_EJECT_REQUEST; |
189 | (scsi_sense_valid(sshdr) && | 198 | else if (med->media_event_code == 2) |
190 | sshdr->sense_key == UNIT_ATTENTION))); | 199 | return DISK_EVENT_MEDIA_CHANGE; |
191 | return the_result; | 200 | return 0; |
192 | } | 201 | } |
193 | 202 | ||
194 | /* | 203 | /* |
195 | * This function checks to see if the media has been changed in the | 204 | * This function checks to see if the media has been changed or eject |
196 | * CDROM drive. It is possible that we have already sensed a change, | 205 | * button has been pressed. It is possible that we have already |
197 | * or the drive may have sensed one and not yet reported it. We must | 206 | * sensed a change, or the drive may have sensed one and not yet |
198 | * be ready for either case. This function always reports the current | 207 | * reported it. The past events are accumulated in sdev->changed and |
199 | * value of the changed bit. If flag is 0, then the changed bit is reset. | 208 | * returned together with the current state. |
200 | * This function could be done as an ioctl, but we would need to have | ||
201 | * an inode for that to work, and we do not always have one. | ||
202 | */ | 209 | */ |
203 | 210 | static unsigned int sr_check_events(struct cdrom_device_info *cdi, | |
204 | static int sr_media_change(struct cdrom_device_info *cdi, int slot) | 211 | unsigned int clearing, int slot) |
205 | { | 212 | { |
206 | struct scsi_cd *cd = cdi->handle; | 213 | struct scsi_cd *cd = cdi->handle; |
207 | int retval; | 214 | bool last_present; |
208 | struct scsi_sense_hdr *sshdr; | 215 | struct scsi_sense_hdr sshdr; |
216 | unsigned int events; | ||
217 | int ret; | ||
209 | 218 | ||
210 | if (CDSL_CURRENT != slot) { | 219 | /* no changer support */ |
211 | /* no changer support */ | 220 | if (CDSL_CURRENT != slot) |
212 | return -EINVAL; | 221 | return 0; |
213 | } | ||
214 | 222 | ||
215 | sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); | 223 | events = sr_get_events(cd->device); |
216 | retval = sr_test_unit_ready(cd->device, sshdr); | 224 | /* |
217 | if (retval || (scsi_sense_valid(sshdr) && | 225 | * GET_EVENT_STATUS_NOTIFICATION is enough unless MEDIA_CHANGE |
218 | /* 0x3a is medium not present */ | 226 | * is being cleared. Note that there are devices which hang |
219 | sshdr->asc == 0x3a)) { | 227 | * if asked to execute TUR repeatedly. |
220 | /* Media not present or unable to test, unit probably not | 228 | */ |
221 | * ready. This usually means there is no disc in the drive. | 229 | if (!(clearing & DISK_EVENT_MEDIA_CHANGE)) |
222 | * Mark as changed, and we will figure it out later once | 230 | goto skip_tur; |
223 | * the drive is available again. | 231 | |
224 | */ | 232 | /* let's see whether the media is there with TUR */ |
225 | cd->device->changed = 1; | 233 | last_present = cd->media_present; |
226 | /* This will force a flush, if called from check_disk_change */ | 234 | ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); |
227 | retval = 1; | 235 | |
228 | goto out; | 236 | /* |
229 | }; | 237 | * Media is considered to be present if TUR succeeds or fails with |
238 | * sense data indicating something other than media-not-present | ||
239 | * (ASC 0x3a). | ||
240 | */ | ||
241 | cd->media_present = scsi_status_is_good(ret) || | ||
242 | (scsi_sense_valid(&sshdr) && sshdr.asc != 0x3a); | ||
230 | 243 | ||
231 | retval = cd->device->changed; | 244 | if (last_present != cd->media_present) |
232 | cd->device->changed = 0; | 245 | events |= DISK_EVENT_MEDIA_CHANGE; |
233 | /* If the disk changed, the capacity will now be different, | 246 | skip_tur: |
234 | * so we force a re-read of this information */ | 247 | if (cd->device->changed) { |
235 | if (retval) { | 248 | events |= DISK_EVENT_MEDIA_CHANGE; |
236 | /* check multisession offset etc */ | 249 | cd->device->changed = 0; |
237 | sr_cd_check(cdi); | ||
238 | get_sectorsize(cd); | ||
239 | } | 250 | } |
240 | 251 | ||
241 | out: | 252 | /* for backward compatibility */ |
242 | /* Notify userspace, that media has changed. */ | 253 | if (events & DISK_EVENT_MEDIA_CHANGE) |
243 | if (retval != cd->previous_state) | ||
244 | sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE, | 254 | sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE, |
245 | GFP_KERNEL); | 255 | GFP_KERNEL); |
246 | cd->previous_state = retval; | 256 | return events; |
247 | kfree(sshdr); | ||
248 | |||
249 | return retval; | ||
250 | } | 257 | } |
251 | 258 | ||
252 | /* | 259 | /* |
253 | * sr_done is the interrupt routine for the device driver. | 260 | * sr_done is the interrupt routine for the device driver. |
254 | * | 261 | * |
@@ -533,10 +540,25 @@ out: | |||
533 | return ret; | 540 | return ret; |
534 | } | 541 | } |
535 | 542 | ||
536 | static int sr_block_media_changed(struct gendisk *disk) | 543 | static unsigned int sr_block_check_events(struct gendisk *disk, |
544 | unsigned int clearing) | ||
537 | { | 545 | { |
538 | struct scsi_cd *cd = scsi_cd(disk); | 546 | struct scsi_cd *cd = scsi_cd(disk); |
539 | return cdrom_media_changed(&cd->cdi); | 547 | return cdrom_check_events(&cd->cdi, clearing); |
548 | } | ||
549 | |||
550 | static int sr_block_revalidate_disk(struct gendisk *disk) | ||
551 | { | ||
552 | struct scsi_cd *cd = scsi_cd(disk); | ||
553 | struct scsi_sense_hdr sshdr; | ||
554 | |||
555 | /* if the unit is not ready, nothing more to do */ | ||
556 | if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) | ||
557 | return 0; | ||
558 | |||
559 | sr_cd_check(&cd->cdi); | ||
560 | get_sectorsize(cd); | ||
561 | return 0; | ||
540 | } | 562 | } |
541 | 563 | ||
542 | static const struct block_device_operations sr_bdops = | 564 | static const struct block_device_operations sr_bdops = |
@@ -545,7 +567,8 @@ static const struct block_device_operations sr_bdops = | |||
545 | .open = sr_block_open, | 567 | .open = sr_block_open, |
546 | .release = sr_block_release, | 568 | .release = sr_block_release, |
547 | .ioctl = sr_block_ioctl, | 569 | .ioctl = sr_block_ioctl, |
548 | .media_changed = sr_block_media_changed, | 570 | .check_events = sr_block_check_events, |
571 | .revalidate_disk = sr_block_revalidate_disk, | ||
549 | /* | 572 | /* |
550 | * No compat_ioctl for now because sr_block_ioctl never | 573 | * No compat_ioctl for now because sr_block_ioctl never |
551 | * seems to pass arbitary ioctls down to host drivers. | 574 | * seems to pass arbitary ioctls down to host drivers. |
@@ -618,6 +641,7 @@ static int sr_probe(struct device *dev) | |||
618 | sprintf(disk->disk_name, "sr%d", minor); | 641 | sprintf(disk->disk_name, "sr%d", minor); |
619 | disk->fops = &sr_bdops; | 642 | disk->fops = &sr_bdops; |
620 | disk->flags = GENHD_FL_CD; | 643 | disk->flags = GENHD_FL_CD; |
644 | disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST; | ||
621 | 645 | ||
622 | blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT); | 646 | blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT); |
623 | 647 | ||
@@ -627,7 +651,7 @@ static int sr_probe(struct device *dev) | |||
627 | cd->disk = disk; | 651 | cd->disk = disk; |
628 | cd->capacity = 0x1fffff; | 652 | cd->capacity = 0x1fffff; |
629 | cd->device->changed = 1; /* force recheck CD type */ | 653 | cd->device->changed = 1; /* force recheck CD type */ |
630 | cd->previous_state = 1; | 654 | cd->media_present = 1; |
631 | cd->use = 1; | 655 | cd->use = 1; |
632 | cd->readcd_known = 0; | 656 | cd->readcd_known = 0; |
633 | cd->readcd_cdda = 0; | 657 | cd->readcd_cdda = 0; |
@@ -780,7 +804,7 @@ static void get_capabilities(struct scsi_cd *cd) | |||
780 | } | 804 | } |
781 | 805 | ||
782 | /* eat unit attentions */ | 806 | /* eat unit attentions */ |
783 | sr_test_unit_ready(cd->device, &sshdr); | 807 | scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); |
784 | 808 | ||
785 | /* ask for mode page 0x2a */ | 809 | /* ask for mode page 0x2a */ |
786 | rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, | 810 | rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, |
diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h index 1e144dfdbd4b..e036f1dc83c8 100644 --- a/drivers/scsi/sr.h +++ b/drivers/scsi/sr.h | |||
@@ -40,7 +40,7 @@ typedef struct scsi_cd { | |||
40 | unsigned xa_flag:1; /* CD has XA sectors ? */ | 40 | unsigned xa_flag:1; /* CD has XA sectors ? */ |
41 | unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ | 41 | unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ |
42 | unsigned readcd_cdda:1; /* reading audio data using READ_CD */ | 42 | unsigned readcd_cdda:1; /* reading audio data using READ_CD */ |
43 | unsigned previous_state:1; /* media has changed */ | 43 | unsigned media_present:1; /* media is present */ |
44 | struct cdrom_device_info cdi; | 44 | struct cdrom_device_info cdi; |
45 | /* We hold gendisk and scsi_device references on probe and use | 45 | /* We hold gendisk and scsi_device references on probe and use |
46 | * the refs on this kref to decide when to release them */ | 46 | * the refs on this kref to decide when to release them */ |
@@ -61,7 +61,6 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed); | |||
61 | int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); | 61 | int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); |
62 | 62 | ||
63 | int sr_is_xa(Scsi_CD *); | 63 | int sr_is_xa(Scsi_CD *); |
64 | int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr); | ||
65 | 64 | ||
66 | /* sr_vendor.c */ | 65 | /* sr_vendor.c */ |
67 | void sr_vendor_init(Scsi_CD *); | 66 | void sr_vendor_init(Scsi_CD *); |
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 3cd8ffbad577..8be30554119b 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c | |||
@@ -307,7 +307,7 @@ int sr_drive_status(struct cdrom_device_info *cdi, int slot) | |||
307 | /* we have no changer support */ | 307 | /* we have no changer support */ |
308 | return -EINVAL; | 308 | return -EINVAL; |
309 | } | 309 | } |
310 | if (0 == sr_test_unit_ready(cd->device, &sshdr)) | 310 | if (!scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) |
311 | return CDS_DISC_OK; | 311 | return CDS_DISC_OK; |
312 | 312 | ||
313 | /* SK/ASC/ASCQ of 2/4/1 means "unit is becoming ready" */ | 313 | /* SK/ASC/ASCQ of 2/4/1 means "unit is becoming ready" */ |