ide-cd.c 47.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
 * 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);
}

268

Borislav Petkov's avatar
Borislav Petkov committed
269
/*
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
 * Allow the drive 5 seconds to recover; some devices will return NOT_READY
 * while flushing data from cache.
 *
 * returns: 0 failed (write timeout expired)
 *	    1 success
 */
static int ide_cd_breathe(ide_drive_t *drive, struct request *rq)
{

	struct cdrom_info *info = drive->driver_data;

	if (!rq->errors)
		info->write_timeout = jiffies +	ATAPI_WAIT_WRITE_BUSY;

	rq->errors = 1;

	if (time_after(jiffies, info->write_timeout))
		return 0;
	else {
		struct request_queue *q = drive->queue;
		unsigned long flags;

		/*
		 * take a breather relying on the unplug timer to kick us again
		 */

		spin_lock_irqsave(q->queue_lock, flags);
		blk_plug_device(q);
		spin_unlock_irqrestore(q->queue_lock, flags);

		return 1;
	}
}

/**
Borislav Petkov's avatar
Borislav Petkov committed
305 306
 * Returns:
 * 0: if the request should be continued.
307 308
 * 1: if the request will be going through error recovery.
 * 2: if the request should be ended.
Borislav Petkov's avatar
Borislav Petkov committed
309
 */
310
static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
Linus Torvalds's avatar
Linus Torvalds committed
311
{
312
	ide_hwif_t *hwif = drive->hwif;
313
	struct request *rq = hwif->rq;
314
	int err, sense_key;
315
	u8 quiet = rq->cmd_flags & REQ_QUIET;
Linus Torvalds's avatar
Linus Torvalds committed
316

Borislav Petkov's avatar
Borislav Petkov committed
317
	/* get the IDE error register */
318
	err = ide_read_error(drive);
Linus Torvalds's avatar
Linus Torvalds committed
319 320
	sense_key = err >> 4;

321 322
	ide_debug_log(IDE_DBG_RQ, "cmd[0]: 0x%x, rq->cmd_type: 0x%x, err: 0x%x",
				  rq->cmd[0], rq->cmd_type, err);
323

324
	if (blk_sense_request(rq)) {
Borislav Petkov's avatar
Borislav Petkov committed
325 326 327 328 329
		/*
		 * We got an error trying to get sense info from the drive
		 * (probably while trying to recover from a former error).
		 * Just give up.
		 */
330
		rq->cmd_flags |= REQ_FAILED;
331
		return 2;
332
	} else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
Linus Torvalds's avatar
Linus Torvalds committed
333 334 335 336 337 338
		/* All other functions, except for READ. */

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

Borislav Petkov's avatar
Borislav Petkov committed
342
		/* check for tray open */
Linus Torvalds's avatar
Linus Torvalds committed
343
		if (sense_key == NOT_READY) {
344
			cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
345
		} else if (sense_key == UNIT_ATTENTION) {
Borislav Petkov's avatar
Borislav Petkov committed
346
			/* check for media change */
347
			cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
348
			return 0;
349 350 351 352 353 354 355 356 357
		} 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!
			 */
358
		} else if (!quiet) {
Borislav Petkov's avatar
Borislav Petkov committed
359
			/* otherwise, print an error */
Linus Torvalds's avatar
Linus Torvalds committed
360 361
			ide_dump_status(drive, "packet command error", stat);
		}
362

363
		rq->cmd_flags |= REQ_FAILED;
Linus Torvalds's avatar
Linus Torvalds committed
364 365 366 367 368 369

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

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

Borislav Petkov's avatar
Borislav Petkov committed
375
		/* handle errors from READ and WRITE requests */
Linus Torvalds's avatar
Linus Torvalds committed
376 377 378 379 380

		if (blk_noretry_request(rq))
			do_end_request = 1;

		if (sense_key == NOT_READY) {
Borislav Petkov's avatar
Borislav Petkov committed
381
			/* tray open */
Linus Torvalds's avatar
Linus Torvalds committed
382
			if (rq_data_dir(rq) == READ) {
383
				cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
384

Borislav Petkov's avatar
Borislav Petkov committed
385
				/* fail the request */
386 387
				if (!quiet)
					printk(KERN_ERR PFX "%s: tray open\n",
388
						drive->name);
Linus Torvalds's avatar
Linus Torvalds committed
389
			} else {
390
				if (ide_cd_breathe(drive, rq))
Linus Torvalds's avatar
Linus Torvalds committed
391 392
					return 1;
			}
393
			do_end_request = 1;
Linus Torvalds's avatar
Linus Torvalds committed
394
		} else if (sense_key == UNIT_ATTENTION) {
Borislav Petkov's avatar
Borislav Petkov committed
395
			/* media change */
396
			cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
397

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

Borislav Petkov's avatar
Borislav Petkov committed
437 438 439 440 441
		/*
		 * End a request through request sense analysis when we have
		 * sense data. We need this in order to perform end of media
		 * processing.
		 */
442 443
		if (do_end_request)
			goto end_request;
444

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

457
end_request:
458
	if (stat & ATA_ERR) {
459
		struct request_queue *q = drive->queue;
460 461
		unsigned long flags;

462
		spin_lock_irqsave(q->queue_lock, flags);
463
		blkdev_dequeue_request(rq);
464
		spin_unlock_irqrestore(q->queue_lock, flags);
465

466
		hwif->rq = NULL;
467

468
		cdrom_queue_request_sense(drive, rq->sense, rq);
469
		return 1;
470
	} else
471
		return 2;
Linus Torvalds's avatar
Linus Torvalds committed
472 473 474 475 476 477 478
}

/*
 * 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.
 */
479 480
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
481
{
482 483
	ide_hwif_t *hwif = drive->hwif;

484
	ide_debug_log(IDE_DBG_FUNC, "ireason: 0x%x, rw: 0x%x", ireason, rw);
485

486 487 488 489 490
	/*
	 * 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
491
		return 0;
492
	else if (ireason == (rw << 1)) {
493

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

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

512 513 514
	if (rq->cmd_type == REQ_TYPE_ATA_PC)
		rq->cmd_flags |= REQ_FAILED;

Linus Torvalds's avatar
Linus Torvalds committed
515 516 517
	return -1;
}

518
static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd)
519
{
520 521
	struct request *rq = cmd->rq;

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

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

		while (cmd->nleft > 0) {
			*((u8 *)rq->data + ofs++) = 0;
			cmd->nleft--;
535
		}
536
	}
537 538
}

539 540 541 542
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
543
{
544 545
	struct cdrom_info *info = drive->driver_data;
	struct request_sense local_sense;
Linus Torvalds's avatar
Linus Torvalds committed
546
	int retries = 10;
547
	unsigned int flags = 0;
Linus Torvalds's avatar
Linus Torvalds committed
548

549 550
	if (!sense)
		sense = &local_sense;
Linus Torvalds's avatar
Linus Torvalds committed
551

552 553 554
	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);
555

Borislav Petkov's avatar
Borislav Petkov committed
556
	/* start of retry loop */
Linus Torvalds's avatar
Linus Torvalds committed
557
	do {
558
		struct request *rq;
Linus Torvalds's avatar
Linus Torvalds committed
559 560
		int error;

561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
		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
580

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

			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
596 597 598 599 600
				/*
				 * 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
601 602
				ssleep(2);
			} else {
Borislav Petkov's avatar
Borislav Petkov committed
603
				/* otherwise, don't retry */
Linus Torvalds's avatar
Linus Torvalds committed
604 605 606 607 608
				retries = 0;
			}
			--retries;
		}

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

Borislav Petkov's avatar
Borislav Petkov committed
612
	/* return an error if the command failed */
613
	return (flags & REQ_FAILED) ? -EIO : 0;
Linus Torvalds's avatar
Linus Torvalds committed
614 615
}

616 617 618 619 620 621 622 623 624 625 626
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
627 628
static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
{
629
	ide_hwif_t *hwif = drive->hwif;
630
	struct ide_cmd *cmd = &hwif->cmd;
631
	struct request *rq = hwif->rq;
632
	ide_expiry_t *expiry = NULL;
633
	int dma_error = 0, dma, thislen, uptodate = 0;
634
	int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc, nsectors;
635
	int sense = blk_sense_request(rq);
636
	unsigned int timeout;
637
	u16 len;
638
	u8 ireason, stat;
Linus Torvalds's avatar
Linus Torvalds committed
639

640 641
	ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x",
				  rq->cmd[0], write);
642

Borislav Petkov's avatar
Borislav Petkov committed
643
	/* check for errors */
644
	dma = drive->dma;
Linus Torvalds's avatar
Linus Torvalds committed
645
	if (dma) {
646
		drive->dma = 0;
647
		drive->waiting_for_dma = 0;
648
		dma_error = hwif->dma_ops->dma_end(drive);
649
		ide_dma_unmap_sg(drive, cmd);
650
		if (dma_error) {
651
			printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name,
652
					write ? "write" : "read");
653 654
			ide_dma_off(drive);
		}
Linus Torvalds's avatar
Linus Torvalds committed
655 656
	}

657 658 659 660 661 662 663 664 665 666
	/* check status */
	stat = hwif->tp_ops->read_status(hwif);

	if (!OK_STAT(stat, 0, BAD_R_STAT)) {
		rc = cdrom_decode_status(drive, stat);
		if (rc) {
			if (rc == 2)
				goto out_end;
			return ide_stopped;
		}
667
	}
Linus Torvalds's avatar
Linus Torvalds committed
668

Borislav Petkov's avatar
Borislav Petkov committed
669
	/* using dma, transfer is complete now */
Linus Torvalds's avatar
Linus Torvalds committed
670
	if (dma) {
671
		if (dma_error)
Linus Torvalds's avatar
Linus Torvalds committed
672
			return ide_error(drive, "dma error", stat);
673
		uptodate = 1;
674
		goto out_end;
Linus Torvalds's avatar
Linus Torvalds committed
675 676
	}

677
	ide_read_bcount_and_ireason(drive, &len, &ireason);
678

679
	thislen = blk_fs_request(rq) ? len : cmd->nleft;
Linus Torvalds's avatar
Linus Torvalds committed
680 681 682
	if (thislen > len)
		thislen = len;

683 684
	ide_debug_log(IDE_DBG_PC, "DRQ: stat: 0x%x, thislen: %d",
				  stat, thislen);
685

Borislav Petkov's avatar
Borislav Petkov committed
686
	/* If DRQ is clear, the command has completed. */
687
	if ((stat & ATA_DRQ) == 0) {
688 689 690 691 692 693
		if (blk_fs_request(rq)) {
			/*
			 * If we're not done reading/writing, complain.
			 * Otherwise, complete the command normally.
			 */
			uptodate = 1;
694
			if (cmd->nleft > 0) {
695
				printk(KERN_ERR PFX "%s: %s: data underrun "
696 697
					"(%u bytes)\n", drive->name, __func__,
					cmd->nleft);
698 699 700 701 702
				if (!write)
					rq->cmd_flags |= REQ_FAILED;
				uptodate = 0;
			}
		} else if (!blk_pc_request(rq)) {
703
			ide_cd_request_sense_fixup(drive, cmd);
Borislav Petkov's avatar
Borislav Petkov committed
704
			/* complain if we still have data left to transfer */
705
			uptodate = cmd->nleft ? 0 : 1;
706 707
			if (uptodate == 0)
				rq->cmd_flags |= REQ_FAILED;
708
		}
709
		goto out_end;
710
	}
Linus Torvalds's avatar
Linus Torvalds committed
711

Borislav Petkov's avatar
Borislav Petkov committed
712
	/* check which way to transfer data */
713 714 715
	rc = ide_cd_check_ireason(drive, rq, len, ireason, write);
	if (rc)
		goto out_end;
716

717
	cmd->last_xfer_len = 0;
Linus Torvalds's avatar
Linus Torvalds committed
718

719 720 721
	ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, "
				  "ireason: 0x%x",
				  rq->cmd_type, ireason);
722

Borislav Petkov's avatar
Borislav Petkov committed
723
	/* transfer data */
Linus Torvalds's avatar
Linus Torvalds committed
724
	while (thislen > 0) {
725
		int blen = min_t(int, thislen, cmd->nleft);
Linus Torvalds's avatar
Linus Torvalds committed
726

727
		if (cmd->nleft == 0)
Linus Torvalds's avatar
Linus Torvalds committed
728 729
			break;

730 731
		ide_pio_bytes(drive, cmd, write, blen);
		cmd->last_xfer_len += blen;
Linus Torvalds's avatar
Linus Torvalds committed
732 733 734 735

		thislen -= blen;
		len -= blen;

736
		if (sense && write == 0)
Andreas Schwab's avatar
Andreas Schwab committed
737
			rq->sense_len += blen;
Linus Torvalds's avatar
Linus Torvalds committed
738 739
	}

Borislav Petkov's avatar
Borislav Petkov committed
740
	/* pad, if necessary */
741 742 743 744 745 746 747 748 749
	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
750

751 752 753 754
	if (blk_pc_request(rq)) {
		timeout = rq->timeout;
	} else {
		timeout = ATAPI_WAIT_PC;
755
		if (!blk_fs_request(rq))
756
			expiry = ide_cd_expiry;
757 758
	}

759 760
	hwif->expiry = expiry;
	ide_set_handler(drive, cdrom_newpc_intr, timeout);
Linus Torvalds's avatar
Linus Torvalds committed
761
	return ide_started;
762

763
out_end:
764
	if (blk_pc_request(rq) && rc == 0) {
765 766
		unsigned int dlen = rq->data_len;

767
		rq->data_len = 0;
768

769
		if (blk_end_request(rq, 0, dlen))
770
			BUG();
771

772
		hwif->rq = NULL;
773
	} else {
774 775 776 777
		if (sense && uptodate)
			ide_cd_complete_failed_rq(drive, rq);

		if (blk_fs_request(rq)) {
778
			if (cmd->nleft == 0)
779 780 781 782 783 784
				uptodate = 1;
		} else {
			if (uptodate <= 0 && rq->errors == 0)
				rq->errors = -EIO;
		}

785 786 787
		if (uptodate == 0)
			ide_cd_error_cmd(drive, cmd);

788 789 790 791
		/* make sure it's fully ended */
		if (blk_pc_request(rq))
			nsectors = (rq->data_len + 511) >> 9;
		else
792
			nsectors = rq->hard_nr_sectors;
793 794 795 796

		if (nsectors == 0)
			nsectors = 1;

797 798 799 800 801 802
		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;
		}

803 804
		ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9);

805 806
		if (sense && rc == 2)
			ide_error(drive, "request sense failure", stat);
807 808
	}
	return ide_stopped;
Linus Torvalds's avatar
Linus Torvalds committed
809 810
}

811
static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
812
{
813
	struct cdrom_info *cd = drive->driver_data;
814
	struct request_queue *q = drive->queue;
815 816
	int write = rq_data_dir(rq) == WRITE;
	unsigned short sectors_per_frame =
817
		queue_hardsect_size(q) >> SECTOR_BITS;
Linus Torvalds's avatar
Linus Torvalds committed
818

819
	ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, "
820
				  "secs_per_frame: %u",
821
				  rq->cmd[0], rq->cmd_flags, sectors_per_frame);
822

823
	if (write) {
Borislav Petkov's avatar
Borislav Petkov committed
824
		/* disk has become write protected */
825
		if (get_disk_ro(cd->disk))
826 827 828 829 830 831
			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.
		 */
832
		q->prep_rq_fn(q, rq);
Linus Torvalds's avatar
Linus Torvalds committed
833 834
	}

835
	/* fs requests *must* be hardware frame aligned */
836
	if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
837 838 839 840 841
	    (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
842

843 844
	if (write)
		cd->devinfo.media_written = 1;
Linus Torvalds's avatar
Linus Torvalds committed
845

846 847
	rq->timeout = ATAPI_WAIT_PC;

848
	return ide_started;
Linus Torvalds's avatar
Linus Torvalds committed
849 850
}

851
static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
852 853
{

854 855
	ide_debug_log(IDE_DBG_PC, "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x",
				  rq->cmd[0], rq->cmd_type);
856