ide-cd.c 53.6 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
104
105
	ide_debug_log(IDE_DBG_SENSE, "Call %s, sense_key: 0x%x\n", __func__,
		      sense->sense_key);

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

	switch (sense->sense_key) {
110
111
112
113
114
	case NO_SENSE:
	case RECOVERED_ERROR:
		break;
	case NOT_READY:
		/*
Borislav Petkov's avatar
Borislav Petkov committed
115
116
		 * don't care about tray state messages for e.g. capacity
		 * commands or in-progress or becoming ready
117
118
		 */
		if (sense->asc == 0x3a || sense->asc == 0x04)
Linus Torvalds's avatar
Linus Torvalds committed
119
			break;
120
121
122
123
		log = 1;
		break;
	case ILLEGAL_REQUEST:
		/*
Borislav Petkov's avatar
Borislav Petkov committed
124
125
		 * don't log START_STOP unit with LoEj set, since we cannot
		 * reliably check if drive can auto-close
126
127
		 */
		if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
Linus Torvalds's avatar
Linus Torvalds committed
128
			break;
129
130
131
132
		log = 1;
		break;
	case UNIT_ATTENTION:
		/*
Borislav Petkov's avatar
Borislav Petkov committed
133
134
135
		 * 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.
136
137
138
139
140
141
		 */
		cdrom_saw_media_change(drive);
		break;
	default:
		log = 1;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
142
143
144
145
	}
	return log;
}

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

154
155
156
157
158
159
160
161
	ide_debug_log(IDE_DBG_SENSE, "Call %s, error_code: 0x%x, "
			"sense_key: 0x%x\n", __func__, sense->error_code,
			sense->sense_key);

	if (failed_command)
		ide_debug_log(IDE_DBG_SENSE, "%s: failed cmd: 0x%x\n",
				__func__, failed_command->cmd[0]);

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

	/*
Borislav Petkov's avatar
Borislav Petkov committed
166
167
168
	 * 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
169
170
171
172
173
	 */
	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
174
175
	/* current error */
	if (sense->error_code == 0x70) {
176
		switch (sense->sense_key) {
177
178
179
180
181
182
183
184
185
186
187
188
189
190
		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
191
192
				/* device sector size is 2K */
				sector <<= 2;
193
194

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

197
198
199
200
201
202
203
204
			/*
			 * 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.
			 */
205
			if (sector < get_capacity(info->disk) &&
206
			    drive->probed_capacity - sector < 4 * 75)
207
				set_capacity(info->disk, sector);
208
209
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
210

211
	ide_cd_log_error(drive->name, failed_command, sense);
Linus Torvalds's avatar
Linus Torvalds committed
212
213
214
215
216
217
218
219
}

static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
				      struct request *failed_command)
{
	struct cdrom_info *info		= drive->driver_data;
	struct request *rq		= &info->request_sense_request;

220
221
	ide_debug_log(IDE_DBG_SENSE, "Call %s\n", __func__);

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

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

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

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

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

241
242
243
244
	if (failed_command)
		ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x\n",
			      failed_command->cmd[0]);

245
	ide_do_drive_cmd(drive, rq);
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
255
256
	ide_debug_log(IDE_DBG_FUNC, "Call %s, cmd: 0x%x, uptodate: 0x%x, "
		      "nsectors: %d\n", __func__, rq->cmd[0], uptodate,
		      nsectors);

257
	if (blk_sense_request(rq) && uptodate) {
Linus Torvalds's avatar
Linus Torvalds committed
258
		/*
259
260
		 * For REQ_TYPE_SENSE, "rq->buffer" points to the original
		 * failed request
Linus Torvalds's avatar
Linus Torvalds committed
261
262
263
264
265
266
267
268
269
270
		 */
		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;
			}
271
			cdrom_analyze_sense_data(drive, failed, sense);
Linus Torvalds's avatar
Linus Torvalds committed
272
			/*
Borislav Petkov's avatar
Borislav Petkov committed
273
			 * now end the failed request
Linus Torvalds's avatar
Linus Torvalds committed
274
			 */
275
276
277
278
279
			if (blk_fs_request(failed)) {
				if (ide_end_dequeued_request(drive, failed, 0,
						failed->hard_nr_sectors))
					BUG();
			} else {
280
281
				if (blk_end_request(failed, -EIO,
						    failed->data_len))
282
					BUG();
283
284
285
			}
		} else
			cdrom_analyze_sense_data(drive, NULL, sense);
Linus Torvalds's avatar
Linus Torvalds committed
286
287
288
289
290
291
292
293
294
295
	}

	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;

296
297
298
	ide_debug_log(IDE_DBG_FUNC, "Exit %s, uptodate: 0x%x, nsectors: %d\n",
		      __func__, uptodate, nsectors);

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

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

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

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

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

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

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

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

339
	ide_debug_log(IDE_DBG_RQ, "%s: stat: 0x%x, good_stat: 0x%x, "
340
341
		      "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x, err: 0x%x\n",
		      __func__, 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
532
533
	ide_debug_log(IDE_DBG_FUNC, "Call %s, ireason: 0x%x, rw: 0x%x\n",
		      __func__, ireason, rw);

534
535
536
537
538
	/*
	 * 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
539
		return 0;
540
	else if (ireason == (rw << 1)) {
541

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

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

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

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

567
568
569
570
571
572
/*
 * 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)
{
573
574
	ide_debug_log(IDE_DBG_FUNC, "Call %s, len: %d\n", __func__, len);

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

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

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

	return 1;
}

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

598
599
600
601
	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
602

603
604
605
606
607
608
609
610
611
612
613
		/*
		 * 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
614
			/* sanity check... */
615
616
			if (rq->current_nr_sectors !=
			    bio_cur_sectors(rq->bio)) {
617
				printk(KERN_ERR PFX "%s: %s: buffer botch (%u)\n",
618
						drive->name, __func__,
619
620
621
622
623
						rq->current_nr_sectors);
				cdrom_end_request(drive, 0);
				return ide_stopped;
			}
			rq->current_nr_sectors += nskip;
Linus Torvalds's avatar
Linus Torvalds committed
624
625
		}
	}
626

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

630
631
632
	return ide_started;
}

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

	ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);

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

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

657
static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq)
658
{
659
660
	ide_debug_log(IDE_DBG_FUNC, "Call %s, rq->cmd[0]: 0x%x\n",
		      __func__, rq->cmd[0]);
661

662
663
664
665
666
667
668
669
670
671
672
673
	/*
	 * 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;
		}
}

674
675
676
677
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
678
{
679
680
	struct cdrom_info *info = drive->driver_data;
	struct request_sense local_sense;
Linus Torvalds's avatar
Linus Torvalds committed
681
	int retries = 10;
682
	unsigned int flags = 0;
Linus Torvalds's avatar
Linus Torvalds committed
683

684
685
	if (!sense)
		sense = &local_sense;
Linus Torvalds's avatar
Linus Torvalds committed
686

687
	ide_debug_log(IDE_DBG_PC, "Call %s, cmd[0]: 0x%x, write: 0x%x, "
688
689
690
		      "timeout: %d, cmd_flags: 0x%x\n", __func__, cmd[0], write,
		      timeout, cmd_flags);

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

696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
		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
715

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

			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
731
732
733
734
735
				/*
				 * 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
736
737
				ssleep(2);
			} else {
Borislav Petkov's avatar
Borislav Petkov committed
738
				/* otherwise, don't retry */
Linus Torvalds's avatar
Linus Torvalds committed
739
740
741
742
743
				retries = 0;
			}
			--retries;
		}

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

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

751
/*
Borislav Petkov's avatar
Borislav Petkov committed
752
753
754
 * 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.
755
756
757
758
759
760
 */
static int cdrom_newpc_intr_dummy_cb(struct request *rq)
{
	return 1;
}

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

773
774
775
	ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd[0]: 0x%x, write: 0x%x\n",
		      __func__, rq->cmd[0], write);

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

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

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

805
	ide_read_bcount_and_ireason(drive, &len, &ireason);
806
807

	thislen = blk_fs_request(rq) ? len : rq->data_len;
Linus Torvalds's avatar
Linus Torvalds committed
808
809
810
	if (thislen > len)
		thislen = len;

811
812
813
	ide_debug_log(IDE_DBG_PC, "%s: DRQ: stat: 0x%x, thislen: %d\n",
		      __func__, stat, thislen);

Borislav Petkov's avatar
Borislav Petkov committed
814
	/* If DRQ is clear, the command has completed. */
815
	if ((stat & ATA_DRQ) == 0) {
816
817
818
819
820
821
822
		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) {
823
				printk(KERN_ERR PFX "%s: %s: data underrun "
824
						"(%d blocks)\n",
825
						drive->name, __func__,
826
827
828
829
830
831
832
833
						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)) {
834
			ide_cd_request_sense_fixup(drive, rq);
Borislav Petkov's avatar
Borislav Petkov committed
835
			/* complain if we still have data left to transfer */
836
837
838
			uptodate = rq->data_len ? 0 : 1;
		}
		goto end_request;
839
	}
Linus Torvalds's avatar
Linus Torvalds committed
840

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

845
846
	if (blk_fs_request(rq)) {
		if (write == 0) {
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
			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) {
862
				ide_pad_transfer(drive, write, nskip << 9);
863
864
865
866
				rq->current_nr_sectors -= nskip;
				thislen -= (nskip << 9);
			}
		}
867
	}
Linus Torvalds's avatar
Linus Torvalds committed
868

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

877
878
879
	ide_debug_log(IDE_DBG_PC, "%s: data transfer, rq->cmd_type: 0x%x, "
		      "ireason: 0x%x\n", __func__, rq->cmd_type, ireason);

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

Borislav Petkov's avatar
Borislav Petkov committed
885
		/* bio backed? */
Linus Torvalds's avatar
Linus Torvalds committed
886
		if (rq->bio) {
887
888
889
890
891
892
893
			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
894
895
896
		}

		if (!ptr) {
897
898
			if (blk_fs_request(rq) && !write)
				/*
899
				 * If the buffers are full, pipe the rest into
Borislav Petkov's avatar
Borislav Petkov committed
900
901
				 * oblivion.
				 */
902
				ide_pad_transfer(drive, 0, thislen);
903
			else {
904
				printk(KERN_ERR PFX "%s: confused, missing data\n",
905
906
907
908
909
						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
910
911
912
913
914
915
			break;
		}

		if (blen > thislen)
			blen = thislen;

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

		thislen -= blen;
		len -= blen;

921
922
923
924
925
926
927
928
929
930
931
		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;

932
933
934
935
936
937
			/*
			 * 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().
			 */
938
939
			if (rq->bio)
				blk_end_request_callback(rq, 0, blen,
940
						 cdrom_newpc_intr_dummy_cb);
941
942
943
			else
				rq->data += blen;
		}
Andreas Schwab's avatar
Andreas Schwab committed
944
945
		if (!write && blk_sense_request(rq))
			rq->sense_len += blen;
Linus Torvalds's avatar
Linus Torvalds committed
946
947
	}

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

952
953
954
955
	if (blk_pc_request(rq)) {
		timeout = rq->timeout;
	} else {
		timeout = ATAPI_WAIT_PC;
956
		if (!blk_fs_request(rq))
957
			expiry = ide_cd_expiry;
958
959
960
	}

	ide_set_handler(drive, cdrom_newpc_intr, timeout, expiry);
Linus Torvalds's avatar
Linus Torvalds committed
961
	return ide_started;
962
963
964

end_request:
	if (blk_pc_request(rq)) {
965
966
967
968
		unsigned int dlen = rq->data_len;

		if (dma)
			rq->data_len = 0;
969

970
		if (blk_end_request(rq, 0, dlen))
971
			BUG();
972

973
		hwif->rq = NULL;
974
975
976
977
978
979
	} else {
		if (!uptodate)
			rq->cmd_flags |= REQ_FAILED;
		cdrom_end_request(drive, uptodate);
	}
	return ide_stopped;
Linus Torvalds's avatar
Linus Torvalds committed
980
981
}

982
static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
983
{
984
985
986
987
	struct cdrom_info *cd = drive->driver_data;
	int write = rq_data_dir(rq) == WRITE;
	unsigned short sectors_per_frame =
		queue_hardsect_size(drive->queue) >> SECTOR_BITS;
Linus Torvalds's avatar
Linus Torvalds committed
988

989
990
991
	ide_debug_log(IDE_DBG_RQ, "Call %s, rq->cmd[0]: 0x%x, write: 0x%x, "
		      "secs_per_frame: %u\n",
		      __func__, rq->cmd[0], write, sectors_per_frame);
992

993
	if (write) {
Borislav Petkov's avatar
Borislav Petkov committed
994
		/* disk has become write protected */
995
		if (get_disk_ro(cd->disk)) {
996
997
998
999
1000
1001
1002
1003
			cdrom_end_request(drive, 0);
			return ide_stopped;
		}
	} else {
		/*
		 * We may be retrying this request after an error.  Fix up any
		 * weirdness which might be present in the request packet.
		 */
1004
		ide_cd_restore_request(drive, rq);
Linus Torvalds's avatar
Linus Torvalds committed
1005
1006
	}

Borislav Petkov's avatar
Borislav Petkov committed
1007
	/* use DMA, if possible / writes *must* be hardware frame aligned */
1008
1009
1010
1011
1012
1013
	if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
	    (rq->sector & (sectors_per_frame - 1))) {
		if (write) {
			cdrom_end_request(drive, 0);
			return ide_stopped;
		}
1014
		drive->dma = 0;
1015
	} else
1016
		drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
Linus Torvalds's avatar
Linus Torvalds committed
1017

1018
1019
	if (write)
		cd->devinfo.media_written = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1020

1021
	return ide_started;
Linus Torvalds's avatar
Linus Torvalds committed
1022
1023
}

1024
static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
1025
1026
{

1027
1028
	ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd[0]: 0x%x, "
		      "rq->cmd_type: 0x%x\n", __func__, rq->cmd[0],
1029
1030
		      rq->cmd_type);

1031
1032
1033
1034
	if (blk_pc_request(rq))
		rq->cmd_flags |= REQ_QUIET;
	else
		rq->cmd_flags &= ~REQ_FAILED;
Linus Torvalds's avatar
Linus Torvalds committed
1035