ide-cd.c 47 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
	if (sense == NULL)
		sense = &info->sense_data;

220 221
	memset(sense, 0, 18);

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

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

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

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

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

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

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

247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
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);
}

270

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

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

323 324 325
	ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, rq->cmd_type: 0x%x, err: 0x%x, "
				  "stat 0x%x",
				  rq->cmd[0], rq->cmd_type, err, stat);
326

327
	if (blk_sense_request(rq)) {
Borislav Petkov's avatar
Borislav Petkov committed
328 329 330 331 332
		/*
		 * We got an error trying to get sense info from the drive
		 * (probably while trying to recover from a former error).
		 * Just give up.
		 */
333
		rq->cmd_flags |= REQ_FAILED;
334
		return 2;
335
	}
Linus Torvalds's avatar
Linus Torvalds committed
336

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

341 342
	if (blk_noretry_request(rq))
		do_end_request = 1;
Linus Torvalds's avatar
Linus Torvalds committed
343

344 345
	switch (sense_key) {
	case NOT_READY:
346 347 348 349
		if (blk_fs_request(rq) && rq_data_dir(rq) == WRITE) {
			if (ide_cd_breathe(drive, rq))
				return 1;
		} else {
350
			cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
351

352 353 354
			if (blk_fs_request(rq) && !quiet)
				printk(KERN_ERR PFX "%s: tray open\n",
					drive->name);
Linus Torvalds's avatar
Linus Torvalds committed
355
		}
356 357 358 359
		do_end_request = 1;
		break;
	case UNIT_ATTENTION:
		cdrom_saw_media_change(drive);
Linus Torvalds's avatar
Linus Torvalds committed
360

361 362
		if (blk_fs_request(rq) == 0)
			return 0;
363

Borislav Petkov's avatar
Borislav Petkov committed
364
		/*
365 366
		 * Arrange to retry the request but be sure to give up if we've
		 * retried too many times.
Borislav Petkov's avatar
Borislav Petkov committed
367
		 */
368 369 370 371
		if (++rq->errors > ERROR_MAX)
			do_end_request = 1;
		break;
	case ILLEGAL_REQUEST:
372
		/*
373 374 375 376 377
		 * 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!
378
		 */
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
		if (rq->cmd[0] == GPCMD_START_STOP_UNIT)
			break;
		/* fall-through */
	case DATA_PROTECT:
		/*
		 * No point in retrying after an illegal request or data
		 * protect error.
		 */
		if (!quiet)
			ide_dump_status(drive, "command error", stat);
		do_end_request = 1;
		break;
	case MEDIUM_ERROR:
		/*
		 * No point in re-trying a zillion times on a bad sector.
		 * If we got here the error is not correctable.
		 */
		if (!quiet)
			ide_dump_status(drive, "media error "
					"(bad sector)", stat);
		do_end_request = 1;
		break;
	case BLANK_CHECK:
		/* disk appears blank? */
		if (!quiet)
			ide_dump_status(drive, "media error (blank)",
					stat);
		do_end_request = 1;
		break;
	default:
		if (blk_fs_request(rq) == 0)
			break;
		if (err & ~ATA_ABORTED) {
			/* 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;
Linus Torvalds's avatar
Linus Torvalds committed
418 419
	}

420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
	if (blk_fs_request(rq) == 0) {
		rq->cmd_flags |= REQ_FAILED;
		do_end_request = 1;
	}

	/*
	 * End a request through request sense analysis when we have sense data.
	 * We need this in order to perform end of media processing.
	 */
	if (do_end_request)
		goto end_request;

	/* if we got a CHECK_CONDITION status, queue a request sense command */
	if (stat & ATA_ERR)
		cdrom_queue_request_sense(drive, NULL, NULL);
	return 1;

437
end_request:
438
	if (stat & ATA_ERR) {
439
		struct request_queue *q = drive->queue;
440 441
		unsigned long flags;

442
		spin_lock_irqsave(q->queue_lock, flags);
443
		blkdev_dequeue_request(rq);
444
		spin_unlock_irqrestore(q->queue_lock, flags);
445

446
		hwif->rq = NULL;
447

448
		cdrom_queue_request_sense(drive, rq->sense, rq);
449
		return 1;
450
	} else
451
		return 2;
Linus Torvalds's avatar
Linus Torvalds committed
452 453 454 455 456 457 458
}

/*
 * 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.
 */
459 460
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
461
{
462 463
	ide_hwif_t *hwif = drive->hwif;

464
	ide_debug_log(IDE_DBG_FUNC, "ireason: 0x%x, rw: 0x%x", ireason, rw);
465

466 467 468 469 470
	/*
	 * 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
471
		return 0;
472
	else if (ireason == (rw << 1)) {
473

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

478
		ide_pad_transfer(drive, rw, len);
479
	} else  if (rw == 0 && ireason == 1) {
Borislav Petkov's avatar
Borislav Petkov committed
480 481 482
		/*
		 * Some drives (ASUS) seem to tell us that status info is
		 * available.  Just get it and ignore.
Linus Torvalds's avatar
Linus Torvalds committed
483
		 */
484
		(void)hwif->tp_ops->read_status(hwif);
Linus Torvalds's avatar
Linus Torvalds committed
485 486
		return 0;
	} else {
Borislav Petkov's avatar
Borislav Petkov committed
487
		/* drive wants a command packet, or invalid ireason... */
488
		printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n",
489
				drive->name, __func__, ireason);
Linus Torvalds's avatar
Linus Torvalds committed
490 491
	}

492 493 494
	if (rq->cmd_type == REQ_TYPE_ATA_PC)
		rq->cmd_flags |= REQ_FAILED;

Linus Torvalds's avatar
Linus Torvalds committed
495 496 497
	return -1;
}

498
static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd)
499
{
500 501
	struct request *rq = cmd->rq;

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

504 505 506 507 508
	/*
	 * Some of the trailing request sense fields are optional,
	 * and some drives don't send them.  Sigh.
	 */
	if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
509 510
	    cmd->nleft > 0 && cmd->nleft <= 5)
		cmd->nleft = 0;
511 512
}

513 514 515 516
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
517
{
518 519
	struct cdrom_info *info = drive->driver_data;
	struct request_sense local_sense;
Linus Torvalds's avatar
Linus Torvalds committed
520
	int retries = 10;
521
	unsigned int flags = 0;
Linus Torvalds's avatar
Linus Torvalds committed
522

523 524
	if (!sense)
		sense = &local_sense;
Linus Torvalds's avatar
Linus Torvalds committed
525

526 527 528
	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);
529

Borislav Petkov's avatar
Borislav Petkov committed
530
	/* start of retry loop */
Linus Torvalds's avatar
Linus Torvalds committed
531
	do {
532
		struct request *rq;
Linus Torvalds's avatar
Linus Torvalds committed
533 534
		int error;

535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
		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
554

Borislav Petkov's avatar
Borislav Petkov committed
555 556 557 558
		/*
		 * FIXME: we should probably abort/retry or something in case of
		 * failure.
		 */
559
		if (flags & REQ_FAILED) {
Borislav Petkov's avatar
Borislav Petkov committed
560 561 562 563
			/*
			 * The request failed.  Retry if it was due to a unit
			 * attention status (usually means media was changed).
			 */
564
			struct request_sense *reqbuf = sense;
Linus Torvalds's avatar
Linus Torvalds committed
565 566 567 568 569

			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
570 571 572 573 574
				/*
				 * 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
575 576
				ssleep(2);
			} else {
Borislav Petkov's avatar
Borislav Petkov committed
577
				/* otherwise, don't retry */
Linus Torvalds's avatar
Linus Torvalds committed
578 579 580 581 582
				retries = 0;
			}
			--retries;
		}

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

Borislav Petkov's avatar
Borislav Petkov committed
586
	/* return an error if the command failed */
587
	return (flags & REQ_FAILED) ? -EIO : 0;
Linus Torvalds's avatar
Linus Torvalds committed
588 589
}

590 591 592 593 594 595 596 597 598 599 600
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
601 602
static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
{
603
	ide_hwif_t *hwif = drive->hwif;
604
	struct ide_cmd *cmd = &hwif->cmd;
605
	struct request *rq = hwif->rq;
606
	ide_expiry_t *expiry = NULL;
607
	int dma_error = 0, dma, thislen, uptodate = 0;
608
	int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0, nsectors;
609
	int sense = blk_sense_request(rq);
610
	unsigned int timeout;
611
	u16 len;
612
	u8 ireason, stat;
Linus Torvalds's avatar
Linus Torvalds committed
613

614
	ide_debug_log(IDE_DBG_PC, "cmd: 0x%x, write: 0x%x", rq->cmd[0], write);
615

Borislav Petkov's avatar
Borislav Petkov committed
616
	/* check for errors */
617
	dma = drive->dma;
Linus Torvalds's avatar
Linus Torvalds committed
618
	if (dma) {
619
		drive->dma = 0;
620
		drive->waiting_for_dma = 0;
621
		dma_error = hwif->dma_ops->dma_end(drive);
622
		ide_dma_unmap_sg(drive, cmd);
623
		if (dma_error) {
624
			printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name,
625
					write ? "write" : "read");
626 627
			ide_dma_off(drive);
		}
Linus Torvalds's avatar
Linus Torvalds committed
628 629
	}

630 631 632 633 634 635 636 637 638 639
	/* 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;
		}
640
	}
Linus Torvalds's avatar
Linus Torvalds committed
641

Borislav Petkov's avatar
Borislav Petkov committed
642
	/* using dma, transfer is complete now */
Linus Torvalds's avatar
Linus Torvalds committed
643
	if (dma) {
644
		if (dma_error)
Linus Torvalds's avatar
Linus Torvalds committed
645
			return ide_error(drive, "dma error", stat);
646
		uptodate = 1;
647
		goto out_end;
Linus Torvalds's avatar
Linus Torvalds committed
648 649
	}

650
	ide_read_bcount_and_ireason(drive, &len, &ireason);
651

652
	thislen = blk_fs_request(rq) ? len : cmd->nleft;
Linus Torvalds's avatar
Linus Torvalds committed
653 654 655
	if (thislen > len)
		thislen = len;

656 657
	ide_debug_log(IDE_DBG_PC, "DRQ: stat: 0x%x, thislen: %d",
				  stat, thislen);
658

Borislav Petkov's avatar
Borislav Petkov committed
659
	/* If DRQ is clear, the command has completed. */
660
	if ((stat & ATA_DRQ) == 0) {
661 662 663 664 665 666
		if (blk_fs_request(rq)) {
			/*
			 * If we're not done reading/writing, complain.
			 * Otherwise, complete the command normally.
			 */
			uptodate = 1;
667
			if (cmd->nleft > 0) {
668
				printk(KERN_ERR PFX "%s: %s: data underrun "
669 670
					"(%u bytes)\n", drive->name, __func__,
					cmd->nleft);
671 672 673 674 675
				if (!write)
					rq->cmd_flags |= REQ_FAILED;
				uptodate = 0;
			}
		} else if (!blk_pc_request(rq)) {
676
			ide_cd_request_sense_fixup(drive, cmd);
Borislav Petkov's avatar
Borislav Petkov committed
677
			/* complain if we still have data left to transfer */
678
			uptodate = cmd->nleft ? 0 : 1;
679 680
			if (uptodate == 0)
				rq->cmd_flags |= REQ_FAILED;
681
		}
682
		goto out_end;
683
	}
Linus Torvalds's avatar
Linus Torvalds committed
684

Borislav Petkov's avatar
Borislav Petkov committed
685
	/* check which way to transfer data */
686 687 688
	rc = ide_cd_check_ireason(drive, rq, len, ireason, write);
	if (rc)
		goto out_end;
689

690
	cmd->last_xfer_len = 0;
Linus Torvalds's avatar
Linus Torvalds committed
691

692 693 694
	ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, "
				  "ireason: 0x%x",
				  rq->cmd_type, ireason);
695

Borislav Petkov's avatar
Borislav Petkov committed
696
	/* transfer data */
Linus Torvalds's avatar
Linus Torvalds committed
697
	while (thislen > 0) {
698
		int blen = min_t(int, thislen, cmd->nleft);
Linus Torvalds's avatar
Linus Torvalds committed
699

700
		if (cmd->nleft == 0)
Linus Torvalds's avatar
Linus Torvalds committed
701 702
			break;

703 704
		ide_pio_bytes(drive, cmd, write, blen);
		cmd->last_xfer_len += blen;
Linus Torvalds's avatar
Linus Torvalds committed
705 706 707 708

		thislen -= blen;
		len -= blen;

709
		if (sense && write == 0)
Andreas Schwab's avatar
Andreas Schwab committed
710
			rq->sense_len += blen;
Linus Torvalds's avatar
Linus Torvalds committed
711 712
	}

Borislav Petkov's avatar
Borislav Petkov committed
713
	/* pad, if necessary */
714 715 716 717 718 719 720 721 722
	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
723

724 725 726 727
	if (blk_pc_request(rq)) {
		timeout = rq->timeout;
	} else {
		timeout = ATAPI_WAIT_PC;
728
		if (!blk_fs_request(rq))
729
			expiry = ide_cd_expiry;
730 731
	}

732 733
	hwif->expiry = expiry;
	ide_set_handler(drive, cdrom_newpc_intr, timeout);
Linus Torvalds's avatar
Linus Torvalds committed
734
	return ide_started;
735

736
out_end:
737
	if (blk_pc_request(rq) && rc == 0) {
738 739
		unsigned int dlen = rq->data_len;

740
		rq->data_len = 0;
741

742
		if (blk_end_request(rq, 0, dlen))
743
			BUG();
744

745
		hwif->rq = NULL;
746
	} else {
747 748 749 750
		if (sense && uptodate)
			ide_cd_complete_failed_rq(drive, rq);

		if (blk_fs_request(rq)) {
751
			if (cmd->nleft == 0)
752 753 754 755 756 757
				uptodate = 1;
		} else {
			if (uptodate <= 0 && rq->errors == 0)
				rq->errors = -EIO;
		}

758 759 760
		if (uptodate == 0)
			ide_cd_error_cmd(drive, cmd);

761 762 763 764
		/* make sure it's fully ended */
		if (blk_pc_request(rq))
			nsectors = (rq->data_len + 511) >> 9;
		else
765
			nsectors = rq->hard_nr_sectors;
766 767 768 769

		if (nsectors == 0)
			nsectors = 1;

770 771 772 773 774 775
		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;
		}

776 777
		ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9);

778 779
		if (sense && rc == 2)
			ide_error(drive, "request sense failure", stat);
780 781
	}
	return ide_stopped;
Linus Torvalds's avatar
Linus Torvalds committed
782 783
}

784
static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
785
{
786
	struct cdrom_info *cd = drive->driver_data;
787
	struct request_queue *q = drive->queue;
788 789
	int write = rq_data_dir(rq) == WRITE;
	unsigned short sectors_per_frame =
790
		queue_hardsect_size(q) >> SECTOR_BITS;
Linus Torvalds's avatar
Linus Torvalds committed
791

792
	ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, "
793
				  "secs_per_frame: %u",
794
				  rq->cmd[0], rq->cmd_flags, sectors_per_frame);
795

796
	if (write) {
Borislav Petkov's avatar
Borislav Petkov committed
797
		/* disk has become write protected */
798
		if (get_disk_ro(cd->disk))
799 800 801 802 803 804
			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.
		 */
805
		q->prep_rq_fn(q, rq);
Linus Torvalds's avatar
Linus Torvalds committed
806 807
	}

808
	/* fs requests *must* be hardware frame aligned */
809
	if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
810 811 812 813 814
	    (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
815

816 817
	if (write)
		cd->devinfo.media_written = 1;
Linus Torvalds's avatar
Linus Torvalds committed
818

819 820
	rq->timeout = ATAPI_WAIT_PC;

821
	return ide_started;
Linus Torvalds's avatar
Linus Torvalds committed
822 823
}

824
static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
Linus Torvalds's avatar
Linus Torvalds committed
825 826
{

827 828
	ide_debug_log(IDE_DBG_PC, "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x",
				  rq->cmd[0], rq->cmd_type);
829

830 831 832 833
	if (blk_pc_request(rq))
		rq->cmd_flags |= REQ_QUIET;
	else
		rq->cmd_flags &= ~REQ_FAILED;
Linus Torvalds's avatar
Linus Torvalds committed
834

835
	drive->dma = 0;
Linus Torvalds's avatar
Linus Torvalds committed
836

Borislav Petkov's avatar
Borislav Petkov committed
837
	/* sg request */
838 839 840
	if (rq->bio || ((rq->cmd_type == REQ_TYPE_ATA_PC) && rq->data_len)) {
		struct request_queue *q = drive->queue;
		unsigned int alignment;
841
		char *buf;
Linus Torvalds's avatar
Linus Torvalds committed
842

843
		if (rq->bio)
844
			buf = bio_data(rq->bio);
845
		else
846
			buf = rq->data;
847

848
		drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
Linus Torvalds's avatar
Linus Torvalds committed
849 850 851

		/*
		 * check if dma is safe
852 853 854
		 *
		 * NOTE! The "len" and "addr" checks should possibly have
		 * separate masks.
Linus Torvalds's avatar
Linus Torvalds committed
855
		 */
856
		alignment = queue_dma_alignment(q) | q->dma_pad_mask;
857 858
		if ((unsigned long)buf & alignment
		    || rq->data_len & q->dma_pad_mask
859
		    || object_is_on_stack(buf))
860
			drive->dma = 0;
Linus Torvalds's avatar
Linus Torvalds committed
861 862 863
	}
}

864
static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
865
					sector_t block)
Linus Torvalds's avatar
Linus Torvalds committed
866
{
867
	struct ide_cmd cmd;
868
	int uptodate = 0, nsectors;
869

870 871 872 873 874
	ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, block: %llu",
				  rq->cmd[0], (unsigned long long)block);

	if (drive->debug_mask & IDE_DBG_RQ)
		blk_dump_rq_flags(rq, "ide_cd_do_request");
875

Linus Torvalds's avatar
Linus Torvalds committed
876
	if (blk_fs_request(rq)) {
877
		if (cdrom_start_rw(drive, rq) == ide_stopped)
878
			goto out_end;
879
	} else if (blk_sense_request(rq) || blk_pc_request(rq) ||
880
		   rq->cmd_type == REQ_TYPE_ATA_PC) {
881 882 883
		if (!rq->timeout)
			rq->timeout = ATAPI_WAIT_PC;