aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJens Axboe <jaxboe@fusionio.com>2011-01-13 08:47:54 -0500
committerJens Axboe <jaxboe@fusionio.com>2011-01-13 08:47:54 -0500
commit81c5e2ae33c4b19e53966b427e33646bf6811830 (patch)
treea602a6dd100165c8948bfa713e6f0b422dcba5d8 /drivers
parent797a455d2c682476c3797dbfecf5bf84c1e3b9d3 (diff)
parentfcc57045d53edc35bcce456e60ac4aa802712934 (diff)
Merge branch 'for-2.6.38/event-handling' into for-2.6.38/core
Diffstat (limited to 'drivers')
-rw-r--r--drivers/cdrom/cdrom.c56
-rw-r--r--drivers/scsi/scsi_lib.c13
-rw-r--r--drivers/scsi/sd.c10
-rw-r--r--drivers/scsi/sr.c174
-rw-r--r--drivers/scsi/sr.h3
-rw-r--r--drivers/scsi/sr_ioctl.c2
6 files changed, 156 insertions, 102 deletions
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index af13c62dc473..14033a36bcd0 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,42 @@ 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 */
1412static 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
1422unsigned 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}
1432EXPORT_SYMBOL(cdrom_check_events);
1433
1395/* We want to make media_changed accessible to the user through an 1434/* 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 1435 * 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 1436 * low-level implementation, to assure that the VFS and the user both
@@ -1403,15 +1442,26 @@ int media_changed(struct cdrom_device_info *cdi, int queue)
1403{ 1442{
1404 unsigned int mask = (1 << (queue & 1)); 1443 unsigned int mask = (1 << (queue & 1));
1405 int ret = !!(cdi->mc_flags & mask); 1444 int ret = !!(cdi->mc_flags & mask);
1445 bool changed;
1406 1446
1407 if (!CDROM_CAN(CDC_MEDIA_CHANGED)) 1447 if (!CDROM_CAN(CDC_MEDIA_CHANGED))
1408 return ret; 1448 return ret;
1449
1409 /* changed since last call? */ 1450 /* changed since last call? */
1410 if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { 1451 if (cdi->ops->check_events) {
1452 BUG_ON(!queue); /* shouldn't be called from VFS path */
1453 cdrom_update_events(cdi, DISK_EVENT_MEDIA_CHANGE);
1454 changed = cdi->ioctl_events & DISK_EVENT_MEDIA_CHANGE;
1455 cdi->ioctl_events = 0;
1456 } else
1457 changed = cdi->ops->media_changed(cdi, CDSL_CURRENT);
1458
1459 if (changed) {
1411 cdi->mc_flags = 0x3; /* set bit on both queues */ 1460 cdi->mc_flags = 0x3; /* set bit on both queues */
1412 ret |= 1; 1461 ret |= 1;
1413 cdi->media_written = 0; 1462 cdi->media_written = 0;
1414 } 1463 }
1464
1415 cdi->mc_flags &= ~mask; /* clear bit */ 1465 cdi->mc_flags &= ~mask; /* clear bit */
1416 return ret; 1466 return ret;
1417} 1467}
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 **/
1990int 1989int
1991scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, 1990scsi_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..8d488a9fef00 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1045,15 +1045,7 @@ static int sd_media_changed(struct gendisk *disk)
1045 sshdr); 1045 sshdr);
1046 } 1046 }
1047 1047
1048 /* 1048 if (retval) {
1049 * Unable to test, unit probably not ready. This usually
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); 1049 set_media_not_present(sdkp);
1058 retval = 1; 1050 retval = 1;
1059 goto out; 1051 goto out;
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 *);
104static void get_sectorsize(struct scsi_cd *); 104static void get_sectorsize(struct scsi_cd *);
105static void get_capabilities(struct scsi_cd *); 105static void get_capabilities(struct scsi_cd *);
106 106
107static int sr_media_change(struct cdrom_device_info *, int); 107static unsigned int sr_check_events(struct cdrom_device_info *cdi,
108 unsigned int clearing, int slot);
108static int sr_packet(struct cdrom_device_info *, struct packet_command *); 109static int sr_packet(struct cdrom_device_info *, struct packet_command *);
109 110
110static struct cdrom_device_ops sr_dops = { 111static 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 169static unsigned int sr_get_events(struct scsi_device *sdev)
169 * eat the NOT_READY returns for removable media */
170int 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 210static unsigned int sr_check_events(struct cdrom_device_info *cdi,
204static 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, 246skip_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
241out: 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
536static int sr_block_media_changed(struct gendisk *disk) 543static 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
550static 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
542static const struct block_device_operations sr_bdops = 564static 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);
61int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); 61int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *);
62 62
63int sr_is_xa(Scsi_CD *); 63int sr_is_xa(Scsi_CD *);
64int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr);
65 64
66/* sr_vendor.c */ 65/* sr_vendor.c */
67void sr_vendor_init(Scsi_CD *); 66void 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" */