ide-cd.c 56.9 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
#define IDECD_VERSION "5.00"
Linus Torvalds's avatar
Linus Torvalds committed
27
28
29
30
31
32
33
34
35
36
37
38

#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>
39
#include <linux/mutex.h>
40
#include <linux/bcd.h>
Linus Torvalds's avatar
Linus Torvalds committed
41
42
43

#include <scsi/scsi.h>	/* For SCSI -> ATAPI command conversion */

44
45
#include <linux/irq.h>
#include <linux/io.h>
Linus Torvalds's avatar
Linus Torvalds committed
46
#include <asm/byteorder.h>
47
#include <linux/uaccess.h>
Linus Torvalds's avatar
Linus Torvalds committed
48
49
50
51
#include <asm/unaligned.h>

#include "ide-cd.h"

52
static DEFINE_MUTEX(idecd_ref_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
53

54
#define to_ide_cd(obj) container_of(obj, struct cdrom_info, kref)
Linus Torvalds's avatar
Linus Torvalds committed
55
56
57
58
59
60
61
62

#define ide_cd_g(disk) \
	container_of((disk)->private_data, struct cdrom_info, driver)

static struct cdrom_info *ide_cd_get(struct gendisk *disk)
{
	struct cdrom_info *cd = NULL;

63
	mutex_lock(&idecd_ref_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
64
65
66
	cd = ide_cd_g(disk);
	if (cd)
		kref_get(&cd->kref);
67
	mutex_unlock(&idecd_ref_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
68
69
70
71
72
73
74
	return cd;
}

static void ide_cd_release(struct kref *);

static void ide_cd_put(struct cdrom_info *cd)
{
75
	mutex_lock(&idecd_ref_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
76
	kref_put(&cd->kref, ide_cd_release);
77
	mutex_unlock(&idecd_ref_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
78
79
80
81
82
83
84
85
}

/****************************************************************************
 * Generic packet command support and error handling routines.
 */

/* Mark that we've seen a media change, and invalidate our internal
   buffers. */
86
static void cdrom_saw_media_change(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
87
{
88
89
	struct cdrom_info *cd = drive->driver_data;

90
91
	cd->cd_flags |= IDE_CD_FLAG_MEDIA_CHANGED;
	cd->cd_flags &= ~IDE_CD_FLAG_TOC_VALID;
Linus Torvalds's avatar
Linus Torvalds committed
92
93
94
95
96
97
98
}

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

99
	if (!sense || !rq || (rq->cmd_flags & REQ_QUIET))
Linus Torvalds's avatar
Linus Torvalds committed
100
101
102
		return 0;

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

static
void cdrom_analyze_sense_data(ide_drive_t *drive,
			      struct request *failed_command,
			      struct request_sense *sense)
{
145
146
147
148
149
	unsigned long sector;
	unsigned long bio_sectors;
	unsigned long valid;
	struct cdrom_info *info = drive->driver_data;

Linus Torvalds's avatar
Linus Torvalds committed
150
151
152
153
154
155
156
157
158
159
160
161
	if (!cdrom_log_sense(drive, failed_command, sense))
		return;

	/*
	 * 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)
	 */
	if (failed_command && failed_command->cmd[0] == GPCMD_READ_TOC_PMA_ATIP)
		if (sense->sense_key == 0x05 && sense->asc == 0x24)
			return;

162
163
	if (sense->error_code == 0x70) {	/* Current Error */
		switch (sense->sense_key) {
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
		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]);

			bio_sectors = bio_sectors(failed_command->bio);
			if (bio_sectors < 4)
				bio_sectors = 4;
			if (drive->queue->hardsect_size == 2048)
				sector <<= 2;	/* Device sector size is 2K */
182
			sector &= ~(bio_sectors - 1);
183
184
185
186
187
188
189
190
			valid = (sector - failed_command->sector) << 9;

			if (valid < 0)
				valid = 0;
			if (sector < get_capacity(info->disk) &&
				drive->probed_capacity - sector < 4 * 75) {
				set_capacity(info->disk, sector);
			}
191
192
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
193

194
	ide_cd_log_error(drive->name, failed_command, sense);
Linus Torvalds's avatar
Linus Torvalds committed
195
196
197
198
199
}

/*
 * Initialize a ide-cd packet command request
 */
200
void ide_cd_init_rq(ide_drive_t *drive, struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
201
202
203
204
{
	struct cdrom_info *cd = drive->driver_data;

	ide_init_drive_cmd(rq);
205
	rq->cmd_type = REQ_TYPE_ATA_PC;
Linus Torvalds's avatar
Linus Torvalds committed
206
207
208
209
210
211
212
213
214
215
216
217
218
	rq->rq_disk = cd->disk;
}

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;

	if (sense == NULL)
		sense = &info->sense_data;

	/* stuff the sense request in front of our current request */
219
	ide_cd_init_rq(drive, rq);
Linus Torvalds's avatar
Linus Torvalds committed
220
221
222
223
224

	rq->data = sense;
	rq->cmd[0] = GPCMD_REQUEST_SENSE;
	rq->cmd[4] = rq->data_len = 18;

225
	rq->cmd_type = REQ_TYPE_SENSE;
Linus Torvalds's avatar
Linus Torvalds committed
226
227
228
229
230
231
232

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

	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
}

233
static void cdrom_end_request(ide_drive_t *drive, int uptodate)
Linus Torvalds's avatar
Linus Torvalds committed
234
235
236
237
{
	struct request *rq = HWGROUP(drive)->rq;
	int nsectors = rq->hard_cur_sectors;

238
	if (blk_sense_request(rq) && uptodate) {
Linus Torvalds's avatar
Linus Torvalds committed
239
		/*
240
241
		 * For REQ_TYPE_SENSE, "rq->buffer" points to the original
		 * failed request
Linus Torvalds's avatar
Linus Torvalds committed
242
243
244
245
246
247
248
249
250
251
252
		 */
		struct request *failed = (struct request *) rq->buffer;
		struct cdrom_info *info = drive->driver_data;
		void *sense = &info->sense_data;
		unsigned long flags;

		if (failed) {
			if (failed->sense) {
				sense = failed->sense;
				failed->sense_len = rq->sense_len;
			}
253
			cdrom_analyze_sense_data(drive, failed, sense);
Linus Torvalds's avatar
Linus Torvalds committed
254
255
256
			/*
			 * now end failed request
			 */
257
258
259
260
261
262
			if (blk_fs_request(failed)) {
				if (ide_end_dequeued_request(drive, failed, 0,
						failed->hard_nr_sectors))
					BUG();
			} else {
				spin_lock_irqsave(&ide_lock, flags);
263
264
265
				if (__blk_end_request(failed, -EIO,
						      failed->data_len))
					BUG();
266
267
268
269
				spin_unlock_irqrestore(&ide_lock, flags);
			}
		} else
			cdrom_analyze_sense_data(drive, NULL, sense);
Linus Torvalds's avatar
Linus Torvalds committed
270
271
272
273
274
275
276
277
278
279
280
281
282
	}

	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;

	ide_end_request(drive, uptodate, nsectors);
}

283
284
285
286
287
288
289
static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 stat)
{
	if (stat & 0x80)
		return;
	ide_dump_status(drive, msg, stat);
}

Linus Torvalds's avatar
Linus Torvalds committed
290
291
292
293
294
295
/* Returns 0 if the request should be continued.
   Returns 1 if the request was ended. */
static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
{
	struct request *rq = HWGROUP(drive)->rq;
	int stat, err, sense_key;
296

Linus Torvalds's avatar
Linus Torvalds committed
297
	/* Check for errors. */
298
299
	stat = ide_read_status(drive);

Linus Torvalds's avatar
Linus Torvalds committed
300
301
302
303
304
305
306
	if (stat_ret)
		*stat_ret = stat;

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

	/* Get the IDE error register. */
307
	err = ide_read_error(drive);
Linus Torvalds's avatar
Linus Torvalds committed
308
309
310
311
312
313
314
	sense_key = err >> 4;

	if (rq == NULL) {
		printk("%s: missing rq in cdrom_decode_status\n", drive->name);
		return 1;
	}

315
	if (blk_sense_request(rq)) {
Linus Torvalds's avatar
Linus Torvalds committed
316
317
318
319
		/* We got an error trying to get sense info
		   from the drive (probably while trying
		   to recover from a former error).  Just give up. */

320
		rq->cmd_flags |= REQ_FAILED;
Linus Torvalds's avatar
Linus Torvalds committed
321
322
323
324
		cdrom_end_request(drive, 0);
		ide_error(drive, "request sense failure", stat);
		return 1;

325
	} else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
Linus Torvalds's avatar
Linus Torvalds committed
326
327
328
329
330
331
		/* All other functions, except for READ. */

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

		/* Check for tray open. */
		if (sense_key == NOT_READY) {
337
			cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
338
339
		} else if (sense_key == UNIT_ATTENTION) {
			/* Check for media change. */
340
			cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
341
342
			/*printk("%s: media changed\n",drive->name);*/
			return 0;
343
344
345
346
347
348
349
350
351
		} 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!
			 */
352
		} else if (!(rq->cmd_flags & REQ_QUIET)) {
Linus Torvalds's avatar
Linus Torvalds committed
353
354
355
			/* Otherwise, print an error. */
			ide_dump_status(drive, "packet command error", stat);
		}
356

357
		rq->cmd_flags |= REQ_FAILED;
Linus Torvalds's avatar
Linus Torvalds committed
358
359
360
361
362
363

		/*
		 * instead of playing games with moving completions around,
		 * remove failed request completely and end it when the
		 * request sense has completed
		 */
364
		goto end_request;
Linus Torvalds's avatar
Linus Torvalds committed
365
366
367
368
369
370
371
372
373
374
375
376

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

		/* Handle errors from READ and WRITE requests. */

		if (blk_noretry_request(rq))
			do_end_request = 1;

		if (sense_key == NOT_READY) {
			/* Tray open. */
			if (rq_data_dir(rq) == READ) {
377
				cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
378
379

				/* Fail the request. */
380
				printk("%s: tray open\n", drive->name);
Linus Torvalds's avatar
Linus Torvalds committed
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
				do_end_request = 1;
			} else {
				struct cdrom_info *info = drive->driver_data;

				/* allow the drive 5 seconds to recover, some
				 * devices will return this error while flushing
				 * data from cache */
				if (!rq->errors)
					info->write_timeout = jiffies + ATAPI_WAIT_WRITE_BUSY;
				rq->errors = 1;
				if (time_after(jiffies, info->write_timeout))
					do_end_request = 1;
				else {
					unsigned long flags;

					/*
					 * take a breather relying on the
					 * unplug timer to kick us again
					 */
					spin_lock_irqsave(&ide_lock, flags);
					blk_plug_device(drive->queue);
402
					spin_unlock_irqrestore(&ide_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
403
404
405
406
407
408
409
					return 1;
				}
			}
		} else if (sense_key == UNIT_ATTENTION) {
			/* Media change. */
			cdrom_saw_media_change (drive);

410
411
412
413
414
			/*
			 * Arrange to retry the request.
			 * But be sure to give up if we've retried
			 * too many times.
			 */
Linus Torvalds's avatar
Linus Torvalds committed
415
416
417
418
			if (++rq->errors > ERROR_MAX)
				do_end_request = 1;
		} else if (sense_key == ILLEGAL_REQUEST ||
			   sense_key == DATA_PROTECT) {
419
420
421
422
423
			/*
			 * No point in retrying after an illegal
			 * request or data protect error.
			 */
			ide_dump_status_no_sense(drive, "command error", stat);
Linus Torvalds's avatar
Linus Torvalds committed
424
425
			do_end_request = 1;
		} else if (sense_key == MEDIUM_ERROR) {
426
427
428
429
430
			/*
			 * No point in re-trying a zillion times on a bad
			 * sector... If we got here the error is not correctable
			 */
			ide_dump_status_no_sense(drive, "media error (bad sector)", stat);
Linus Torvalds's avatar
Linus Torvalds committed
431
432
433
			do_end_request = 1;
		} else if (sense_key == BLANK_CHECK) {
			/* Disk appears blank ?? */
434
			ide_dump_status_no_sense(drive, "media error (blank)", stat);
Linus Torvalds's avatar
Linus Torvalds committed
435
436
437
438
439
440
441
442
443
444
445
			do_end_request = 1;
		} else if ((err & ~ABRT_ERR) != 0) {
			/* Go to the default handler
			   for other errors. */
			ide_error(drive, "cdrom_decode_status", stat);
			return 1;
		} else if ((++rq->errors > ERROR_MAX)) {
			/* We've racked up too many retries.  Abort. */
			do_end_request = 1;
		}

446
447
448
449
		/* End a request through request sense analysis when we have
		   sense data. We need this in order to perform end of media
		   processing */

450
451
		if (do_end_request)
			goto end_request;
452

453
454
455
456
457
458
		/*
		 * If we got a CHECK_CONDITION status,
		 * queue a request sense command.
		 */
		if (stat & ERR_STAT)
			cdrom_queue_request_sense(drive, NULL, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
459
460
461
462
463
464
465
	} else {
		blk_dump_rq_flags(rq, "ide-cd: bad rq");
		cdrom_end_request(drive, 0);
	}

	/* Retry, or handle the next request. */
	return 1;
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480

end_request:
	if (stat & ERR_STAT) {
		unsigned long flags;

		spin_lock_irqsave(&ide_lock, flags);
		blkdev_dequeue_request(rq);
		HWGROUP(drive)->rq = NULL;
		spin_unlock_irqrestore(&ide_lock, flags);

		cdrom_queue_request_sense(drive, rq->sense, rq);
	} else
		cdrom_end_request(drive, 0);

	return 1;
Linus Torvalds's avatar
Linus Torvalds committed
481
482
483
484
485
486
487
488
489
490
491
492
493
494
}

static int cdrom_timer_expiry(ide_drive_t *drive)
{
	struct request *rq = HWGROUP(drive)->rq;
	unsigned long wait = 0;

	/*
	 * Some commands are *slow* and normally take a long time to
	 * complete. Usually we can use the ATAPI "disconnect" to bypass
	 * this, but not all commands/drives support that. Let
	 * ide_timer_expiry keep polling us for these.
	 */
	switch (rq->cmd[0]) {
495
496
497
498
499
500
501
502
503
504
505
506
	case GPCMD_BLANK:
	case GPCMD_FORMAT_UNIT:
	case GPCMD_RESERVE_RZONE_TRACK:
	case GPCMD_CLOSE_TRACK:
	case GPCMD_FLUSH_CACHE:
		wait = ATAPI_WAIT_PC;
		break;
	default:
		if (!(rq->cmd_flags & REQ_QUIET))
			printk(KERN_INFO "ide-cd: cmd 0x%x timed out\n", rq->cmd[0]);
		wait = 0;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
	}
	return wait;
}

/* Set up the device registers for transferring a packet command on DEV,
   expecting to later transfer XFERLEN bytes.  HANDLER is the routine
   which actually transfers the command to the drive.  If this is a
   drq_interrupt device, this routine will arrange for HANDLER to be
   called when the interrupt from the drive arrives.  Otherwise, HANDLER
   will be called immediately after the drive is prepared for the transfer. */

static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
						  int xferlen,
						  ide_handler_t *handler)
{
	ide_startstop_t startstop;
	struct cdrom_info *info = drive->driver_data;
	ide_hwif_t *hwif = drive->hwif;

	/* Wait for the controller to be idle. */
	if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY))
		return startstop;

530
	/* FIXME: for Virtual DMA we must check harder */
Linus Torvalds's avatar
Linus Torvalds committed
531
532
533
534
	if (info->dma)
		info->dma = !hwif->dma_setup(drive);

	/* Set up the controller registers. */
535
536
	ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL |
			   IDE_TFLAG_NO_SELECT_MASK, xferlen, info->dma);
537

538
	if (info->cd_flags & IDE_CD_FLAG_DRQ_INTERRUPT) {
539
540
541
542
		/* waiting for CDB interrupt, not DMA yet. */
		if (info->dma)
			drive->waiting_for_dma = 0;

Linus Torvalds's avatar
Linus Torvalds committed
543
544
545
546
547
548
549
550
		/* packet command */
		ide_execute_command(drive, WIN_PACKETCMD, handler, ATAPI_WAIT_PC, cdrom_timer_expiry);
		return ide_started;
	} else {
		unsigned long flags;

		/* packet command */
		spin_lock_irqsave(&ide_lock, flags);
551
552
		hwif->OUTBSYNC(drive, WIN_PACKETCMD,
			       hwif->io_ports[IDE_COMMAND_OFFSET]);
Linus Torvalds's avatar
Linus Torvalds committed
553
554
555
556
557
558
559
560
561
562
563
564
565
		ndelay(400);
		spin_unlock_irqrestore(&ide_lock, flags);

		return (*handler) (drive);
	}
}

/* Send a packet command to DRIVE described by CMD_BUF and CMD_LEN.
   The device registers must have already been prepared
   by cdrom_start_packet_command.
   HANDLER is the interrupt handler to call when the command completes
   or there's data ready. */
#define ATAPI_MIN_CDB_BYTES 12
566
static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *drive,
Linus Torvalds's avatar
Linus Torvalds committed
567
568
569
570
571
572
573
574
					  struct request *rq,
					  ide_handler_t *handler)
{
	ide_hwif_t *hwif = drive->hwif;
	int cmd_len;
	struct cdrom_info *info = drive->driver_data;
	ide_startstop_t startstop;

575
	if (info->cd_flags & IDE_CD_FLAG_DRQ_INTERRUPT) {
Linus Torvalds's avatar
Linus Torvalds committed
576
577
578
579
580
581
		/* Here we should have been called after receiving an interrupt
		   from the device.  DRQ should how be set. */

		/* Check for errors. */
		if (cdrom_decode_status(drive, DRQ_STAT, NULL))
			return ide_stopped;
582
583
584
585

		/* Ok, next interrupt will be DMA interrupt. */
		if (info->dma)
			drive->waiting_for_dma = 1;
Linus Torvalds's avatar
Linus Torvalds committed
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
	} else {
		/* Otherwise, we must wait for DRQ to get set. */
		if (ide_wait_stat(&startstop, drive, DRQ_STAT,
				BUSY_STAT, WAIT_READY))
			return startstop;
	}

	/* Arm the interrupt handler. */
	ide_set_handler(drive, handler, rq->timeout, cdrom_timer_expiry);

	/* ATAPI commands get padded out to 12 bytes minimum */
	cmd_len = COMMAND_SIZE(rq->cmd[0]);
	if (cmd_len < ATAPI_MIN_CDB_BYTES)
		cmd_len = ATAPI_MIN_CDB_BYTES;

	/* Send the command to the device. */
	HWIF(drive)->atapi_output_bytes(drive, rq->cmd, cmd_len);

	/* Start the DMA if need be */
	if (info->dma)
		hwif->dma_start(drive);

	return ide_started;
}

/****************************************************************************
 * Block read functions.
 */

615
616
617
618
619
620
621
622
623
static void ide_cd_pad_transfer(ide_drive_t *drive, xfer_func_t *xf, int len)
{
	while (len > 0) {
		int dum = 0;
		xf(drive, &dum, sizeof(dum));
		len -= sizeof(dum);
	}
}

624
625
626
627
628
629
630
631
632
633
static void ide_cd_drain_data(ide_drive_t *drive, int nsects)
{
	while (nsects > 0) {
		static char dum[SECTOR_SIZE];

		drive->hwif->atapi_input_bytes(drive, dum, sizeof(dum));
		nsects--;
	}
}

Linus Torvalds's avatar
Linus Torvalds committed
634
635
636
637
638
/*
 * 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.
 */
639
640
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
641
{
642
643
644
645
646
	/*
	 * 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
647
		return 0;
648
	else if (ireason == (rw << 1)) {
649
		ide_hwif_t *hwif = drive->hwif;
650
		xfer_func_t *xf;
651

652
		/* Whoops... */
653
		printk(KERN_ERR "%s: %s: wrong transfer direction!\n",
654
				drive->name, __func__);
Linus Torvalds's avatar
Linus Torvalds committed
655

656
657
658
		xf = rw ? hwif->atapi_output_bytes : hwif->atapi_input_bytes;
		ide_cd_pad_transfer(drive, xf, len);
	} else  if (rw == 0 && ireason == 1) {
Linus Torvalds's avatar
Linus Torvalds committed
659
660
661
		/* Some drives (ASUS) seem to tell us that status
		 * info is available. just get it and ignore.
		 */
662
		(void)ide_read_status(drive);
Linus Torvalds's avatar
Linus Torvalds committed
663
664
665
		return 0;
	} else {
		/* Drive wants a command packet, or invalid ireason... */
666
		printk(KERN_ERR "%s: %s: bad interrupt reason 0x%02x\n",
667
				drive->name, __func__, ireason);
Linus Torvalds's avatar
Linus Torvalds committed
668
669
	}

670
671
672
	if (rq->cmd_type == REQ_TYPE_ATA_PC)
		rq->cmd_flags |= REQ_FAILED;

Linus Torvalds's avatar
Linus Torvalds committed
673
674
675
676
	cdrom_end_request(drive, 0);
	return -1;
}

677
678
679
680
681
682
683
684
685
686
687
688
/*
 * 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)
{
	struct cdrom_info *cd = drive->driver_data;

	if ((len % SECTOR_SIZE) == 0)
		return 0;

	printk(KERN_ERR "%s: %s: Bad transfer size %d\n",
689
			drive->name, __func__, len);
690
691
692
693
694
695
696
697
698
699
700
701

	if (cd->cd_flags & IDE_CD_FLAG_LIMIT_NFRAMES)
		printk(KERN_ERR "  This drive is not supported by "
				"this version of the driver\n");
	else {
		printk(KERN_ERR "  Trying to limit transfer sizes\n");
		cd->cd_flags |= IDE_CD_FLAG_LIMIT_NFRAMES;
	}

	return 1;
}

702
static ide_startstop_t cdrom_newpc_intr(ide_drive_t *);
703

Linus Torvalds's avatar
Linus Torvalds committed
704
/*
705
706
 * Routine to send a read/write packet command to the drive.
 * This is usually called directly from cdrom_start_{read,write}().
Linus Torvalds's avatar
Linus Torvalds committed
707
708
709
 * However, for drq_interrupt devices, it is called from an interrupt
 * when the drive is ready to accept the command.
 */
710
static ide_startstop_t cdrom_start_rw_cont(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
711
712
713
{
	struct request *rq = HWGROUP(drive)->rq;

714
715
716
717
	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
718

719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
		/*
		 * 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) {
			/* Sanity check... */
			if (rq->current_nr_sectors !=
			    bio_cur_sectors(rq->bio)) {
				printk(KERN_ERR "%s: %s: buffer botch (%u)\n",
734
						drive->name, __func__,
735
736
737
738
739
						rq->current_nr_sectors);
				cdrom_end_request(drive, 0);
				return ide_stopped;
			}
			rq->current_nr_sectors += nskip;
Linus Torvalds's avatar
Linus Torvalds committed
740
741
		}
	}
742
743
744
745
746
#if 0
	else
		/* the immediate bit */
		rq->cmd[1] = 1 << 3;
#endif
Linus Torvalds's avatar
Linus Torvalds committed
747
748
749
750
	/* Set up the command */
	rq->timeout = ATAPI_WAIT_PC;

	/* Send the command to the drive and return. */
751
	return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);
Linus Torvalds's avatar
Linus Torvalds committed
752
753
754
755
756
757
}

#define IDECD_SEEK_THRESHOLD	(1000)			/* 1000 blocks */
#define IDECD_SEEK_TIMER	(5 * WAIT_MIN_SLEEP)	/* 100 ms */
#define IDECD_SEEK_TIMEOUT	(2 * WAIT_CMD)		/* 20 sec */

758
static ide_startstop_t cdrom_seek_intr(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
759
760
761
762
763
764
765
{
	struct cdrom_info *info = drive->driver_data;
	int stat;
	static int retry = 10;

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

767
	info->cd_flags |= IDE_CD_FLAG_SEEKING;
Linus Torvalds's avatar
Linus Torvalds committed
768
769
770
771
772
773
774

	if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
		if (--retry == 0) {
			/*
			 * this condition is far too common, to bother
			 * users about it
			 */
775
			/* printk("%s: disabled DSC seek overlap\n", drive->name);*/
Linus Torvalds's avatar
Linus Torvalds committed
776
777
778
779
780
781
			drive->dsc_overlap = 0;
		}
	}
	return ide_stopped;
}

782
static ide_startstop_t cdrom_start_seek_continuation(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
783
784
785
786
787
788
789
790
791
792
793
794
795
796
{
	struct request *rq = HWGROUP(drive)->rq;
	sector_t frame = rq->sector;

	sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS);

	memset(rq->cmd, 0, sizeof(rq->cmd));
	rq->cmd[0] = GPCMD_SEEK;
	put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]);

	rq->timeout = ATAPI_WAIT_PC;
	return cdrom_transfer_packet_command(drive, rq, &cdrom_seek_intr);
}

797
static ide_startstop_t cdrom_start_seek(ide_drive_t *drive, unsigned int block)
Linus Torvalds's avatar
Linus Torvalds committed
798
799
800
801
802
803
804
805
{
	struct cdrom_info *info = drive->driver_data;

	info->dma = 0;
	info->start_seek = jiffies;
	return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation);
}

806
807
808
809
810
/*
 * Fix up a possibly partially-processed request so that we can
 * start it over entirely, or even put it back on the request queue.
 */
static void restore_request(struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
{
	if (rq->buffer != bio_data(rq->bio)) {
		sector_t n = (rq->buffer - (char *) bio_data(rq->bio)) / SECTOR_SIZE;

		rq->buffer = bio_data(rq->bio);
		rq->nr_sectors += n;
		rq->sector -= n;
	}
	rq->hard_cur_sectors = rq->current_nr_sectors = bio_cur_sectors(rq->bio);
	rq->hard_nr_sectors = rq->nr_sectors;
	rq->hard_sector = rq->sector;
	rq->q->prep_rq_fn(rq->q, rq);
}

/****************************************************************************
 * Execute all other packet commands.
 */

829
830
831
832
833
834
835
836
837
838
839
840
841
842
static void ide_cd_request_sense_fixup(struct request *rq)
{
	/*
	 * 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;
		}
}

843
int ide_cd_queue_pc(ide_drive_t *drive, struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
844
845
846
{
	struct request_sense sense;
	int retries = 10;
847
	unsigned int flags = rq->cmd_flags;
Linus Torvalds's avatar
Linus Torvalds committed
848
849
850
851
852
853
854
855

	if (rq->sense == NULL)
		rq->sense = &sense;

	/* Start of retry loop. */
	do {
		int error;
		unsigned long time = jiffies;
856
		rq->cmd_flags = flags;
Linus Torvalds's avatar
Linus Torvalds committed
857
858
859
860

		error = ide_do_drive_cmd(drive, rq, ide_wait);
		time = jiffies - time;

861
		/* FIXME: we should probably abort/retry or something
Linus Torvalds's avatar
Linus Torvalds committed
862
		 * in case of failure */
863
		if (rq->cmd_flags & REQ_FAILED) {
Linus Torvalds's avatar
Linus Torvalds committed
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
			/* The request failed.  Retry if it was due to a unit
			   attention status
			   (usually means media was changed). */
			struct request_sense *reqbuf = rq->sense;

			if (reqbuf->sense_key == UNIT_ATTENTION)
				cdrom_saw_media_change(drive);
			else if (reqbuf->sense_key == NOT_READY &&
				 reqbuf->asc == 4 && reqbuf->ascq != 4) {
				/* The drive is in the process of loading
				   a disk.  Retry, but wait a little to give
				   the drive time to complete the load. */
				ssleep(2);
			} else {
				/* Otherwise, don't retry. */
				retries = 0;
			}
			--retries;
		}

		/* End of retry loop. */
885
	} while ((rq->cmd_flags & REQ_FAILED) && retries >= 0);
Linus Torvalds's avatar
Linus Torvalds committed
886
887

	/* Return an error if the command failed. */
888
	return (rq->cmd_flags & REQ_FAILED) ? -EIO : 0;
Linus Torvalds's avatar
Linus Torvalds committed
889
890
}

891
892
893
894
895
896
897
898
899
900
901
/*
 * Called from blk_end_request_callback() after the data of the request
 * is completed and before the request is completed.
 * By returning value '1', blk_end_request_callback() returns immediately
 * without completing the request.
 */
static int cdrom_newpc_intr_dummy_cb(struct request *rq)
{
	return 1;
}

Linus Torvalds's avatar
Linus Torvalds committed
902
903
static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
{
904
	ide_hwif_t *hwif = drive->hwif;
Linus Torvalds's avatar
Linus Torvalds committed
905
906
907
	struct cdrom_info *info = drive->driver_data;
	struct request *rq = HWGROUP(drive)->rq;
	xfer_func_t *xferfunc;
908
	ide_expiry_t *expiry = NULL;
909
910
911
912
	int dma_error = 0, dma, stat, ireason, len, thislen, uptodate = 0;
	int write = (rq_data_dir(rq) == WRITE) ? 1 : 0;
	unsigned int timeout;
	u8 lowcyl, highcyl;
Linus Torvalds's avatar
Linus Torvalds committed
913
914
915
916
917
918

	/* Check for errors. */
	dma = info->dma;
	if (dma) {
		info->dma = 0;
		dma_error = HWIF(drive)->ide_dma_end(drive);
919
920
		if (dma_error) {
			printk(KERN_ERR "%s: DMA %s error\n", drive->name,
921
					write ? "write" : "read");
922
923
			ide_dma_off(drive);
		}
Linus Torvalds's avatar
Linus Torvalds committed
924
925
926
927
928
929
930
931
932
	}

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

	/*
	 * using dma, transfer is complete now
	 */
	if (dma) {
933
		if (dma_error)
Linus Torvalds's avatar
Linus Torvalds committed
934
			return ide_error(drive, "dma error", stat);
935
936
937
938
		if (blk_fs_request(rq)) {
			ide_end_request(drive, 1, rq->nr_sectors);
			return ide_stopped;
		}
939
		goto end_request;
Linus Torvalds's avatar
Linus Torvalds committed
940
941
942
943
944
	}

	/*
	 * ok we fall to pio :/
	 */
945
946
947
	ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]) & 0x3;
	lowcyl  = hwif->INB(hwif->io_ports[IDE_BCOUNTL_OFFSET]);
	highcyl = hwif->INB(hwif->io_ports[IDE_BCOUNTH_OFFSET]);
Linus Torvalds's avatar
Linus Torvalds committed
948
949

	len = lowcyl + (256 * highcyl);
950
951

	thislen = blk_fs_request(rq) ? len : rq->data_len;
Linus Torvalds's avatar
Linus Torvalds committed
952
953
954
955
956
957
	if (thislen > len)
		thislen = len;

	/*
	 * If DRQ is clear, the command has completed.
	 */
958
	if ((stat & DRQ_STAT) == 0) {
959
960
961
962
963
964
965
966
967
		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) {
				printk(KERN_ERR "%s: %s: data underrun "
						"(%d blocks)\n",
968
						drive->name, __func__,
969
970
971
972
973
974
975
976
						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)) {
977
978
979
980
981
			ide_cd_request_sense_fixup(rq);
			/* Complain if we still have data left to transfer. */
			uptodate = rq->data_len ? 0 : 1;
		}
		goto end_request;
982
	}
Linus Torvalds's avatar
Linus Torvalds committed
983
984
985
986

	/*
	 * check which way to transfer data
	 */
987
988
	if (ide_cd_check_ireason(drive, rq, len, ireason, write))
		return ide_stopped;
989

990
991
	if (blk_fs_request(rq)) {
		if (write == 0) {
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
			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) {
				ide_cd_drain_data(drive, nskip);
				rq->current_nr_sectors -= nskip;
				thislen -= (nskip << 9);
			}
		}
1012
	}
Linus Torvalds's avatar
Linus Torvalds committed
1013

1014
1015
1016
	if (ireason == 0) {
		write = 1;
		xferfunc = HWIF(drive)->atapi_output_bytes;
1017
	} else {
1018
		write = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1019
1020
1021
1022
1023
1024
1025
		xferfunc = HWIF(drive)->atapi_input_bytes;
	}

	/*
	 * transfer data
	 */
	while (thislen > 0) {
1026
		u8 *ptr = blk_fs_request(rq) ? NULL : rq->data;
1027
		int blen = rq->data_len;
Linus Torvalds's avatar
Linus Torvalds committed
1028
1029
1030
1031
1032

		/*
		 * bio backed?
		 */
		if (rq->bio) {
1033
1034
1035
1036
1037
1038
1039
			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
1040
1041
1042
		}

		if (!ptr) {
1043
1044
			if (blk_fs_request(rq) && !write)
				/*
1045
1046
1047
				 * If the buffers are full, pipe the rest into
				 * oblivion. */
				ide_cd_drain_data(drive, thislen >> 9);
1048
1049
1050
1051
1052
1053
1054
			else {
				printk(KERN_ERR "%s: confused, missing data\n",
						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
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
			break;
		}

		if (blen > thislen)
			blen = thislen;

		xferfunc(drive, ptr, blen);

		thislen -= blen;
		len -= blen;

1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
		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;

1077
1078
1079
1080
1081
1082
			/*
			 * 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().
			 */
1083
1084
			if (rq->bio)
				blk_end_request_callback(rq, 0, blen,
1085
						 cdrom_newpc_intr_dummy_cb);
1086
1087
1088
			else
				rq->data += blen;
		}
Andreas Schwab's avatar
Andreas Schwab committed
1089
1090
		if (!write && blk_sense_request(rq))
			rq->sense_len += blen;
Linus Torvalds's avatar
Linus Torvalds committed
1091
1092
1093
1094
1095
	}

	/*
	 * pad, if necessary
	 */
1096
	if (!blk_fs_request(rq) && len > 0)
1097
		ide_cd_pad_transfer(drive, xferfunc, len);
Linus Torvalds's avatar
Linus Torvalds committed
1098

1099
1100
1101
1102
	if (blk_pc_request(rq)) {
		timeout = rq->timeout;
	} else {
		timeout = ATAPI_WAIT_PC;
1103
1104
		if (!blk_fs_request(rq))
			expiry = cdrom_timer_expiry;
1105
1106
1107
	}

	ide_set_handler(drive, cdrom_newpc_intr, timeout, expiry);
Linus Torvalds's avatar
Linus Torvalds committed
1108
	return ide_started;
1109
1110
1111
1112

end_request:
	if (blk_pc_request(rq)) {
		unsigned long flags;
1113
1114
1115
1116
		unsigned int dlen = rq->data_len;

		if (dma)
			rq->data_len = 0;
1117
1118

		spin_lock_irqsave(&ide_lock, flags);
1119
		if (__blk_end_request(rq, 0, dlen))
1120
1121
1122
1123
1124
1125
1126
1127
1128
			BUG();
		HWGROUP(drive)->rq = NULL;
		spin_unlock_irqrestore(&ide_lock, flags);
	} else {
		if (!uptodate)
			rq->cmd_flags |= REQ_FAILED;
		cdrom_end_request(drive, uptodate);
	}
	return ide_stopped;
Linus Torvalds's avatar
Linus Torvalds committed
1129
1130
}

1131
static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
1132
{
1133
1134
1135
1136
	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
1137

1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
	if (write) {
		/*
		 * disk has become write protected
		 */
		if (cd->disk->policy) {
			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.
		 */
		restore_request(rq);
Linus Torvalds's avatar
Linus Torvalds committed
1152
1153
1154
	}

	/*
1155
	 * use DMA, if possible / writes *must* be hardware frame aligned
Linus Torvalds's avatar
Linus Torvalds committed
1156
	 */
1157
1158
1159
1160
1161
1162
1163
1164
1165
	if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
	    (rq->sector & (sectors_per_frame - 1))) {
		if (write) {
			cdrom_end_request(drive, 0);
			return ide_stopped;
		}
		cd->dma = 0;
	} else
		cd->dma = drive->using_dma;
Linus Torvalds's avatar
Linus Torvalds committed
1166

1167
1168
	if (write)
		cd->devinfo.media_written = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1169

1170
	/* Start sending the read/write request to the drive. */
1171
	return cdrom_start_packet_command(drive, 32768, cdrom_start_rw_cont);
Linus Torvalds's avatar
Linus Torvalds committed
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
}

static ide_startstop_t cdrom_do_newpc_cont(ide_drive_t *drive)
{
	struct request *rq = HWGROUP(drive)->rq;

	if (!rq->timeout)
		rq->timeout = ATAPI_WAIT_PC;

	return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);
}

static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
{
	struct cdrom_info *info = drive->driver_data;

1188
1189
1190
1191
	if (blk_pc_request(rq))
		rq->cmd_flags |= REQ_QUIET;
	else
		rq->cmd_flags &= ~REQ_FAILED;
Linus Torvalds's avatar
Linus Torvalds committed
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205

	info->dma = 0;

	/*
	 * sg request
	 */
	if (rq->bio) {
		int mask = drive->queue->dma_alignment;
		unsigned long addr = (unsigned long) page_address(bio_page(rq->bio));

		info->dma = drive->using_dma;

		/*
		 * check if dma is safe
1206
1207
1208
		 *
		 * NOTE! The "len" and "addr" checks should possibly have
		 * separate masks.
Linus Torvalds's avatar
Linus Torvalds committed
1209
		 */
1210
		if ((rq->data_len & 15) || (addr & mask))
Linus Torvalds's avatar
Linus Torvalds committed
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
			info->dma = 0;
	}

	/* Start sending the command to the drive. */
	return cdrom_start_packet_command(drive, rq->data_len, cdrom_do_newpc_cont);
}

/****************************************************************************
 * cdrom driver request routine.
 */
static ide_startstop_t
1222
ide_do_rw_cdrom(ide_drive_t *drive, struct request *rq, sector_t block)
Linus Torvalds's avatar
Linus Torvalds committed
1223
1224
1225
1226
1227
{
	ide_startstop_t action;
	struct cdrom_info *info = drive->driver_data;

	if (blk_fs_request(rq)) {
1228
		if (info->cd_flags & IDE_CD_FLAG_SEEKING) {
Linus Torvalds's avatar
Linus Torvalds committed
1229
			unsigned long elapsed = jiffies - info->start_seek;
1230
			int stat = ide_read_status(drive);
Linus Torvalds's avatar
Linus Torvalds committed
1231
1232
1233
1234
1235
1236

			if ((stat & SEEK_STAT) != SEEK_STAT) {
				if (elapsed < IDECD_SEEK_TIMEOUT) {
					ide_stall_queue(drive, IDECD_SEEK_TIMER);
					return ide_stopped;
				}
1237
				printk(KERN_ERR "%s: DSC timeout\n", drive->name);
Linus Torvalds's avatar
Linus Torvalds committed
1238
			}
1239
			info->cd_flags &= ~IDE_CD_FLAG_SEEKING;
Linus Torvalds's avatar
Linus Torvalds committed
1240
		}
1241
		if ((rq_data_dir(rq) == READ) && IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap)
Linus Torvalds's avatar
Linus Torvalds committed
1242
			action = cdrom_start_seek(drive, block);
1243
		else
1244
			action = cdrom_start_rw(drive, rq);
Linus Torvalds's avatar
Linus Torvalds committed
1245
1246
		info->last_block = block;
		return action;
1247
	} else if (blk_sense_request(rq) || blk_pc_request(rq) ||
1248
		   rq->cmd_type == REQ_TYPE_ATA_PC) {
Linus Torvalds's avatar
Linus Torvalds committed
1249
		return cdrom_do_block_pc(drive, rq);
1250
	} else if (blk_special_request(rq)) {
Linus Torvalds's avatar
Linus Torvalds committed
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
		/*
		 * right now this can only be a reset...
		 */
		cdrom_end_request(drive, 1);
		return ide_stopped;
	}

	blk_dump_rq_flags(rq, "ide-cd bad flags");
	cdrom_end_request(drive, 0);
	return ide_stopped;
}



/****************************************************************************
 * Ioctl handling.
 *
 * Routines which queue packet commands take as a final argument a pointer
 * to a request_sense struct.  If execution of the command results
 * in an error with a CHECK CONDITION status, this structure will be filled
 * with the results of the subsequent request sense command.  The pointer
 * can also be NULL, in which case no sense information is returned.
 */

static
1276
void msf_from_bcd(struct atapi_msf *msf)
Linus Torvalds's avatar
Linus Torvalds committed
1277
{
1278
1279
1280
	msf->minute = BCD2BIN(msf->minute);
	msf->second = BCD2BIN(msf->second);
	msf->frame  = BCD2BIN(msf->frame);
Linus Torvalds's avatar
Linus Torvalds committed
1281
1282
}

1283
int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
Linus Torvalds's avatar
Linus Torvalds committed
1284
1285
1286
1287
1288
{
	struct request req;
	struct cdrom_info *info = drive->driver_data;
	struct cdrom_device_info *cdi = &info->devinfo;

1289
	ide_cd_init_rq(drive, &req);
Linus Torvalds's avatar
Linus Torvalds committed
1290
1291
1292

	req.sense = sense;
	req.cmd[0] = GPCMD_TEST_UNIT_READY;
1293
	req.cmd_flags |= REQ_QUIET;
Linus Torvalds's avatar
Linus Torvalds committed
1294

1295
1296
1297
1298
	/*
	 * Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to
	 * switch CDs instead of supporting the LOAD_UNLOAD opcode.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
1299
1300
	req.cmd[7] = cdi->sanyo_slot % 3;

1301
	return ide_cd_queue_pc(drive, &req);
Linus Torvalds's avatar
Linus Torvalds committed
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
}

static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
			       unsigned long *sectors_per_frame,
			       struct request_sense *sense)
{
	struct {
		__u32 lba;
		__u32 blocklen;
	} capbuf;

	int stat;
	struct request req;

1316
	ide_cd_init_rq(drive, &req);
Linus Torvalds's avatar
Linus Torvalds committed
1317
1318
1319
1320
1321

	req.sense = sense;
	req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
	req.data = (char *)&capbuf;
	req.data_len = sizeof(capbuf);
1322
	req.cmd_flags |= REQ_QUIET;
Linus Torvalds's avatar
Linus Torvalds committed
1323

1324
	stat = ide_cd_queue_pc(drive, &req);
Linus Torvalds's avatar
Linus Torvalds committed
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
	if (stat == 0) {
		*capacity = 1 + be32_to_cpu(capbuf.lba);
		*sectors_per_frame =
			be32_to_cpu(capbuf.blocklen) >> SECTOR_BITS;
	}

	return stat;
}

static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
				int format, char *buf, int buflen,
				struct request_sense *sense)
{
	struct request req;

1340
	ide_cd_init_rq(drive, &req);
Linus Torvalds's avatar
Linus Torvalds committed
1341
1342
1343
1344

	req.sense = sense;
	req.data =  buf;
	req.data_len = buflen;
1345
	req.cmd_flags |= REQ_QUIET;
Linus Torvalds's avatar
Linus Torvalds committed
1346
1347
1348
1349
1350
1351
1352
1353
1354
	req.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
	req.cmd[6] = trackno;
	req.cmd[7] = (buflen >> 8);
	req.cmd[8] = (buflen & 0xff);
	req.cmd[9] = (format << 6);

	if (msf_flag)
		req.cmd[1] = 2;

1355
	return ide_cd_queue_pc(drive, &req);
Linus Torvalds's avatar
Linus Torvalds committed
1356
1357
1358
}

/* Try to read the entire TOC for the disk into our internal buffer. */
1359
int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
Linus Torvalds's avatar
Linus Torvalds committed
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
{
	int stat, ntracks, i;
	struct cdrom_info *info = drive->driver_data;
	struct cdrom_device_info *cdi = &info->devinfo;
	struct atapi_toc *toc = info->toc;
	struct {
		struct atapi_toc_header hdr;
		struct atapi_toc_entry  ent;
	} ms_tmp;
	long last_written;
	unsigned long sectors_per_frame = SECTORS_PER_FRAME;

	if (toc == NULL) {
		/* Try to allocate space. */
1374
		toc = kmalloc(sizeof(struct atapi_toc), GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
1375
		if (toc == NULL) {
1376
			printk(KERN_ERR "%s: No cdrom TOC buffer!\n", drive->name);
Linus Torvalds's avatar
Linus Torvalds committed
1377
1378
			return -ENOMEM;
		}
1379
		info->toc = toc;
Linus Torvalds's avatar
Linus Torvalds committed
1380
1381
1382
1383
1384
1385
	}

	/* Check to see if the existing data is still valid.
	   If it is, just return. */
	(void) cdrom_check_status(drive, sense);

1386
	if (info->cd_flags & IDE_CD_FLAG_TOC_VALID)
Linus Torvalds's avatar
Linus Torvalds committed
1387
1388
1389
1390
1391
1392
1393
1394
1395
		return 0;

	/* Try to get the total cdrom capacity and sector size. */
	stat = cdrom_read_capacity(drive, &toc->capacity, &sectors_per_frame,
				   sense);
	if (stat)
		toc->capacity = 0x1fffff;

	set_capacity(info->disk, toc->capacity * sectors_per_frame);
1396
1397
1398
	/* Save a private copy of te TOC capacity for error handling */
	drive->probed_capacity = toc->capacity * sectors_per_frame;

Linus Torvalds's avatar
Linus Torvalds committed
1399
1400
1401
1402
1403
1404
	blk_queue_hardsect_size(drive->queue,
				sectors_per_frame << SECTOR_BITS);

	/* First read just the header, so we know how long the TOC is. */
	stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr,
				    sizeof(struct atapi_toc_header), sense);
1405
1406
	if (stat)
		return stat;
Linus Torvalds's avatar
Linus Torvalds committed
1407

1408
	if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD) {
1409
1410
		toc->hdr.first_track = BCD2BIN(toc->hdr.first_track);
		toc->hdr.last_track  = BCD2BIN(toc->hdr.last_track);
Linus Torvalds's avatar
Linus Torvalds committed
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
	}

	ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
	if (ntracks <= 0)
		return -EIO;
	if (ntracks > MAX_TRACKS)
		ntracks = MAX_TRACKS;

	/* Now read the whole schmeer. */
	stat = cdrom_read_tocentry(drive, toc->hdr.first_track, 1, 0,
				  (char *)&toc->hdr,
				   sizeof(struct atapi_toc_header) +
				   (ntracks + 1) *
				   sizeof(struct atapi_toc_entry), sense);

	if (stat && toc->hdr.first_track > 1) {
		/* Cds with CDI tracks only don't have any TOC entries,
		   despite of this the returned values are
		   first_track == last_track = number of CDI tracks + 1,
		   so that this case is indistinguishable from the same
		   layout plus an additional audio track.
		   If we get an error for the regular case, we assume
		   a CDI without additional audio tracks. In this case
		   the readable TOC is empty (CDI tracks are not included)
1435
		   and only holds the Leadout entry. Heiko Eißfeldt */
Linus Torvalds's avatar
Linus Torvalds committed
1436
1437
1438
1439
1440
1441
1442
		ntracks = 0;
		stat = cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0,
					   (char *)&toc->hdr,
					   sizeof(struct atapi_toc_header) +
					   (ntracks + 1) *
					   sizeof(struct atapi_toc_entry),
					   sense);
1443
		if (stat)
Linus Torvalds's avatar
Linus Torvalds committed
1444
			return stat;
1445