18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include <linux/kernel.h> 48c2ecf20Sopenharmony_ci#include <linux/gfp.h> 58c2ecf20Sopenharmony_ci#include <linux/ide.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ciDEFINE_MUTEX(ide_setting_mtx); 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ciide_devset_get(io_32bit, io_32bit); 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistatic int set_io_32bit(ide_drive_t *drive, int arg) 128c2ecf20Sopenharmony_ci{ 138c2ecf20Sopenharmony_ci if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) 148c2ecf20Sopenharmony_ci return -EPERM; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1)) 178c2ecf20Sopenharmony_ci return -EINVAL; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci drive->io_32bit = arg; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci return 0; 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int set_ksettings(ide_drive_t *drive, int arg) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci if (arg < 0 || arg > 1) 298c2ecf20Sopenharmony_ci return -EINVAL; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (arg) 328c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS; 338c2ecf20Sopenharmony_ci else 348c2ecf20Sopenharmony_ci drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci return 0; 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ciide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic int set_using_dma(ide_drive_t *drive, int arg) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci#ifdef CONFIG_BLK_DEV_IDEDMA 448c2ecf20Sopenharmony_ci int err = -EPERM; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (arg < 0 || arg > 1) 478c2ecf20Sopenharmony_ci return -EINVAL; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (ata_id_has_dma(drive->id) == 0) 508c2ecf20Sopenharmony_ci goto out; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (drive->hwif->dma_ops == NULL) 538c2ecf20Sopenharmony_ci goto out; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci err = 0; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (arg) { 588c2ecf20Sopenharmony_ci if (ide_set_dma(drive)) 598c2ecf20Sopenharmony_ci err = -EIO; 608c2ecf20Sopenharmony_ci } else 618c2ecf20Sopenharmony_ci ide_dma_off(drive); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ciout: 648c2ecf20Sopenharmony_ci return err; 658c2ecf20Sopenharmony_ci#else 668c2ecf20Sopenharmony_ci if (arg < 0 || arg > 1) 678c2ecf20Sopenharmony_ci return -EINVAL; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return -EPERM; 708c2ecf20Sopenharmony_ci#endif 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_cistatic int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci switch (req_pio) { 798c2ecf20Sopenharmony_ci case 202: 808c2ecf20Sopenharmony_ci case 201: 818c2ecf20Sopenharmony_ci case 200: 828c2ecf20Sopenharmony_ci case 102: 838c2ecf20Sopenharmony_ci case 101: 848c2ecf20Sopenharmony_ci case 100: 858c2ecf20Sopenharmony_ci return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0; 868c2ecf20Sopenharmony_ci case 9: 878c2ecf20Sopenharmony_ci case 8: 888c2ecf20Sopenharmony_ci return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0; 898c2ecf20Sopenharmony_ci case 7: 908c2ecf20Sopenharmony_ci case 6: 918c2ecf20Sopenharmony_ci return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0; 928c2ecf20Sopenharmony_ci default: 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int set_pio_mode(ide_drive_t *drive, int arg) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 1008c2ecf20Sopenharmony_ci const struct ide_port_ops *port_ops = hwif->port_ops; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (arg < 0 || arg > 255) 1038c2ecf20Sopenharmony_ci return -EINVAL; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (port_ops == NULL || port_ops->set_pio_mode == NULL || 1068c2ecf20Sopenharmony_ci (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)) 1078c2ecf20Sopenharmony_ci return -ENOSYS; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (set_pio_mode_abuse(drive->hwif, arg)) { 1108c2ecf20Sopenharmony_ci drive->pio_mode = arg + XFER_PIO_0; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (arg == 8 || arg == 9) { 1138c2ecf20Sopenharmony_ci unsigned long flags; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */ 1168c2ecf20Sopenharmony_ci spin_lock_irqsave(&hwif->lock, flags); 1178c2ecf20Sopenharmony_ci port_ops->set_pio_mode(hwif, drive); 1188c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hwif->lock, flags); 1198c2ecf20Sopenharmony_ci } else 1208c2ecf20Sopenharmony_ci port_ops->set_pio_mode(hwif, drive); 1218c2ecf20Sopenharmony_ci } else { 1228c2ecf20Sopenharmony_ci int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci ide_set_pio(drive, arg); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) { 1278c2ecf20Sopenharmony_ci if (keep_dma) 1288c2ecf20Sopenharmony_ci ide_dma_on(drive); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ciide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int set_unmaskirq(ide_drive_t *drive, int arg) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci if (drive->dev_flags & IDE_DFLAG_NO_UNMASK) 1408c2ecf20Sopenharmony_ci return -EPERM; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (arg < 0 || arg > 1) 1438c2ecf20Sopenharmony_ci return -EINVAL; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (arg) 1468c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_UNMASK; 1478c2ecf20Sopenharmony_ci else 1488c2ecf20Sopenharmony_ci drive->dev_flags &= ~IDE_DFLAG_UNMASK; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return 0; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ciide_ext_devset_rw_sync(io_32bit, io_32bit); 1548c2ecf20Sopenharmony_ciide_ext_devset_rw_sync(keepsettings, ksettings); 1558c2ecf20Sopenharmony_ciide_ext_devset_rw_sync(unmaskirq, unmaskirq); 1568c2ecf20Sopenharmony_ciide_ext_devset_rw_sync(using_dma, using_dma); 1578c2ecf20Sopenharmony_ci__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ciint ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting, 1608c2ecf20Sopenharmony_ci int arg) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct request_queue *q = drive->queue; 1638c2ecf20Sopenharmony_ci struct request *rq; 1648c2ecf20Sopenharmony_ci int ret = 0; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (!(setting->flags & DS_SYNC)) 1678c2ecf20Sopenharmony_ci return setting->set(drive, arg); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci rq = blk_get_request(q, REQ_OP_DRV_IN, 0); 1708c2ecf20Sopenharmony_ci ide_req(rq)->type = ATA_PRIV_MISC; 1718c2ecf20Sopenharmony_ci scsi_req(rq)->cmd_len = 5; 1728c2ecf20Sopenharmony_ci scsi_req(rq)->cmd[0] = REQ_DEVSET_EXEC; 1738c2ecf20Sopenharmony_ci *(int *)&scsi_req(rq)->cmd[1] = arg; 1748c2ecf20Sopenharmony_ci ide_req(rq)->special = setting->set; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci blk_execute_rq(q, NULL, rq, 0); 1778c2ecf20Sopenharmony_ci ret = scsi_req(rq)->result; 1788c2ecf20Sopenharmony_ci blk_put_request(rq); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return ret; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ciide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci int err, (*setfunc)(ide_drive_t *, int) = ide_req(rq)->special; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci err = setfunc(drive, *(int *)&scsi_req(rq)->cmd[1]); 1888c2ecf20Sopenharmony_ci if (err) 1898c2ecf20Sopenharmony_ci scsi_req(rq)->result = err; 1908c2ecf20Sopenharmony_ci ide_complete_rq(drive, 0, blk_rq_bytes(rq)); 1918c2ecf20Sopenharmony_ci return ide_stopped; 1928c2ecf20Sopenharmony_ci} 193