Commit c8d2e937355d02db3055c2fc203e5f017297ee1f

Authored by Tejun Heo
Committed by Jens Axboe
1 parent 93aae17af1

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>

Showing 2 changed files with 47 additions and 41 deletions Side-by-side Diff

... ... @@ -991,31 +991,51 @@
991 991  
992 992 static void set_media_not_present(struct scsi_disk *sdkp)
993 993 {
  994 + if (sdkp->media_present)
  995 + sdkp->device->changed = 1;
994 996 sdkp->media_present = 0;
995 997 sdkp->capacity = 0;
996   - sdkp->device->changed = 1;
997 998 }
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;
  1019 +}
  1020 +
999 1021 /**
1000   - * sd_media_changed - check if our medium changed
1001   - * @disk: kernel device descriptor
  1022 + * sd_check_events - check media events
  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 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 1032 struct scsi_disk *sdkp = scsi_disk(disk);
1010 1033 struct scsi_device *sdp = sdkp->device;
1011 1034 struct scsi_sense_hdr *sshdr = NULL;
1012 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 1038  
1016   - if (!sdp->removable)
1017   - return 0;
1018   -
1019 1039 /*
1020 1040 * If the device is offline, don't send any commands - just pretend as
1021 1041 * if the command failed. If the device ever comes back online, we
... ... @@ -1024,7 +1044,6 @@
1024 1044 */
1025 1045 if (!scsi_device_online(sdp)) {
1026 1046 set_media_not_present(sdkp);
1027   - retval = 1;
1028 1047 goto out;
1029 1048 }
1030 1049  
1031 1050  
1032 1051  
1033 1052  
1034 1053  
1035 1054  
1036 1055  
1037 1056  
1038 1057  
... ... @@ -1045,26 +1064,30 @@
1045 1064 sshdr);
1046 1065 }
1047 1066  
1048   - if (retval) {
  1067 + /* failed to execute TUR, assume media not present */
  1068 + if (host_byte(retval)) {
1049 1069 set_media_not_present(sdkp);
1050   - retval = 1;
1051 1070 goto out;
1052 1071 }
1053 1072  
  1073 + if (media_not_present(sdkp, sshdr))
  1074 + goto out;
  1075 +
1054 1076 /*
1055 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
1057   - * struct and tested at open ! Daniel Roche (dan@lectra.fr)
  1078 + * of a disk in the drive.
1058 1079 */
  1080 + if (!sdkp->media_present)
  1081 + sdp->changed = 1;
1059 1082 sdkp->media_present = 1;
1060   -
1061   - retval = sdp->changed;
1062   - sdp->changed = 0;
1063 1083 out:
1064   - if (retval != sdkp->previous_state)
  1084 + /* for backward compatibility */
  1085 + if (sdp->changed)
1065 1086 sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL);
1066   - sdkp->previous_state = retval;
1067 1087 kfree(sshdr);
  1088 +
  1089 + retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0;
  1090 + sdp->changed = 0;
1068 1091 return retval;
1069 1092 }
1070 1093  
... ... @@ -1157,7 +1180,7 @@
1157 1180 #ifdef CONFIG_COMPAT
1158 1181 .compat_ioctl = sd_compat_ioctl,
1159 1182 #endif
1160   - .media_changed = sd_media_changed,
  1183 + .check_events = sd_check_events,
1161 1184 .revalidate_disk = sd_revalidate_disk,
1162 1185 .unlock_native_capacity = sd_unlock_native_capacity,
1163 1186 };
... ... @@ -1293,23 +1316,6 @@
1293 1316 return good_bytes;
1294 1317 }
1295 1318  
1296   -static 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 1320 * spinup disk - called only in sd_revalidate_disk()
1315 1321 */
... ... @@ -1484,7 +1490,7 @@
1484 1490 */
1485 1491 if (sdp->removable &&
1486 1492 sense_valid && sshdr->sense_key == NOT_READY)
1487   - sdp->changed = 1;
  1493 + set_media_not_present(sdkp);
1488 1494  
1489 1495 /*
1490 1496 * We used to set media_present to 0 here to indicate no media
1491 1497  
... ... @@ -2339,8 +2345,10 @@
2339 2345  
2340 2346 gd->driverfs_dev = &sdp->sdev_gendev;
2341 2347 gd->flags = GENHD_FL_EXT_DEVT;
2342   - if (sdp->removable)
  2348 + if (sdp->removable) {
2343 2349 gd->flags |= GENHD_FL_REMOVABLE;
  2350 + gd->events |= DISK_EVENT_MEDIA_CHANGE;
  2351 + }
2344 2352  
2345 2353 add_disk(gd);
2346 2354 sd_dif_config_host(sdkp);
... ... @@ -2422,7 +2430,6 @@
2422 2430 sdkp->disk = gd;
2423 2431 sdkp->index = index;
2424 2432 atomic_set(&sdkp->openers, 0);
2425   - sdkp->previous_state = 1;
2426 2433  
2427 2434 if (!sdp->request_queue->rq_timeout) {
2428 2435 if (sdp->type != TYPE_MOD)
... ... @@ -55,7 +55,6 @@
55 55 u8 media_present;
56 56 u8 write_prot;
57 57 u8 protection_type;/* Data Integrity Field */
58   - unsigned previous_state : 1;
59 58 unsigned ATO : 1; /* state of disk ATO bit */
60 59 unsigned WCE : 1; /* state of disk WCE bit */
61 60 unsigned RCD : 1; /* state of disk RCD bit, unused */