aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2010-12-08 14:57:42 -0500
committerJens Axboe <jaxboe@fusionio.com>2010-12-16 11:53:39 -0500
commitc8d2e937355d02db3055c2fc203e5f017297ee1f (patch)
treea6055c0940d5e8d9f282da45adf43e84a038e470 /drivers
parent93aae17af1172c40c6f74b7294e93a90c3cfaa5d (diff)
sd: implement sd_check_events()
Replace sd_media_change() with sd_check_events(). sd used to set the changed state whenever the device is not ready, which can cause event loop while the device is not ready. Media presence handling code is changed such that the changed state is set iff the media presence actually changes. UA still always sets the changed state and NOT_READY always (at least where it used to set ->changed) clears media presence, so no event is lost. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/sd.c87
-rw-r--r--drivers/scsi/sd.h1
2 files changed, 47 insertions, 41 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 8d488a9fef00..b179b0e39a3b 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -991,30 +991,50 @@ out:
991 991
992static void set_media_not_present(struct scsi_disk *sdkp) 992static 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
1000static 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 **/
1007static int sd_media_changed(struct gendisk *disk) 1030static 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,26 +1064,30 @@ static int sd_media_changed(struct gendisk *disk)
1045 sshdr); 1064 sshdr);
1046 } 1065 }
1047 1066
1048 if (retval) { 1067 /* failed to execute TUR, assume media not present */
1068 if (host_byte(retval)) {
1049 set_media_not_present(sdkp); 1069 set_media_not_present(sdkp);
1050 retval = 1;
1051 goto out; 1070 goto out;
1052 } 1071 }
1053 1072
1073 if (media_not_present(sdkp, sshdr))
1074 goto out;
1075
1054 /* 1076 /*
1055 * For removable scsi disk we have to recognise the presence 1077 * For removable scsi disk we have to recognise the presence
1056 * of a disk in the drive. This is kept in the struct scsi_disk 1078 * of a disk in the drive.
1057 * struct and tested at open ! Daniel Roche (dan@lectra.fr)
1058 */ 1079 */
1080 if (!sdkp->media_present)
1081 sdp->changed = 1;
1059 sdkp->media_present = 1; 1082 sdkp->media_present = 1;
1060
1061 retval = sdp->changed;
1062 sdp->changed = 0;
1063out: 1083out:
1064 if (retval != sdkp->previous_state) 1084 /* for backward compatibility */
1085 if (sdp->changed)
1065 sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); 1086 sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL);
1066 sdkp->previous_state = retval;
1067 kfree(sshdr); 1087 kfree(sshdr);
1088
1089 retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0;
1090 sdp->changed = 0;
1068 return retval; 1091 return retval;
1069} 1092}
1070 1093
@@ -1157,7 +1180,7 @@ static const struct block_device_operations sd_fops = {
1157#ifdef CONFIG_COMPAT 1180#ifdef CONFIG_COMPAT
1158 .compat_ioctl = sd_compat_ioctl, 1181 .compat_ioctl = sd_compat_ioctl,
1159#endif 1182#endif
1160 .media_changed = sd_media_changed, 1183 .check_events = sd_check_events,
1161 .revalidate_disk = sd_revalidate_disk, 1184 .revalidate_disk = sd_revalidate_disk,
1162 .unlock_native_capacity = sd_unlock_native_capacity, 1185 .unlock_native_capacity = sd_unlock_native_capacity,
1163}; 1186};
@@ -1293,23 +1316,6 @@ static int sd_done(struct scsi_cmnd *SCpnt)
1293 return good_bytes; 1316 return good_bytes;
1294} 1317}
1295 1318
1296static int media_not_present(struct scsi_disk *sdkp,
1297 struct scsi_sense_hdr *sshdr)
1298{
1299
1300 if (!scsi_sense_valid(sshdr))
1301 return 0;
1302 /* not invoked for commands that could return deferred errors */
1303 if (sshdr->sense_key != NOT_READY &&
1304 sshdr->sense_key != UNIT_ATTENTION)
1305 return 0;
1306 if (sshdr->asc != 0x3A) /* medium not present */
1307 return 0;
1308
1309 set_media_not_present(sdkp);
1310 return 1;
1311}
1312
1313/* 1319/*
1314 * spinup disk - called only in sd_revalidate_disk() 1320 * spinup disk - called only in sd_revalidate_disk()
1315 */ 1321 */
@@ -1484,7 +1490,7 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
1484 */ 1490 */
1485 if (sdp->removable && 1491 if (sdp->removable &&
1486 sense_valid && sshdr->sense_key == NOT_READY) 1492 sense_valid && sshdr->sense_key == NOT_READY)
1487 sdp->changed = 1; 1493 set_media_not_present(sdkp);
1488 1494
1489 /* 1495 /*
1490 * 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
@@ -2339,8 +2345,10 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
2339 2345
2340 gd->driverfs_dev = &sdp->sdev_gendev; 2346 gd->driverfs_dev = &sdp->sdev_gendev;
2341 gd->flags = GENHD_FL_EXT_DEVT; 2347 gd->flags = GENHD_FL_EXT_DEVT;
2342 if (sdp->removable) 2348 if (sdp->removable) {
2343 gd->flags |= GENHD_FL_REMOVABLE; 2349 gd->flags |= GENHD_FL_REMOVABLE;
2350 gd->events |= DISK_EVENT_MEDIA_CHANGE;
2351 }
2344 2352
2345 add_disk(gd); 2353 add_disk(gd);
2346 sd_dif_config_host(sdkp); 2354 sd_dif_config_host(sdkp);
@@ -2422,7 +2430,6 @@ static int sd_probe(struct device *dev)
2422 sdkp->disk = gd; 2430 sdkp->disk = gd;
2423 sdkp->index = index; 2431 sdkp->index = index;
2424 atomic_set(&sdkp->openers, 0); 2432 atomic_set(&sdkp->openers, 0);
2425 sdkp->previous_state = 1;
2426 2433
2427 if (!sdp->request_queue->rq_timeout) { 2434 if (!sdp->request_queue->rq_timeout) {
2428 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 */