ide-cd.c 53 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
2
 * ATAPI CD-ROM driver.
Linus Torvalds's avatar
Linus Torvalds committed
3
 *
4
5
6
7
 * Copyright (C) 1994-1996   Scott Snyder <snyder@fnald0.fnal.gov>
 * Copyright (C) 1996-1998   Erik Andersen <andersee@debian.org>
 * Copyright (C) 1998-2000   Jens Axboe <axboe@suse.de>
 * Copyright (C) 2005, 2007  Bartlomiej Zolnierkiewicz
Linus Torvalds's avatar
Linus Torvalds committed
8
9
10
11
12
13
14
15
 *
 * May be copied or modified under the terms of the GNU General Public
 * License.  See linux/COPYING for more information.
 *
 * See Documentation/cdrom/ide-cd for usage information.
 *
 * Suggestions are welcome. Patches that work are more welcome though. ;-)
 * For those wishing to work on this driver, please be sure you download
16
17
 * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI
 * (SFF-8020i rev 2.6) standards. These documents can be obtained by
Linus Torvalds's avatar
Linus Torvalds committed
18
19
20
21
 * anonymous ftp from:
 * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps
 * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf
 *
22
23
24
25
 * For historical changelog please see:
 *	Documentation/ide/ChangeLog.ide-cd.1994-2004
 */

26
27
28
#define DRV_NAME "ide-cd"
#define PFX DRV_NAME ": "

29
#define IDECD_VERSION "5.00"
Linus Torvalds's avatar
Linus Torvalds committed
30
31
32
33
34
35
36
37
38
39
40
41

#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/cdrom.h>
#include <linux/ide.h>
#include <linux/completion.h>
42
#include <linux/mutex.h>
43
#include <linux/bcd.h>
Linus Torvalds's avatar
Linus Torvalds committed
44

Borislav Petkov's avatar
Borislav Petkov committed
45
46
/* For SCSI -> ATAPI command conversion */
#include <scsi/scsi.h>
Linus Torvalds's avatar
Linus Torvalds committed
47

48
49
#include <linux/irq.h>
#include <linux/io.h>
Linus Torvalds's avatar
Linus Torvalds committed
50
#include <asm/byteorder.h>
51
#include <linux/uaccess.h>
Linus Torvalds's avatar
Linus Torvalds committed
52
53
54
55
#include <asm/unaligned.h>

#include "ide-cd.h"

56
static DEFINE_MUTEX(idecd_ref_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
57

58
static void ide_cd_release(struct device *);
59

Linus Torvalds's avatar
Linus Torvalds committed
60
61
62
63
static struct cdrom_info *ide_cd_get(struct gendisk *disk)
{
	struct cdrom_info *cd = NULL;

64
	mutex_lock(&idecd_ref_mutex);
Borislav Petkov's avatar
Borislav Petkov committed
65
	cd = ide_drv_g(disk, cdrom_info);
66
	if (cd) {
67
		if (ide_device_get(cd->drive))
68
			cd = NULL;
69
		else
70
			get_device(&cd->dev);
71

72
	}
73
	mutex_unlock(&idecd_ref_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
74
75
76
77
78
	return cd;
}

static void ide_cd_put(struct cdrom_info *cd)
{
79
80
	ide_drive_t *drive = cd->drive;

81
	mutex_lock(&idecd_ref_mutex);
82
	put_device(&cd->dev);
83
	ide_device_put(drive);
84
	mutex_unlock(&idecd_ref_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
85
86
}

Borislav Petkov's avatar
Borislav Petkov committed
87
/*
Linus Torvalds's avatar
Linus Torvalds committed
88
89
90
 * Generic packet command support and error handling routines.
 */

Borislav Petkov's avatar
Borislav Petkov committed
91
/* Mark that we've seen a media change and invalidate our internal buffers. */
92
static void cdrom_saw_media_change(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
93
{
94
	drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
95
	drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID;
Linus Torvalds's avatar
Linus Torvalds committed
96
97
98
99
100
101
102
}

static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
			   struct request_sense *sense)
{
	int log = 0;

103
	ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key);
104

105
	if (!sense || !rq || (rq->cmd_flags & REQ_QUIET))
Linus Torvalds's avatar
Linus Torvalds committed
106
107
108
		return 0;

	switch (sense->sense_key) {
109
110
111
112
113
	case NO_SENSE:
	case RECOVERED_ERROR:
		break;
	case NOT_READY:
		/*
Borislav Petkov's avatar
Borislav Petkov committed
114
115
		 * don't care about tray state messages for e.g. capacity
		 * commands or in-progress or becoming ready
116
117
		 */
		if (sense->asc == 0x3a || sense->asc == 0x04)
Linus Torvalds's avatar
Linus Torvalds committed
118
			break;
119
120
121
122
		log = 1;
		break;
	case ILLEGAL_REQUEST:
		/*
Borislav Petkov's avatar
Borislav Petkov committed
123
124
		 * don't log START_STOP unit with LoEj set, since we cannot
		 * reliably check if drive can auto-close
125
126
		 */
		if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
Linus Torvalds's avatar
Linus Torvalds committed
127
			break;
128
129
130
131
		log = 1;
		break;
	case UNIT_ATTENTION:
		/*
Borislav Petkov's avatar
Borislav Petkov committed
132
133
134
		 * Make good and sure we've seen this potential media change.
		 * Some drives (i.e. Creative) fail to present the correct sense
		 * key in the error register.
135
136
137
138
139
140
		 */
		cdrom_saw_media_change(drive);
		break;
	default:
		log = 1;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
141
142
143
144
	}
	return log;
}

145
static void cdrom_analyze_sense_data(ide_drive_t *drive,
Linus Torvalds's avatar
Linus Torvalds committed
146
147
148
			      struct request *failed_command,
			      struct request_sense *sense)
{
149
150
151
152
	unsigned long sector;
	unsigned long bio_sectors;
	struct cdrom_info *info = drive->driver_data;

153
154
	ide_debug_log(IDE_DBG_SENSE, "error_code: 0x%x, sense_key: 0x%x",
				     sense->error_code, sense->sense_key);
155
156

	if (failed_command)
157
158
		ide_debug_log(IDE_DBG_SENSE, "failed cmd: 0x%x",
					     failed_command->cmd[0]);
159

Linus Torvalds's avatar
Linus Torvalds committed
160
161
162
163
	if (!cdrom_log_sense(drive, failed_command, sense))
		return;

	/*
Borislav Petkov's avatar
Borislav Petkov committed
164
165
166
	 * If a read toc is executed for a CD-R or CD-RW medium where the first
	 * toc has not been recorded yet, it will fail with 05/24/00 (which is a
	 * confusing error)
Linus Torvalds's avatar
Linus Torvalds committed
167
168
169
170
171
	 */
	if (failed_command && failed_command->cmd[0] == GPCMD_READ_TOC_PMA_ATIP)
		if (sense->sense_key == 0x05 && sense->asc == 0x24)
			return;

Borislav Petkov's avatar
Borislav Petkov committed
172
173
	/* current error */
	if (sense->error_code == 0x70) {
174
		switch (sense->sense_key) {
175
176
177
178
179
180
181
182
183
184
185
186
187
188
		case MEDIUM_ERROR:
		case VOLUME_OVERFLOW:
		case ILLEGAL_REQUEST:
			if (!sense->valid)
				break;
			if (failed_command == NULL ||
					!blk_fs_request(failed_command))
				break;
			sector = (sense->information[0] << 24) |
				 (sense->information[1] << 16) |
				 (sense->information[2] <<  8) |
				 (sense->information[3]);

			if (drive->queue->hardsect_size == 2048)
Borislav Petkov's avatar
Borislav Petkov committed
189
190
				/* device sector size is 2K */
				sector <<= 2;
191
192

			bio_sectors = max(bio_sectors(failed_command->bio), 4U);
193
			sector &= ~(bio_sectors - 1);
194

195
196
197
198
199
200
201
202
			/*
			 * The SCSI specification allows for the value
			 * returned by READ CAPACITY to be up to 75 2K
			 * sectors past the last readable block.
			 * Therefore, if we hit a medium error within the
			 * last 75 2K sectors, we decrease the saved size
			 * value.
			 */
203
			if (sector < get_capacity(info->disk) &&
204
			    drive->probed_capacity - sector < 4 * 75)
205
				set_capacity(info->disk, sector);
206
207
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
208

209
	ide_cd_log_error(drive->name, failed_command, sense);
Linus Torvalds's avatar
Linus Torvalds committed
210
211
212
213
214
215
}

static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
				      struct request *failed_command)
{
	struct cdrom_info *info		= drive->driver_data;
216
	struct request *rq		= &drive->request_sense_rq;
Linus Torvalds's avatar
Linus Torvalds committed
217

218
	ide_debug_log(IDE_DBG_SENSE, "enter");
219

Linus Torvalds's avatar
Linus Torvalds committed
220
221
222
223
	if (sense == NULL)
		sense = &info->sense_data;

	/* stuff the sense request in front of our current request */
224
225
226
	blk_rq_init(NULL, rq);
	rq->cmd_type = REQ_TYPE_ATA_PC;
	rq->rq_disk = info->disk;
Linus Torvalds's avatar
Linus Torvalds committed
227
228
229

	rq->data = sense;
	rq->cmd[0] = GPCMD_REQUEST_SENSE;
230
231
	rq->cmd[4] = 18;
	rq->data_len = 18;
Linus Torvalds's avatar
Linus Torvalds committed
232

233
	rq->cmd_type = REQ_TYPE_SENSE;
234
	rq->cmd_flags |= REQ_PREEMPT;
Linus Torvalds's avatar
Linus Torvalds committed
235
236
237
238

	/* NOTE! Save the failed command in "rq->buffer" */
	rq->buffer = (void *) failed_command;

239
	if (failed_command)
240
241
		ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x",
					     failed_command->cmd[0]);
242

243
244
245
	drive->hwif->rq = NULL;

	elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0);
Linus Torvalds's avatar
Linus Torvalds committed
246
247
}

248
static void cdrom_end_request(ide_drive_t *drive, int uptodate)
Linus Torvalds's avatar
Linus Torvalds committed
249
{
250
	struct request *rq = drive->hwif->rq;
Linus Torvalds's avatar
Linus Torvalds committed
251
252
	int nsectors = rq->hard_cur_sectors;

253
254
	ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, uptodate: 0x%x, nsectors: %d",
				    rq->cmd[0], uptodate, nsectors);
255

256
	if (blk_sense_request(rq) && uptodate) {
Linus Torvalds's avatar
Linus Torvalds committed
257
		/*
258
259
		 * For REQ_TYPE_SENSE, "rq->buffer" points to the original
		 * failed request
Linus Torvalds's avatar
Linus Torvalds committed
260
261
262
263
264
265
266
267
268
269
		 */
		struct request *failed = (struct request *) rq->buffer;
		struct cdrom_info *info = drive->driver_data;
		void *sense = &info->sense_data;

		if (failed) {
			if (failed->sense) {
				sense = failed->sense;
				failed->sense_len = rq->sense_len;
			}
270
			cdrom_analyze_sense_data(drive, failed, sense);
Linus Torvalds's avatar
Linus Torvalds committed
271
			/*
Borislav Petkov's avatar
Borislav Petkov committed
272
			 * now end the failed request
Linus Torvalds's avatar
Linus Torvalds committed
273
			 */
274
275
276
277
278
			if (blk_fs_request(failed)) {
				if (ide_end_dequeued_request(drive, failed, 0,
						failed->hard_nr_sectors))
					BUG();
			} else {
279
280
				if (blk_end_request(failed, -EIO,
						    failed->data_len))
281
					BUG();
282
283
284
			}
		} else
			cdrom_analyze_sense_data(drive, NULL, sense);
Linus Torvalds's avatar
Linus Torvalds committed
285
286
287
288
289
290
291
292
293
294
	}

	if (!rq->current_nr_sectors && blk_fs_request(rq))
		uptodate = 1;
	/* make sure it's fully ended */
	if (blk_pc_request(rq))
		nsectors = (rq->data_len + 511) >> 9;
	if (!nsectors)
		nsectors = 1;

295
296
	ide_debug_log(IDE_DBG_FUNC, "uptodate: 0x%x, nsectors: %d",
				    uptodate, nsectors);
297

Linus Torvalds's avatar
Linus Torvalds committed
298
299
300
	ide_end_request(drive, uptodate, nsectors);
}

301
static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 st)
302
{
303
	if (st & 0x80)
304
		return;
305
	ide_dump_status(drive, msg, st);
306
307
}

Borislav Petkov's avatar
Borislav Petkov committed
308
309
310
311
312
/*
 * Returns:
 * 0: if the request should be continued.
 * 1: if the request was ended.
 */
Linus Torvalds's avatar
Linus Torvalds committed
313
314
static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
{
315
	ide_hwif_t *hwif = drive->hwif;
316
	struct request *rq = hwif->rq;
Linus Torvalds's avatar
Linus Torvalds committed
317
	int stat, err, sense_key;
318

Borislav Petkov's avatar
Borislav Petkov committed
319
	/* check for errors */
320
	stat = hwif->tp_ops->read_status(hwif);
321

Linus Torvalds's avatar
Linus Torvalds committed
322
323
324
325
326
327
	if (stat_ret)
		*stat_ret = stat;

	if (OK_STAT(stat, good_stat, BAD_R_STAT))
		return 0;

Borislav Petkov's avatar
Borislav Petkov committed
328
	/* get the IDE error register */
329
	err = ide_read_error(drive);
Linus Torvalds's avatar
Linus Torvalds committed
330
331
332
	sense_key = err >> 4;

	if (rq == NULL) {
333
		printk(KERN_ERR PFX "%s: missing rq in %s\n",
334
				drive->name, __func__);
Linus Torvalds's avatar
Linus Torvalds committed
335
336
337
		return 1;
	}

338
339
340
341
	ide_debug_log(IDE_DBG_RQ, "stat: 0x%x, good_stat: 0x%x, cmd[0]: 0x%x, "
				  "rq->cmd_type: 0x%x, err: 0x%x",
				  stat, good_stat, rq->cmd[0], rq->cmd_type,
				  err);
342

343
	if (blk_sense_request(rq)) {
Borislav Petkov's avatar
Borislav Petkov committed
344
345
346
347
348
		/*
		 * We got an error trying to get sense info from the drive
		 * (probably while trying to recover from a former error).
		 * Just give up.
		 */
349
		rq->cmd_flags |= REQ_FAILED;
Linus Torvalds's avatar
Linus Torvalds committed
350
351
352
353
		cdrom_end_request(drive, 0);
		ide_error(drive, "request sense failure", stat);
		return 1;

354
	} else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
Linus Torvalds's avatar
Linus Torvalds committed
355
356
357
358
359
360
		/* All other functions, except for READ. */

		/*
		 * if we have an error, pass back CHECK_CONDITION as the
		 * scsi status byte
		 */
361
		if (blk_pc_request(rq) && !rq->errors)
Linus Torvalds's avatar
Linus Torvalds committed
362
363
			rq->errors = SAM_STAT_CHECK_CONDITION;

Borislav Petkov's avatar
Borislav Petkov committed
364
		/* check for tray open */
Linus Torvalds's avatar
Linus Torvalds committed
365
		if (sense_key == NOT_READY) {
366
			cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
367
		} else if (sense_key == UNIT_ATTENTION) {
Borislav Petkov's avatar
Borislav Petkov committed
368
			/* check for media change */
369
			cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
370
			return 0;
371
372
373
374
375
376
377
378
379
		} else if (sense_key == ILLEGAL_REQUEST &&
			   rq->cmd[0] == GPCMD_START_STOP_UNIT) {
			/*
			 * Don't print error message for this condition--
			 * SFF8090i indicates that 5/24/00 is the correct
			 * response to a request to close the tray if the
			 * drive doesn't have that capability.
			 * cdrom_log_sense() knows this!
			 */
380
		} else if (!(rq->cmd_flags & REQ_QUIET)) {
Borislav Petkov's avatar
Borislav Petkov committed
381
			/* otherwise, print an error */
Linus Torvalds's avatar
Linus Torvalds committed
382
383
			ide_dump_status(drive, "packet command error", stat);
		}
384

385
		rq->cmd_flags |= REQ_FAILED;
Linus Torvalds's avatar
Linus Torvalds committed
386
387
388
389
390
391

		/*
		 * instead of playing games with moving completions around,
		 * remove failed request completely and end it when the
		 * request sense has completed
		 */
392
		goto end_request;
Linus Torvalds's avatar
Linus Torvalds committed
393
394
395
396

	} else if (blk_fs_request(rq)) {
		int do_end_request = 0;

Borislav Petkov's avatar
Borislav Petkov committed
397
		/* handle errors from READ and WRITE requests */
Linus Torvalds's avatar
Linus Torvalds committed
398
399
400
401
402

		if (blk_noretry_request(rq))
			do_end_request = 1;

		if (sense_key == NOT_READY) {
Borislav Petkov's avatar
Borislav Petkov committed
403
			/* tray open */
Linus Torvalds's avatar
Linus Torvalds committed
404
			if (rq_data_dir(rq) == READ) {
405
				cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
406

Borislav Petkov's avatar
Borislav Petkov committed
407
				/* fail the request */
408
409
				printk(KERN_ERR PFX "%s: tray open\n",
						drive->name);
Linus Torvalds's avatar
Linus Torvalds committed
410
411
412
413
				do_end_request = 1;
			} else {
				struct cdrom_info *info = drive->driver_data;

Borislav Petkov's avatar
Borislav Petkov committed
414
415
				/*
				 * Allow the drive 5 seconds to recover, some
Linus Torvalds's avatar
Linus Torvalds committed
416
				 * devices will return this error while flushing
Borislav Petkov's avatar
Borislav Petkov committed
417
418
				 * data from cache.
				 */
Linus Torvalds's avatar
Linus Torvalds committed
419
				if (!rq->errors)
420
421
					info->write_timeout = jiffies +
							ATAPI_WAIT_WRITE_BUSY;
Linus Torvalds's avatar
Linus Torvalds committed
422
423
424
425
				rq->errors = 1;
				if (time_after(jiffies, info->write_timeout))
					do_end_request = 1;
				else {
426
					struct request_queue *q = drive->queue;
Linus Torvalds's avatar
Linus Torvalds committed
427
428
429
					unsigned long flags;

					/*
Borislav Petkov's avatar
Borislav Petkov committed
430
431
					 * take a breather relying on the unplug
					 * timer to kick us again
Linus Torvalds's avatar
Linus Torvalds committed
432
					 */
433
434
435
436
					spin_lock_irqsave(q->queue_lock, flags);
					blk_plug_device(q);
					spin_unlock_irqrestore(q->queue_lock, flags);

Linus Torvalds's avatar
Linus Torvalds committed
437
438
439
440
					return 1;
				}
			}
		} else if (sense_key == UNIT_ATTENTION) {
Borislav Petkov's avatar
Borislav Petkov committed
441
			/* media change */
442
			cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
443

444
			/*
Borislav Petkov's avatar
Borislav Petkov committed
445
446
			 * Arrange to retry the request but be sure to give up
			 * if we've retried too many times.
447
			 */
Linus Torvalds's avatar
Linus Torvalds committed
448
449
450
451
			if (++rq->errors > ERROR_MAX)
				do_end_request = 1;
		} else if (sense_key == ILLEGAL_REQUEST ||
			   sense_key == DATA_PROTECT) {
452
			/*
Borislav Petkov's avatar
Borislav Petkov committed
453
454
			 * No point in retrying after an illegal request or data
			 * protect error.
455
456
			 */
			ide_dump_status_no_sense(drive, "command error", stat);
Linus Torvalds's avatar
Linus Torvalds committed
457
458
			do_end_request = 1;
		} else if (sense_key == MEDIUM_ERROR) {
459
460
			/*
			 * No point in re-trying a zillion times on a bad
Borislav Petkov's avatar
Borislav Petkov committed
461
			 * sector. If we got here the error is not correctable.
462
			 */
463
464
465
			ide_dump_status_no_sense(drive,
						 "media error (bad sector)",
						 stat);
Linus Torvalds's avatar
Linus Torvalds committed
466
467
			do_end_request = 1;
		} else if (sense_key == BLANK_CHECK) {
Borislav Petkov's avatar
Borislav Petkov committed
468
			/* disk appears blank ?? */
469
470
			ide_dump_status_no_sense(drive, "media error (blank)",
						 stat);
Linus Torvalds's avatar
Linus Torvalds committed
471
			do_end_request = 1;
472
		} else if ((err & ~ATA_ABORTED) != 0) {
Borislav Petkov's avatar
Borislav Petkov committed
473
			/* go to the default handler for other errors */
Linus Torvalds's avatar
Linus Torvalds committed
474
475
476
			ide_error(drive, "cdrom_decode_status", stat);
			return 1;
		} else if ((++rq->errors > ERROR_MAX)) {
Borislav Petkov's avatar
Borislav Petkov committed
477
			/* we've racked up too many retries, abort */
Linus Torvalds's avatar
Linus Torvalds committed
478
479
480
			do_end_request = 1;
		}

Borislav Petkov's avatar
Borislav Petkov committed
481
482
483
484
485
		/*
		 * End a request through request sense analysis when we have
		 * sense data. We need this in order to perform end of media
		 * processing.
		 */
486
487
		if (do_end_request)
			goto end_request;
488

489
		/*
Borislav Petkov's avatar
Borislav Petkov committed
490
491
		 * If we got a CHECK_CONDITION status, queue
		 * a request sense command.
492
		 */
493
		if (stat & ATA_ERR)
494
			cdrom_queue_request_sense(drive, NULL, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
495
	} else {
496
		blk_dump_rq_flags(rq, PFX "bad rq");
Linus Torvalds's avatar
Linus Torvalds committed
497
498
499
		cdrom_end_request(drive, 0);
	}

Borislav Petkov's avatar
Borislav Petkov committed
500
	/* retry, or handle the next request */
Linus Torvalds's avatar
Linus Torvalds committed
501
	return 1;
502
503

end_request:
504
	if (stat & ATA_ERR) {
505
		struct request_queue *q = drive->queue;
506
507
		unsigned long flags;

508
		spin_lock_irqsave(q->queue_lock, flags);
509
		blkdev_dequeue_request(rq);
510
		spin_unlock_irqrestore(q->queue_lock, flags);
511

512
		hwif->rq = NULL;
513

514
515
516
517
518
		cdrom_queue_request_sense(drive, rq->sense, rq);
	} else
		cdrom_end_request(drive, 0);

	return 1;
Linus Torvalds's avatar
Linus Torvalds committed
519
520
521
522
523
524
525
}

/*
 * Check the contents of the interrupt reason register from the cdrom
 * and attempt to recover if there are problems.  Returns  0 if everything's
 * ok; nonzero if the request has been terminated.
 */
526
527
static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
				int len, int ireason, int rw)
Linus Torvalds's avatar
Linus Torvalds committed
528
{
529
530
	ide_hwif_t *hwif = drive->hwif;

531
	ide_debug_log(IDE_DBG_FUNC, "ireason: 0x%x, rw: 0x%x", ireason, rw);
532

533
534
535
536
537
	/*
	 * ireason == 0: the drive wants to receive data from us
	 * ireason == 2: the drive is expecting to transfer data to us
	 */
	if (ireason == (!rw << 1))
Linus Torvalds's avatar
Linus Torvalds committed
538
		return 0;
539
	else if (ireason == (rw << 1)) {
540

Borislav Petkov's avatar
Borislav Petkov committed
541
		/* whoops... */
542
		printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n",
543
				drive->name, __func__);
Linus Torvalds's avatar
Linus Torvalds committed
544

545
		ide_pad_transfer(drive, rw, len);
546
	} else  if (rw == 0 && ireason == 1) {
Borislav Petkov's avatar
Borislav Petkov committed
547
548
549
		/*
		 * Some drives (ASUS) seem to tell us that status info is
		 * available.  Just get it and ignore.
Linus Torvalds's avatar
Linus Torvalds committed
550
		 */
551
		(void)hwif->tp_ops->read_status(hwif);
Linus Torvalds's avatar
Linus Torvalds committed
552
553
		return 0;
	} else {
Borislav Petkov's avatar
Borislav Petkov committed
554
		/* drive wants a command packet, or invalid ireason... */
555
		printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n",
556
				drive->name, __func__, ireason);
Linus Torvalds's avatar
Linus Torvalds committed
557
558
	}

559
560
561
	if (rq->cmd_type == REQ_TYPE_ATA_PC)
		rq->cmd_flags |= REQ_FAILED;

Linus Torvalds's avatar
Linus Torvalds committed
562
563
564
565
	cdrom_end_request(drive, 0);
	return -1;
}

566
567
568
569
570
571
/*
 * Assume that the drive will always provide data in multiples of at least
 * SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise.
 */
static int ide_cd_check_transfer_size(ide_drive_t *drive, int len)
{
572
	ide_debug_log(IDE_DBG_FUNC, "len: %d", len);
573

574
575
576
	if ((len % SECTOR_SIZE) == 0)
		return 0;

577
578
	printk(KERN_ERR PFX "%s: %s: Bad transfer size %d\n", drive->name,
			__func__, len);
579

580
	if (drive->atapi_flags & IDE_AFLAG_LIMIT_NFRAMES)
581
582
		printk(KERN_ERR PFX "This drive is not supported by this "
				"version of the driver\n");
583
	else {
584
		printk(KERN_ERR PFX "Trying to limit transfer sizes\n");
585
		drive->atapi_flags |= IDE_AFLAG_LIMIT_NFRAMES;
586
587
588
589
590
	}

	return 1;
}

591
592
static ide_startstop_t ide_cd_prepare_rw_request(ide_drive_t *drive,
						 struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
593
{
594
	ide_debug_log(IDE_DBG_RQ, "rq->cmd_flags: 0x%x", rq->cmd_flags);
595

596
597
598
599
	if (rq_data_dir(rq) == READ) {
		unsigned short sectors_per_frame =
			queue_hardsect_size(drive->queue) >> SECTOR_BITS;
		int nskip = rq->sector & (sectors_per_frame - 1);
Linus Torvalds's avatar
Linus Torvalds committed
600

601
602
603
604
605
606
607
608
609
610
611
		/*
		 * If the requested sector doesn't start on a frame boundary,
		 * we must adjust the start of the transfer so that it does,
		 * and remember to skip the first few sectors.
		 *
		 * If the rq->current_nr_sectors field is larger than the size
		 * of the buffer, it will mean that we're to skip a number of
		 * sectors equal to the amount by which rq->current_nr_sectors
		 * is larger than the buffer size.
		 */
		if (nskip > 0) {
Borislav Petkov's avatar
Borislav Petkov committed
612
			/* sanity check... */
613
614
			if (rq->current_nr_sectors !=
			    bio_cur_sectors(rq->bio)) {
615
				printk(KERN_ERR PFX "%s: %s: buffer botch (%u)\n",
616
						drive->name, __func__,
617
618
619
620
621
						rq->current_nr_sectors);
				cdrom_end_request(drive, 0);
				return ide_stopped;
			}
			rq->current_nr_sectors += nskip;
Linus Torvalds's avatar
Linus Torvalds committed
622
623
		}
	}
624

Borislav Petkov's avatar
Borislav Petkov committed
625
	/* set up the command */
Linus Torvalds's avatar
Linus Torvalds committed
626
627
	rq->timeout = ATAPI_WAIT_PC;

628
629
630
	return ide_started;
}

631
/*
Borislav Petkov's avatar
Borislav Petkov committed
632
633
 * Fix up a possibly partially-processed request so that we can start it over
 * entirely, or even put it back on the request queue.
634
 */
635
static void ide_cd_restore_request(ide_drive_t *drive, struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
636
{
637

638
	ide_debug_log(IDE_DBG_FUNC, "enter");
639

Linus Torvalds's avatar
Linus Torvalds committed
640
	if (rq->buffer != bio_data(rq->bio)) {
641
642
		sector_t n =
			(rq->buffer - (char *)bio_data(rq->bio)) / SECTOR_SIZE;
Linus Torvalds's avatar
Linus Torvalds committed
643
644
645
646
647

		rq->buffer = bio_data(rq->bio);
		rq->nr_sectors += n;
		rq->sector -= n;
	}
648
649
	rq->current_nr_sectors = bio_cur_sectors(rq->bio);
	rq->hard_cur_sectors = rq->current_nr_sectors;
Linus Torvalds's avatar
Linus Torvalds committed
650
651
652
653
654
	rq->hard_nr_sectors = rq->nr_sectors;
	rq->hard_sector = rq->sector;
	rq->q->prep_rq_fn(rq->q, rq);
}

655
static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq)
656
{
657
	ide_debug_log(IDE_DBG_FUNC, "rq->cmd[0]: 0x%x", rq->cmd[0]);
658

659
660
661
662
663
664
665
666
667
668
669
670
	/*
	 * Some of the trailing request sense fields are optional,
	 * and some drives don't send them.  Sigh.
	 */
	if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
	    rq->data_len > 0 && rq->data_len <= 5)
		while (rq->data_len > 0) {
			*(u8 *)rq->data++ = 0;
			--rq->data_len;
		}
}

671
672
673
674
int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
		    int write, void *buffer, unsigned *bufflen,
		    struct request_sense *sense, int timeout,
		    unsigned int cmd_flags)
Linus Torvalds's avatar
Linus Torvalds committed
675
{
676
677
	struct cdrom_info *info = drive->driver_data;
	struct request_sense local_sense;
Linus Torvalds's avatar
Linus Torvalds committed
678
	int retries = 10;
679
	unsigned int flags = 0;
Linus Torvalds's avatar
Linus Torvalds committed
680

681
682
	if (!sense)
		sense = &local_sense;
Linus Torvalds's avatar
Linus Torvalds committed
683

684
685
686
	ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x, timeout: %d, "
				  "cmd_flags: 0x%x",
				  cmd[0], write, timeout, cmd_flags);
687

Borislav Petkov's avatar
Borislav Petkov committed
688
	/* start of retry loop */
Linus Torvalds's avatar
Linus Torvalds committed
689
	do {
690
		struct request *rq;
Linus Torvalds's avatar
Linus Torvalds committed
691
692
		int error;

693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
		rq = blk_get_request(drive->queue, write, __GFP_WAIT);

		memcpy(rq->cmd, cmd, BLK_MAX_CDB);
		rq->cmd_type = REQ_TYPE_ATA_PC;
		rq->sense = sense;
		rq->cmd_flags |= cmd_flags;
		rq->timeout = timeout;
		if (buffer) {
			rq->data = buffer;
			rq->data_len = *bufflen;
		}

		error = blk_execute_rq(drive->queue, info->disk, rq, 0);

		if (buffer)
			*bufflen = rq->data_len;

		flags = rq->cmd_flags;
		blk_put_request(rq);
Linus Torvalds's avatar
Linus Torvalds committed
712

Borislav Petkov's avatar
Borislav Petkov committed
713
714
715
716
		/*
		 * FIXME: we should probably abort/retry or something in case of
		 * failure.
		 */
717
		if (flags & REQ_FAILED) {
Borislav Petkov's avatar
Borislav Petkov committed
718
719
720
721
			/*
			 * The request failed.  Retry if it was due to a unit
			 * attention status (usually means media was changed).
			 */
722
			struct request_sense *reqbuf = sense;
Linus Torvalds's avatar
Linus Torvalds committed
723
724
725
726
727

			if (reqbuf->sense_key == UNIT_ATTENTION)
				cdrom_saw_media_change(drive);
			else if (reqbuf->sense_key == NOT_READY &&
				 reqbuf->asc == 4 && reqbuf->ascq != 4) {
Borislav Petkov's avatar
Borislav Petkov committed
728
729
730
731
732
				/*
				 * The drive is in the process of loading
				 * a disk.  Retry, but wait a little to give
				 * the drive time to complete the load.
				 */
Linus Torvalds's avatar
Linus Torvalds committed
733
734
				ssleep(2);
			} else {
Borislav Petkov's avatar
Borislav Petkov committed
735
				/* otherwise, don't retry */
Linus Torvalds's avatar
Linus Torvalds committed
736
737
738
739
740
				retries = 0;
			}
			--retries;
		}

Borislav Petkov's avatar
Borislav Petkov committed
741
		/* end of retry loop */
742
	} while ((flags & REQ_FAILED) && retries >= 0);
Linus Torvalds's avatar
Linus Torvalds committed
743

Borislav Petkov's avatar
Borislav Petkov committed
744
	/* return an error if the command failed */
745
	return (flags & REQ_FAILED) ? -EIO : 0;
Linus Torvalds's avatar
Linus Torvalds committed
746
747
}

748
/*
Borislav Petkov's avatar
Borislav Petkov committed
749
750
751
 * Called from blk_end_request_callback() after the data of the request is
 * completed and before the request itself is completed. By returning value '1',
 * blk_end_request_callback() returns immediately without completing it.
752
753
754
755
756
757
 */
static int cdrom_newpc_intr_dummy_cb(struct request *rq)
{
	return 1;
}

Linus Torvalds's avatar
Linus Torvalds committed
758
759
static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
{
760
	ide_hwif_t *hwif = drive->hwif;
761
	struct request *rq = hwif->rq;
Linus Torvalds's avatar
Linus Torvalds committed
762
	xfer_func_t *xferfunc;
763
	ide_expiry_t *expiry = NULL;
764
	int dma_error = 0, dma, stat, thislen, uptodate = 0;
765
766
	int write = (rq_data_dir(rq) == WRITE) ? 1 : 0;
	unsigned int timeout;
767
768
	u16 len;
	u8 ireason;
Linus Torvalds's avatar
Linus Torvalds committed
769

770
771
	ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x",
				  rq->cmd[0], write);
772

Borislav Petkov's avatar
Borislav Petkov committed
773
	/* check for errors */
774
	dma = drive->dma;
Linus Torvalds's avatar
Linus Torvalds committed
775
	if (dma) {
776
		drive->dma = 0;
777
		dma_error = hwif->dma_ops->dma_end(drive);
778
		if (dma_error) {
779
			printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name,
780
					write ? "write" : "read");
781
782
			ide_dma_off(drive);
		}
Linus Torvalds's avatar
Linus Torvalds committed
783
784
785
786
787
	}

	if (cdrom_decode_status(drive, 0, &stat))
		return ide_stopped;

Borislav Petkov's avatar
Borislav Petkov committed
788
	/* using dma, transfer is complete now */
Linus Torvalds's avatar
Linus Torvalds committed
789
	if (dma) {
790
		if (dma_error)
Linus Torvalds's avatar
Linus Torvalds committed
791
			return ide_error(drive, "dma error", stat);
792
793
794
		if (blk_fs_request(rq)) {
			ide_end_request(drive, 1, rq->nr_sectors);
			return ide_stopped;
795
796
797
		} else if (rq->cmd_type == REQ_TYPE_ATA_PC && !rq->bio) {
			ide_end_request(drive, 1, 1);
			return ide_stopped;
798
		}
799
		goto end_request;
Linus Torvalds's avatar
Linus Torvalds committed
800
801
	}

802
	ide_read_bcount_and_ireason(drive, &len, &ireason);
803
804

	thislen = blk_fs_request(rq) ? len : rq->data_len;
Linus Torvalds's avatar
Linus Torvalds committed
805
806
807
	if (thislen > len)
		thislen = len;

808
809
	ide_debug_log(IDE_DBG_PC, "DRQ: stat: 0x%x, thislen: %d",
				  stat, thislen);
810

Borislav Petkov's avatar
Borislav Petkov committed
811
	/* If DRQ is clear, the command has completed. */
812
	if ((stat & ATA_DRQ) == 0) {
813
814
815
816
817
818
819
		if (blk_fs_request(rq)) {
			/*
			 * If we're not done reading/writing, complain.
			 * Otherwise, complete the command normally.
			 */
			uptodate = 1;
			if (rq->current_nr_sectors > 0) {
820
				printk(KERN_ERR PFX "%s: %s: data underrun "
821
						"(%d blocks)\n",
822
						drive->name, __func__,
823
824
825
826
827
828
829
830
						rq->current_nr_sectors);
				if (!write)
					rq->cmd_flags |= REQ_FAILED;
				uptodate = 0;
			}
			cdrom_end_request(drive, uptodate);
			return ide_stopped;
		} else if (!blk_pc_request(rq)) {
831
			ide_cd_request_sense_fixup(drive, rq);
Borislav Petkov's avatar
Borislav Petkov committed
832
			/* complain if we still have data left to transfer */
833
834
835
			uptodate = rq->data_len ? 0 : 1;
		}
		goto end_request;
836
	}
Linus Torvalds's avatar
Linus Torvalds committed
837

Borislav Petkov's avatar
Borislav Petkov committed
838
	/* check which way to transfer data */
839
840
	if (ide_cd_check_ireason(drive, rq, len, ireason, write))
		return ide_stopped;
841

842
843
	if (blk_fs_request(rq)) {
		if (write == 0) {
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
			int nskip;

			if (ide_cd_check_transfer_size(drive, len)) {
				cdrom_end_request(drive, 0);
				return ide_stopped;
			}

			/*
			 * First, figure out if we need to bit-bucket
			 * any of the leading sectors.
			 */
			nskip = min_t(int, rq->current_nr_sectors
					   - bio_cur_sectors(rq->bio),
					   thislen >> 9);
			if (nskip > 0) {
859
				ide_pad_transfer(drive, write, nskip << 9);
860
861
862
863
				rq->current_nr_sectors -= nskip;
				thislen -= (nskip << 9);
			}
		}
864
	}
Linus Torvalds's avatar
Linus Torvalds committed
865

866
867
	if (ireason == 0) {
		write = 1;
868
		xferfunc = hwif->tp_ops->output_data;
869
	} else {
870
		write = 0;
871
		xferfunc = hwif->tp_ops->input_data;
Linus Torvalds's avatar
Linus Torvalds committed
872
873
	}

874
875
876
	ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, "
				  "ireason: 0x%x",
				  rq->cmd_type, ireason);
877

Borislav Petkov's avatar
Borislav Petkov committed
878
	/* transfer data */
Linus Torvalds's avatar
Linus Torvalds committed
879
	while (thislen > 0) {
880
		u8 *ptr = blk_fs_request(rq) ? NULL : rq->data;
881
		int blen = rq->data_len;
Linus Torvalds's avatar
Linus Torvalds committed
882

Borislav Petkov's avatar
Borislav Petkov committed
883
		/* bio backed? */
Linus Torvalds's avatar
Linus Torvalds committed
884
		if (rq->bio) {
885
886
887
888
889
890
891
			if (blk_fs_request(rq)) {
				ptr = rq->buffer;
				blen = rq->current_nr_sectors << 9;
			} else {
				ptr = bio_data(rq->bio);
				blen = bio_iovec(rq->bio)->bv_len;
			}
Linus Torvalds's avatar
Linus Torvalds committed
892
893
894
		}

		if (!ptr) {
895
896
			if (blk_fs_request(rq) && !write)
				/*
897
				 * If the buffers are full, pipe the rest into
Borislav Petkov's avatar
Borislav Petkov committed
898
899
				 * oblivion.
				 */
900
				ide_pad_transfer(drive, 0, thislen);
901
			else {
902
				printk(KERN_ERR PFX "%s: confused, missing data\n",
903
904
905
906
907
						drive->name);
				blk_dump_rq_flags(rq, rq_data_dir(rq)
						  ? "cdrom_newpc_intr, write"
						  : "cdrom_newpc_intr, read");
			}
Linus Torvalds's avatar
Linus Torvalds committed
908
909
910
911
912
913
			break;
		}

		if (blen > thislen)
			blen = thislen;

914
		xferfunc(drive, NULL, ptr, blen);
Linus Torvalds's avatar
Linus Torvalds committed
915
916
917
918

		thislen -= blen;
		len -= blen;

919
920
921
922
923
924
925
926
927
928
929
		if (blk_fs_request(rq)) {
			rq->buffer += blen;
			rq->nr_sectors -= (blen >> 9);
			rq->current_nr_sectors -= (blen >> 9);
			rq->sector += (blen >> 9);

			if (rq->current_nr_sectors == 0 && rq->nr_sectors)
				cdrom_end_request(drive, 1);
		} else {
			rq->data_len -= blen;

930
931
932
933
934
935
			/*
			 * The request can't be completed until DRQ is cleared.
			 * So complete the data, but don't complete the request
			 * using the dummy function for the callback feature
			 * of blk_end_request_callback().
			 */
936
937
			if (rq->bio)
				blk_end_request_callback(rq, 0, blen,
938
						 cdrom_newpc_intr_dummy_cb);
939
940
941
			else
				rq->data += blen;
		}
Andreas Schwab's avatar
Andreas Schwab committed
942
943
		if (!write && blk_sense_request(rq))
			rq->sense_len += blen;
Linus Torvalds's avatar
Linus Torvalds committed
944
945
	}

Borislav Petkov's avatar
Borislav Petkov committed
946
	/* pad, if necessary */
947
	if (!blk_fs_request(rq) && len > 0)
948
		ide_pad_transfer(drive, write, len);
Linus Torvalds's avatar
Linus Torvalds committed
949

950
951
952
953
	if (blk_pc_request(rq)) {
		timeout = rq->timeout;
	} else {
		timeout = ATAPI_WAIT_PC;
954
		if (!blk_fs_request(rq))
955
			expiry = ide_cd_expiry;