18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * ATAPI support.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/kernel.h>
78c2ecf20Sopenharmony_ci#include <linux/cdrom.h>
88c2ecf20Sopenharmony_ci#include <linux/delay.h>
98c2ecf20Sopenharmony_ci#include <linux/export.h>
108c2ecf20Sopenharmony_ci#include <linux/ide.h>
118c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
128c2ecf20Sopenharmony_ci#include <linux/gfp.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define DRV_NAME "ide-atapi"
178c2ecf20Sopenharmony_ci#define PFX DRV_NAME ": "
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#ifdef DEBUG
208c2ecf20Sopenharmony_ci#define debug_log(fmt, args...) \
218c2ecf20Sopenharmony_ci	printk(KERN_INFO "ide: " fmt, ## args)
228c2ecf20Sopenharmony_ci#else
238c2ecf20Sopenharmony_ci#define debug_log(fmt, args...) do {} while (0)
248c2ecf20Sopenharmony_ci#endif
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define ATAPI_MIN_CDB_BYTES	12
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic inline int dev_is_idecd(ide_drive_t *drive)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	return drive->media == ide_cdrom || drive->media == ide_optical;
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/*
348c2ecf20Sopenharmony_ci * Check whether we can support a device,
358c2ecf20Sopenharmony_ci * based on the ATAPI IDENTIFY command results.
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_ciint ide_check_atapi_device(ide_drive_t *drive, const char *s)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	u16 *id = drive->id;
408c2ecf20Sopenharmony_ci	u8 gcw[2], protocol, device_type, removable, drq_type, packet_size;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	*((u16 *)&gcw) = id[ATA_ID_CONFIG];
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	protocol    = (gcw[1] & 0xC0) >> 6;
458c2ecf20Sopenharmony_ci	device_type =  gcw[1] & 0x1F;
468c2ecf20Sopenharmony_ci	removable   = (gcw[0] & 0x80) >> 7;
478c2ecf20Sopenharmony_ci	drq_type    = (gcw[0] & 0x60) >> 5;
488c2ecf20Sopenharmony_ci	packet_size =  gcw[0] & 0x03;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC
518c2ecf20Sopenharmony_ci	/* kludge for Apple PowerBook internal zip */
528c2ecf20Sopenharmony_ci	if (drive->media == ide_floppy && device_type == 5 &&
538c2ecf20Sopenharmony_ci	    !strstr((char *)&id[ATA_ID_PROD], "CD-ROM") &&
548c2ecf20Sopenharmony_ci	    strstr((char *)&id[ATA_ID_PROD], "ZIP"))
558c2ecf20Sopenharmony_ci		device_type = 0;
568c2ecf20Sopenharmony_ci#endif
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (protocol != 2)
598c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: %s: protocol (0x%02x) is not ATAPI\n",
608c2ecf20Sopenharmony_ci			s, drive->name, protocol);
618c2ecf20Sopenharmony_ci	else if ((drive->media == ide_floppy && device_type != 0) ||
628c2ecf20Sopenharmony_ci		 (drive->media == ide_tape && device_type != 1))
638c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: %s: invalid device type (0x%02x)\n",
648c2ecf20Sopenharmony_ci			s, drive->name, device_type);
658c2ecf20Sopenharmony_ci	else if (removable == 0)
668c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: %s: the removable flag is not set\n",
678c2ecf20Sopenharmony_ci			s, drive->name);
688c2ecf20Sopenharmony_ci	else if (drive->media == ide_floppy && drq_type == 3)
698c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: %s: sorry, DRQ type (0x%02x) not "
708c2ecf20Sopenharmony_ci			"supported\n", s, drive->name, drq_type);
718c2ecf20Sopenharmony_ci	else if (packet_size != 0)
728c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: %s: packet size (0x%02x) is not 12 "
738c2ecf20Sopenharmony_ci			"bytes\n", s, drive->name, packet_size);
748c2ecf20Sopenharmony_ci	else
758c2ecf20Sopenharmony_ci		return 1;
768c2ecf20Sopenharmony_ci	return 0;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_check_atapi_device);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_civoid ide_init_pc(struct ide_atapi_pc *pc)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	memset(pc, 0, sizeof(*pc));
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_init_pc);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/*
878c2ecf20Sopenharmony_ci * Add a special packet command request to the tail of the request queue,
888c2ecf20Sopenharmony_ci * and wait for it to be serviced.
898c2ecf20Sopenharmony_ci */
908c2ecf20Sopenharmony_ciint ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk,
918c2ecf20Sopenharmony_ci		      struct ide_atapi_pc *pc, void *buf, unsigned int bufflen)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct request *rq;
948c2ecf20Sopenharmony_ci	int error;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
978c2ecf20Sopenharmony_ci	ide_req(rq)->type = ATA_PRIV_MISC;
988c2ecf20Sopenharmony_ci	ide_req(rq)->special = pc;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	if (buf && bufflen) {
1018c2ecf20Sopenharmony_ci		error = blk_rq_map_kern(drive->queue, rq, buf, bufflen,
1028c2ecf20Sopenharmony_ci					GFP_NOIO);
1038c2ecf20Sopenharmony_ci		if (error)
1048c2ecf20Sopenharmony_ci			goto put_req;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	memcpy(scsi_req(rq)->cmd, pc->c, 12);
1088c2ecf20Sopenharmony_ci	if (drive->media == ide_tape)
1098c2ecf20Sopenharmony_ci		scsi_req(rq)->cmd[13] = REQ_IDETAPE_PC1;
1108c2ecf20Sopenharmony_ci	blk_execute_rq(drive->queue, disk, rq, 0);
1118c2ecf20Sopenharmony_ci	error = scsi_req(rq)->result ? -EIO : 0;
1128c2ecf20Sopenharmony_ciput_req:
1138c2ecf20Sopenharmony_ci	blk_put_request(rq);
1148c2ecf20Sopenharmony_ci	return error;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_queue_pc_tail);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ciint ide_do_test_unit_ready(ide_drive_t *drive, struct gendisk *disk)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	struct ide_atapi_pc pc;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	ide_init_pc(&pc);
1238c2ecf20Sopenharmony_ci	pc.c[0] = TEST_UNIT_READY;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_do_test_unit_ready);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ciint ide_do_start_stop(ide_drive_t *drive, struct gendisk *disk, int start)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	struct ide_atapi_pc pc;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	ide_init_pc(&pc);
1348c2ecf20Sopenharmony_ci	pc.c[0] = START_STOP;
1358c2ecf20Sopenharmony_ci	pc.c[4] = start;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	if (drive->media == ide_tape)
1388c2ecf20Sopenharmony_ci		pc.flags |= PC_FLAG_WAIT_FOR_DSC;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_do_start_stop);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ciint ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct ide_atapi_pc pc;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0)
1498c2ecf20Sopenharmony_ci		return 0;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	ide_init_pc(&pc);
1528c2ecf20Sopenharmony_ci	pc.c[0] = ALLOW_MEDIUM_REMOVAL;
1538c2ecf20Sopenharmony_ci	pc.c[4] = on;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_set_media_lock);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_civoid ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	ide_init_pc(pc);
1628c2ecf20Sopenharmony_ci	pc->c[0] = REQUEST_SENSE;
1638c2ecf20Sopenharmony_ci	if (drive->media == ide_floppy) {
1648c2ecf20Sopenharmony_ci		pc->c[4] = 255;
1658c2ecf20Sopenharmony_ci		pc->req_xfer = 18;
1668c2ecf20Sopenharmony_ci	} else {
1678c2ecf20Sopenharmony_ci		pc->c[4] = 20;
1688c2ecf20Sopenharmony_ci		pc->req_xfer = 20;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_create_request_sense_cmd);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_civoid ide_prep_sense(ide_drive_t *drive, struct request *rq)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	struct request_sense *sense = &drive->sense_data;
1768c2ecf20Sopenharmony_ci	struct request *sense_rq;
1778c2ecf20Sopenharmony_ci	struct scsi_request *req;
1788c2ecf20Sopenharmony_ci	unsigned int cmd_len, sense_len;
1798c2ecf20Sopenharmony_ci	int err;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	switch (drive->media) {
1828c2ecf20Sopenharmony_ci	case ide_floppy:
1838c2ecf20Sopenharmony_ci		cmd_len = 255;
1848c2ecf20Sopenharmony_ci		sense_len = 18;
1858c2ecf20Sopenharmony_ci		break;
1868c2ecf20Sopenharmony_ci	case ide_tape:
1878c2ecf20Sopenharmony_ci		cmd_len = 20;
1888c2ecf20Sopenharmony_ci		sense_len = 20;
1898c2ecf20Sopenharmony_ci		break;
1908c2ecf20Sopenharmony_ci	default:
1918c2ecf20Sopenharmony_ci		cmd_len = 18;
1928c2ecf20Sopenharmony_ci		sense_len = 18;
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	BUG_ON(sense_len > sizeof(*sense));
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (ata_sense_request(rq) || drive->sense_rq_armed)
1988c2ecf20Sopenharmony_ci		return;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	sense_rq = drive->sense_rq;
2018c2ecf20Sopenharmony_ci	if (!sense_rq) {
2028c2ecf20Sopenharmony_ci		sense_rq = blk_mq_alloc_request(drive->queue, REQ_OP_DRV_IN,
2038c2ecf20Sopenharmony_ci					BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
2048c2ecf20Sopenharmony_ci		drive->sense_rq = sense_rq;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci	req = scsi_req(sense_rq);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	memset(sense, 0, sizeof(*sense));
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	scsi_req_init(req);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	err = blk_rq_map_kern(drive->queue, sense_rq, sense, sense_len,
2138c2ecf20Sopenharmony_ci			      GFP_NOIO);
2148c2ecf20Sopenharmony_ci	if (unlikely(err)) {
2158c2ecf20Sopenharmony_ci		if (printk_ratelimit())
2168c2ecf20Sopenharmony_ci			printk(KERN_WARNING PFX "%s: failed to map sense "
2178c2ecf20Sopenharmony_ci					    "buffer\n", drive->name);
2188c2ecf20Sopenharmony_ci		blk_mq_free_request(sense_rq);
2198c2ecf20Sopenharmony_ci		drive->sense_rq = NULL;
2208c2ecf20Sopenharmony_ci		return;
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	sense_rq->rq_disk = rq->rq_disk;
2248c2ecf20Sopenharmony_ci	sense_rq->cmd_flags = REQ_OP_DRV_IN;
2258c2ecf20Sopenharmony_ci	ide_req(sense_rq)->type = ATA_PRIV_SENSE;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	req->cmd[0] = GPCMD_REQUEST_SENSE;
2288c2ecf20Sopenharmony_ci	req->cmd[4] = cmd_len;
2298c2ecf20Sopenharmony_ci	if (drive->media == ide_tape)
2308c2ecf20Sopenharmony_ci		req->cmd[13] = REQ_IDETAPE_PC1;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	drive->sense_rq_armed = true;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_prep_sense);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ciint ide_queue_sense_rq(ide_drive_t *drive, void *special)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
2398c2ecf20Sopenharmony_ci	struct request *sense_rq;
2408c2ecf20Sopenharmony_ci	unsigned long flags;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hwif->lock, flags);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/* deferred failure from ide_prep_sense() */
2458c2ecf20Sopenharmony_ci	if (!drive->sense_rq_armed) {
2468c2ecf20Sopenharmony_ci		printk(KERN_WARNING PFX "%s: error queuing a sense request\n",
2478c2ecf20Sopenharmony_ci		       drive->name);
2488c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hwif->lock, flags);
2498c2ecf20Sopenharmony_ci		return -ENOMEM;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	sense_rq = drive->sense_rq;
2538c2ecf20Sopenharmony_ci	ide_req(sense_rq)->special = special;
2548c2ecf20Sopenharmony_ci	drive->sense_rq_armed = false;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	drive->hwif->rq = NULL;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	ide_insert_request_head(drive, sense_rq);
2598c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hwif->lock, flags);
2608c2ecf20Sopenharmony_ci	return 0;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_queue_sense_rq);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci/*
2658c2ecf20Sopenharmony_ci * Called when an error was detected during the last packet command.
2668c2ecf20Sopenharmony_ci * We queue a request sense packet command at the head of the request
2678c2ecf20Sopenharmony_ci * queue.
2688c2ecf20Sopenharmony_ci */
2698c2ecf20Sopenharmony_civoid ide_retry_pc(ide_drive_t *drive)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	struct request *failed_rq = drive->hwif->rq;
2728c2ecf20Sopenharmony_ci	struct request *sense_rq = drive->sense_rq;
2738c2ecf20Sopenharmony_ci	struct ide_atapi_pc *pc = &drive->request_sense_pc;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	(void)ide_read_error(drive);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	/* init pc from sense_rq */
2788c2ecf20Sopenharmony_ci	ide_init_pc(pc);
2798c2ecf20Sopenharmony_ci	memcpy(pc->c, scsi_req(sense_rq)->cmd, 12);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (drive->media == ide_tape)
2828c2ecf20Sopenharmony_ci		drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	/*
2858c2ecf20Sopenharmony_ci	 * Push back the failed request and put request sense on top
2868c2ecf20Sopenharmony_ci	 * of it.  The failed command will be retried after sense data
2878c2ecf20Sopenharmony_ci	 * is acquired.
2888c2ecf20Sopenharmony_ci	 */
2898c2ecf20Sopenharmony_ci	drive->hwif->rq = NULL;
2908c2ecf20Sopenharmony_ci	ide_requeue_and_plug(drive, failed_rq);
2918c2ecf20Sopenharmony_ci	if (ide_queue_sense_rq(drive, pc))
2928c2ecf20Sopenharmony_ci		ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(failed_rq));
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_retry_pc);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ciint ide_cd_expiry(ide_drive_t *drive)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	struct request *rq = drive->hwif->rq;
2998c2ecf20Sopenharmony_ci	unsigned long wait = 0;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	debug_log("%s: scsi_req(rq)->cmd[0]: 0x%x\n", __func__, scsi_req(rq)->cmd[0]);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	/*
3048c2ecf20Sopenharmony_ci	 * Some commands are *slow* and normally take a long time to complete.
3058c2ecf20Sopenharmony_ci	 * Usually we can use the ATAPI "disconnect" to bypass this, but not all
3068c2ecf20Sopenharmony_ci	 * commands/drives support that. Let ide_timer_expiry keep polling us
3078c2ecf20Sopenharmony_ci	 * for these.
3088c2ecf20Sopenharmony_ci	 */
3098c2ecf20Sopenharmony_ci	switch (scsi_req(rq)->cmd[0]) {
3108c2ecf20Sopenharmony_ci	case GPCMD_BLANK:
3118c2ecf20Sopenharmony_ci	case GPCMD_FORMAT_UNIT:
3128c2ecf20Sopenharmony_ci	case GPCMD_RESERVE_RZONE_TRACK:
3138c2ecf20Sopenharmony_ci	case GPCMD_CLOSE_TRACK:
3148c2ecf20Sopenharmony_ci	case GPCMD_FLUSH_CACHE:
3158c2ecf20Sopenharmony_ci		wait = ATAPI_WAIT_PC;
3168c2ecf20Sopenharmony_ci		break;
3178c2ecf20Sopenharmony_ci	default:
3188c2ecf20Sopenharmony_ci		if (!(rq->rq_flags & RQF_QUIET))
3198c2ecf20Sopenharmony_ci			printk(KERN_INFO PFX "cmd 0x%x timed out\n",
3208c2ecf20Sopenharmony_ci					 scsi_req(rq)->cmd[0]);
3218c2ecf20Sopenharmony_ci		wait = 0;
3228c2ecf20Sopenharmony_ci		break;
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci	return wait;
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_cd_expiry);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ciint ide_cd_get_xferlen(struct request *rq)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	switch (req_op(rq)) {
3318c2ecf20Sopenharmony_ci	default:
3328c2ecf20Sopenharmony_ci		return 32768;
3338c2ecf20Sopenharmony_ci	case REQ_OP_SCSI_IN:
3348c2ecf20Sopenharmony_ci	case REQ_OP_SCSI_OUT:
3358c2ecf20Sopenharmony_ci		return blk_rq_bytes(rq);
3368c2ecf20Sopenharmony_ci	case REQ_OP_DRV_IN:
3378c2ecf20Sopenharmony_ci	case REQ_OP_DRV_OUT:
3388c2ecf20Sopenharmony_ci		switch (ide_req(rq)->type) {
3398c2ecf20Sopenharmony_ci		case ATA_PRIV_PC:
3408c2ecf20Sopenharmony_ci		case ATA_PRIV_SENSE:
3418c2ecf20Sopenharmony_ci			return blk_rq_bytes(rq);
3428c2ecf20Sopenharmony_ci		default:
3438c2ecf20Sopenharmony_ci			return 0;
3448c2ecf20Sopenharmony_ci		}
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_cd_get_xferlen);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_civoid ide_read_bcount_and_ireason(ide_drive_t *drive, u16 *bcount, u8 *ireason)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct ide_taskfile tf;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_NSECT |
3548c2ecf20Sopenharmony_ci				     IDE_VALID_LBAM | IDE_VALID_LBAH);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	*bcount = (tf.lbah << 8) | tf.lbam;
3578c2ecf20Sopenharmony_ci	*ireason = tf.nsect & 3;
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci/*
3628c2ecf20Sopenharmony_ci * Check the contents of the interrupt reason register and attempt to recover if
3638c2ecf20Sopenharmony_ci * there are problems.
3648c2ecf20Sopenharmony_ci *
3658c2ecf20Sopenharmony_ci * Returns:
3668c2ecf20Sopenharmony_ci * - 0 if everything's ok
3678c2ecf20Sopenharmony_ci * - 1 if the request has to be terminated.
3688c2ecf20Sopenharmony_ci */
3698c2ecf20Sopenharmony_ciint ide_check_ireason(ide_drive_t *drive, struct request *rq, int len,
3708c2ecf20Sopenharmony_ci		      int ireason, int rw)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	debug_log("ireason: 0x%x, rw: 0x%x\n", ireason, rw);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	if (ireason == (!rw << 1))
3778c2ecf20Sopenharmony_ci		return 0;
3788c2ecf20Sopenharmony_ci	else if (ireason == (rw << 1)) {
3798c2ecf20Sopenharmony_ci		printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n",
3808c2ecf20Sopenharmony_ci				drive->name, __func__);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci		if (dev_is_idecd(drive))
3838c2ecf20Sopenharmony_ci			ide_pad_transfer(drive, rw, len);
3848c2ecf20Sopenharmony_ci	} else if (!rw && ireason == ATAPI_COD) {
3858c2ecf20Sopenharmony_ci		if (dev_is_idecd(drive)) {
3868c2ecf20Sopenharmony_ci			/*
3878c2ecf20Sopenharmony_ci			 * Some drives (ASUS) seem to tell us that status info
3888c2ecf20Sopenharmony_ci			 * is available.  Just get it and ignore.
3898c2ecf20Sopenharmony_ci			 */
3908c2ecf20Sopenharmony_ci			(void)hwif->tp_ops->read_status(hwif);
3918c2ecf20Sopenharmony_ci			return 0;
3928c2ecf20Sopenharmony_ci		}
3938c2ecf20Sopenharmony_ci	} else {
3948c2ecf20Sopenharmony_ci		if (ireason & ATAPI_COD)
3958c2ecf20Sopenharmony_ci			printk(KERN_ERR PFX "%s: CoD != 0 in %s\n", drive->name,
3968c2ecf20Sopenharmony_ci					__func__);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci		/* drive wants a command packet, or invalid ireason... */
3998c2ecf20Sopenharmony_ci		printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n",
4008c2ecf20Sopenharmony_ci				drive->name, __func__, ireason);
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	if (dev_is_idecd(drive) && ata_pc_request(rq))
4048c2ecf20Sopenharmony_ci		rq->rq_flags |= RQF_FAILED;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	return 1;
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_check_ireason);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci/*
4118c2ecf20Sopenharmony_ci * This is the usual interrupt handler which will be called during a packet
4128c2ecf20Sopenharmony_ci * command.  We will transfer some of the data (as requested by the drive)
4138c2ecf20Sopenharmony_ci * and will re-point interrupt handler to us.
4148c2ecf20Sopenharmony_ci */
4158c2ecf20Sopenharmony_cistatic ide_startstop_t ide_pc_intr(ide_drive_t *drive)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	struct ide_atapi_pc *pc = drive->pc;
4188c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
4198c2ecf20Sopenharmony_ci	struct ide_cmd *cmd = &hwif->cmd;
4208c2ecf20Sopenharmony_ci	struct request *rq = hwif->rq;
4218c2ecf20Sopenharmony_ci	const struct ide_tp_ops *tp_ops = hwif->tp_ops;
4228c2ecf20Sopenharmony_ci	unsigned int timeout, done;
4238c2ecf20Sopenharmony_ci	u16 bcount;
4248c2ecf20Sopenharmony_ci	u8 stat, ireason, dsc = 0;
4258c2ecf20Sopenharmony_ci	u8 write = !!(pc->flags & PC_FLAG_WRITING);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	debug_log("Enter %s - interrupt handler\n", __func__);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
4308c2ecf20Sopenharmony_ci					       : WAIT_TAPE_CMD;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	/* Clear the interrupt */
4338c2ecf20Sopenharmony_ci	stat = tp_ops->read_status(hwif);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
4368c2ecf20Sopenharmony_ci		int rc;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci		drive->waiting_for_dma = 0;
4398c2ecf20Sopenharmony_ci		rc = hwif->dma_ops->dma_end(drive);
4408c2ecf20Sopenharmony_ci		ide_dma_unmap_sg(drive, cmd);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci		if (rc || (drive->media == ide_tape && (stat & ATA_ERR))) {
4438c2ecf20Sopenharmony_ci			if (drive->media == ide_floppy)
4448c2ecf20Sopenharmony_ci				printk(KERN_ERR PFX "%s: DMA %s error\n",
4458c2ecf20Sopenharmony_ci					drive->name, rq_data_dir(pc->rq)
4468c2ecf20Sopenharmony_ci						     ? "write" : "read");
4478c2ecf20Sopenharmony_ci			pc->flags |= PC_FLAG_DMA_ERROR;
4488c2ecf20Sopenharmony_ci		} else
4498c2ecf20Sopenharmony_ci			scsi_req(rq)->resid_len = 0;
4508c2ecf20Sopenharmony_ci		debug_log("%s: DMA finished\n", drive->name);
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* No more interrupts */
4548c2ecf20Sopenharmony_ci	if ((stat & ATA_DRQ) == 0) {
4558c2ecf20Sopenharmony_ci		int uptodate;
4568c2ecf20Sopenharmony_ci		blk_status_t error;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		debug_log("Packet command completed, %d bytes transferred\n",
4598c2ecf20Sopenharmony_ci			  blk_rq_bytes(rq));
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci		local_irq_enable_in_hardirq();
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci		if (drive->media == ide_tape &&
4668c2ecf20Sopenharmony_ci		    (stat & ATA_ERR) && scsi_req(rq)->cmd[0] == REQUEST_SENSE)
4678c2ecf20Sopenharmony_ci			stat &= ~ATA_ERR;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci		if ((stat & ATA_ERR) || (pc->flags & PC_FLAG_DMA_ERROR)) {
4708c2ecf20Sopenharmony_ci			/* Error detected */
4718c2ecf20Sopenharmony_ci			debug_log("%s: I/O error\n", drive->name);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci			if (drive->media != ide_tape)
4748c2ecf20Sopenharmony_ci				scsi_req(pc->rq)->result++;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci			if (scsi_req(rq)->cmd[0] == REQUEST_SENSE) {
4778c2ecf20Sopenharmony_ci				printk(KERN_ERR PFX "%s: I/O error in request "
4788c2ecf20Sopenharmony_ci						"sense command\n", drive->name);
4798c2ecf20Sopenharmony_ci				return ide_do_reset(drive);
4808c2ecf20Sopenharmony_ci			}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci			debug_log("[cmd %x]: check condition\n", scsi_req(rq)->cmd[0]);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci			/* Retry operation */
4858c2ecf20Sopenharmony_ci			ide_retry_pc(drive);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci			/* queued, but not started */
4888c2ecf20Sopenharmony_ci			return ide_stopped;
4898c2ecf20Sopenharmony_ci		}
4908c2ecf20Sopenharmony_ci		pc->error = 0;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0)
4938c2ecf20Sopenharmony_ci			dsc = 1;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci		/*
4968c2ecf20Sopenharmony_ci		 * ->pc_callback() might change rq->data_len for
4978c2ecf20Sopenharmony_ci		 * residual count, cache total length.
4988c2ecf20Sopenharmony_ci		 */
4998c2ecf20Sopenharmony_ci		done = blk_rq_bytes(rq);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci		/* Command finished - Call the callback function */
5028c2ecf20Sopenharmony_ci		uptodate = drive->pc_callback(drive, dsc);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci		if (uptodate == 0)
5058c2ecf20Sopenharmony_ci			drive->failed_pc = NULL;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci		if (ata_misc_request(rq)) {
5088c2ecf20Sopenharmony_ci			scsi_req(rq)->result = 0;
5098c2ecf20Sopenharmony_ci			error = BLK_STS_OK;
5108c2ecf20Sopenharmony_ci		} else {
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci			if (blk_rq_is_passthrough(rq) && uptodate <= 0) {
5138c2ecf20Sopenharmony_ci				if (scsi_req(rq)->result == 0)
5148c2ecf20Sopenharmony_ci					scsi_req(rq)->result = -EIO;
5158c2ecf20Sopenharmony_ci			}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci			error = uptodate ? BLK_STS_OK : BLK_STS_IOERR;
5188c2ecf20Sopenharmony_ci		}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci		ide_complete_rq(drive, error, blk_rq_bytes(rq));
5218c2ecf20Sopenharmony_ci		return ide_stopped;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
5258c2ecf20Sopenharmony_ci		pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
5268c2ecf20Sopenharmony_ci		printk(KERN_ERR PFX "%s: The device wants to issue more "
5278c2ecf20Sopenharmony_ci				"interrupts in DMA mode\n", drive->name);
5288c2ecf20Sopenharmony_ci		ide_dma_off(drive);
5298c2ecf20Sopenharmony_ci		return ide_do_reset(drive);
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	/* Get the number of bytes to transfer on this interrupt. */
5338c2ecf20Sopenharmony_ci	ide_read_bcount_and_ireason(drive, &bcount, &ireason);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	if (ide_check_ireason(drive, rq, bcount, ireason, write))
5368c2ecf20Sopenharmony_ci		return ide_do_reset(drive);
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	done = min_t(unsigned int, bcount, cmd->nleft);
5398c2ecf20Sopenharmony_ci	ide_pio_bytes(drive, cmd, write, done);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	/* Update transferred byte count */
5428c2ecf20Sopenharmony_ci	scsi_req(rq)->resid_len -= done;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	bcount -= done;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	if (bcount)
5478c2ecf20Sopenharmony_ci		ide_pad_transfer(drive, write, bcount);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	debug_log("[cmd %x] transferred %d bytes, padded %d bytes, resid: %u\n",
5508c2ecf20Sopenharmony_ci		  scsi_req(rq)->cmd[0], done, bcount, scsi_req(rq)->resid_len);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	/* And set the interrupt handler again */
5538c2ecf20Sopenharmony_ci	ide_set_handler(drive, ide_pc_intr, timeout);
5548c2ecf20Sopenharmony_ci	return ide_started;
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistatic void ide_init_packet_cmd(struct ide_cmd *cmd, u8 valid_tf,
5588c2ecf20Sopenharmony_ci				u16 bcount, u8 dma)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	cmd->protocol = dma ? ATAPI_PROT_DMA : ATAPI_PROT_PIO;
5618c2ecf20Sopenharmony_ci	cmd->valid.out.tf = IDE_VALID_LBAH | IDE_VALID_LBAM |
5628c2ecf20Sopenharmony_ci			    IDE_VALID_FEATURE | valid_tf;
5638c2ecf20Sopenharmony_ci	cmd->tf.command = ATA_CMD_PACKET;
5648c2ecf20Sopenharmony_ci	cmd->tf.feature = dma;		/* Use PIO/DMA */
5658c2ecf20Sopenharmony_ci	cmd->tf.lbam    = bcount & 0xff;
5668c2ecf20Sopenharmony_ci	cmd->tf.lbah    = (bcount >> 8) & 0xff;
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_cistatic u8 ide_read_ireason(ide_drive_t *drive)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	struct ide_taskfile tf;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_NSECT);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	return tf.nsect & 3;
5768c2ecf20Sopenharmony_ci}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_cistatic u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	int retries = 100;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	while (retries-- && ((ireason & ATAPI_COD) == 0 ||
5838c2ecf20Sopenharmony_ci		(ireason & ATAPI_IO))) {
5848c2ecf20Sopenharmony_ci		printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing "
5858c2ecf20Sopenharmony_ci				"a packet command, retrying\n", drive->name);
5868c2ecf20Sopenharmony_ci		udelay(100);
5878c2ecf20Sopenharmony_ci		ireason = ide_read_ireason(drive);
5888c2ecf20Sopenharmony_ci		if (retries == 0) {
5898c2ecf20Sopenharmony_ci			printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing"
5908c2ecf20Sopenharmony_ci					" a packet command, ignoring\n",
5918c2ecf20Sopenharmony_ci					drive->name);
5928c2ecf20Sopenharmony_ci			ireason |= ATAPI_COD;
5938c2ecf20Sopenharmony_ci			ireason &= ~ATAPI_IO;
5948c2ecf20Sopenharmony_ci		}
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	return ireason;
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cistatic int ide_delayed_transfer_pc(ide_drive_t *drive)
6018c2ecf20Sopenharmony_ci{
6028c2ecf20Sopenharmony_ci	/* Send the actual packet */
6038c2ecf20Sopenharmony_ci	drive->hwif->tp_ops->output_data(drive, NULL, drive->pc->c, 12);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	/* Timeout for the packet command */
6068c2ecf20Sopenharmony_ci	return WAIT_FLOPPY_CMD;
6078c2ecf20Sopenharmony_ci}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_cistatic ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
6108c2ecf20Sopenharmony_ci{
6118c2ecf20Sopenharmony_ci	struct ide_atapi_pc *pc;
6128c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
6138c2ecf20Sopenharmony_ci	struct request *rq = hwif->rq;
6148c2ecf20Sopenharmony_ci	ide_expiry_t *expiry;
6158c2ecf20Sopenharmony_ci	unsigned int timeout;
6168c2ecf20Sopenharmony_ci	int cmd_len;
6178c2ecf20Sopenharmony_ci	ide_startstop_t startstop;
6188c2ecf20Sopenharmony_ci	u8 ireason;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	if (ide_wait_stat(&startstop, drive, ATA_DRQ, ATA_BUSY, WAIT_READY)) {
6218c2ecf20Sopenharmony_ci		printk(KERN_ERR PFX "%s: Strange, packet command initiated yet "
6228c2ecf20Sopenharmony_ci				"DRQ isn't asserted\n", drive->name);
6238c2ecf20Sopenharmony_ci		return startstop;
6248c2ecf20Sopenharmony_ci	}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
6278c2ecf20Sopenharmony_ci		if (drive->dma)
6288c2ecf20Sopenharmony_ci			drive->waiting_for_dma = 1;
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	if (dev_is_idecd(drive)) {
6328c2ecf20Sopenharmony_ci		/* ATAPI commands get padded out to 12 bytes minimum */
6338c2ecf20Sopenharmony_ci		cmd_len = COMMAND_SIZE(scsi_req(rq)->cmd[0]);
6348c2ecf20Sopenharmony_ci		if (cmd_len < ATAPI_MIN_CDB_BYTES)
6358c2ecf20Sopenharmony_ci			cmd_len = ATAPI_MIN_CDB_BYTES;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci		timeout = rq->timeout;
6388c2ecf20Sopenharmony_ci		expiry  = ide_cd_expiry;
6398c2ecf20Sopenharmony_ci	} else {
6408c2ecf20Sopenharmony_ci		pc = drive->pc;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		cmd_len = ATAPI_MIN_CDB_BYTES;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci		/*
6458c2ecf20Sopenharmony_ci		 * If necessary schedule the packet transfer to occur 'timeout'
6468c2ecf20Sopenharmony_ci		 * milliseconds later in ide_delayed_transfer_pc() after the
6478c2ecf20Sopenharmony_ci		 * device says it's ready for a packet.
6488c2ecf20Sopenharmony_ci		 */
6498c2ecf20Sopenharmony_ci		if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) {
6508c2ecf20Sopenharmony_ci			timeout = drive->pc_delay;
6518c2ecf20Sopenharmony_ci			expiry = &ide_delayed_transfer_pc;
6528c2ecf20Sopenharmony_ci		} else {
6538c2ecf20Sopenharmony_ci			timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
6548c2ecf20Sopenharmony_ci							       : WAIT_TAPE_CMD;
6558c2ecf20Sopenharmony_ci			expiry = NULL;
6568c2ecf20Sopenharmony_ci		}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci		ireason = ide_read_ireason(drive);
6598c2ecf20Sopenharmony_ci		if (drive->media == ide_tape)
6608c2ecf20Sopenharmony_ci			ireason = ide_wait_ireason(drive, ireason);
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci		if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) {
6638c2ecf20Sopenharmony_ci			printk(KERN_ERR PFX "%s: (IO,CoD) != (0,1) while "
6648c2ecf20Sopenharmony_ci				"issuing a packet command\n", drive->name);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci			return ide_do_reset(drive);
6678c2ecf20Sopenharmony_ci		}
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	hwif->expiry = expiry;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	/* Set the interrupt routine */
6738c2ecf20Sopenharmony_ci	ide_set_handler(drive,
6748c2ecf20Sopenharmony_ci			(dev_is_idecd(drive) ? drive->irq_handler
6758c2ecf20Sopenharmony_ci					     : ide_pc_intr),
6768c2ecf20Sopenharmony_ci			timeout);
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	/* Send the actual packet */
6798c2ecf20Sopenharmony_ci	if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0)
6808c2ecf20Sopenharmony_ci		hwif->tp_ops->output_data(drive, NULL, scsi_req(rq)->cmd, cmd_len);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	/* Begin DMA, if necessary */
6838c2ecf20Sopenharmony_ci	if (dev_is_idecd(drive)) {
6848c2ecf20Sopenharmony_ci		if (drive->dma)
6858c2ecf20Sopenharmony_ci			hwif->dma_ops->dma_start(drive);
6868c2ecf20Sopenharmony_ci	} else {
6878c2ecf20Sopenharmony_ci		if (pc->flags & PC_FLAG_DMA_OK) {
6888c2ecf20Sopenharmony_ci			pc->flags |= PC_FLAG_DMA_IN_PROGRESS;
6898c2ecf20Sopenharmony_ci			hwif->dma_ops->dma_start(drive);
6908c2ecf20Sopenharmony_ci		}
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	return ide_started;
6948c2ecf20Sopenharmony_ci}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ciide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	struct ide_atapi_pc *pc;
6998c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
7008c2ecf20Sopenharmony_ci	ide_expiry_t *expiry = NULL;
7018c2ecf20Sopenharmony_ci	struct request *rq = hwif->rq;
7028c2ecf20Sopenharmony_ci	unsigned int timeout, bytes;
7038c2ecf20Sopenharmony_ci	u16 bcount;
7048c2ecf20Sopenharmony_ci	u8 valid_tf;
7058c2ecf20Sopenharmony_ci	u8 drq_int = !!(drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	if (dev_is_idecd(drive)) {
7088c2ecf20Sopenharmony_ci		valid_tf = IDE_VALID_NSECT | IDE_VALID_LBAL;
7098c2ecf20Sopenharmony_ci		bcount = ide_cd_get_xferlen(rq);
7108c2ecf20Sopenharmony_ci		expiry = ide_cd_expiry;
7118c2ecf20Sopenharmony_ci		timeout = ATAPI_WAIT_PC;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci		if (drive->dma)
7148c2ecf20Sopenharmony_ci			drive->dma = !ide_dma_prepare(drive, cmd);
7158c2ecf20Sopenharmony_ci	} else {
7168c2ecf20Sopenharmony_ci		pc = drive->pc;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci		valid_tf = IDE_VALID_DEVICE;
7198c2ecf20Sopenharmony_ci		bytes = blk_rq_bytes(rq);
7208c2ecf20Sopenharmony_ci		bcount = ((drive->media == ide_tape) ? bytes
7218c2ecf20Sopenharmony_ci						     : min_t(unsigned int,
7228c2ecf20Sopenharmony_ci							     bytes, 63 * 1024));
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci		/* We haven't transferred any data yet */
7258c2ecf20Sopenharmony_ci		scsi_req(rq)->resid_len = bcount;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci		if (pc->flags & PC_FLAG_DMA_ERROR) {
7288c2ecf20Sopenharmony_ci			pc->flags &= ~PC_FLAG_DMA_ERROR;
7298c2ecf20Sopenharmony_ci			ide_dma_off(drive);
7308c2ecf20Sopenharmony_ci		}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci		if (pc->flags & PC_FLAG_DMA_OK)
7338c2ecf20Sopenharmony_ci			drive->dma = !ide_dma_prepare(drive, cmd);
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci		if (!drive->dma)
7368c2ecf20Sopenharmony_ci			pc->flags &= ~PC_FLAG_DMA_OK;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci		timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
7398c2ecf20Sopenharmony_ci						       : WAIT_TAPE_CMD;
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	ide_init_packet_cmd(cmd, valid_tf, bcount, drive->dma);
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	(void)do_rw_taskfile(drive, cmd);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	if (drq_int) {
7478c2ecf20Sopenharmony_ci		if (drive->dma)
7488c2ecf20Sopenharmony_ci			drive->waiting_for_dma = 0;
7498c2ecf20Sopenharmony_ci		hwif->expiry = expiry;
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	ide_execute_command(drive, cmd, ide_transfer_pc, timeout);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	return drq_int ? ide_started : ide_transfer_pc(drive);
7558c2ecf20Sopenharmony_ci}
7568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_issue_pc);
757