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