aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2010-12-18 12:42:23 -0500
committerJames Bottomley <James.Bottomley@suse.de>2011-01-14 10:17:34 -0500
commit2bae0093cab4ee0a7a8728fdfc35b74569350863 (patch)
treec80ef5a2f293ef01f72561535f476955a465ddba /drivers/scsi
parent52cfd503ad7176d23a5dd7af3981744feb60622f (diff)
[SCSI] sd: implement sd_check_events()
Replace sd_media_change() with sd_check_events(). * Move media removed logic into set_media_not_present() and media_not_present() and set sdev->changed iff an existing media is removed or the device indicates UNIT_ATTENTION. * Make sd_check_events() sets sdev->changed if previously missing media becomes present. * Event is reported only if sdev->changed is set. This makes media presence event reported if scsi_disk->media_present actually changed or the device indicated UNIT_ATTENTION. For backward compatibility, SDEV_EVT_MEDIA_CHANGE is generated each time sd_check_events() detects media change event. [jejb: fix boot failure] Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Jens Axboe <jaxboe@fusionio.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/sd.c104
-rw-r--r--drivers/scsi/sd.h1
2 files changed, 53 insertions, 52 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index b65e65aa07eb..7d257465bd98 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -990,30 +990,51 @@ out:
990 990
991static void set_media_not_present(struct scsi_disk *sdkp) 991static void set_media_not_present(struct scsi_disk *sdkp)
992{ 992{
993 sdkp->media_present = 0; 993 if (sdkp->media_present)
994 sdkp->capacity = 0; 994 sdkp->device->changed = 1;
995 sdkp->device->changed = 1; 995
996 if (sdkp->device->removable) {
997 sdkp->media_present = 0;
998 sdkp->capacity = 0;
999 }
1000}
1001
1002static int media_not_present(struct scsi_disk *sdkp,
1003 struct scsi_sense_hdr *sshdr)
1004{
1005 if (!scsi_sense_valid(sshdr))
1006 return 0;
1007
1008 /* not invoked for commands that could return deferred errors */
1009 switch (sshdr->sense_key) {
1010 case UNIT_ATTENTION:
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;
996} 1019}
997 1020
998/** 1021/**
999 * sd_media_changed - check if our medium changed 1022 * sd_check_events - check media events
1000 * @disk: kernel device descriptor 1023 * @disk: kernel device descriptor
1024 * @clearing: disk events currently being cleared
1001 * 1025 *
1002 * Returns 0 if not applicable or no change; 1 if change 1026 * Returns mask of DISK_EVENT_*.
1003 * 1027 *
1004 * Note: this function is invoked from the block subsystem. 1028 * Note: this function is invoked from the block subsystem.
1005 **/ 1029 **/
1006static int sd_media_changed(struct gendisk *disk) 1030static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing)
1007{ 1031{
1008 struct scsi_disk *sdkp = scsi_disk(disk); 1032 struct scsi_disk *sdkp = scsi_disk(disk);
1009 struct scsi_device *sdp = sdkp->device; 1033 struct scsi_device *sdp = sdkp->device;
1010 struct scsi_sense_hdr *sshdr = NULL; 1034 struct scsi_sense_hdr *sshdr = NULL;
1011 int retval; 1035 int retval;
1012 1036
1013 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"));
1014
1015 if (!sdp->removable)
1016 return 0;
1017 1038
1018 /* 1039 /*
1019 * 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
@@ -1043,40 +1064,37 @@ static int sd_media_changed(struct gendisk *disk)
1043 sshdr); 1064 sshdr);
1044 } 1065 }
1045 1066
1046 if (retval) { 1067 /* failed to execute TUR, assume media not present */
1068 if (host_byte(retval)) {
1047 set_media_not_present(sdkp); 1069 set_media_not_present(sdkp);
1048 goto out; 1070 goto out;
1049 } 1071 }
1050 1072
1073 if (media_not_present(sdkp, sshdr))
1074 goto out;
1075
1051 /* 1076 /*
1052 * For removable scsi disk we have to recognise the presence 1077 * For removable scsi disk we have to recognise the presence
1053 * of a disk in the drive. This is kept in the struct scsi_disk 1078 * of a disk in the drive.
1054 * struct and tested at open ! Daniel Roche (dan@lectra.fr)
1055 */ 1079 */
1080 if (!sdkp->media_present)
1081 sdp->changed = 1;
1056 sdkp->media_present = 1; 1082 sdkp->media_present = 1;
1057
1058out: 1083out:
1059 /* 1084 /*
1060 * Report a media change under the following conditions: 1085 * sdp->changed is set under the following conditions:
1061 * 1086 *
1062 * Medium is present now and wasn't present before. 1087 * Medium present state has changed in either direction.
1063 * Medium wasn't present before and is present now. 1088 * Device has indicated UNIT_ATTENTION.
1064 * Medium was present at all times, but it changed while
1065 * we weren't looking (sdp->changed is set).
1066 * 1089 *
1067 * If there was no medium before and there is no medium now then 1090 * Report SDEV_EVT_MEDIA_CHANGE too for backward compatibility.
1068 * don't report a change, even if a medium was inserted and removed
1069 * while we weren't looking.
1070 */ 1091 */
1071 retval = (sdkp->media_present != sdkp->previous_state || 1092 if (sdp->changed)
1072 (sdkp->media_present && sdp->changed));
1073 if (retval)
1074 sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); 1093 sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL);
1075 sdkp->previous_state = sdkp->media_present;
1076
1077 /* sdp->changed indicates medium was changed or is not present */
1078 sdp->changed = !sdkp->media_present;
1079 kfree(sshdr); 1094 kfree(sshdr);
1095
1096 retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0;
1097 sdp->changed = 0;
1080 return retval; 1098 return retval;
1081} 1099}
1082 1100
@@ -1169,7 +1187,7 @@ static const struct block_device_operations sd_fops = {
1169#ifdef CONFIG_COMPAT 1187#ifdef CONFIG_COMPAT
1170 .compat_ioctl = sd_compat_ioctl, 1188 .compat_ioctl = sd_compat_ioctl,
1171#endif 1189#endif
1172 .media_changed = sd_media_changed, 1190 .check_events = sd_check_events,
1173 .revalidate_disk = sd_revalidate_disk, 1191 .revalidate_disk = sd_revalidate_disk,
1174 .unlock_native_capacity = sd_unlock_native_capacity, 1192 .unlock_native_capacity = sd_unlock_native_capacity,
1175}; 1193};
@@ -1312,23 +1330,6 @@ static int sd_done(struct scsi_cmnd *SCpnt)
1312 return good_bytes; 1330 return good_bytes;
1313} 1331}
1314 1332
1315static int media_not_present(struct scsi_disk *sdkp,
1316 struct scsi_sense_hdr *sshdr)
1317{
1318
1319 if (!scsi_sense_valid(sshdr))
1320 return 0;
1321 /* not invoked for commands that could return deferred errors */
1322 if (sshdr->sense_key != NOT_READY &&
1323 sshdr->sense_key != UNIT_ATTENTION)
1324 return 0;
1325 if (sshdr->asc != 0x3A) /* medium not present */
1326 return 0;
1327
1328 set_media_not_present(sdkp);
1329 return 1;
1330}
1331
1332/* 1333/*
1333 * spinup disk - called only in sd_revalidate_disk() 1334 * spinup disk - called only in sd_revalidate_disk()
1334 */ 1335 */
@@ -1503,7 +1504,7 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
1503 */ 1504 */
1504 if (sdp->removable && 1505 if (sdp->removable &&
1505 sense_valid && sshdr->sense_key == NOT_READY) 1506 sense_valid && sshdr->sense_key == NOT_READY)
1506 sdp->changed = 1; 1507 set_media_not_present(sdkp);
1507 1508
1508 /* 1509 /*
1509 * We used to set media_present to 0 here to indicate no media 1510 * We used to set media_present to 0 here to indicate no media
@@ -2389,8 +2390,10 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
2389 2390
2390 gd->driverfs_dev = &sdp->sdev_gendev; 2391 gd->driverfs_dev = &sdp->sdev_gendev;
2391 gd->flags = GENHD_FL_EXT_DEVT; 2392 gd->flags = GENHD_FL_EXT_DEVT;
2392 if (sdp->removable) 2393 if (sdp->removable) {
2393 gd->flags |= GENHD_FL_REMOVABLE; 2394 gd->flags |= GENHD_FL_REMOVABLE;
2395 gd->events |= DISK_EVENT_MEDIA_CHANGE;
2396 }
2394 2397
2395 add_disk(gd); 2398 add_disk(gd);
2396 sd_dif_config_host(sdkp); 2399 sd_dif_config_host(sdkp);
@@ -2472,7 +2475,6 @@ static int sd_probe(struct device *dev)
2472 sdkp->disk = gd; 2475 sdkp->disk = gd;
2473 sdkp->index = index; 2476 sdkp->index = index;
2474 atomic_set(&sdkp->openers, 0); 2477 atomic_set(&sdkp->openers, 0);
2475 sdkp->previous_state = 1;
2476 2478
2477 if (!sdp->request_queue->rq_timeout) { 2479 if (!sdp->request_queue->rq_timeout) {
2478 if (sdp->type != TYPE_MOD) 2480 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 */