xref: /kernel/linux/linux-5.10/drivers/ide/ide-cd.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * ATAPI CD-ROM driver.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 1994-1996   Scott Snyder <snyder@fnald0.fnal.gov>
58c2ecf20Sopenharmony_ci * Copyright (C) 1996-1998   Erik Andersen <andersee@debian.org>
68c2ecf20Sopenharmony_ci * Copyright (C) 1998-2000   Jens Axboe <axboe@suse.de>
78c2ecf20Sopenharmony_ci * Copyright (C) 2005, 2007-2009  Bartlomiej Zolnierkiewicz
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * May be copied or modified under the terms of the GNU General Public
108c2ecf20Sopenharmony_ci * License.  See linux/COPYING for more information.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * See Documentation/cdrom/ide-cd.rst for usage information.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Suggestions are welcome. Patches that work are more welcome though. ;-)
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Documentation:
178c2ecf20Sopenharmony_ci *	Mt. Fuji (SFF8090 version 4) and ATAPI (SFF-8020i rev 2.6) standards.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * For historical changelog please see:
208c2ecf20Sopenharmony_ci *	Documentation/ide/ChangeLog.ide-cd.1994-2004
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define DRV_NAME "ide-cd"
248c2ecf20Sopenharmony_ci#define PFX DRV_NAME ": "
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define IDECD_VERSION "5.00"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <linux/compat.h>
298c2ecf20Sopenharmony_ci#include <linux/module.h>
308c2ecf20Sopenharmony_ci#include <linux/types.h>
318c2ecf20Sopenharmony_ci#include <linux/kernel.h>
328c2ecf20Sopenharmony_ci#include <linux/sched/task_stack.h>
338c2ecf20Sopenharmony_ci#include <linux/delay.h>
348c2ecf20Sopenharmony_ci#include <linux/timer.h>
358c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
368c2ecf20Sopenharmony_ci#include <linux/slab.h>
378c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
388c2ecf20Sopenharmony_ci#include <linux/errno.h>
398c2ecf20Sopenharmony_ci#include <linux/cdrom.h>
408c2ecf20Sopenharmony_ci#include <linux/ide.h>
418c2ecf20Sopenharmony_ci#include <linux/completion.h>
428c2ecf20Sopenharmony_ci#include <linux/mutex.h>
438c2ecf20Sopenharmony_ci#include <linux/bcd.h>
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* For SCSI -> ATAPI command conversion */
468c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#include <linux/io.h>
498c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
508c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
518c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#include "ide-cd.h"
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(ide_cd_mutex);
568c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(idecd_ref_mutex);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic void ide_cd_release(struct device *);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic struct cdrom_info *ide_cd_get(struct gendisk *disk)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	struct cdrom_info *cd = NULL;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	mutex_lock(&idecd_ref_mutex);
658c2ecf20Sopenharmony_ci	cd = ide_drv_g(disk, cdrom_info);
668c2ecf20Sopenharmony_ci	if (cd) {
678c2ecf20Sopenharmony_ci		if (ide_device_get(cd->drive))
688c2ecf20Sopenharmony_ci			cd = NULL;
698c2ecf20Sopenharmony_ci		else
708c2ecf20Sopenharmony_ci			get_device(&cd->dev);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci	mutex_unlock(&idecd_ref_mutex);
748c2ecf20Sopenharmony_ci	return cd;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic void ide_cd_put(struct cdrom_info *cd)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	ide_drive_t *drive = cd->drive;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	mutex_lock(&idecd_ref_mutex);
828c2ecf20Sopenharmony_ci	put_device(&cd->dev);
838c2ecf20Sopenharmony_ci	ide_device_put(drive);
848c2ecf20Sopenharmony_ci	mutex_unlock(&idecd_ref_mutex);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/*
888c2ecf20Sopenharmony_ci * Generic packet command support and error handling routines.
898c2ecf20Sopenharmony_ci */
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/* Mark that we've seen a media change and invalidate our internal buffers. */
928c2ecf20Sopenharmony_cistatic void cdrom_saw_media_change(ide_drive_t *drive)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
958c2ecf20Sopenharmony_ci	drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int cdrom_log_sense(ide_drive_t *drive, struct request *rq)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct request_sense *sense = &drive->sense_data;
1018c2ecf20Sopenharmony_ci	int log = 0;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	if (!sense || !rq || (rq->rq_flags & RQF_QUIET))
1048c2ecf20Sopenharmony_ci		return 0;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	switch (sense->sense_key) {
1098c2ecf20Sopenharmony_ci	case NO_SENSE:
1108c2ecf20Sopenharmony_ci	case RECOVERED_ERROR:
1118c2ecf20Sopenharmony_ci		break;
1128c2ecf20Sopenharmony_ci	case NOT_READY:
1138c2ecf20Sopenharmony_ci		/*
1148c2ecf20Sopenharmony_ci		 * don't care about tray state messages for e.g. capacity
1158c2ecf20Sopenharmony_ci		 * commands or in-progress or becoming ready
1168c2ecf20Sopenharmony_ci		 */
1178c2ecf20Sopenharmony_ci		if (sense->asc == 0x3a || sense->asc == 0x04)
1188c2ecf20Sopenharmony_ci			break;
1198c2ecf20Sopenharmony_ci		log = 1;
1208c2ecf20Sopenharmony_ci		break;
1218c2ecf20Sopenharmony_ci	case ILLEGAL_REQUEST:
1228c2ecf20Sopenharmony_ci		/*
1238c2ecf20Sopenharmony_ci		 * don't log START_STOP unit with LoEj set, since we cannot
1248c2ecf20Sopenharmony_ci		 * reliably check if drive can auto-close
1258c2ecf20Sopenharmony_ci		 */
1268c2ecf20Sopenharmony_ci		if (scsi_req(rq)->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
1278c2ecf20Sopenharmony_ci			break;
1288c2ecf20Sopenharmony_ci		log = 1;
1298c2ecf20Sopenharmony_ci		break;
1308c2ecf20Sopenharmony_ci	case UNIT_ATTENTION:
1318c2ecf20Sopenharmony_ci		/*
1328c2ecf20Sopenharmony_ci		 * Make good and sure we've seen this potential media change.
1338c2ecf20Sopenharmony_ci		 * Some drives (i.e. Creative) fail to present the correct sense
1348c2ecf20Sopenharmony_ci		 * key in the error register.
1358c2ecf20Sopenharmony_ci		 */
1368c2ecf20Sopenharmony_ci		cdrom_saw_media_change(drive);
1378c2ecf20Sopenharmony_ci		break;
1388c2ecf20Sopenharmony_ci	default:
1398c2ecf20Sopenharmony_ci		log = 1;
1408c2ecf20Sopenharmony_ci		break;
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci	return log;
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic void cdrom_analyze_sense_data(ide_drive_t *drive,
1468c2ecf20Sopenharmony_ci				     struct request *failed_command)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	struct request_sense *sense = &drive->sense_data;
1498c2ecf20Sopenharmony_ci	struct cdrom_info *info = drive->driver_data;
1508c2ecf20Sopenharmony_ci	unsigned long sector;
1518c2ecf20Sopenharmony_ci	unsigned long bio_sectors;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_SENSE, "error_code: 0x%x, sense_key: 0x%x",
1548c2ecf20Sopenharmony_ci				     sense->error_code, sense->sense_key);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if (failed_command)
1578c2ecf20Sopenharmony_ci		ide_debug_log(IDE_DBG_SENSE, "failed cmd: 0x%x",
1588c2ecf20Sopenharmony_ci					     failed_command->cmd[0]);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (!cdrom_log_sense(drive, failed_command))
1618c2ecf20Sopenharmony_ci		return;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/*
1648c2ecf20Sopenharmony_ci	 * If a read toc is executed for a CD-R or CD-RW medium where the first
1658c2ecf20Sopenharmony_ci	 * toc has not been recorded yet, it will fail with 05/24/00 (which is a
1668c2ecf20Sopenharmony_ci	 * confusing error)
1678c2ecf20Sopenharmony_ci	 */
1688c2ecf20Sopenharmony_ci	if (failed_command && scsi_req(failed_command)->cmd[0] == GPCMD_READ_TOC_PMA_ATIP)
1698c2ecf20Sopenharmony_ci		if (sense->sense_key == 0x05 && sense->asc == 0x24)
1708c2ecf20Sopenharmony_ci			return;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	/* current error */
1738c2ecf20Sopenharmony_ci	if (sense->error_code == 0x70) {
1748c2ecf20Sopenharmony_ci		switch (sense->sense_key) {
1758c2ecf20Sopenharmony_ci		case MEDIUM_ERROR:
1768c2ecf20Sopenharmony_ci		case VOLUME_OVERFLOW:
1778c2ecf20Sopenharmony_ci		case ILLEGAL_REQUEST:
1788c2ecf20Sopenharmony_ci			if (!sense->valid)
1798c2ecf20Sopenharmony_ci				break;
1808c2ecf20Sopenharmony_ci			if (failed_command == NULL ||
1818c2ecf20Sopenharmony_ci			    blk_rq_is_passthrough(failed_command))
1828c2ecf20Sopenharmony_ci				break;
1838c2ecf20Sopenharmony_ci			sector = (sense->information[0] << 24) |
1848c2ecf20Sopenharmony_ci				 (sense->information[1] << 16) |
1858c2ecf20Sopenharmony_ci				 (sense->information[2] <<  8) |
1868c2ecf20Sopenharmony_ci				 (sense->information[3]);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci			if (queue_logical_block_size(drive->queue) == 2048)
1898c2ecf20Sopenharmony_ci				/* device sector size is 2K */
1908c2ecf20Sopenharmony_ci				sector <<= 2;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci			bio_sectors = max(bio_sectors(failed_command->bio), 4U);
1938c2ecf20Sopenharmony_ci			sector &= ~(bio_sectors - 1);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci			/*
1968c2ecf20Sopenharmony_ci			 * The SCSI specification allows for the value
1978c2ecf20Sopenharmony_ci			 * returned by READ CAPACITY to be up to 75 2K
1988c2ecf20Sopenharmony_ci			 * sectors past the last readable block.
1998c2ecf20Sopenharmony_ci			 * Therefore, if we hit a medium error within the
2008c2ecf20Sopenharmony_ci			 * last 75 2K sectors, we decrease the saved size
2018c2ecf20Sopenharmony_ci			 * value.
2028c2ecf20Sopenharmony_ci			 */
2038c2ecf20Sopenharmony_ci			if (sector < get_capacity(info->disk) &&
2048c2ecf20Sopenharmony_ci			    drive->probed_capacity - sector < 4 * 75)
2058c2ecf20Sopenharmony_ci				set_capacity(info->disk, sector);
2068c2ecf20Sopenharmony_ci		}
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	ide_cd_log_error(drive->name, failed_command, sense);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	/*
2158c2ecf20Sopenharmony_ci	 * For ATA_PRIV_SENSE, "ide_req(rq)->special" points to the original
2168c2ecf20Sopenharmony_ci	 * failed request.  Also, the sense data should be read
2178c2ecf20Sopenharmony_ci	 * directly from rq which might be different from the original
2188c2ecf20Sopenharmony_ci	 * sense buffer if it got copied during mapping.
2198c2ecf20Sopenharmony_ci	 */
2208c2ecf20Sopenharmony_ci	struct request *failed = ide_req(rq)->special;
2218c2ecf20Sopenharmony_ci	void *sense = bio_data(rq->bio);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (failed) {
2248c2ecf20Sopenharmony_ci		/*
2258c2ecf20Sopenharmony_ci		 * Sense is always read into drive->sense_data, copy back to the
2268c2ecf20Sopenharmony_ci		 * original request.
2278c2ecf20Sopenharmony_ci		 */
2288c2ecf20Sopenharmony_ci		memcpy(scsi_req(failed)->sense, sense, 18);
2298c2ecf20Sopenharmony_ci		scsi_req(failed)->sense_len = scsi_req(rq)->sense_len;
2308c2ecf20Sopenharmony_ci		cdrom_analyze_sense_data(drive, failed);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci		if (ide_end_rq(drive, failed, BLK_STS_IOERR, blk_rq_bytes(failed)))
2338c2ecf20Sopenharmony_ci			BUG();
2348c2ecf20Sopenharmony_ci	} else
2358c2ecf20Sopenharmony_ci		cdrom_analyze_sense_data(drive, NULL);
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci/*
2408c2ecf20Sopenharmony_ci * Allow the drive 5 seconds to recover; some devices will return NOT_READY
2418c2ecf20Sopenharmony_ci * while flushing data from cache.
2428c2ecf20Sopenharmony_ci *
2438c2ecf20Sopenharmony_ci * returns: 0 failed (write timeout expired)
2448c2ecf20Sopenharmony_ci *	    1 success
2458c2ecf20Sopenharmony_ci */
2468c2ecf20Sopenharmony_cistatic int ide_cd_breathe(ide_drive_t *drive, struct request *rq)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	struct cdrom_info *info = drive->driver_data;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (!scsi_req(rq)->result)
2528c2ecf20Sopenharmony_ci		info->write_timeout = jiffies +	ATAPI_WAIT_WRITE_BUSY;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	scsi_req(rq)->result = 1;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if (time_after(jiffies, info->write_timeout))
2578c2ecf20Sopenharmony_ci		return 0;
2588c2ecf20Sopenharmony_ci	else {
2598c2ecf20Sopenharmony_ci		/*
2608c2ecf20Sopenharmony_ci		 * take a breather
2618c2ecf20Sopenharmony_ci		 */
2628c2ecf20Sopenharmony_ci		blk_mq_requeue_request(rq, false);
2638c2ecf20Sopenharmony_ci		blk_mq_delay_kick_requeue_list(drive->queue, 1);
2648c2ecf20Sopenharmony_ci		return 1;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic void ide_cd_free_sense(ide_drive_t *drive)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	if (!drive->sense_rq)
2718c2ecf20Sopenharmony_ci		return;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	blk_mq_free_request(drive->sense_rq);
2748c2ecf20Sopenharmony_ci	drive->sense_rq = NULL;
2758c2ecf20Sopenharmony_ci	drive->sense_rq_armed = false;
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci/**
2798c2ecf20Sopenharmony_ci * Returns:
2808c2ecf20Sopenharmony_ci * 0: if the request should be continued.
2818c2ecf20Sopenharmony_ci * 1: if the request will be going through error recovery.
2828c2ecf20Sopenharmony_ci * 2: if the request should be ended.
2838c2ecf20Sopenharmony_ci */
2848c2ecf20Sopenharmony_cistatic int cdrom_decode_status(ide_drive_t *drive, u8 stat)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
2878c2ecf20Sopenharmony_ci	struct request *rq = hwif->rq;
2888c2ecf20Sopenharmony_ci	int err, sense_key, do_end_request = 0;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	/* get the IDE error register */
2918c2ecf20Sopenharmony_ci	err = ide_read_error(drive);
2928c2ecf20Sopenharmony_ci	sense_key = err >> 4;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, rq->cmd_type: 0x%x, err: 0x%x, "
2958c2ecf20Sopenharmony_ci				  "stat 0x%x",
2968c2ecf20Sopenharmony_ci				  rq->cmd[0], rq->cmd_type, err, stat);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (ata_sense_request(rq)) {
2998c2ecf20Sopenharmony_ci		/*
3008c2ecf20Sopenharmony_ci		 * We got an error trying to get sense info from the drive
3018c2ecf20Sopenharmony_ci		 * (probably while trying to recover from a former error).
3028c2ecf20Sopenharmony_ci		 * Just give up.
3038c2ecf20Sopenharmony_ci		 */
3048c2ecf20Sopenharmony_ci		rq->rq_flags |= RQF_FAILED;
3058c2ecf20Sopenharmony_ci		return 2;
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	/* if we have an error, pass CHECK_CONDITION as the SCSI status byte */
3098c2ecf20Sopenharmony_ci	if (blk_rq_is_scsi(rq) && !scsi_req(rq)->result)
3108c2ecf20Sopenharmony_ci		scsi_req(rq)->result = SAM_STAT_CHECK_CONDITION;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (blk_noretry_request(rq))
3138c2ecf20Sopenharmony_ci		do_end_request = 1;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	switch (sense_key) {
3168c2ecf20Sopenharmony_ci	case NOT_READY:
3178c2ecf20Sopenharmony_ci		if (req_op(rq) == REQ_OP_WRITE) {
3188c2ecf20Sopenharmony_ci			if (ide_cd_breathe(drive, rq))
3198c2ecf20Sopenharmony_ci				return 1;
3208c2ecf20Sopenharmony_ci		} else {
3218c2ecf20Sopenharmony_ci			cdrom_saw_media_change(drive);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci			if (!blk_rq_is_passthrough(rq) &&
3248c2ecf20Sopenharmony_ci			    !(rq->rq_flags & RQF_QUIET))
3258c2ecf20Sopenharmony_ci				printk(KERN_ERR PFX "%s: tray open\n",
3268c2ecf20Sopenharmony_ci					drive->name);
3278c2ecf20Sopenharmony_ci		}
3288c2ecf20Sopenharmony_ci		do_end_request = 1;
3298c2ecf20Sopenharmony_ci		break;
3308c2ecf20Sopenharmony_ci	case UNIT_ATTENTION:
3318c2ecf20Sopenharmony_ci		cdrom_saw_media_change(drive);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		if (blk_rq_is_passthrough(rq))
3348c2ecf20Sopenharmony_ci			return 0;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci		/*
3378c2ecf20Sopenharmony_ci		 * Arrange to retry the request but be sure to give up if we've
3388c2ecf20Sopenharmony_ci		 * retried too many times.
3398c2ecf20Sopenharmony_ci		 */
3408c2ecf20Sopenharmony_ci		if (++scsi_req(rq)->result > ERROR_MAX)
3418c2ecf20Sopenharmony_ci			do_end_request = 1;
3428c2ecf20Sopenharmony_ci		break;
3438c2ecf20Sopenharmony_ci	case ILLEGAL_REQUEST:
3448c2ecf20Sopenharmony_ci		/*
3458c2ecf20Sopenharmony_ci		 * Don't print error message for this condition -- SFF8090i
3468c2ecf20Sopenharmony_ci		 * indicates that 5/24/00 is the correct response to a request
3478c2ecf20Sopenharmony_ci		 * to close the tray if the drive doesn't have that capability.
3488c2ecf20Sopenharmony_ci		 *
3498c2ecf20Sopenharmony_ci		 * cdrom_log_sense() knows this!
3508c2ecf20Sopenharmony_ci		 */
3518c2ecf20Sopenharmony_ci		if (scsi_req(rq)->cmd[0] == GPCMD_START_STOP_UNIT)
3528c2ecf20Sopenharmony_ci			break;
3538c2ecf20Sopenharmony_ci		fallthrough;
3548c2ecf20Sopenharmony_ci	case DATA_PROTECT:
3558c2ecf20Sopenharmony_ci		/*
3568c2ecf20Sopenharmony_ci		 * No point in retrying after an illegal request or data
3578c2ecf20Sopenharmony_ci		 * protect error.
3588c2ecf20Sopenharmony_ci		 */
3598c2ecf20Sopenharmony_ci		if (!(rq->rq_flags & RQF_QUIET))
3608c2ecf20Sopenharmony_ci			ide_dump_status(drive, "command error", stat);
3618c2ecf20Sopenharmony_ci		do_end_request = 1;
3628c2ecf20Sopenharmony_ci		break;
3638c2ecf20Sopenharmony_ci	case MEDIUM_ERROR:
3648c2ecf20Sopenharmony_ci		/*
3658c2ecf20Sopenharmony_ci		 * No point in re-trying a zillion times on a bad sector.
3668c2ecf20Sopenharmony_ci		 * If we got here the error is not correctable.
3678c2ecf20Sopenharmony_ci		 */
3688c2ecf20Sopenharmony_ci		if (!(rq->rq_flags & RQF_QUIET))
3698c2ecf20Sopenharmony_ci			ide_dump_status(drive, "media error "
3708c2ecf20Sopenharmony_ci					"(bad sector)", stat);
3718c2ecf20Sopenharmony_ci		do_end_request = 1;
3728c2ecf20Sopenharmony_ci		break;
3738c2ecf20Sopenharmony_ci	case BLANK_CHECK:
3748c2ecf20Sopenharmony_ci		/* disk appears blank? */
3758c2ecf20Sopenharmony_ci		if (!(rq->rq_flags & RQF_QUIET))
3768c2ecf20Sopenharmony_ci			ide_dump_status(drive, "media error (blank)",
3778c2ecf20Sopenharmony_ci					stat);
3788c2ecf20Sopenharmony_ci		do_end_request = 1;
3798c2ecf20Sopenharmony_ci		break;
3808c2ecf20Sopenharmony_ci	default:
3818c2ecf20Sopenharmony_ci		if (blk_rq_is_passthrough(rq))
3828c2ecf20Sopenharmony_ci			break;
3838c2ecf20Sopenharmony_ci		if (err & ~ATA_ABORTED) {
3848c2ecf20Sopenharmony_ci			/* go to the default handler for other errors */
3858c2ecf20Sopenharmony_ci			ide_error(drive, "cdrom_decode_status", stat);
3868c2ecf20Sopenharmony_ci			return 1;
3878c2ecf20Sopenharmony_ci		} else if (++scsi_req(rq)->result > ERROR_MAX)
3888c2ecf20Sopenharmony_ci			/* we've racked up too many retries, abort */
3898c2ecf20Sopenharmony_ci			do_end_request = 1;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	if (blk_rq_is_passthrough(rq)) {
3938c2ecf20Sopenharmony_ci		rq->rq_flags |= RQF_FAILED;
3948c2ecf20Sopenharmony_ci		do_end_request = 1;
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	/*
3988c2ecf20Sopenharmony_ci	 * End a request through request sense analysis when we have sense data.
3998c2ecf20Sopenharmony_ci	 * We need this in order to perform end of media processing.
4008c2ecf20Sopenharmony_ci	 */
4018c2ecf20Sopenharmony_ci	if (do_end_request)
4028c2ecf20Sopenharmony_ci		goto end_request;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	/* if we got a CHECK_CONDITION status, queue a request sense command */
4058c2ecf20Sopenharmony_ci	if (stat & ATA_ERR)
4068c2ecf20Sopenharmony_ci		return ide_queue_sense_rq(drive, NULL) ? 2 : 1;
4078c2ecf20Sopenharmony_ci	return 1;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ciend_request:
4108c2ecf20Sopenharmony_ci	if (stat & ATA_ERR) {
4118c2ecf20Sopenharmony_ci		hwif->rq = NULL;
4128c2ecf20Sopenharmony_ci		return ide_queue_sense_rq(drive, rq) ? 2 : 1;
4138c2ecf20Sopenharmony_ci	} else
4148c2ecf20Sopenharmony_ci		return 2;
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_cistatic void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	struct request *rq = cmd->rq;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_FUNC, "rq->cmd[0]: 0x%x", rq->cmd[0]);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/*
4248c2ecf20Sopenharmony_ci	 * Some of the trailing request sense fields are optional,
4258c2ecf20Sopenharmony_ci	 * and some drives don't send them.  Sigh.
4268c2ecf20Sopenharmony_ci	 */
4278c2ecf20Sopenharmony_ci	if (scsi_req(rq)->cmd[0] == GPCMD_REQUEST_SENSE &&
4288c2ecf20Sopenharmony_ci	    cmd->nleft > 0 && cmd->nleft <= 5)
4298c2ecf20Sopenharmony_ci		cmd->nleft = 0;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ciint ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
4338c2ecf20Sopenharmony_ci		    int write, void *buffer, unsigned *bufflen,
4348c2ecf20Sopenharmony_ci		    struct scsi_sense_hdr *sshdr, int timeout,
4358c2ecf20Sopenharmony_ci		    req_flags_t rq_flags)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	struct cdrom_info *info = drive->driver_data;
4388c2ecf20Sopenharmony_ci	struct scsi_sense_hdr local_sshdr;
4398c2ecf20Sopenharmony_ci	int retries = 10;
4408c2ecf20Sopenharmony_ci	bool failed;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x, timeout: %d, "
4438c2ecf20Sopenharmony_ci				  "rq_flags: 0x%x",
4448c2ecf20Sopenharmony_ci				  cmd[0], write, timeout, rq_flags);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	if (!sshdr)
4478c2ecf20Sopenharmony_ci		sshdr = &local_sshdr;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/* start of retry loop */
4508c2ecf20Sopenharmony_ci	do {
4518c2ecf20Sopenharmony_ci		struct request *rq;
4528c2ecf20Sopenharmony_ci		int error;
4538c2ecf20Sopenharmony_ci		bool delay = false;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci		rq = blk_get_request(drive->queue,
4568c2ecf20Sopenharmony_ci			write ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
4578c2ecf20Sopenharmony_ci		memcpy(scsi_req(rq)->cmd, cmd, BLK_MAX_CDB);
4588c2ecf20Sopenharmony_ci		ide_req(rq)->type = ATA_PRIV_PC;
4598c2ecf20Sopenharmony_ci		rq->rq_flags |= rq_flags;
4608c2ecf20Sopenharmony_ci		rq->timeout = timeout;
4618c2ecf20Sopenharmony_ci		if (buffer) {
4628c2ecf20Sopenharmony_ci			error = blk_rq_map_kern(drive->queue, rq, buffer,
4638c2ecf20Sopenharmony_ci						*bufflen, GFP_NOIO);
4648c2ecf20Sopenharmony_ci			if (error) {
4658c2ecf20Sopenharmony_ci				blk_put_request(rq);
4668c2ecf20Sopenharmony_ci				return error;
4678c2ecf20Sopenharmony_ci			}
4688c2ecf20Sopenharmony_ci		}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci		blk_execute_rq(drive->queue, info->disk, rq, 0);
4718c2ecf20Sopenharmony_ci		error = scsi_req(rq)->result ? -EIO : 0;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci		if (buffer)
4748c2ecf20Sopenharmony_ci			*bufflen = scsi_req(rq)->resid_len;
4758c2ecf20Sopenharmony_ci		scsi_normalize_sense(scsi_req(rq)->sense,
4768c2ecf20Sopenharmony_ci				     scsi_req(rq)->sense_len, sshdr);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		/*
4798c2ecf20Sopenharmony_ci		 * FIXME: we should probably abort/retry or something in case of
4808c2ecf20Sopenharmony_ci		 * failure.
4818c2ecf20Sopenharmony_ci		 */
4828c2ecf20Sopenharmony_ci		failed = (rq->rq_flags & RQF_FAILED) != 0;
4838c2ecf20Sopenharmony_ci		if (failed) {
4848c2ecf20Sopenharmony_ci			/*
4858c2ecf20Sopenharmony_ci			 * The request failed.  Retry if it was due to a unit
4868c2ecf20Sopenharmony_ci			 * attention status (usually means media was changed).
4878c2ecf20Sopenharmony_ci			 */
4888c2ecf20Sopenharmony_ci			if (sshdr->sense_key == UNIT_ATTENTION)
4898c2ecf20Sopenharmony_ci				cdrom_saw_media_change(drive);
4908c2ecf20Sopenharmony_ci			else if (sshdr->sense_key == NOT_READY &&
4918c2ecf20Sopenharmony_ci				 sshdr->asc == 4 && sshdr->ascq != 4) {
4928c2ecf20Sopenharmony_ci				/*
4938c2ecf20Sopenharmony_ci				 * The drive is in the process of loading
4948c2ecf20Sopenharmony_ci				 * a disk.  Retry, but wait a little to give
4958c2ecf20Sopenharmony_ci				 * the drive time to complete the load.
4968c2ecf20Sopenharmony_ci				 */
4978c2ecf20Sopenharmony_ci				delay = true;
4988c2ecf20Sopenharmony_ci			} else {
4998c2ecf20Sopenharmony_ci				/* otherwise, don't retry */
5008c2ecf20Sopenharmony_ci				retries = 0;
5018c2ecf20Sopenharmony_ci			}
5028c2ecf20Sopenharmony_ci			--retries;
5038c2ecf20Sopenharmony_ci		}
5048c2ecf20Sopenharmony_ci		blk_put_request(rq);
5058c2ecf20Sopenharmony_ci		if (delay)
5068c2ecf20Sopenharmony_ci			ssleep(2);
5078c2ecf20Sopenharmony_ci	} while (failed && retries >= 0);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	/* return an error if the command failed */
5108c2ecf20Sopenharmony_ci	return failed ? -EIO : 0;
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci/*
5148c2ecf20Sopenharmony_ci * returns true if rq has been completed
5158c2ecf20Sopenharmony_ci */
5168c2ecf20Sopenharmony_cistatic bool ide_cd_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	unsigned int nr_bytes = cmd->nbytes - cmd->nleft;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	if (cmd->tf_flags & IDE_TFLAG_WRITE)
5218c2ecf20Sopenharmony_ci		nr_bytes -= cmd->last_xfer_len;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (nr_bytes > 0) {
5248c2ecf20Sopenharmony_ci		ide_complete_rq(drive, BLK_STS_OK, nr_bytes);
5258c2ecf20Sopenharmony_ci		return true;
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	return false;
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci/* standard prep_rq that builds 10 byte cmds */
5328c2ecf20Sopenharmony_cistatic bool ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	int hard_sect = queue_logical_block_size(q);
5358c2ecf20Sopenharmony_ci	long block = (long)blk_rq_pos(rq) / (hard_sect >> 9);
5368c2ecf20Sopenharmony_ci	unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9);
5378c2ecf20Sopenharmony_ci	struct scsi_request *req = scsi_req(rq);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	if (rq_data_dir(rq) == READ)
5408c2ecf20Sopenharmony_ci		req->cmd[0] = GPCMD_READ_10;
5418c2ecf20Sopenharmony_ci	else
5428c2ecf20Sopenharmony_ci		req->cmd[0] = GPCMD_WRITE_10;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	/*
5458c2ecf20Sopenharmony_ci	 * fill in lba
5468c2ecf20Sopenharmony_ci	 */
5478c2ecf20Sopenharmony_ci	req->cmd[2] = (block >> 24) & 0xff;
5488c2ecf20Sopenharmony_ci	req->cmd[3] = (block >> 16) & 0xff;
5498c2ecf20Sopenharmony_ci	req->cmd[4] = (block >>  8) & 0xff;
5508c2ecf20Sopenharmony_ci	req->cmd[5] = block & 0xff;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	/*
5538c2ecf20Sopenharmony_ci	 * and transfer length
5548c2ecf20Sopenharmony_ci	 */
5558c2ecf20Sopenharmony_ci	req->cmd[7] = (blocks >> 8) & 0xff;
5568c2ecf20Sopenharmony_ci	req->cmd[8] = blocks & 0xff;
5578c2ecf20Sopenharmony_ci	req->cmd_len = 10;
5588c2ecf20Sopenharmony_ci	return true;
5598c2ecf20Sopenharmony_ci}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci/*
5628c2ecf20Sopenharmony_ci * Most of the SCSI commands are supported directly by ATAPI devices.
5638c2ecf20Sopenharmony_ci * This transform handles the few exceptions.
5648c2ecf20Sopenharmony_ci */
5658c2ecf20Sopenharmony_cistatic bool ide_cdrom_prep_pc(struct request *rq)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	u8 *c = scsi_req(rq)->cmd;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	/* transform 6-byte read/write commands to the 10-byte version */
5708c2ecf20Sopenharmony_ci	if (c[0] == READ_6 || c[0] == WRITE_6) {
5718c2ecf20Sopenharmony_ci		c[8] = c[4];
5728c2ecf20Sopenharmony_ci		c[5] = c[3];
5738c2ecf20Sopenharmony_ci		c[4] = c[2];
5748c2ecf20Sopenharmony_ci		c[3] = c[1] & 0x1f;
5758c2ecf20Sopenharmony_ci		c[2] = 0;
5768c2ecf20Sopenharmony_ci		c[1] &= 0xe0;
5778c2ecf20Sopenharmony_ci		c[0] += (READ_10 - READ_6);
5788c2ecf20Sopenharmony_ci		scsi_req(rq)->cmd_len = 10;
5798c2ecf20Sopenharmony_ci		return true;
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	/*
5838c2ecf20Sopenharmony_ci	 * it's silly to pretend we understand 6-byte sense commands, just
5848c2ecf20Sopenharmony_ci	 * reject with ILLEGAL_REQUEST and the caller should take the
5858c2ecf20Sopenharmony_ci	 * appropriate action
5868c2ecf20Sopenharmony_ci	 */
5878c2ecf20Sopenharmony_ci	if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
5888c2ecf20Sopenharmony_ci		scsi_req(rq)->result = ILLEGAL_REQUEST;
5898c2ecf20Sopenharmony_ci		return false;
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	return true;
5938c2ecf20Sopenharmony_ci}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cistatic bool ide_cdrom_prep_rq(ide_drive_t *drive, struct request *rq)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	if (!blk_rq_is_passthrough(rq)) {
5988c2ecf20Sopenharmony_ci		scsi_req_init(scsi_req(rq));
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci		return ide_cdrom_prep_fs(drive->queue, rq);
6018c2ecf20Sopenharmony_ci	} else if (blk_rq_is_scsi(rq))
6028c2ecf20Sopenharmony_ci		return ide_cdrom_prep_pc(rq);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	return true;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
6108c2ecf20Sopenharmony_ci	struct ide_cmd *cmd = &hwif->cmd;
6118c2ecf20Sopenharmony_ci	struct request *rq = hwif->rq;
6128c2ecf20Sopenharmony_ci	ide_expiry_t *expiry = NULL;
6138c2ecf20Sopenharmony_ci	int dma_error = 0, dma, thislen, uptodate = 0;
6148c2ecf20Sopenharmony_ci	int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0;
6158c2ecf20Sopenharmony_ci	int sense = ata_sense_request(rq);
6168c2ecf20Sopenharmony_ci	unsigned int timeout;
6178c2ecf20Sopenharmony_ci	u16 len;
6188c2ecf20Sopenharmony_ci	u8 ireason, stat;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_PC, "cmd: 0x%x, write: 0x%x", rq->cmd[0], write);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	/* check for errors */
6238c2ecf20Sopenharmony_ci	dma = drive->dma;
6248c2ecf20Sopenharmony_ci	if (dma) {
6258c2ecf20Sopenharmony_ci		drive->dma = 0;
6268c2ecf20Sopenharmony_ci		drive->waiting_for_dma = 0;
6278c2ecf20Sopenharmony_ci		dma_error = hwif->dma_ops->dma_end(drive);
6288c2ecf20Sopenharmony_ci		ide_dma_unmap_sg(drive, cmd);
6298c2ecf20Sopenharmony_ci		if (dma_error) {
6308c2ecf20Sopenharmony_ci			printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name,
6318c2ecf20Sopenharmony_ci					write ? "write" : "read");
6328c2ecf20Sopenharmony_ci			ide_dma_off(drive);
6338c2ecf20Sopenharmony_ci		}
6348c2ecf20Sopenharmony_ci	}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	/* check status */
6378c2ecf20Sopenharmony_ci	stat = hwif->tp_ops->read_status(hwif);
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	if (!OK_STAT(stat, 0, BAD_R_STAT)) {
6408c2ecf20Sopenharmony_ci		rc = cdrom_decode_status(drive, stat);
6418c2ecf20Sopenharmony_ci		if (rc) {
6428c2ecf20Sopenharmony_ci			if (rc == 2)
6438c2ecf20Sopenharmony_ci				goto out_end;
6448c2ecf20Sopenharmony_ci			return ide_stopped;
6458c2ecf20Sopenharmony_ci		}
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	/* using dma, transfer is complete now */
6498c2ecf20Sopenharmony_ci	if (dma) {
6508c2ecf20Sopenharmony_ci		if (dma_error)
6518c2ecf20Sopenharmony_ci			return ide_error(drive, "dma error", stat);
6528c2ecf20Sopenharmony_ci		uptodate = 1;
6538c2ecf20Sopenharmony_ci		goto out_end;
6548c2ecf20Sopenharmony_ci	}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	ide_read_bcount_and_ireason(drive, &len, &ireason);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	thislen = !blk_rq_is_passthrough(rq) ? len : cmd->nleft;
6598c2ecf20Sopenharmony_ci	if (thislen > len)
6608c2ecf20Sopenharmony_ci		thislen = len;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_PC, "DRQ: stat: 0x%x, thislen: %d",
6638c2ecf20Sopenharmony_ci				  stat, thislen);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	/* If DRQ is clear, the command has completed. */
6668c2ecf20Sopenharmony_ci	if ((stat & ATA_DRQ) == 0) {
6678c2ecf20Sopenharmony_ci		switch (req_op(rq)) {
6688c2ecf20Sopenharmony_ci		default:
6698c2ecf20Sopenharmony_ci			/*
6708c2ecf20Sopenharmony_ci			 * If we're not done reading/writing, complain.
6718c2ecf20Sopenharmony_ci			 * Otherwise, complete the command normally.
6728c2ecf20Sopenharmony_ci			 */
6738c2ecf20Sopenharmony_ci			uptodate = 1;
6748c2ecf20Sopenharmony_ci			if (cmd->nleft > 0) {
6758c2ecf20Sopenharmony_ci				printk(KERN_ERR PFX "%s: %s: data underrun "
6768c2ecf20Sopenharmony_ci					"(%u bytes)\n", drive->name, __func__,
6778c2ecf20Sopenharmony_ci					cmd->nleft);
6788c2ecf20Sopenharmony_ci				if (!write)
6798c2ecf20Sopenharmony_ci					rq->rq_flags |= RQF_FAILED;
6808c2ecf20Sopenharmony_ci				uptodate = 0;
6818c2ecf20Sopenharmony_ci			}
6828c2ecf20Sopenharmony_ci			goto out_end;
6838c2ecf20Sopenharmony_ci		case REQ_OP_DRV_IN:
6848c2ecf20Sopenharmony_ci		case REQ_OP_DRV_OUT:
6858c2ecf20Sopenharmony_ci			ide_cd_request_sense_fixup(drive, cmd);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci			uptodate = cmd->nleft ? 0 : 1;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci			/*
6908c2ecf20Sopenharmony_ci			 * suck out the remaining bytes from the drive in an
6918c2ecf20Sopenharmony_ci			 * attempt to complete the data xfer. (see BZ#13399)
6928c2ecf20Sopenharmony_ci			 */
6938c2ecf20Sopenharmony_ci			if (!(stat & ATA_ERR) && !uptodate && thislen) {
6948c2ecf20Sopenharmony_ci				ide_pio_bytes(drive, cmd, write, thislen);
6958c2ecf20Sopenharmony_ci				uptodate = cmd->nleft ? 0 : 1;
6968c2ecf20Sopenharmony_ci			}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci			if (!uptodate)
6998c2ecf20Sopenharmony_ci				rq->rq_flags |= RQF_FAILED;
7008c2ecf20Sopenharmony_ci			goto out_end;
7018c2ecf20Sopenharmony_ci		case REQ_OP_SCSI_IN:
7028c2ecf20Sopenharmony_ci		case REQ_OP_SCSI_OUT:
7038c2ecf20Sopenharmony_ci			goto out_end;
7048c2ecf20Sopenharmony_ci		}
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	rc = ide_check_ireason(drive, rq, len, ireason, write);
7088c2ecf20Sopenharmony_ci	if (rc)
7098c2ecf20Sopenharmony_ci		goto out_end;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	cmd->last_xfer_len = 0;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, "
7148c2ecf20Sopenharmony_ci				  "ireason: 0x%x",
7158c2ecf20Sopenharmony_ci				  rq->cmd_type, ireason);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	/* transfer data */
7188c2ecf20Sopenharmony_ci	while (thislen > 0) {
7198c2ecf20Sopenharmony_ci		int blen = min_t(int, thislen, cmd->nleft);
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci		if (cmd->nleft == 0)
7228c2ecf20Sopenharmony_ci			break;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci		ide_pio_bytes(drive, cmd, write, blen);
7258c2ecf20Sopenharmony_ci		cmd->last_xfer_len += blen;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci		thislen -= blen;
7288c2ecf20Sopenharmony_ci		len -= blen;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci		if (sense && write == 0)
7318c2ecf20Sopenharmony_ci			scsi_req(rq)->sense_len += blen;
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	/* pad, if necessary */
7358c2ecf20Sopenharmony_ci	if (len > 0) {
7368c2ecf20Sopenharmony_ci		if (blk_rq_is_passthrough(rq) || write == 0)
7378c2ecf20Sopenharmony_ci			ide_pad_transfer(drive, write, len);
7388c2ecf20Sopenharmony_ci		else {
7398c2ecf20Sopenharmony_ci			printk(KERN_ERR PFX "%s: confused, missing data\n",
7408c2ecf20Sopenharmony_ci				drive->name);
7418c2ecf20Sopenharmony_ci			blk_dump_rq_flags(rq, "cdrom_newpc_intr");
7428c2ecf20Sopenharmony_ci		}
7438c2ecf20Sopenharmony_ci	}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	switch (req_op(rq)) {
7468c2ecf20Sopenharmony_ci	case REQ_OP_SCSI_IN:
7478c2ecf20Sopenharmony_ci	case REQ_OP_SCSI_OUT:
7488c2ecf20Sopenharmony_ci		timeout = rq->timeout;
7498c2ecf20Sopenharmony_ci		break;
7508c2ecf20Sopenharmony_ci	case REQ_OP_DRV_IN:
7518c2ecf20Sopenharmony_ci	case REQ_OP_DRV_OUT:
7528c2ecf20Sopenharmony_ci		expiry = ide_cd_expiry;
7538c2ecf20Sopenharmony_ci		fallthrough;
7548c2ecf20Sopenharmony_ci	default:
7558c2ecf20Sopenharmony_ci		timeout = ATAPI_WAIT_PC;
7568c2ecf20Sopenharmony_ci		break;
7578c2ecf20Sopenharmony_ci	}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	hwif->expiry = expiry;
7608c2ecf20Sopenharmony_ci	ide_set_handler(drive, cdrom_newpc_intr, timeout);
7618c2ecf20Sopenharmony_ci	return ide_started;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ciout_end:
7648c2ecf20Sopenharmony_ci	if (blk_rq_is_scsi(rq) && rc == 0) {
7658c2ecf20Sopenharmony_ci		scsi_req(rq)->resid_len = 0;
7668c2ecf20Sopenharmony_ci		blk_mq_end_request(rq, BLK_STS_OK);
7678c2ecf20Sopenharmony_ci		hwif->rq = NULL;
7688c2ecf20Sopenharmony_ci	} else {
7698c2ecf20Sopenharmony_ci		if (sense && uptodate)
7708c2ecf20Sopenharmony_ci			ide_cd_complete_failed_rq(drive, rq);
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci		if (!blk_rq_is_passthrough(rq)) {
7738c2ecf20Sopenharmony_ci			if (cmd->nleft == 0)
7748c2ecf20Sopenharmony_ci				uptodate = 1;
7758c2ecf20Sopenharmony_ci		} else {
7768c2ecf20Sopenharmony_ci			if (uptodate <= 0 && scsi_req(rq)->result == 0)
7778c2ecf20Sopenharmony_ci				scsi_req(rq)->result = -EIO;
7788c2ecf20Sopenharmony_ci		}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci		if (uptodate == 0 && rq->bio)
7818c2ecf20Sopenharmony_ci			if (ide_cd_error_cmd(drive, cmd))
7828c2ecf20Sopenharmony_ci				return ide_stopped;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci		/* make sure it's fully ended */
7858c2ecf20Sopenharmony_ci		if (blk_rq_is_passthrough(rq)) {
7868c2ecf20Sopenharmony_ci			scsi_req(rq)->resid_len -= cmd->nbytes - cmd->nleft;
7878c2ecf20Sopenharmony_ci			if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE))
7888c2ecf20Sopenharmony_ci				scsi_req(rq)->resid_len += cmd->last_xfer_len;
7898c2ecf20Sopenharmony_ci		}
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci		ide_complete_rq(drive, uptodate ? BLK_STS_OK : BLK_STS_IOERR, blk_rq_bytes(rq));
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci		if (sense && rc == 2)
7948c2ecf20Sopenharmony_ci			ide_error(drive, "request sense failure", stat);
7958c2ecf20Sopenharmony_ci	}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	ide_cd_free_sense(drive);
7988c2ecf20Sopenharmony_ci	return ide_stopped;
7998c2ecf20Sopenharmony_ci}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_cistatic ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	struct cdrom_info *cd = drive->driver_data;
8048c2ecf20Sopenharmony_ci	struct request_queue *q = drive->queue;
8058c2ecf20Sopenharmony_ci	int write = rq_data_dir(rq) == WRITE;
8068c2ecf20Sopenharmony_ci	unsigned short sectors_per_frame =
8078c2ecf20Sopenharmony_ci		queue_logical_block_size(q) >> SECTOR_SHIFT;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, "
8108c2ecf20Sopenharmony_ci				  "secs_per_frame: %u",
8118c2ecf20Sopenharmony_ci				  rq->cmd[0], rq->cmd_flags, sectors_per_frame);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	if (write) {
8148c2ecf20Sopenharmony_ci		/* disk has become write protected */
8158c2ecf20Sopenharmony_ci		if (get_disk_ro(cd->disk))
8168c2ecf20Sopenharmony_ci			return ide_stopped;
8178c2ecf20Sopenharmony_ci	} else {
8188c2ecf20Sopenharmony_ci		/*
8198c2ecf20Sopenharmony_ci		 * We may be retrying this request after an error.  Fix up any
8208c2ecf20Sopenharmony_ci		 * weirdness which might be present in the request packet.
8218c2ecf20Sopenharmony_ci		 */
8228c2ecf20Sopenharmony_ci		ide_cdrom_prep_rq(drive, rq);
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	/* fs requests *must* be hardware frame aligned */
8268c2ecf20Sopenharmony_ci	if ((blk_rq_sectors(rq) & (sectors_per_frame - 1)) ||
8278c2ecf20Sopenharmony_ci	    (blk_rq_pos(rq) & (sectors_per_frame - 1)))
8288c2ecf20Sopenharmony_ci		return ide_stopped;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	/* use DMA, if possible */
8318c2ecf20Sopenharmony_ci	drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	if (write)
8348c2ecf20Sopenharmony_ci		cd->devinfo.media_written = 1;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	rq->timeout = ATAPI_WAIT_PC;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	return ide_started;
8398c2ecf20Sopenharmony_ci}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_cistatic void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
8428c2ecf20Sopenharmony_ci{
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_PC, "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x",
8458c2ecf20Sopenharmony_ci				  rq->cmd[0], rq->cmd_type);
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	if (blk_rq_is_scsi(rq))
8488c2ecf20Sopenharmony_ci		rq->rq_flags |= RQF_QUIET;
8498c2ecf20Sopenharmony_ci	else
8508c2ecf20Sopenharmony_ci		rq->rq_flags &= ~RQF_FAILED;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	drive->dma = 0;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	/* sg request */
8558c2ecf20Sopenharmony_ci	if (rq->bio) {
8568c2ecf20Sopenharmony_ci		struct request_queue *q = drive->queue;
8578c2ecf20Sopenharmony_ci		char *buf = bio_data(rq->bio);
8588c2ecf20Sopenharmony_ci		unsigned int alignment;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci		drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci		/*
8638c2ecf20Sopenharmony_ci		 * check if dma is safe
8648c2ecf20Sopenharmony_ci		 *
8658c2ecf20Sopenharmony_ci		 * NOTE! The "len" and "addr" checks should possibly have
8668c2ecf20Sopenharmony_ci		 * separate masks.
8678c2ecf20Sopenharmony_ci		 */
8688c2ecf20Sopenharmony_ci		alignment = queue_dma_alignment(q) | q->dma_pad_mask;
8698c2ecf20Sopenharmony_ci		if ((unsigned long)buf & alignment
8708c2ecf20Sopenharmony_ci		    || blk_rq_bytes(rq) & q->dma_pad_mask
8718c2ecf20Sopenharmony_ci		    || object_is_on_stack(buf))
8728c2ecf20Sopenharmony_ci			drive->dma = 0;
8738c2ecf20Sopenharmony_ci	}
8748c2ecf20Sopenharmony_ci}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_cistatic ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
8778c2ecf20Sopenharmony_ci					sector_t block)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	struct ide_cmd cmd;
8808c2ecf20Sopenharmony_ci	int uptodate = 0;
8818c2ecf20Sopenharmony_ci	unsigned int nsectors;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, block: %llu",
8848c2ecf20Sopenharmony_ci				  rq->cmd[0], (unsigned long long)block);
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	if (drive->debug_mask & IDE_DBG_RQ)
8878c2ecf20Sopenharmony_ci		blk_dump_rq_flags(rq, "ide_cd_do_request");
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	switch (req_op(rq)) {
8908c2ecf20Sopenharmony_ci	default:
8918c2ecf20Sopenharmony_ci		if (cdrom_start_rw(drive, rq) == ide_stopped)
8928c2ecf20Sopenharmony_ci			goto out_end;
8938c2ecf20Sopenharmony_ci		break;
8948c2ecf20Sopenharmony_ci	case REQ_OP_SCSI_IN:
8958c2ecf20Sopenharmony_ci	case REQ_OP_SCSI_OUT:
8968c2ecf20Sopenharmony_ci	handle_pc:
8978c2ecf20Sopenharmony_ci		if (!rq->timeout)
8988c2ecf20Sopenharmony_ci			rq->timeout = ATAPI_WAIT_PC;
8998c2ecf20Sopenharmony_ci		cdrom_do_block_pc(drive, rq);
9008c2ecf20Sopenharmony_ci		break;
9018c2ecf20Sopenharmony_ci	case REQ_OP_DRV_IN:
9028c2ecf20Sopenharmony_ci	case REQ_OP_DRV_OUT:
9038c2ecf20Sopenharmony_ci		switch (ide_req(rq)->type) {
9048c2ecf20Sopenharmony_ci		case ATA_PRIV_MISC:
9058c2ecf20Sopenharmony_ci			/* right now this can only be a reset... */
9068c2ecf20Sopenharmony_ci			uptodate = 1;
9078c2ecf20Sopenharmony_ci			goto out_end;
9088c2ecf20Sopenharmony_ci		case ATA_PRIV_SENSE:
9098c2ecf20Sopenharmony_ci		case ATA_PRIV_PC:
9108c2ecf20Sopenharmony_ci			goto handle_pc;
9118c2ecf20Sopenharmony_ci		default:
9128c2ecf20Sopenharmony_ci			BUG();
9138c2ecf20Sopenharmony_ci		}
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	/* prepare sense request for this command */
9178c2ecf20Sopenharmony_ci	ide_prep_sense(drive, rq);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	memset(&cmd, 0, sizeof(cmd));
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	if (rq_data_dir(rq))
9228c2ecf20Sopenharmony_ci		cmd.tf_flags |= IDE_TFLAG_WRITE;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	cmd.rq = rq;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	if (!blk_rq_is_passthrough(rq) || blk_rq_bytes(rq)) {
9278c2ecf20Sopenharmony_ci		ide_init_sg_cmd(&cmd, blk_rq_bytes(rq));
9288c2ecf20Sopenharmony_ci		ide_map_sg(drive, &cmd);
9298c2ecf20Sopenharmony_ci	}
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	return ide_issue_pc(drive, &cmd);
9328c2ecf20Sopenharmony_ciout_end:
9338c2ecf20Sopenharmony_ci	nsectors = blk_rq_sectors(rq);
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	if (nsectors == 0)
9368c2ecf20Sopenharmony_ci		nsectors = 1;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	ide_complete_rq(drive, uptodate ? BLK_STS_OK : BLK_STS_IOERR, nsectors << 9);
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	return ide_stopped;
9418c2ecf20Sopenharmony_ci}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci/*
9448c2ecf20Sopenharmony_ci * Ioctl handling.
9458c2ecf20Sopenharmony_ci *
9468c2ecf20Sopenharmony_ci * Routines which queue packet commands take as a final argument a pointer to a
9478c2ecf20Sopenharmony_ci * request_sense struct. If execution of the command results in an error with a
9488c2ecf20Sopenharmony_ci * CHECK CONDITION status, this structure will be filled with the results of the
9498c2ecf20Sopenharmony_ci * subsequent request sense command. The pointer can also be NULL, in which case
9508c2ecf20Sopenharmony_ci * no sense information is returned.
9518c2ecf20Sopenharmony_ci */
9528c2ecf20Sopenharmony_cistatic void msf_from_bcd(struct atapi_msf *msf)
9538c2ecf20Sopenharmony_ci{
9548c2ecf20Sopenharmony_ci	msf->minute = bcd2bin(msf->minute);
9558c2ecf20Sopenharmony_ci	msf->second = bcd2bin(msf->second);
9568c2ecf20Sopenharmony_ci	msf->frame  = bcd2bin(msf->frame);
9578c2ecf20Sopenharmony_ci}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ciint cdrom_check_status(ide_drive_t *drive, struct scsi_sense_hdr *sshdr)
9608c2ecf20Sopenharmony_ci{
9618c2ecf20Sopenharmony_ci	struct cdrom_info *info = drive->driver_data;
9628c2ecf20Sopenharmony_ci	struct cdrom_device_info *cdi;
9638c2ecf20Sopenharmony_ci	unsigned char cmd[BLK_MAX_CDB];
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_FUNC, "enter");
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	if (!info)
9688c2ecf20Sopenharmony_ci		return -EIO;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	cdi = &info->devinfo;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	memset(cmd, 0, BLK_MAX_CDB);
9738c2ecf20Sopenharmony_ci	cmd[0] = GPCMD_TEST_UNIT_READY;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	/*
9768c2ecf20Sopenharmony_ci	 * Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to switch CDs
9778c2ecf20Sopenharmony_ci	 * instead of supporting the LOAD_UNLOAD opcode.
9788c2ecf20Sopenharmony_ci	 */
9798c2ecf20Sopenharmony_ci	cmd[7] = cdi->sanyo_slot % 3;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, sshdr, 0, RQF_QUIET);
9828c2ecf20Sopenharmony_ci}
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_cistatic int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
9858c2ecf20Sopenharmony_ci			       unsigned long *sectors_per_frame)
9868c2ecf20Sopenharmony_ci{
9878c2ecf20Sopenharmony_ci	struct {
9888c2ecf20Sopenharmony_ci		__be32 lba;
9898c2ecf20Sopenharmony_ci		__be32 blocklen;
9908c2ecf20Sopenharmony_ci	} capbuf;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	int stat;
9938c2ecf20Sopenharmony_ci	unsigned char cmd[BLK_MAX_CDB];
9948c2ecf20Sopenharmony_ci	unsigned len = sizeof(capbuf);
9958c2ecf20Sopenharmony_ci	u32 blocklen;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_FUNC, "enter");
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	memset(cmd, 0, BLK_MAX_CDB);
10008c2ecf20Sopenharmony_ci	cmd[0] = GPCMD_READ_CDVD_CAPACITY;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	stat = ide_cd_queue_pc(drive, cmd, 0, &capbuf, &len, NULL, 0,
10038c2ecf20Sopenharmony_ci			       RQF_QUIET);
10048c2ecf20Sopenharmony_ci	if (stat)
10058c2ecf20Sopenharmony_ci		return stat;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	/*
10088c2ecf20Sopenharmony_ci	 * Sanity check the given block size, in so far as making
10098c2ecf20Sopenharmony_ci	 * sure the sectors_per_frame we give to the caller won't
10108c2ecf20Sopenharmony_ci	 * end up being bogus.
10118c2ecf20Sopenharmony_ci	 */
10128c2ecf20Sopenharmony_ci	blocklen = be32_to_cpu(capbuf.blocklen);
10138c2ecf20Sopenharmony_ci	blocklen = (blocklen >> SECTOR_SHIFT) << SECTOR_SHIFT;
10148c2ecf20Sopenharmony_ci	switch (blocklen) {
10158c2ecf20Sopenharmony_ci	case 512:
10168c2ecf20Sopenharmony_ci	case 1024:
10178c2ecf20Sopenharmony_ci	case 2048:
10188c2ecf20Sopenharmony_ci	case 4096:
10198c2ecf20Sopenharmony_ci		break;
10208c2ecf20Sopenharmony_ci	default:
10218c2ecf20Sopenharmony_ci		printk_once(KERN_ERR PFX "%s: weird block size %u; "
10228c2ecf20Sopenharmony_ci				"setting default block size to 2048\n",
10238c2ecf20Sopenharmony_ci				drive->name, blocklen);
10248c2ecf20Sopenharmony_ci		blocklen = 2048;
10258c2ecf20Sopenharmony_ci		break;
10268c2ecf20Sopenharmony_ci	}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	*capacity = 1 + be32_to_cpu(capbuf.lba);
10298c2ecf20Sopenharmony_ci	*sectors_per_frame = blocklen >> SECTOR_SHIFT;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_PROBE, "cap: %lu, sectors_per_frame: %lu",
10328c2ecf20Sopenharmony_ci				     *capacity, *sectors_per_frame);
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	return 0;
10358c2ecf20Sopenharmony_ci}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic int ide_cdrom_read_tocentry(ide_drive_t *drive, int trackno,
10388c2ecf20Sopenharmony_ci		int msf_flag, int format, char *buf, int buflen)
10398c2ecf20Sopenharmony_ci{
10408c2ecf20Sopenharmony_ci	unsigned char cmd[BLK_MAX_CDB];
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_FUNC, "enter");
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	memset(cmd, 0, BLK_MAX_CDB);
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
10478c2ecf20Sopenharmony_ci	cmd[6] = trackno;
10488c2ecf20Sopenharmony_ci	cmd[7] = (buflen >> 8);
10498c2ecf20Sopenharmony_ci	cmd[8] = (buflen & 0xff);
10508c2ecf20Sopenharmony_ci	cmd[9] = (format << 6);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	if (msf_flag)
10538c2ecf20Sopenharmony_ci		cmd[1] = 2;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	return ide_cd_queue_pc(drive, cmd, 0, buf, &buflen, NULL, 0, RQF_QUIET);
10568c2ecf20Sopenharmony_ci}
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci/* Try to read the entire TOC for the disk into our internal buffer. */
10598c2ecf20Sopenharmony_ciint ide_cd_read_toc(ide_drive_t *drive)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	int stat, ntracks, i;
10628c2ecf20Sopenharmony_ci	struct cdrom_info *info = drive->driver_data;
10638c2ecf20Sopenharmony_ci	struct cdrom_device_info *cdi = &info->devinfo;
10648c2ecf20Sopenharmony_ci	struct atapi_toc *toc = info->toc;
10658c2ecf20Sopenharmony_ci	struct {
10668c2ecf20Sopenharmony_ci		struct atapi_toc_header hdr;
10678c2ecf20Sopenharmony_ci		struct atapi_toc_entry  ent;
10688c2ecf20Sopenharmony_ci	} ms_tmp;
10698c2ecf20Sopenharmony_ci	long last_written;
10708c2ecf20Sopenharmony_ci	unsigned long sectors_per_frame = SECTORS_PER_FRAME;
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_FUNC, "enter");
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	if (toc == NULL) {
10758c2ecf20Sopenharmony_ci		/* try to allocate space */
10768c2ecf20Sopenharmony_ci		toc = kmalloc(sizeof(struct atapi_toc), GFP_KERNEL);
10778c2ecf20Sopenharmony_ci		if (toc == NULL) {
10788c2ecf20Sopenharmony_ci			printk(KERN_ERR PFX "%s: No cdrom TOC buffer!\n",
10798c2ecf20Sopenharmony_ci					drive->name);
10808c2ecf20Sopenharmony_ci			return -ENOMEM;
10818c2ecf20Sopenharmony_ci		}
10828c2ecf20Sopenharmony_ci		info->toc = toc;
10838c2ecf20Sopenharmony_ci	}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	/*
10868c2ecf20Sopenharmony_ci	 * Check to see if the existing data is still valid. If it is,
10878c2ecf20Sopenharmony_ci	 * just return.
10888c2ecf20Sopenharmony_ci	 */
10898c2ecf20Sopenharmony_ci	(void) cdrom_check_status(drive, NULL);
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	if (drive->atapi_flags & IDE_AFLAG_TOC_VALID)
10928c2ecf20Sopenharmony_ci		return 0;
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	/* try to get the total cdrom capacity and sector size */
10958c2ecf20Sopenharmony_ci	stat = cdrom_read_capacity(drive, &toc->capacity, &sectors_per_frame);
10968c2ecf20Sopenharmony_ci	if (stat)
10978c2ecf20Sopenharmony_ci		toc->capacity = 0x1fffff;
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	set_capacity(info->disk, toc->capacity * sectors_per_frame);
11008c2ecf20Sopenharmony_ci	/* save a private copy of the TOC capacity for error handling */
11018c2ecf20Sopenharmony_ci	drive->probed_capacity = toc->capacity * sectors_per_frame;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	blk_queue_logical_block_size(drive->queue,
11048c2ecf20Sopenharmony_ci				     sectors_per_frame << SECTOR_SHIFT);
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	/* first read just the header, so we know how long the TOC is */
11078c2ecf20Sopenharmony_ci	stat = ide_cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr,
11088c2ecf20Sopenharmony_ci				    sizeof(struct atapi_toc_header));
11098c2ecf20Sopenharmony_ci	if (stat)
11108c2ecf20Sopenharmony_ci		return stat;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) {
11138c2ecf20Sopenharmony_ci		toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
11148c2ecf20Sopenharmony_ci		toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
11158c2ecf20Sopenharmony_ci	}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
11188c2ecf20Sopenharmony_ci	if (ntracks <= 0)
11198c2ecf20Sopenharmony_ci		return -EIO;
11208c2ecf20Sopenharmony_ci	if (ntracks > MAX_TRACKS)
11218c2ecf20Sopenharmony_ci		ntracks = MAX_TRACKS;
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	/* now read the whole schmeer */
11248c2ecf20Sopenharmony_ci	stat = ide_cdrom_read_tocentry(drive, toc->hdr.first_track, 1, 0,
11258c2ecf20Sopenharmony_ci				  (char *)&toc->hdr,
11268c2ecf20Sopenharmony_ci				   sizeof(struct atapi_toc_header) +
11278c2ecf20Sopenharmony_ci				   (ntracks + 1) *
11288c2ecf20Sopenharmony_ci				   sizeof(struct atapi_toc_entry));
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	if (stat && toc->hdr.first_track > 1) {
11318c2ecf20Sopenharmony_ci		/*
11328c2ecf20Sopenharmony_ci		 * Cds with CDI tracks only don't have any TOC entries, despite
11338c2ecf20Sopenharmony_ci		 * of this the returned values are
11348c2ecf20Sopenharmony_ci		 * first_track == last_track = number of CDI tracks + 1,
11358c2ecf20Sopenharmony_ci		 * so that this case is indistinguishable from the same layout
11368c2ecf20Sopenharmony_ci		 * plus an additional audio track. If we get an error for the
11378c2ecf20Sopenharmony_ci		 * regular case, we assume a CDI without additional audio
11388c2ecf20Sopenharmony_ci		 * tracks. In this case the readable TOC is empty (CDI tracks
11398c2ecf20Sopenharmony_ci		 * are not included) and only holds the Leadout entry.
11408c2ecf20Sopenharmony_ci		 *
11418c2ecf20Sopenharmony_ci		 * Heiko Eißfeldt.
11428c2ecf20Sopenharmony_ci		 */
11438c2ecf20Sopenharmony_ci		ntracks = 0;
11448c2ecf20Sopenharmony_ci		stat = ide_cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0,
11458c2ecf20Sopenharmony_ci					   (char *)&toc->hdr,
11468c2ecf20Sopenharmony_ci					   sizeof(struct atapi_toc_header) +
11478c2ecf20Sopenharmony_ci					   (ntracks + 1) *
11488c2ecf20Sopenharmony_ci					   sizeof(struct atapi_toc_entry));
11498c2ecf20Sopenharmony_ci		if (stat)
11508c2ecf20Sopenharmony_ci			return stat;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci		if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) {
11538c2ecf20Sopenharmony_ci			toc->hdr.first_track = (u8)bin2bcd(CDROM_LEADOUT);
11548c2ecf20Sopenharmony_ci			toc->hdr.last_track = (u8)bin2bcd(CDROM_LEADOUT);
11558c2ecf20Sopenharmony_ci		} else {
11568c2ecf20Sopenharmony_ci			toc->hdr.first_track = CDROM_LEADOUT;
11578c2ecf20Sopenharmony_ci			toc->hdr.last_track = CDROM_LEADOUT;
11588c2ecf20Sopenharmony_ci		}
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	if (stat)
11628c2ecf20Sopenharmony_ci		return stat;
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	toc->hdr.toc_length = be16_to_cpu(toc->hdr.toc_length);
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) {
11678c2ecf20Sopenharmony_ci		toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
11688c2ecf20Sopenharmony_ci		toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
11698c2ecf20Sopenharmony_ci	}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	for (i = 0; i <= ntracks; i++) {
11728c2ecf20Sopenharmony_ci		if (drive->atapi_flags & IDE_AFLAG_TOCADDR_AS_BCD) {
11738c2ecf20Sopenharmony_ci			if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD)
11748c2ecf20Sopenharmony_ci				toc->ent[i].track = bcd2bin(toc->ent[i].track);
11758c2ecf20Sopenharmony_ci			msf_from_bcd(&toc->ent[i].addr.msf);
11768c2ecf20Sopenharmony_ci		}
11778c2ecf20Sopenharmony_ci		toc->ent[i].addr.lba = msf_to_lba(toc->ent[i].addr.msf.minute,
11788c2ecf20Sopenharmony_ci						  toc->ent[i].addr.msf.second,
11798c2ecf20Sopenharmony_ci						  toc->ent[i].addr.msf.frame);
11808c2ecf20Sopenharmony_ci	}
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	if (toc->hdr.first_track != CDROM_LEADOUT) {
11838c2ecf20Sopenharmony_ci		/* read the multisession information */
11848c2ecf20Sopenharmony_ci		stat = ide_cdrom_read_tocentry(drive, 0, 0, 1, (char *)&ms_tmp,
11858c2ecf20Sopenharmony_ci					   sizeof(ms_tmp));
11868c2ecf20Sopenharmony_ci		if (stat)
11878c2ecf20Sopenharmony_ci			return stat;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci		toc->last_session_lba = be32_to_cpu(ms_tmp.ent.addr.lba);
11908c2ecf20Sopenharmony_ci	} else {
11918c2ecf20Sopenharmony_ci		ms_tmp.hdr.last_track = CDROM_LEADOUT;
11928c2ecf20Sopenharmony_ci		ms_tmp.hdr.first_track = ms_tmp.hdr.last_track;
11938c2ecf20Sopenharmony_ci		toc->last_session_lba = msf_to_lba(0, 2, 0); /* 0m 2s 0f */
11948c2ecf20Sopenharmony_ci	}
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	if (drive->atapi_flags & IDE_AFLAG_TOCADDR_AS_BCD) {
11978c2ecf20Sopenharmony_ci		/* re-read multisession information using MSF format */
11988c2ecf20Sopenharmony_ci		stat = ide_cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp,
11998c2ecf20Sopenharmony_ci					   sizeof(ms_tmp));
12008c2ecf20Sopenharmony_ci		if (stat)
12018c2ecf20Sopenharmony_ci			return stat;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci		msf_from_bcd(&ms_tmp.ent.addr.msf);
12048c2ecf20Sopenharmony_ci		toc->last_session_lba = msf_to_lba(ms_tmp.ent.addr.msf.minute,
12058c2ecf20Sopenharmony_ci						   ms_tmp.ent.addr.msf.second,
12068c2ecf20Sopenharmony_ci						   ms_tmp.ent.addr.msf.frame);
12078c2ecf20Sopenharmony_ci	}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	/* now try to get the total cdrom capacity */
12128c2ecf20Sopenharmony_ci	stat = cdrom_get_last_written(cdi, &last_written);
12138c2ecf20Sopenharmony_ci	if (!stat && (last_written > toc->capacity)) {
12148c2ecf20Sopenharmony_ci		toc->capacity = last_written;
12158c2ecf20Sopenharmony_ci		set_capacity(info->disk, toc->capacity * sectors_per_frame);
12168c2ecf20Sopenharmony_ci		drive->probed_capacity = toc->capacity * sectors_per_frame;
12178c2ecf20Sopenharmony_ci	}
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	/* Remember that we've read this stuff. */
12208c2ecf20Sopenharmony_ci	drive->atapi_flags |= IDE_AFLAG_TOC_VALID;
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	return 0;
12238c2ecf20Sopenharmony_ci}
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ciint ide_cdrom_get_capabilities(ide_drive_t *drive, u8 *buf)
12268c2ecf20Sopenharmony_ci{
12278c2ecf20Sopenharmony_ci	struct cdrom_info *info = drive->driver_data;
12288c2ecf20Sopenharmony_ci	struct cdrom_device_info *cdi = &info->devinfo;
12298c2ecf20Sopenharmony_ci	struct packet_command cgc;
12308c2ecf20Sopenharmony_ci	int stat, attempts = 3, size = ATAPI_CAPABILITIES_PAGE_SIZE;
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_FUNC, "enter");
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	if ((drive->atapi_flags & IDE_AFLAG_FULL_CAPS_PAGE) == 0)
12358c2ecf20Sopenharmony_ci		size -= ATAPI_CAPABILITIES_PAGE_PAD_SIZE;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	init_cdrom_command(&cgc, buf, size, CGC_DATA_UNKNOWN);
12388c2ecf20Sopenharmony_ci	do {
12398c2ecf20Sopenharmony_ci		/* we seem to get stat=0x01,err=0x00 the first time (??) */
12408c2ecf20Sopenharmony_ci		stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
12418c2ecf20Sopenharmony_ci		if (!stat)
12428c2ecf20Sopenharmony_ci			break;
12438c2ecf20Sopenharmony_ci	} while (--attempts);
12448c2ecf20Sopenharmony_ci	return stat;
12458c2ecf20Sopenharmony_ci}
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_civoid ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	struct cdrom_info *cd = drive->driver_data;
12508c2ecf20Sopenharmony_ci	u16 curspeed, maxspeed;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_FUNC, "enter");
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	if (drive->atapi_flags & IDE_AFLAG_LE_SPEED_FIELDS) {
12558c2ecf20Sopenharmony_ci		curspeed = le16_to_cpup((__le16 *)&buf[8 + 14]);
12568c2ecf20Sopenharmony_ci		maxspeed = le16_to_cpup((__le16 *)&buf[8 + 8]);
12578c2ecf20Sopenharmony_ci	} else {
12588c2ecf20Sopenharmony_ci		curspeed = be16_to_cpup((__be16 *)&buf[8 + 14]);
12598c2ecf20Sopenharmony_ci		maxspeed = be16_to_cpup((__be16 *)&buf[8 + 8]);
12608c2ecf20Sopenharmony_ci	}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_PROBE, "curspeed: %u, maxspeed: %u",
12638c2ecf20Sopenharmony_ci				     curspeed, maxspeed);
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	cd->current_speed = DIV_ROUND_CLOSEST(curspeed, 176);
12668c2ecf20Sopenharmony_ci	cd->max_speed = DIV_ROUND_CLOSEST(maxspeed, 176);
12678c2ecf20Sopenharmony_ci}
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci#define IDE_CD_CAPABILITIES \
12708c2ecf20Sopenharmony_ci	(CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | \
12718c2ecf20Sopenharmony_ci	 CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | \
12728c2ecf20Sopenharmony_ci	 CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R | \
12738c2ecf20Sopenharmony_ci	 CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET | \
12748c2ecf20Sopenharmony_ci	 CDC_MO_DRIVE | CDC_MRW | CDC_MRW_W | CDC_RAM)
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_cistatic const struct cdrom_device_ops ide_cdrom_dops = {
12778c2ecf20Sopenharmony_ci	.open			= ide_cdrom_open_real,
12788c2ecf20Sopenharmony_ci	.release		= ide_cdrom_release_real,
12798c2ecf20Sopenharmony_ci	.drive_status		= ide_cdrom_drive_status,
12808c2ecf20Sopenharmony_ci	.check_events		= ide_cdrom_check_events_real,
12818c2ecf20Sopenharmony_ci	.tray_move		= ide_cdrom_tray_move,
12828c2ecf20Sopenharmony_ci	.lock_door		= ide_cdrom_lock_door,
12838c2ecf20Sopenharmony_ci	.select_speed		= ide_cdrom_select_speed,
12848c2ecf20Sopenharmony_ci	.get_last_session	= ide_cdrom_get_last_session,
12858c2ecf20Sopenharmony_ci	.get_mcn		= ide_cdrom_get_mcn,
12868c2ecf20Sopenharmony_ci	.reset			= ide_cdrom_reset,
12878c2ecf20Sopenharmony_ci	.audio_ioctl		= ide_cdrom_audio_ioctl,
12888c2ecf20Sopenharmony_ci	.capability		= IDE_CD_CAPABILITIES,
12898c2ecf20Sopenharmony_ci	.generic_packet		= ide_cdrom_packet,
12908c2ecf20Sopenharmony_ci};
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_cistatic int ide_cdrom_register(ide_drive_t *drive, int nslots)
12938c2ecf20Sopenharmony_ci{
12948c2ecf20Sopenharmony_ci	struct cdrom_info *info = drive->driver_data;
12958c2ecf20Sopenharmony_ci	struct cdrom_device_info *devinfo = &info->devinfo;
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_PROBE, "nslots: %d", nslots);
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	devinfo->ops = &ide_cdrom_dops;
13008c2ecf20Sopenharmony_ci	devinfo->speed = info->current_speed;
13018c2ecf20Sopenharmony_ci	devinfo->capacity = nslots;
13028c2ecf20Sopenharmony_ci	devinfo->handle = drive;
13038c2ecf20Sopenharmony_ci	strcpy(devinfo->name, drive->name);
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	if (drive->atapi_flags & IDE_AFLAG_NO_SPEED_SELECT)
13068c2ecf20Sopenharmony_ci		devinfo->mask |= CDC_SELECT_SPEED;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	return register_cdrom(info->disk, devinfo);
13098c2ecf20Sopenharmony_ci}
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_cistatic int ide_cdrom_probe_capabilities(ide_drive_t *drive)
13128c2ecf20Sopenharmony_ci{
13138c2ecf20Sopenharmony_ci	struct cdrom_info *cd = drive->driver_data;
13148c2ecf20Sopenharmony_ci	struct cdrom_device_info *cdi = &cd->devinfo;
13158c2ecf20Sopenharmony_ci	u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE];
13168c2ecf20Sopenharmony_ci	mechtype_t mechtype;
13178c2ecf20Sopenharmony_ci	int nslots = 1;
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_PROBE, "media: 0x%x, atapi_flags: 0x%lx",
13208c2ecf20Sopenharmony_ci				     drive->media, drive->atapi_flags);
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	cdi->mask = (CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R |
13238c2ecf20Sopenharmony_ci		     CDC_DVD_RAM | CDC_SELECT_DISC | CDC_PLAY_AUDIO |
13248c2ecf20Sopenharmony_ci		     CDC_MO_DRIVE | CDC_RAM);
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	if (drive->media == ide_optical) {
13278c2ecf20Sopenharmony_ci		cdi->mask &= ~(CDC_MO_DRIVE | CDC_RAM);
13288c2ecf20Sopenharmony_ci		printk(KERN_ERR PFX "%s: ATAPI magneto-optical drive\n",
13298c2ecf20Sopenharmony_ci				drive->name);
13308c2ecf20Sopenharmony_ci		return nslots;
13318c2ecf20Sopenharmony_ci	}
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	if (drive->atapi_flags & IDE_AFLAG_PRE_ATAPI12) {
13348c2ecf20Sopenharmony_ci		drive->atapi_flags &= ~IDE_AFLAG_NO_EJECT;
13358c2ecf20Sopenharmony_ci		cdi->mask &= ~CDC_PLAY_AUDIO;
13368c2ecf20Sopenharmony_ci		return nslots;
13378c2ecf20Sopenharmony_ci	}
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	/*
13408c2ecf20Sopenharmony_ci	 * We have to cheat a little here. the packet will eventually be queued
13418c2ecf20Sopenharmony_ci	 * with ide_cdrom_packet(), which extracts the drive from cdi->handle.
13428c2ecf20Sopenharmony_ci	 * Since this device hasn't been registered with the Uniform layer yet,
13438c2ecf20Sopenharmony_ci	 * it can't do this. Same goes for cdi->ops.
13448c2ecf20Sopenharmony_ci	 */
13458c2ecf20Sopenharmony_ci	cdi->handle = drive;
13468c2ecf20Sopenharmony_ci	cdi->ops = &ide_cdrom_dops;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	if (ide_cdrom_get_capabilities(drive, buf))
13498c2ecf20Sopenharmony_ci		return 0;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	if ((buf[8 + 6] & 0x01) == 0)
13528c2ecf20Sopenharmony_ci		drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
13538c2ecf20Sopenharmony_ci	if (buf[8 + 6] & 0x08)
13548c2ecf20Sopenharmony_ci		drive->atapi_flags &= ~IDE_AFLAG_NO_EJECT;
13558c2ecf20Sopenharmony_ci	if (buf[8 + 3] & 0x01)
13568c2ecf20Sopenharmony_ci		cdi->mask &= ~CDC_CD_R;
13578c2ecf20Sopenharmony_ci	if (buf[8 + 3] & 0x02)
13588c2ecf20Sopenharmony_ci		cdi->mask &= ~(CDC_CD_RW | CDC_RAM);
13598c2ecf20Sopenharmony_ci	if (buf[8 + 2] & 0x38)
13608c2ecf20Sopenharmony_ci		cdi->mask &= ~CDC_DVD;
13618c2ecf20Sopenharmony_ci	if (buf[8 + 3] & 0x20)
13628c2ecf20Sopenharmony_ci		cdi->mask &= ~(CDC_DVD_RAM | CDC_RAM);
13638c2ecf20Sopenharmony_ci	if (buf[8 + 3] & 0x10)
13648c2ecf20Sopenharmony_ci		cdi->mask &= ~CDC_DVD_R;
13658c2ecf20Sopenharmony_ci	if ((buf[8 + 4] & 0x01) || (drive->atapi_flags & IDE_AFLAG_PLAY_AUDIO_OK))
13668c2ecf20Sopenharmony_ci		cdi->mask &= ~CDC_PLAY_AUDIO;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	mechtype = buf[8 + 6] >> 5;
13698c2ecf20Sopenharmony_ci	if (mechtype == mechtype_caddy ||
13708c2ecf20Sopenharmony_ci	    mechtype == mechtype_popup ||
13718c2ecf20Sopenharmony_ci	    (drive->atapi_flags & IDE_AFLAG_NO_AUTOCLOSE))
13728c2ecf20Sopenharmony_ci		cdi->mask |= CDC_CLOSE_TRAY;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	if (cdi->sanyo_slot > 0) {
13758c2ecf20Sopenharmony_ci		cdi->mask &= ~CDC_SELECT_DISC;
13768c2ecf20Sopenharmony_ci		nslots = 3;
13778c2ecf20Sopenharmony_ci	} else if (mechtype == mechtype_individual_changer ||
13788c2ecf20Sopenharmony_ci		   mechtype == mechtype_cartridge_changer) {
13798c2ecf20Sopenharmony_ci		nslots = cdrom_number_of_slots(cdi);
13808c2ecf20Sopenharmony_ci		if (nslots > 1)
13818c2ecf20Sopenharmony_ci			cdi->mask &= ~CDC_SELECT_DISC;
13828c2ecf20Sopenharmony_ci	}
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci	ide_cdrom_update_speed(drive, buf);
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	printk(KERN_INFO PFX "%s: ATAPI", drive->name);
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	/* don't print speed if the drive reported 0 */
13898c2ecf20Sopenharmony_ci	if (cd->max_speed)
13908c2ecf20Sopenharmony_ci		printk(KERN_CONT " %dX", cd->max_speed);
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	printk(KERN_CONT " %s", (cdi->mask & CDC_DVD) ? "CD-ROM" : "DVD-ROM");
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	if ((cdi->mask & CDC_DVD_R) == 0 || (cdi->mask & CDC_DVD_RAM) == 0)
13958c2ecf20Sopenharmony_ci		printk(KERN_CONT " DVD%s%s",
13968c2ecf20Sopenharmony_ci				 (cdi->mask & CDC_DVD_R) ? "" : "-R",
13978c2ecf20Sopenharmony_ci				 (cdi->mask & CDC_DVD_RAM) ? "" : "/RAM");
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	if ((cdi->mask & CDC_CD_R) == 0 || (cdi->mask & CDC_CD_RW) == 0)
14008c2ecf20Sopenharmony_ci		printk(KERN_CONT " CD%s%s",
14018c2ecf20Sopenharmony_ci				 (cdi->mask & CDC_CD_R) ? "" : "-R",
14028c2ecf20Sopenharmony_ci				 (cdi->mask & CDC_CD_RW) ? "" : "/RW");
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	if ((cdi->mask & CDC_SELECT_DISC) == 0)
14058c2ecf20Sopenharmony_ci		printk(KERN_CONT " changer w/%d slots", nslots);
14068c2ecf20Sopenharmony_ci	else
14078c2ecf20Sopenharmony_ci		printk(KERN_CONT " drive");
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	printk(KERN_CONT ", %dkB Cache\n",
14108c2ecf20Sopenharmony_ci			 be16_to_cpup((__be16 *)&buf[8 + 12]));
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	return nslots;
14138c2ecf20Sopenharmony_ci}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_cistruct cd_list_entry {
14168c2ecf20Sopenharmony_ci	const char	*id_model;
14178c2ecf20Sopenharmony_ci	const char	*id_firmware;
14188c2ecf20Sopenharmony_ci	unsigned int	cd_flags;
14198c2ecf20Sopenharmony_ci};
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci#ifdef CONFIG_IDE_PROC_FS
14228c2ecf20Sopenharmony_cistatic sector_t ide_cdrom_capacity(ide_drive_t *drive)
14238c2ecf20Sopenharmony_ci{
14248c2ecf20Sopenharmony_ci	unsigned long capacity, sectors_per_frame;
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	if (cdrom_read_capacity(drive, &capacity, &sectors_per_frame))
14278c2ecf20Sopenharmony_ci		return 0;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	return capacity * sectors_per_frame;
14308c2ecf20Sopenharmony_ci}
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_cistatic int idecd_capacity_proc_show(struct seq_file *m, void *v)
14338c2ecf20Sopenharmony_ci{
14348c2ecf20Sopenharmony_ci	ide_drive_t *drive = m->private;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	seq_printf(m, "%llu\n", (long long)ide_cdrom_capacity(drive));
14378c2ecf20Sopenharmony_ci	return 0;
14388c2ecf20Sopenharmony_ci}
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_cistatic ide_proc_entry_t idecd_proc[] = {
14418c2ecf20Sopenharmony_ci	{ "capacity", S_IFREG|S_IRUGO, idecd_capacity_proc_show },
14428c2ecf20Sopenharmony_ci	{}
14438c2ecf20Sopenharmony_ci};
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_cistatic ide_proc_entry_t *ide_cd_proc_entries(ide_drive_t *drive)
14468c2ecf20Sopenharmony_ci{
14478c2ecf20Sopenharmony_ci	return idecd_proc;
14488c2ecf20Sopenharmony_ci}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_cistatic const struct ide_proc_devset *ide_cd_proc_devsets(ide_drive_t *drive)
14518c2ecf20Sopenharmony_ci{
14528c2ecf20Sopenharmony_ci	return NULL;
14538c2ecf20Sopenharmony_ci}
14548c2ecf20Sopenharmony_ci#endif
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_cistatic const struct cd_list_entry ide_cd_quirks_list[] = {
14578c2ecf20Sopenharmony_ci	/* SCR-3231 doesn't support the SET_CD_SPEED command. */
14588c2ecf20Sopenharmony_ci	{ "SAMSUNG CD-ROM SCR-3231", NULL,   IDE_AFLAG_NO_SPEED_SELECT	     },
14598c2ecf20Sopenharmony_ci	/* Old NEC260 (not R) was released before ATAPI 1.2 spec. */
14608c2ecf20Sopenharmony_ci	{ "NEC CD-ROM DRIVE:260",    "1.01", IDE_AFLAG_TOCADDR_AS_BCD |
14618c2ecf20Sopenharmony_ci					     IDE_AFLAG_PRE_ATAPI12,	     },
14628c2ecf20Sopenharmony_ci	/* Vertos 300, some versions of this drive like to talk BCD. */
14638c2ecf20Sopenharmony_ci	{ "V003S0DS",		     NULL,   IDE_AFLAG_VERTOS_300_SSD,	     },
14648c2ecf20Sopenharmony_ci	/* Vertos 600 ESD. */
14658c2ecf20Sopenharmony_ci	{ "V006E0DS",		     NULL,   IDE_AFLAG_VERTOS_600_ESD,	     },
14668c2ecf20Sopenharmony_ci	/*
14678c2ecf20Sopenharmony_ci	 * Sanyo 3 CD changer uses a non-standard command for CD changing
14688c2ecf20Sopenharmony_ci	 * (by default standard ATAPI support for CD changers is used).
14698c2ecf20Sopenharmony_ci	 */
14708c2ecf20Sopenharmony_ci	{ "CD-ROM CDR-C3 G",	     NULL,   IDE_AFLAG_SANYO_3CD	     },
14718c2ecf20Sopenharmony_ci	{ "CD-ROM CDR-C3G",	     NULL,   IDE_AFLAG_SANYO_3CD	     },
14728c2ecf20Sopenharmony_ci	{ "CD-ROM CDR_C36",	     NULL,   IDE_AFLAG_SANYO_3CD	     },
14738c2ecf20Sopenharmony_ci	/* Stingray 8X CD-ROM. */
14748c2ecf20Sopenharmony_ci	{ "STINGRAY 8422 IDE 8X CD-ROM 7-27-95", NULL, IDE_AFLAG_PRE_ATAPI12 },
14758c2ecf20Sopenharmony_ci	/*
14768c2ecf20Sopenharmony_ci	 * ACER 50X CD-ROM and WPI 32X CD-ROM require the full spec length
14778c2ecf20Sopenharmony_ci	 * mode sense page capabilities size, but older drives break.
14788c2ecf20Sopenharmony_ci	 */
14798c2ecf20Sopenharmony_ci	{ "ATAPI CD ROM DRIVE 50X MAX",	NULL,	IDE_AFLAG_FULL_CAPS_PAGE     },
14808c2ecf20Sopenharmony_ci	{ "WPI CDS-32X",		NULL,	IDE_AFLAG_FULL_CAPS_PAGE     },
14818c2ecf20Sopenharmony_ci	/* ACER/AOpen 24X CD-ROM has the speed fields byte-swapped. */
14828c2ecf20Sopenharmony_ci	{ "",			     "241N", IDE_AFLAG_LE_SPEED_FIELDS       },
14838c2ecf20Sopenharmony_ci	/*
14848c2ecf20Sopenharmony_ci	 * Some drives used by Apple don't advertise audio play
14858c2ecf20Sopenharmony_ci	 * but they do support reading TOC & audio datas.
14868c2ecf20Sopenharmony_ci	 */
14878c2ecf20Sopenharmony_ci	{ "MATSHITADVD-ROM SR-8187", NULL,   IDE_AFLAG_PLAY_AUDIO_OK	     },
14888c2ecf20Sopenharmony_ci	{ "MATSHITADVD-ROM SR-8186", NULL,   IDE_AFLAG_PLAY_AUDIO_OK	     },
14898c2ecf20Sopenharmony_ci	{ "MATSHITADVD-ROM SR-8176", NULL,   IDE_AFLAG_PLAY_AUDIO_OK	     },
14908c2ecf20Sopenharmony_ci	{ "MATSHITADVD-ROM SR-8174", NULL,   IDE_AFLAG_PLAY_AUDIO_OK	     },
14918c2ecf20Sopenharmony_ci	{ "Optiarc DVD RW AD-5200A", NULL,   IDE_AFLAG_PLAY_AUDIO_OK	     },
14928c2ecf20Sopenharmony_ci	{ "Optiarc DVD RW AD-7200A", NULL,   IDE_AFLAG_PLAY_AUDIO_OK	     },
14938c2ecf20Sopenharmony_ci	{ "Optiarc DVD RW AD-7543A", NULL,   IDE_AFLAG_NO_AUTOCLOSE	     },
14948c2ecf20Sopenharmony_ci	{ "TEAC CD-ROM CD-224E",     NULL,   IDE_AFLAG_NO_AUTOCLOSE	     },
14958c2ecf20Sopenharmony_ci	{ NULL, NULL, 0 }
14968c2ecf20Sopenharmony_ci};
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_cistatic unsigned int ide_cd_flags(u16 *id)
14998c2ecf20Sopenharmony_ci{
15008c2ecf20Sopenharmony_ci	const struct cd_list_entry *cle = ide_cd_quirks_list;
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	while (cle->id_model) {
15038c2ecf20Sopenharmony_ci		if (strcmp(cle->id_model, (char *)&id[ATA_ID_PROD]) == 0 &&
15048c2ecf20Sopenharmony_ci		    (cle->id_firmware == NULL ||
15058c2ecf20Sopenharmony_ci		     strstr((char *)&id[ATA_ID_FW_REV], cle->id_firmware)))
15068c2ecf20Sopenharmony_ci			return cle->cd_flags;
15078c2ecf20Sopenharmony_ci		cle++;
15088c2ecf20Sopenharmony_ci	}
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	return 0;
15118c2ecf20Sopenharmony_ci}
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_cistatic int ide_cdrom_setup(ide_drive_t *drive)
15148c2ecf20Sopenharmony_ci{
15158c2ecf20Sopenharmony_ci	struct cdrom_info *cd = drive->driver_data;
15168c2ecf20Sopenharmony_ci	struct cdrom_device_info *cdi = &cd->devinfo;
15178c2ecf20Sopenharmony_ci	struct request_queue *q = drive->queue;
15188c2ecf20Sopenharmony_ci	u16 *id = drive->id;
15198c2ecf20Sopenharmony_ci	char *fw_rev = (char *)&id[ATA_ID_FW_REV];
15208c2ecf20Sopenharmony_ci	int nslots;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_PROBE, "enter");
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	drive->prep_rq = ide_cdrom_prep_rq;
15258c2ecf20Sopenharmony_ci	blk_queue_dma_alignment(q, 31);
15268c2ecf20Sopenharmony_ci	blk_queue_update_dma_pad(q, 15);
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
15298c2ecf20Sopenharmony_ci	drive->atapi_flags = IDE_AFLAG_NO_EJECT | ide_cd_flags(id);
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	if ((drive->atapi_flags & IDE_AFLAG_VERTOS_300_SSD) &&
15328c2ecf20Sopenharmony_ci	    fw_rev[4] == '1' && fw_rev[6] <= '2')
15338c2ecf20Sopenharmony_ci		drive->atapi_flags |= (IDE_AFLAG_TOCTRACKS_AS_BCD |
15348c2ecf20Sopenharmony_ci				     IDE_AFLAG_TOCADDR_AS_BCD);
15358c2ecf20Sopenharmony_ci	else if ((drive->atapi_flags & IDE_AFLAG_VERTOS_600_ESD) &&
15368c2ecf20Sopenharmony_ci		 fw_rev[4] == '1' && fw_rev[6] <= '2')
15378c2ecf20Sopenharmony_ci		drive->atapi_flags |= IDE_AFLAG_TOCTRACKS_AS_BCD;
15388c2ecf20Sopenharmony_ci	else if (drive->atapi_flags & IDE_AFLAG_SANYO_3CD)
15398c2ecf20Sopenharmony_ci		/* 3 => use CD in slot 0 */
15408c2ecf20Sopenharmony_ci		cdi->sanyo_slot = 3;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	nslots = ide_cdrom_probe_capabilities(drive);
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	blk_queue_logical_block_size(q, CD_FRAMESIZE);
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	if (ide_cdrom_register(drive, nslots)) {
15478c2ecf20Sopenharmony_ci		printk(KERN_ERR PFX "%s: %s failed to register device with the"
15488c2ecf20Sopenharmony_ci				" cdrom driver.\n", drive->name, __func__);
15498c2ecf20Sopenharmony_ci		cd->devinfo.handle = NULL;
15508c2ecf20Sopenharmony_ci		return 1;
15518c2ecf20Sopenharmony_ci	}
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	ide_proc_register_driver(drive, cd->driver);
15548c2ecf20Sopenharmony_ci	return 0;
15558c2ecf20Sopenharmony_ci}
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_cistatic void ide_cd_remove(ide_drive_t *drive)
15588c2ecf20Sopenharmony_ci{
15598c2ecf20Sopenharmony_ci	struct cdrom_info *info = drive->driver_data;
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_FUNC, "enter");
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	ide_proc_unregister_driver(drive, info->driver);
15648c2ecf20Sopenharmony_ci	device_del(&info->dev);
15658c2ecf20Sopenharmony_ci	del_gendisk(info->disk);
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	mutex_lock(&idecd_ref_mutex);
15688c2ecf20Sopenharmony_ci	put_device(&info->dev);
15698c2ecf20Sopenharmony_ci	mutex_unlock(&idecd_ref_mutex);
15708c2ecf20Sopenharmony_ci}
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_cistatic void ide_cd_release(struct device *dev)
15738c2ecf20Sopenharmony_ci{
15748c2ecf20Sopenharmony_ci	struct cdrom_info *info = to_ide_drv(dev, cdrom_info);
15758c2ecf20Sopenharmony_ci	struct cdrom_device_info *devinfo = &info->devinfo;
15768c2ecf20Sopenharmony_ci	ide_drive_t *drive = info->drive;
15778c2ecf20Sopenharmony_ci	struct gendisk *g = info->disk;
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_FUNC, "enter");
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	kfree(info->toc);
15828c2ecf20Sopenharmony_ci	if (devinfo->handle == drive)
15838c2ecf20Sopenharmony_ci		unregister_cdrom(devinfo);
15848c2ecf20Sopenharmony_ci	drive->driver_data = NULL;
15858c2ecf20Sopenharmony_ci	drive->prep_rq = NULL;
15868c2ecf20Sopenharmony_ci	g->private_data = NULL;
15878c2ecf20Sopenharmony_ci	put_disk(g);
15888c2ecf20Sopenharmony_ci	kfree(info);
15898c2ecf20Sopenharmony_ci}
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_cistatic int ide_cd_probe(ide_drive_t *);
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_cistatic struct ide_driver ide_cdrom_driver = {
15948c2ecf20Sopenharmony_ci	.gen_driver = {
15958c2ecf20Sopenharmony_ci		.owner		= THIS_MODULE,
15968c2ecf20Sopenharmony_ci		.name		= "ide-cdrom",
15978c2ecf20Sopenharmony_ci		.bus		= &ide_bus_type,
15988c2ecf20Sopenharmony_ci	},
15998c2ecf20Sopenharmony_ci	.probe			= ide_cd_probe,
16008c2ecf20Sopenharmony_ci	.remove			= ide_cd_remove,
16018c2ecf20Sopenharmony_ci	.version		= IDECD_VERSION,
16028c2ecf20Sopenharmony_ci	.do_request		= ide_cd_do_request,
16038c2ecf20Sopenharmony_ci#ifdef CONFIG_IDE_PROC_FS
16048c2ecf20Sopenharmony_ci	.proc_entries		= ide_cd_proc_entries,
16058c2ecf20Sopenharmony_ci	.proc_devsets		= ide_cd_proc_devsets,
16068c2ecf20Sopenharmony_ci#endif
16078c2ecf20Sopenharmony_ci};
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_cistatic int idecd_open(struct block_device *bdev, fmode_t mode)
16108c2ecf20Sopenharmony_ci{
16118c2ecf20Sopenharmony_ci	struct cdrom_info *info;
16128c2ecf20Sopenharmony_ci	int rc = -ENXIO;
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci	if (bdev_check_media_change(bdev)) {
16158c2ecf20Sopenharmony_ci		info = ide_drv_g(bdev->bd_disk, cdrom_info);
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci		ide_cd_read_toc(info->drive);
16188c2ecf20Sopenharmony_ci	}
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	mutex_lock(&ide_cd_mutex);
16218c2ecf20Sopenharmony_ci	info = ide_cd_get(bdev->bd_disk);
16228c2ecf20Sopenharmony_ci	if (!info)
16238c2ecf20Sopenharmony_ci		goto out;
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci	rc = cdrom_open(&info->devinfo, bdev, mode);
16268c2ecf20Sopenharmony_ci	if (rc < 0)
16278c2ecf20Sopenharmony_ci		ide_cd_put(info);
16288c2ecf20Sopenharmony_ciout:
16298c2ecf20Sopenharmony_ci	mutex_unlock(&ide_cd_mutex);
16308c2ecf20Sopenharmony_ci	return rc;
16318c2ecf20Sopenharmony_ci}
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_cistatic void idecd_release(struct gendisk *disk, fmode_t mode)
16348c2ecf20Sopenharmony_ci{
16358c2ecf20Sopenharmony_ci	struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci	mutex_lock(&ide_cd_mutex);
16388c2ecf20Sopenharmony_ci	cdrom_release(&info->devinfo, mode);
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	ide_cd_put(info);
16418c2ecf20Sopenharmony_ci	mutex_unlock(&ide_cd_mutex);
16428c2ecf20Sopenharmony_ci}
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_cistatic int idecd_set_spindown(struct cdrom_device_info *cdi, unsigned long arg)
16458c2ecf20Sopenharmony_ci{
16468c2ecf20Sopenharmony_ci	struct packet_command cgc;
16478c2ecf20Sopenharmony_ci	char buffer[16];
16488c2ecf20Sopenharmony_ci	int stat;
16498c2ecf20Sopenharmony_ci	char spindown;
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	if (copy_from_user(&spindown, (void __user *)arg, sizeof(char)))
16528c2ecf20Sopenharmony_ci		return -EFAULT;
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
16578c2ecf20Sopenharmony_ci	if (stat)
16588c2ecf20Sopenharmony_ci		return stat;
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
16618c2ecf20Sopenharmony_ci	return cdrom_mode_select(cdi, &cgc);
16628c2ecf20Sopenharmony_ci}
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_cistatic int idecd_get_spindown(struct cdrom_device_info *cdi, unsigned long arg)
16658c2ecf20Sopenharmony_ci{
16668c2ecf20Sopenharmony_ci	struct packet_command cgc;
16678c2ecf20Sopenharmony_ci	char buffer[16];
16688c2ecf20Sopenharmony_ci	int stat;
16698c2ecf20Sopenharmony_ci	char spindown;
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
16748c2ecf20Sopenharmony_ci	if (stat)
16758c2ecf20Sopenharmony_ci		return stat;
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	spindown = buffer[11] & 0x0f;
16788c2ecf20Sopenharmony_ci	if (copy_to_user((void __user *)arg, &spindown, sizeof(char)))
16798c2ecf20Sopenharmony_ci		return -EFAULT;
16808c2ecf20Sopenharmony_ci	return 0;
16818c2ecf20Sopenharmony_ci}
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_cistatic int idecd_locked_ioctl(struct block_device *bdev, fmode_t mode,
16848c2ecf20Sopenharmony_ci			unsigned int cmd, unsigned long arg)
16858c2ecf20Sopenharmony_ci{
16868c2ecf20Sopenharmony_ci	struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info);
16878c2ecf20Sopenharmony_ci	int err;
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci	switch (cmd) {
16908c2ecf20Sopenharmony_ci	case CDROMSETSPINDOWN:
16918c2ecf20Sopenharmony_ci		return idecd_set_spindown(&info->devinfo, arg);
16928c2ecf20Sopenharmony_ci	case CDROMGETSPINDOWN:
16938c2ecf20Sopenharmony_ci		return idecd_get_spindown(&info->devinfo, arg);
16948c2ecf20Sopenharmony_ci	default:
16958c2ecf20Sopenharmony_ci		break;
16968c2ecf20Sopenharmony_ci	}
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	err = generic_ide_ioctl(info->drive, bdev, cmd, arg);
16998c2ecf20Sopenharmony_ci	if (err == -EINVAL)
17008c2ecf20Sopenharmony_ci		err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd, arg);
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	return err;
17038c2ecf20Sopenharmony_ci}
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_cistatic int idecd_ioctl(struct block_device *bdev, fmode_t mode,
17068c2ecf20Sopenharmony_ci			     unsigned int cmd, unsigned long arg)
17078c2ecf20Sopenharmony_ci{
17088c2ecf20Sopenharmony_ci	int ret;
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci	mutex_lock(&ide_cd_mutex);
17118c2ecf20Sopenharmony_ci	ret = idecd_locked_ioctl(bdev, mode, cmd, arg);
17128c2ecf20Sopenharmony_ci	mutex_unlock(&ide_cd_mutex);
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	return ret;
17158c2ecf20Sopenharmony_ci}
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_cistatic int idecd_locked_compat_ioctl(struct block_device *bdev, fmode_t mode,
17188c2ecf20Sopenharmony_ci			unsigned int cmd, unsigned long arg)
17198c2ecf20Sopenharmony_ci{
17208c2ecf20Sopenharmony_ci	struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info);
17218c2ecf20Sopenharmony_ci	void __user *argp = compat_ptr(arg);
17228c2ecf20Sopenharmony_ci	int err;
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	switch (cmd) {
17258c2ecf20Sopenharmony_ci	case CDROMSETSPINDOWN:
17268c2ecf20Sopenharmony_ci		return idecd_set_spindown(&info->devinfo, (unsigned long)argp);
17278c2ecf20Sopenharmony_ci	case CDROMGETSPINDOWN:
17288c2ecf20Sopenharmony_ci		return idecd_get_spindown(&info->devinfo, (unsigned long)argp);
17298c2ecf20Sopenharmony_ci	default:
17308c2ecf20Sopenharmony_ci		break;
17318c2ecf20Sopenharmony_ci	}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	err = generic_ide_ioctl(info->drive, bdev, cmd, arg);
17348c2ecf20Sopenharmony_ci	if (err == -EINVAL)
17358c2ecf20Sopenharmony_ci		err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd,
17368c2ecf20Sopenharmony_ci				  (unsigned long)argp);
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	return err;
17398c2ecf20Sopenharmony_ci}
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_cistatic int idecd_compat_ioctl(struct block_device *bdev, fmode_t mode,
17428c2ecf20Sopenharmony_ci			     unsigned int cmd, unsigned long arg)
17438c2ecf20Sopenharmony_ci{
17448c2ecf20Sopenharmony_ci	int ret;
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	mutex_lock(&ide_cd_mutex);
17478c2ecf20Sopenharmony_ci	ret = idecd_locked_compat_ioctl(bdev, mode, cmd, arg);
17488c2ecf20Sopenharmony_ci	mutex_unlock(&ide_cd_mutex);
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	return ret;
17518c2ecf20Sopenharmony_ci}
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_cistatic unsigned int idecd_check_events(struct gendisk *disk,
17548c2ecf20Sopenharmony_ci				       unsigned int clearing)
17558c2ecf20Sopenharmony_ci{
17568c2ecf20Sopenharmony_ci	struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
17578c2ecf20Sopenharmony_ci	return cdrom_check_events(&info->devinfo, clearing);
17588c2ecf20Sopenharmony_ci}
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_cistatic const struct block_device_operations idecd_ops = {
17618c2ecf20Sopenharmony_ci	.owner			= THIS_MODULE,
17628c2ecf20Sopenharmony_ci	.open			= idecd_open,
17638c2ecf20Sopenharmony_ci	.release		= idecd_release,
17648c2ecf20Sopenharmony_ci	.ioctl			= idecd_ioctl,
17658c2ecf20Sopenharmony_ci	.compat_ioctl		= IS_ENABLED(CONFIG_COMPAT) ?
17668c2ecf20Sopenharmony_ci				  idecd_compat_ioctl : NULL,
17678c2ecf20Sopenharmony_ci	.check_events		= idecd_check_events,
17688c2ecf20Sopenharmony_ci};
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci/* module options */
17718c2ecf20Sopenharmony_cistatic unsigned long debug_mask;
17728c2ecf20Sopenharmony_cimodule_param(debug_mask, ulong, 0644);
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ATAPI CD-ROM Driver");
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_cistatic int ide_cd_probe(ide_drive_t *drive)
17778c2ecf20Sopenharmony_ci{
17788c2ecf20Sopenharmony_ci	struct cdrom_info *info;
17798c2ecf20Sopenharmony_ci	struct gendisk *g;
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	ide_debug_log(IDE_DBG_PROBE, "driver_req: %s, media: 0x%x",
17828c2ecf20Sopenharmony_ci				     drive->driver_req, drive->media);
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	if (!strstr("ide-cdrom", drive->driver_req))
17858c2ecf20Sopenharmony_ci		goto failed;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	if (drive->media != ide_cdrom && drive->media != ide_optical)
17888c2ecf20Sopenharmony_ci		goto failed;
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	drive->debug_mask = debug_mask;
17918c2ecf20Sopenharmony_ci	drive->irq_handler = cdrom_newpc_intr;
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci	info = kzalloc(sizeof(struct cdrom_info), GFP_KERNEL);
17948c2ecf20Sopenharmony_ci	if (info == NULL) {
17958c2ecf20Sopenharmony_ci		printk(KERN_ERR PFX "%s: Can't allocate a cdrom structure\n",
17968c2ecf20Sopenharmony_ci				drive->name);
17978c2ecf20Sopenharmony_ci		goto failed;
17988c2ecf20Sopenharmony_ci	}
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	g = alloc_disk(1 << PARTN_BITS);
18018c2ecf20Sopenharmony_ci	if (!g)
18028c2ecf20Sopenharmony_ci		goto out_free_cd;
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	ide_init_disk(g, drive);
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	info->dev.parent = &drive->gendev;
18078c2ecf20Sopenharmony_ci	info->dev.release = ide_cd_release;
18088c2ecf20Sopenharmony_ci	dev_set_name(&info->dev, "%s", dev_name(&drive->gendev));
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	if (device_register(&info->dev))
18118c2ecf20Sopenharmony_ci		goto out_free_disk;
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci	info->drive = drive;
18148c2ecf20Sopenharmony_ci	info->driver = &ide_cdrom_driver;
18158c2ecf20Sopenharmony_ci	info->disk = g;
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	g->private_data = &info->driver;
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	drive->driver_data = info;
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci	g->minors = 1;
18228c2ecf20Sopenharmony_ci	g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
18238c2ecf20Sopenharmony_ci	if (ide_cdrom_setup(drive)) {
18248c2ecf20Sopenharmony_ci		put_device(&info->dev);
18258c2ecf20Sopenharmony_ci		goto failed;
18268c2ecf20Sopenharmony_ci	}
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	ide_cd_read_toc(drive);
18298c2ecf20Sopenharmony_ci	g->fops = &idecd_ops;
18308c2ecf20Sopenharmony_ci	g->flags |= GENHD_FL_REMOVABLE | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
18318c2ecf20Sopenharmony_ci	g->events = DISK_EVENT_MEDIA_CHANGE;
18328c2ecf20Sopenharmony_ci	device_add_disk(&drive->gendev, g, NULL);
18338c2ecf20Sopenharmony_ci	return 0;
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ciout_free_disk:
18368c2ecf20Sopenharmony_ci	put_disk(g);
18378c2ecf20Sopenharmony_ciout_free_cd:
18388c2ecf20Sopenharmony_ci	kfree(info);
18398c2ecf20Sopenharmony_cifailed:
18408c2ecf20Sopenharmony_ci	return -ENODEV;
18418c2ecf20Sopenharmony_ci}
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_cistatic void __exit ide_cdrom_exit(void)
18448c2ecf20Sopenharmony_ci{
18458c2ecf20Sopenharmony_ci	driver_unregister(&ide_cdrom_driver.gen_driver);
18468c2ecf20Sopenharmony_ci}
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_cistatic int __init ide_cdrom_init(void)
18498c2ecf20Sopenharmony_ci{
18508c2ecf20Sopenharmony_ci	printk(KERN_INFO DRV_NAME " driver " IDECD_VERSION "\n");
18518c2ecf20Sopenharmony_ci	return driver_register(&ide_cdrom_driver.gen_driver);
18528c2ecf20Sopenharmony_ci}
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ciMODULE_ALIAS("ide:*m-cdrom*");
18558c2ecf20Sopenharmony_ciMODULE_ALIAS("ide-cd");
18568c2ecf20Sopenharmony_cimodule_init(ide_cdrom_init);
18578c2ecf20Sopenharmony_cimodule_exit(ide_cdrom_exit);
18588c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1859