[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>

authored by Tejun Heo and committed by James Bottomley 2bae0093 52cfd503

+53 -52
+53 -51
drivers/scsi/sd.c
··· 990 991 static void set_media_not_present(struct scsi_disk *sdkp) 992 { 993 - sdkp->media_present = 0; 994 - sdkp->capacity = 0; 995 - sdkp->device->changed = 1; 996 } 997 998 /** 999 - * sd_media_changed - check if our medium changed 1000 - * @disk: kernel device descriptor 1001 * 1002 - * Returns 0 if not applicable or no change; 1 if change 1003 * 1004 * Note: this function is invoked from the block subsystem. 1005 **/ 1006 - static int sd_media_changed(struct gendisk *disk) 1007 { 1008 struct scsi_disk *sdkp = scsi_disk(disk); 1009 struct scsi_device *sdp = sdkp->device; 1010 struct scsi_sense_hdr *sshdr = NULL; 1011 int retval; 1012 1013 - SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n")); 1014 - 1015 - if (!sdp->removable) 1016 - return 0; 1017 1018 /* 1019 * If the device is offline, don't send any commands - just pretend as ··· 1064 sshdr); 1065 } 1066 1067 - if (retval) { 1068 set_media_not_present(sdkp); 1069 goto out; 1070 } 1071 1072 /* 1073 * For removable scsi disk we have to recognise the presence 1074 - * of a disk in the drive. This is kept in the struct scsi_disk 1075 - * struct and tested at open ! Daniel Roche (dan@lectra.fr) 1076 */ 1077 sdkp->media_present = 1; 1078 - 1079 out: 1080 /* 1081 - * Report a media change under the following conditions: 1082 * 1083 - * Medium is present now and wasn't present before. 1084 - * Medium wasn't present before and is present now. 1085 - * Medium was present at all times, but it changed while 1086 - * we weren't looking (sdp->changed is set). 1087 * 1088 - * If there was no medium before and there is no medium now then 1089 - * don't report a change, even if a medium was inserted and removed 1090 - * while we weren't looking. 1091 */ 1092 - retval = (sdkp->media_present != sdkp->previous_state || 1093 - (sdkp->media_present && sdp->changed)); 1094 - if (retval) 1095 sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); 1096 - sdkp->previous_state = sdkp->media_present; 1097 - 1098 - /* sdp->changed indicates medium was changed or is not present */ 1099 - sdp->changed = !sdkp->media_present; 1100 kfree(sshdr); 1101 return retval; 1102 } 1103 ··· 1187 #ifdef CONFIG_COMPAT 1188 .compat_ioctl = sd_compat_ioctl, 1189 #endif 1190 - .media_changed = sd_media_changed, 1191 .revalidate_disk = sd_revalidate_disk, 1192 .unlock_native_capacity = sd_unlock_native_capacity, 1193 }; ··· 1328 } 1329 1330 return good_bytes; 1331 - } 1332 - 1333 - static int media_not_present(struct scsi_disk *sdkp, 1334 - struct scsi_sense_hdr *sshdr) 1335 - { 1336 - 1337 - if (!scsi_sense_valid(sshdr)) 1338 - return 0; 1339 - /* not invoked for commands that could return deferred errors */ 1340 - if (sshdr->sense_key != NOT_READY && 1341 - sshdr->sense_key != UNIT_ATTENTION) 1342 - return 0; 1343 - if (sshdr->asc != 0x3A) /* medium not present */ 1344 - return 0; 1345 - 1346 - set_media_not_present(sdkp); 1347 - return 1; 1348 } 1349 1350 /* ··· 1504 */ 1505 if (sdp->removable && 1506 sense_valid && sshdr->sense_key == NOT_READY) 1507 - sdp->changed = 1; 1508 1509 /* 1510 * We used to set media_present to 0 here to indicate no media ··· 2390 2391 gd->driverfs_dev = &sdp->sdev_gendev; 2392 gd->flags = GENHD_FL_EXT_DEVT; 2393 - if (sdp->removable) 2394 gd->flags |= GENHD_FL_REMOVABLE; 2395 2396 add_disk(gd); 2397 sd_dif_config_host(sdkp); ··· 2475 sdkp->disk = gd; 2476 sdkp->index = index; 2477 atomic_set(&sdkp->openers, 0); 2478 - sdkp->previous_state = 1; 2479 2480 if (!sdp->request_queue->rq_timeout) { 2481 if (sdp->type != TYPE_MOD)
··· 990 991 static void set_media_not_present(struct scsi_disk *sdkp) 992 { 993 + if (sdkp->media_present) 994 + sdkp->device->changed = 1; 995 + 996 + if (sdkp->device->removable) { 997 + sdkp->media_present = 0; 998 + sdkp->capacity = 0; 999 + } 1000 + } 1001 + 1002 + static 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; 1019 } 1020 1021 /** 1022 + * sd_check_events - check media events 1023 + * @disk: kernel device descriptor 1024 + * @clearing: disk events currently being cleared 1025 * 1026 + * Returns mask of DISK_EVENT_*. 1027 * 1028 * Note: this function is invoked from the block subsystem. 1029 **/ 1030 + static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing) 1031 { 1032 struct scsi_disk *sdkp = scsi_disk(disk); 1033 struct scsi_device *sdp = sdkp->device; 1034 struct scsi_sense_hdr *sshdr = NULL; 1035 int retval; 1036 1037 + SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_check_events\n")); 1038 1039 /* 1040 * If the device is offline, don't send any commands - just pretend as ··· 1043 sshdr); 1044 } 1045 1046 + /* failed to execute TUR, assume media not present */ 1047 + if (host_byte(retval)) { 1048 set_media_not_present(sdkp); 1049 goto out; 1050 } 1051 1052 + if (media_not_present(sdkp, sshdr)) 1053 + goto out; 1054 + 1055 /* 1056 * For removable scsi disk we have to recognise the presence 1057 + * of a disk in the drive. 1058 */ 1059 + if (!sdkp->media_present) 1060 + sdp->changed = 1; 1061 sdkp->media_present = 1; 1062 out: 1063 /* 1064 + * sdp->changed is set under the following conditions: 1065 * 1066 + * Medium present state has changed in either direction. 1067 + * Device has indicated UNIT_ATTENTION. 1068 * 1069 + * Report SDEV_EVT_MEDIA_CHANGE too for backward compatibility. 1070 */ 1071 + if (sdp->changed) 1072 sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); 1073 kfree(sshdr); 1074 + 1075 + retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0; 1076 + sdp->changed = 0; 1077 return retval; 1078 } 1079 ··· 1169 #ifdef CONFIG_COMPAT 1170 .compat_ioctl = sd_compat_ioctl, 1171 #endif 1172 + .check_events = sd_check_events, 1173 .revalidate_disk = sd_revalidate_disk, 1174 .unlock_native_capacity = sd_unlock_native_capacity, 1175 }; ··· 1310 } 1311 1312 return good_bytes; 1313 } 1314 1315 /* ··· 1503 */ 1504 if (sdp->removable && 1505 sense_valid && sshdr->sense_key == NOT_READY) 1506 + set_media_not_present(sdkp); 1507 1508 /* 1509 * We used to set media_present to 0 here to indicate no media ··· 2389 2390 gd->driverfs_dev = &sdp->sdev_gendev; 2391 gd->flags = GENHD_FL_EXT_DEVT; 2392 + if (sdp->removable) { 2393 gd->flags |= GENHD_FL_REMOVABLE; 2394 + gd->events |= DISK_EVENT_MEDIA_CHANGE; 2395 + } 2396 2397 add_disk(gd); 2398 sd_dif_config_host(sdkp); ··· 2472 sdkp->disk = gd; 2473 sdkp->index = index; 2474 atomic_set(&sdkp->openers, 0); 2475 2476 if (!sdp->request_queue->rq_timeout) { 2477 if (sdp->type != TYPE_MOD)
-1
drivers/scsi/sd.h
··· 55 u8 media_present; 56 u8 write_prot; 57 u8 protection_type;/* Data Integrity Field */ 58 - unsigned previous_state : 1; 59 unsigned ATO : 1; /* state of disk ATO bit */ 60 unsigned WCE : 1; /* state of disk WCE bit */ 61 unsigned RCD : 1; /* state of disk RCD bit, unused */
··· 55 u8 media_present; 56 u8 write_prot; 57 u8 protection_type;/* Data Integrity Field */ 58 unsigned ATO : 1; /* state of disk ATO bit */ 59 unsigned WCE : 1; /* state of disk WCE bit */ 60 unsigned RCD : 1; /* state of disk RCD bit, unused */