ide-cd.c 47.8 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
 * 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>
7
 * Copyright (C) 2005, 2007-2009  Bartlomiej Zolnierkiewicz
Linus Torvalds's avatar
Linus Torvalds committed
8 9 10 11 12 13 14
 *
 * 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. ;-)
15 16 17
 *
 * Documentation:
 *	Mt. Fuji (SFF8090 version 4) and ATAPI (SFF-8020i rev 2.6) standards.
Linus Torvalds's avatar
Linus Torvalds committed
18
 *
19 20 21 22
 * For historical changelog please see:
 *	Documentation/ide/ChangeLog.ide-cd.1994-2004
 */

23 24 25
#define DRV_NAME "ide-cd"
#define PFX DRV_NAME ": "

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

Borislav Petkov's avatar
Borislav Petkov committed
42 43
/* For SCSI -> ATAPI command conversion */
#include <scsi/scsi.h>
Linus Torvalds's avatar
Linus Torvalds committed
44

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

#include "ide-cd.h"

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

55
static void ide_cd_release(struct device *);
56

Linus Torvalds's avatar
Linus Torvalds committed
57 58 59 60
static struct cdrom_info *ide_cd_get(struct gendisk *disk)
{
	struct cdrom_info *cd = NULL;

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

69
	}
70
	mutex_unlock(&idecd_ref_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
71 72 73 74 75
	return cd;
}

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

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

Borislav Petkov's avatar
Borislav Petkov committed
84
/*
Linus Torvalds's avatar
Linus Torvalds committed
85 86 87
 * Generic packet command support and error handling routines.
 */

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

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

100
	ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key);
101

102
	if (!sense || !rq || (rq->cmd_flags & REQ_QUIET))
Linus Torvalds's avatar
Linus Torvalds committed
103 104 105
		return 0;

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

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

150 151
	ide_debug_log(IDE_DBG_SENSE, "error_code: 0x%x, sense_key: 0x%x",
				     sense->error_code, sense->sense_key);
152 153

	if (failed_command)
154 155
		ide_debug_log(IDE_DBG_SENSE, "failed cmd: 0x%x",
					     failed_command->cmd[0]);
156

Linus Torvalds's avatar
Linus Torvalds committed
157 158 159 160
	if (!cdrom_log_sense(drive, failed_command, sense))
		return;

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

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

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

206
	ide_cd_log_error(drive->name, failed_command, sense);
Linus Torvalds's avatar
Linus Torvalds committed
207 208 209 210 211 212
}

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

215
	ide_debug_log(IDE_DBG_SENSE, "enter");
216

Linus Torvalds's avatar
Linus Torvalds committed
217 218 219 220
	if (sense == NULL)
		sense = &info->sense_data;

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

	rq->data = sense;
	rq->cmd[0] = GPCMD_REQUEST_SENSE;
227 228
	rq->cmd[4] = 18;
	rq->data_len = 18;
Linus Torvalds's avatar
Linus Torvalds committed
229

230
	rq->cmd_type = REQ_TYPE_SENSE;
231
	rq->cmd_flags |= REQ_PREEMPT;
Linus Torvalds's avatar
Linus Torvalds committed
232 233 234 235

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

236
	if (failed_command)
237 238
		ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x",
					     failed_command->cmd[0]);
239

240 241 242
	drive->hwif->rq = NULL;

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

245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq)
{
	/*
	 * For REQ_TYPE_SENSE, "rq->buffer" points to the original
	 * failed request
	 */
	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;
		}
		cdrom_analyze_sense_data(drive, failed, sense);

		if (ide_end_rq(drive, failed, -EIO, blk_rq_bytes(failed)))
			BUG();
	} else
		cdrom_analyze_sense_data(drive, NULL, sense);
}

Borislav Petkov's avatar
Borislav Petkov committed
268 269 270
/*
 * Returns:
 * 0: if the request should be continued.
271 272
 * 1: if the request will be going through error recovery.
 * 2: if the request should be ended.
Borislav Petkov's avatar
Borislav Petkov committed
273
 */
Linus Torvalds's avatar
Linus Torvalds committed
274 275
static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
{
276
	ide_hwif_t *hwif = drive->hwif;
277
	struct request *rq = hwif->rq;
Linus Torvalds's avatar
Linus Torvalds committed
278
	int stat, err, sense_key;
279

Borislav Petkov's avatar
Borislav Petkov committed
280
	/* check for errors */
281
	stat = hwif->tp_ops->read_status(hwif);
282

Linus Torvalds's avatar
Linus Torvalds committed
283 284 285 286 287 288
	if (stat_ret)
		*stat_ret = stat;

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

Borislav Petkov's avatar
Borislav Petkov committed
289
	/* get the IDE error register */
290
	err = ide_read_error(drive);
Linus Torvalds's avatar
Linus Torvalds committed
291 292
	sense_key = err >> 4;

293 294 295 296
	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);
297

298
	if (blk_sense_request(rq)) {
Borislav Petkov's avatar
Borislav Petkov committed
299 300 301 302 303
		/*
		 * We got an error trying to get sense info from the drive
		 * (probably while trying to recover from a former error).
		 * Just give up.
		 */
304
		rq->cmd_flags |= REQ_FAILED;
305
		return 2;
306
	} else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
Linus Torvalds's avatar
Linus Torvalds committed
307 308 309 310 311 312
		/* All other functions, except for READ. */

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

Borislav Petkov's avatar
Borislav Petkov committed
316
		/* check for tray open */
Linus Torvalds's avatar
Linus Torvalds committed
317
		if (sense_key == NOT_READY) {
318
			cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
319
		} else if (sense_key == UNIT_ATTENTION) {
Borislav Petkov's avatar
Borislav Petkov committed
320
			/* check for media change */
321
			cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
322
			return 0;
323 324 325 326 327 328 329 330 331
		} 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!
			 */
332
		} else if (!(rq->cmd_flags & REQ_QUIET)) {
Borislav Petkov's avatar
Borislav Petkov committed
333
			/* otherwise, print an error */
Linus Torvalds's avatar
Linus Torvalds committed
334 335
			ide_dump_status(drive, "packet command error", stat);
		}
336

337
		rq->cmd_flags |= REQ_FAILED;
Linus Torvalds's avatar
Linus Torvalds committed
338 339 340 341 342 343

		/*
		 * instead of playing games with moving completions around,
		 * remove failed request completely and end it when the
		 * request sense has completed
		 */
344
		goto end_request;
Linus Torvalds's avatar
Linus Torvalds committed
345 346 347 348

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

Borislav Petkov's avatar
Borislav Petkov committed
349
		/* handle errors from READ and WRITE requests */
Linus Torvalds's avatar
Linus Torvalds committed
350 351 352 353 354

		if (blk_noretry_request(rq))
			do_end_request = 1;

		if (sense_key == NOT_READY) {
Borislav Petkov's avatar
Borislav Petkov committed
355
			/* tray open */
Linus Torvalds's avatar
Linus Torvalds committed
356
			if (rq_data_dir(rq) == READ) {
357
				cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
358

Borislav Petkov's avatar
Borislav Petkov committed
359
				/* fail the request */
360 361
				printk(KERN_ERR PFX "%s: tray open\n",
						drive->name);
Linus Torvalds's avatar
Linus Torvalds committed
362 363 364 365
				do_end_request = 1;
			} else {
				struct cdrom_info *info = drive->driver_data;

Borislav Petkov's avatar
Borislav Petkov committed
366 367
				/*
				 * Allow the drive 5 seconds to recover, some
Linus Torvalds's avatar
Linus Torvalds committed
368
				 * devices will return this error while flushing
Borislav Petkov's avatar
Borislav Petkov committed
369 370
				 * data from cache.
				 */
Linus Torvalds's avatar
Linus Torvalds committed
371
				if (!rq->errors)
372 373
					info->write_timeout = jiffies +
							ATAPI_WAIT_WRITE_BUSY;
Linus Torvalds's avatar
Linus Torvalds committed
374 375 376 377
				rq->errors = 1;
				if (time_after(jiffies, info->write_timeout))
					do_end_request = 1;
				else {
378
					struct request_queue *q = drive->queue;
Linus Torvalds's avatar
Linus Torvalds committed
379 380 381
					unsigned long flags;

					/*
Borislav Petkov's avatar
Borislav Petkov committed
382 383
					 * take a breather relying on the unplug
					 * timer to kick us again
Linus Torvalds's avatar
Linus Torvalds committed
384
					 */
385 386 387 388
					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
389 390 391 392
					return 1;
				}
			}
		} else if (sense_key == UNIT_ATTENTION) {
Borislav Petkov's avatar
Borislav Petkov committed
393
			/* media change */
394
			cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
395

396
			/*
Borislav Petkov's avatar
Borislav Petkov committed
397 398
			 * Arrange to retry the request but be sure to give up
			 * if we've retried too many times.
399
			 */
Linus Torvalds's avatar
Linus Torvalds committed
400 401 402 403
			if (++rq->errors > ERROR_MAX)
				do_end_request = 1;
		} else if (sense_key == ILLEGAL_REQUEST ||
			   sense_key == DATA_PROTECT) {
404
			/*
Borislav Petkov's avatar
Borislav Petkov committed
405 406
			 * No point in retrying after an illegal request or data
			 * protect error.
407
			 */
408
			ide_dump_status(drive, "command error", stat);
Linus Torvalds's avatar
Linus Torvalds committed
409 410
			do_end_request = 1;
		} else if (sense_key == MEDIUM_ERROR) {
411 412
			/*
			 * No point in re-trying a zillion times on a bad
Borislav Petkov's avatar
Borislav Petkov committed
413
			 * sector. If we got here the error is not correctable.
414
			 */
415 416
			ide_dump_status(drive, "media error (bad sector)",
					stat);
Linus Torvalds's avatar
Linus Torvalds committed
417 418
			do_end_request = 1;
		} else if (sense_key == BLANK_CHECK) {
Borislav Petkov's avatar
Borislav Petkov committed
419
			/* disk appears blank ?? */
420
			ide_dump_status(drive, "media error (blank)", stat);
Linus Torvalds's avatar
Linus Torvalds committed
421
			do_end_request = 1;
422
		} else if ((err & ~ATA_ABORTED) != 0) {
Borislav Petkov's avatar
Borislav Petkov committed
423
			/* go to the default handler for other errors */
Linus Torvalds's avatar
Linus Torvalds committed
424 425 426
			ide_error(drive, "cdrom_decode_status", stat);
			return 1;
		} else if ((++rq->errors > ERROR_MAX)) {
Borislav Petkov's avatar
Borislav Petkov committed
427
			/* we've racked up too many retries, abort */
Linus Torvalds's avatar
Linus Torvalds committed
428 429 430
			do_end_request = 1;
		}

Borislav Petkov's avatar
Borislav Petkov committed
431 432 433 434 435
		/*
		 * End a request through request sense analysis when we have
		 * sense data. We need this in order to perform end of media
		 * processing.
		 */
436 437
		if (do_end_request)
			goto end_request;
438

439
		/*
Borislav Petkov's avatar
Borislav Petkov committed
440 441
		 * If we got a CHECK_CONDITION status, queue
		 * a request sense command.
442
		 */
443
		if (stat & ATA_ERR)
444
			cdrom_queue_request_sense(drive, NULL, NULL);
445
		return 1;
Linus Torvalds's avatar
Linus Torvalds committed
446
	} else {
447
		blk_dump_rq_flags(rq, PFX "bad rq");
448
		return 2;
Linus Torvalds's avatar
Linus Torvalds committed
449 450
	}

451
end_request:
452
	if (stat & ATA_ERR) {
453
		struct request_queue *q = drive->queue;
454 455
		unsigned long flags;

456
		spin_lock_irqsave(q->queue_lock, flags);
457
		blkdev_dequeue_request(rq);
458
		spin_unlock_irqrestore(q->queue_lock, flags);
459

460
		hwif->rq = NULL;
461

462
		cdrom_queue_request_sense(drive, rq->sense, rq);
463
		return 1;
464
	} else
465
		return 2;
Linus Torvalds's avatar
Linus Torvalds committed
466 467 468 469 470 471 472
}

/*
 * 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.
 */
473 474
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
475
{
476 477
	ide_hwif_t *hwif = drive->hwif;

478
	ide_debug_log(IDE_DBG_FUNC, "ireason: 0x%x, rw: 0x%x", ireason, rw);
479

480 481 482 483 484
	/*
	 * 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
485
		return 0;
486
	else if (ireason == (rw << 1)) {
487

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

492
		ide_pad_transfer(drive, rw, len);
493
	} else  if (rw == 0 && ireason == 1) {
Borislav Petkov's avatar
Borislav Petkov committed
494 495 496
		/*
		 * Some drives (ASUS) seem to tell us that status info is
		 * available.  Just get it and ignore.
Linus Torvalds's avatar
Linus Torvalds committed
497
		 */
498
		(void)hwif->tp_ops->read_status(hwif);
Linus Torvalds's avatar
Linus Torvalds committed
499 500
		return 0;
	} else {
Borislav Petkov's avatar
Borislav Petkov committed
501
		/* drive wants a command packet, or invalid ireason... */
502
		printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n",
503
				drive->name, __func__, ireason);
Linus Torvalds's avatar
Linus Torvalds committed
504 505
	}

506 507 508
	if (rq->cmd_type == REQ_TYPE_ATA_PC)
		rq->cmd_flags |= REQ_FAILED;

Linus Torvalds's avatar
Linus Torvalds committed
509 510 511
	return -1;
}

512
static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd)
513
{
514 515
	struct request *rq = cmd->rq;

516
	ide_debug_log(IDE_DBG_FUNC, "rq->cmd[0]: 0x%x", rq->cmd[0]);
517

518 519 520 521 522
	/*
	 * Some of the trailing request sense fields are optional,
	 * and some drives don't send them.  Sigh.
	 */
	if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
523 524 525 526 527 528
	    cmd->nleft > 0 && cmd->nleft <= 5) {
		unsigned int ofs = cmd->nbytes - cmd->nleft;

		while (cmd->nleft > 0) {
			*((u8 *)rq->data + ofs++) = 0;
			cmd->nleft--;
529
		}
530
	}
531 532
}

533 534 535 536
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
537
{
538 539
	struct cdrom_info *info = drive->driver_data;
	struct request_sense local_sense;
Linus Torvalds's avatar
Linus Torvalds committed
540
	int retries = 10;
541
	unsigned int flags = 0;
Linus Torvalds's avatar
Linus Torvalds committed
542

543 544
	if (!sense)
		sense = &local_sense;
Linus Torvalds's avatar
Linus Torvalds committed
545

546 547 548
	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);
549

Borislav Petkov's avatar
Borislav Petkov committed
550
	/* start of retry loop */
Linus Torvalds's avatar
Linus Torvalds committed
551
	do {
552
		struct request *rq;
Linus Torvalds's avatar
Linus Torvalds committed
553 554
		int error;

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
		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
574

Borislav Petkov's avatar
Borislav Petkov committed
575 576 577 578
		/*
		 * FIXME: we should probably abort/retry or something in case of
		 * failure.
		 */
579
		if (flags & REQ_FAILED) {
Borislav Petkov's avatar
Borislav Petkov committed
580 581 582 583
			/*
			 * The request failed.  Retry if it was due to a unit
			 * attention status (usually means media was changed).
			 */
584
			struct request_sense *reqbuf = sense;
Linus Torvalds's avatar
Linus Torvalds committed
585 586 587 588 589

			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
590 591 592 593 594
				/*
				 * 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
595 596
				ssleep(2);
			} else {
Borislav Petkov's avatar
Borislav Petkov committed
597
				/* otherwise, don't retry */
Linus Torvalds's avatar
Linus Torvalds committed
598 599 600 601 602
				retries = 0;
			}
			--retries;
		}

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

Borislav Petkov's avatar
Borislav Petkov committed
606
	/* return an error if the command failed */
607
	return (flags & REQ_FAILED) ? -EIO : 0;
Linus Torvalds's avatar
Linus Torvalds committed
608 609
}

610 611 612 613 614 615 616 617 618 619 620
static void ide_cd_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
{
	unsigned int nr_bytes = cmd->nbytes - cmd->nleft;

	if (cmd->tf_flags & IDE_TFLAG_WRITE)
		nr_bytes -= cmd->last_xfer_len;

	if (nr_bytes > 0)
		ide_complete_rq(drive, 0, nr_bytes);
}

Linus Torvalds's avatar
Linus Torvalds committed
621 622
static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
{
623
	ide_hwif_t *hwif = drive->hwif;
624
	struct ide_cmd *cmd = &hwif->cmd;
625
	struct request *rq = hwif->rq;
626
	ide_expiry_t *expiry = NULL;
627
	int dma_error = 0, dma, stat, thislen, uptodate = 0;
628
	int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc, nsectors;
629
	int sense = blk_sense_request(rq);
630
	unsigned int timeout;
631 632
	u16 len;
	u8 ireason;
Linus Torvalds's avatar
Linus Torvalds committed
633

634 635
	ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x",
				  rq->cmd[0], write);
636

Borislav Petkov's avatar
Borislav Petkov committed
637
	/* check for errors */
638
	dma = drive->dma;
Linus Torvalds's avatar
Linus Torvalds committed
639
	if (dma) {
640
		drive->dma = 0;
641
		dma_error = hwif->dma_ops->dma_end(drive);
642
		ide_destroy_dmatable(drive);
643
		if (dma_error) {
644
			printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name,
645
					write ? "write" : "read");
646 647
			ide_dma_off(drive);
		}
Linus Torvalds's avatar
Linus Torvalds committed
648 649
	}

650 651 652 653
	rc = cdrom_decode_status(drive, 0, &stat);
	if (rc) {
		if (rc == 2)
			goto out_end;
Linus Torvalds's avatar
Linus Torvalds committed
654
		return ide_stopped;
655
	}
Linus Torvalds's avatar
Linus Torvalds committed
656

Borislav Petkov's avatar
Borislav Petkov committed
657
	/* using dma, transfer is complete now */
Linus Torvalds's avatar
Linus Torvalds committed
658
	if (dma) {
659
		if (dma_error)
Linus Torvalds's avatar
Linus Torvalds committed
660
			return ide_error(drive, "dma error", stat);
661
		uptodate = 1;
662
		goto out_end;
Linus Torvalds's avatar
Linus Torvalds committed
663 664
	}

665
	ide_read_bcount_and_ireason(drive, &len, &ireason);
666

667
	thislen = blk_fs_request(rq) ? len : cmd->nleft;
Linus Torvalds's avatar
Linus Torvalds committed
668 669 670
	if (thislen > len)
		thislen = len;

671 672
	ide_debug_log(IDE_DBG_PC, "DRQ: stat: 0x%x, thislen: %d",
				  stat, thislen);
673

Borislav Petkov's avatar
Borislav Petkov committed
674
	/* If DRQ is clear, the command has completed. */
675
	if ((stat & ATA_DRQ) == 0) {
676 677 678 679 680 681
		if (blk_fs_request(rq)) {
			/*
			 * If we're not done reading/writing, complain.
			 * Otherwise, complete the command normally.
			 */
			uptodate = 1;
682
			if (cmd->nleft > 0) {
683
				printk(KERN_ERR PFX "%s: %s: data underrun "
684 685
					"(%u bytes)\n", drive->name, __func__,
					cmd->nleft);
686 687 688 689 690
				if (!write)
					rq->cmd_flags |= REQ_FAILED;
				uptodate = 0;
			}
		} else if (!blk_pc_request(rq)) {
691
			ide_cd_request_sense_fixup(drive, cmd);
Borislav Petkov's avatar
Borislav Petkov committed
692
			/* complain if we still have data left to transfer */
693
			uptodate = cmd->nleft ? 0 : 1;
694 695
			if (uptodate == 0)
				rq->cmd_flags |= REQ_FAILED;
696
		}
697
		goto out_end;
698
	}
Linus Torvalds's avatar
Linus Torvalds committed
699

Borislav Petkov's avatar
Borislav Petkov committed
700
	/* check which way to transfer data */
701 702 703
	rc = ide_cd_check_ireason(drive, rq, len, ireason, write);
	if (rc)
		goto out_end;
704

705
	cmd->last_xfer_len = 0;
Linus Torvalds's avatar
Linus Torvalds committed
706

707 708 709
	ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, "
				  "ireason: 0x%x",
				  rq->cmd_type, ireason);
710

Borislav Petkov's avatar
Borislav Petkov committed
711
	/* transfer data */
Linus Torvalds's avatar
Linus Torvalds committed
712
	while (thislen > 0) {
713
		int blen = min_t(int, thislen, cmd->nleft);
Linus Torvalds's avatar
Linus Torvalds committed
714

715
		if (cmd->nleft == 0)
Linus Torvalds's avatar
Linus Torvalds committed
716 717
			break;

718 719
		ide_pio_bytes(drive, cmd, write, blen);
		cmd->last_xfer_len += blen;
Linus Torvalds's avatar
Linus Torvalds committed
720 721 722 723

		thislen -= blen;
		len -= blen;

724
		if (sense && write == 0)
Andreas Schwab's avatar
Andreas Schwab committed
725
			rq->sense_len += blen;
Linus Torvalds's avatar
Linus Torvalds committed
726 727
	}

Borislav Petkov's avatar
Borislav Petkov committed
728
	/* pad, if necessary */
729 730 731 732 733 734 735 736 737
	if (len > 0) {
		if (blk_fs_request(rq) == 0 || write == 0)
			ide_pad_transfer(drive, write, len);
		else {
			printk(KERN_ERR PFX "%s: confused, missing data\n",
				drive->name);
			blk_dump_rq_flags(rq, "cdrom_newpc_intr");
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
738

739 740 741 742
	if (blk_pc_request(rq)) {
		timeout = rq->timeout;
	} else {
		timeout = ATAPI_WAIT_PC;
743
		if (!blk_fs_request(rq))
744
			expiry = ide_cd_expiry;
745 746
	}

747 748
	hwif->expiry = expiry;
	ide_set_handler(drive, cdrom_newpc_intr, timeout);
Linus Torvalds's avatar
Linus Torvalds committed
749
	return ide_started;
750

751
out_end:
752
	if (blk_pc_request(rq) && rc == 0) {
753 754
		unsigned int dlen = rq->data_len;

755
		rq->data_len = 0;
756

757
		if (blk_end_request(rq, 0, dlen))
758
			BUG();
759

760
		hwif->rq = NULL;
761
	} else {
762 763 764 765
		if (sense && uptodate)
			ide_cd_complete_failed_rq(drive, rq);

		if (blk_fs_request(rq)) {
766
			if (cmd->nleft == 0)
767 768 769 770 771 772
				uptodate = 1;
		} else {
			if (uptodate <= 0 && rq->errors == 0)
				rq->errors = -EIO;
		}

773 774 775
		if (uptodate == 0)
			ide_cd_error_cmd(drive, cmd);

776 777 778 779
		/* make sure it's fully ended */
		if (blk_pc_request(rq))
			nsectors = (rq->data_len + 511) >> 9;
		else
780
			nsectors = rq->hard_nr_sectors;
781 782 783 784

		if (nsectors == 0)
			nsectors = 1;

785 786 787 788 789 790
		if (blk_fs_request(rq) == 0) {
			rq->data_len -= (cmd->nbytes - cmd->nleft);
			if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE))
				rq->data_len += cmd->last_xfer_len;
		}

791 792
		ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9);

793 794
		if (sense && rc == 2)
			ide_error(drive, "request sense failure", stat);
795 796
	}
	return ide_stopped;
Linus Torvalds's avatar
Linus Torvalds committed
797 798
}

799
static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
800
{
801
	struct cdrom_info *cd = drive->driver_data;
802
	struct request_queue *q = drive->queue;
803 804
	int write = rq_data_dir(rq) == WRITE;
	unsigned short sectors_per_frame =
805
		queue_hardsect_size(q) >> SECTOR_BITS;
Linus Torvalds's avatar
Linus Torvalds committed
806

807
	ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, "
808
				  "secs_per_frame: %u",
809
				  rq->cmd[0], rq->cmd_flags, sectors_per_frame);
810

811
	if (write) {
Borislav Petkov's avatar
Borislav Petkov committed
812
		/* disk has become write protected */
813
		if (get_disk_ro(cd->disk))
814 815 816 817 818 819
			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.
		 */
820
		q->prep_rq_fn(q, rq);
Linus Torvalds's avatar
Linus Torvalds committed
821 822
	}

823
	/* fs requests *must* be hardware frame aligned */
824
	if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
825 826 827 828 829
	    (rq->sector & (sectors_per_frame - 1)))
		return ide_stopped;

	/* use DMA, if possible */
	drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
Linus Torvalds's avatar
Linus Torvalds committed
830

831 832
	if (write)
		cd->devinfo.media_written = 1;
Linus Torvalds's avatar
Linus Torvalds committed
833

834 835
	rq->timeout = ATAPI_WAIT_PC;

836
	return ide_started;
Linus Torvalds's avatar
Linus Torvalds committed
837 838
}

839
static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
840 841
{

842 843
	ide_debug_log(IDE_DBG_PC, "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x",
				  rq->cmd[0], rq->cmd_type);
844

845 846 847