18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include <linux/kernel.h> 48c2ecf20Sopenharmony_ci#include <linux/export.h> 58c2ecf20Sopenharmony_ci#include <linux/ide.h> 68c2ecf20Sopenharmony_ci#include <linux/delay.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_cistatic ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, 98c2ecf20Sopenharmony_ci u8 stat, u8 err) 108c2ecf20Sopenharmony_ci{ 118c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci if ((stat & ATA_BUSY) || 148c2ecf20Sopenharmony_ci ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) { 158c2ecf20Sopenharmony_ci /* other bits are useless when BUSY */ 168c2ecf20Sopenharmony_ci scsi_req(rq)->result |= ERROR_RESET; 178c2ecf20Sopenharmony_ci } else if (stat & ATA_ERR) { 188c2ecf20Sopenharmony_ci /* err has different meaning on cdrom and tape */ 198c2ecf20Sopenharmony_ci if (err == ATA_ABORTED) { 208c2ecf20Sopenharmony_ci if ((drive->dev_flags & IDE_DFLAG_LBA) && 218c2ecf20Sopenharmony_ci /* some newer drives don't support ATA_CMD_INIT_DEV_PARAMS */ 228c2ecf20Sopenharmony_ci hwif->tp_ops->read_status(hwif) == ATA_CMD_INIT_DEV_PARAMS) 238c2ecf20Sopenharmony_ci return ide_stopped; 248c2ecf20Sopenharmony_ci } else if ((err & BAD_CRC) == BAD_CRC) { 258c2ecf20Sopenharmony_ci /* UDMA crc error, just retry the operation */ 268c2ecf20Sopenharmony_ci drive->crc_count++; 278c2ecf20Sopenharmony_ci } else if (err & (ATA_BBK | ATA_UNC)) { 288c2ecf20Sopenharmony_ci /* retries won't help these */ 298c2ecf20Sopenharmony_ci scsi_req(rq)->result = ERROR_MAX; 308c2ecf20Sopenharmony_ci } else if (err & ATA_TRK0NF) { 318c2ecf20Sopenharmony_ci /* help it find track zero */ 328c2ecf20Sopenharmony_ci scsi_req(rq)->result |= ERROR_RECAL; 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if ((stat & ATA_DRQ) && rq_data_dir(rq) == READ && 378c2ecf20Sopenharmony_ci (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) { 388c2ecf20Sopenharmony_ci int nsect = drive->mult_count ? drive->mult_count : 1; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci ide_pad_transfer(drive, READ, nsect * SECTOR_SIZE); 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (scsi_req(rq)->result >= ERROR_MAX || blk_noretry_request(rq)) { 448c2ecf20Sopenharmony_ci ide_kill_rq(drive, rq); 458c2ecf20Sopenharmony_ci return ide_stopped; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ)) 498c2ecf20Sopenharmony_ci scsi_req(rq)->result |= ERROR_RESET; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if ((scsi_req(rq)->result & ERROR_RESET) == ERROR_RESET) { 528c2ecf20Sopenharmony_ci ++scsi_req(rq)->result; 538c2ecf20Sopenharmony_ci return ide_do_reset(drive); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if ((scsi_req(rq)->result & ERROR_RECAL) == ERROR_RECAL) 578c2ecf20Sopenharmony_ci drive->special_flags |= IDE_SFLAG_RECALIBRATE; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci ++scsi_req(rq)->result; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return ide_stopped; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, 658c2ecf20Sopenharmony_ci u8 stat, u8 err) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if ((stat & ATA_BUSY) || 708c2ecf20Sopenharmony_ci ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) { 718c2ecf20Sopenharmony_ci /* other bits are useless when BUSY */ 728c2ecf20Sopenharmony_ci scsi_req(rq)->result |= ERROR_RESET; 738c2ecf20Sopenharmony_ci } else { 748c2ecf20Sopenharmony_ci /* add decoding error stuff */ 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ)) 788c2ecf20Sopenharmony_ci /* force an abort */ 798c2ecf20Sopenharmony_ci hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (scsi_req(rq)->result >= ERROR_MAX) { 828c2ecf20Sopenharmony_ci ide_kill_rq(drive, rq); 838c2ecf20Sopenharmony_ci } else { 848c2ecf20Sopenharmony_ci if ((scsi_req(rq)->result & ERROR_RESET) == ERROR_RESET) { 858c2ecf20Sopenharmony_ci ++scsi_req(rq)->result; 868c2ecf20Sopenharmony_ci return ide_do_reset(drive); 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci ++scsi_req(rq)->result; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return ide_stopped; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic ide_startstop_t __ide_error(ide_drive_t *drive, struct request *rq, 958c2ecf20Sopenharmony_ci u8 stat, u8 err) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci if (drive->media == ide_disk) 988c2ecf20Sopenharmony_ci return ide_ata_error(drive, rq, stat, err); 998c2ecf20Sopenharmony_ci return ide_atapi_error(drive, rq, stat, err); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/** 1038c2ecf20Sopenharmony_ci * ide_error - handle an error on the IDE 1048c2ecf20Sopenharmony_ci * @drive: drive the error occurred on 1058c2ecf20Sopenharmony_ci * @msg: message to report 1068c2ecf20Sopenharmony_ci * @stat: status bits 1078c2ecf20Sopenharmony_ci * 1088c2ecf20Sopenharmony_ci * ide_error() takes action based on the error returned by the drive. 1098c2ecf20Sopenharmony_ci * For normal I/O that may well include retries. We deal with 1108c2ecf20Sopenharmony_ci * both new-style (taskfile) and old style command handling here. 1118c2ecf20Sopenharmony_ci * In the case of taskfile command handling there is work left to 1128c2ecf20Sopenharmony_ci * do 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciide_startstop_t ide_error(ide_drive_t *drive, const char *msg, u8 stat) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct request *rq; 1188c2ecf20Sopenharmony_ci u8 err; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci err = ide_dump_status(drive, msg, stat); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci rq = drive->hwif->rq; 1238c2ecf20Sopenharmony_ci if (rq == NULL) 1248c2ecf20Sopenharmony_ci return ide_stopped; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* retry only "normal" I/O: */ 1278c2ecf20Sopenharmony_ci if (blk_rq_is_passthrough(rq)) { 1288c2ecf20Sopenharmony_ci if (ata_taskfile_request(rq)) { 1298c2ecf20Sopenharmony_ci struct ide_cmd *cmd = ide_req(rq)->special; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (cmd) 1328c2ecf20Sopenharmony_ci ide_complete_cmd(drive, cmd, stat, err); 1338c2ecf20Sopenharmony_ci } else if (ata_pm_request(rq)) { 1348c2ecf20Sopenharmony_ci scsi_req(rq)->result = 1; 1358c2ecf20Sopenharmony_ci ide_complete_pm_rq(drive, rq); 1368c2ecf20Sopenharmony_ci return ide_stopped; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci scsi_req(rq)->result = err; 1398c2ecf20Sopenharmony_ci ide_complete_rq(drive, err ? BLK_STS_IOERR : BLK_STS_OK, blk_rq_bytes(rq)); 1408c2ecf20Sopenharmony_ci return ide_stopped; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return __ide_error(drive, rq, stat, err); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_error); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic inline void ide_complete_drive_reset(ide_drive_t *drive, blk_status_t err) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct request *rq = drive->hwif->rq; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (rq && ata_misc_request(rq) && 1528c2ecf20Sopenharmony_ci scsi_req(rq)->cmd[0] == REQ_DRIVE_RESET) { 1538c2ecf20Sopenharmony_ci if (err <= 0 && scsi_req(rq)->result == 0) 1548c2ecf20Sopenharmony_ci scsi_req(rq)->result = -EIO; 1558c2ecf20Sopenharmony_ci ide_complete_rq(drive, err, blk_rq_bytes(rq)); 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* needed below */ 1608c2ecf20Sopenharmony_cistatic ide_startstop_t do_reset1(ide_drive_t *, int); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* 1638c2ecf20Sopenharmony_ci * atapi_reset_pollfunc() gets invoked to poll the interface for completion 1648c2ecf20Sopenharmony_ci * every 50ms during an atapi drive reset operation. If the drive has not yet 1658c2ecf20Sopenharmony_ci * responded, and we have not yet hit our maximum waiting time, then the timer 1668c2ecf20Sopenharmony_ci * is restarted for another 50ms. 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_cistatic ide_startstop_t atapi_reset_pollfunc(ide_drive_t *drive) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 1718c2ecf20Sopenharmony_ci const struct ide_tp_ops *tp_ops = hwif->tp_ops; 1728c2ecf20Sopenharmony_ci u8 stat; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci tp_ops->dev_select(drive); 1758c2ecf20Sopenharmony_ci udelay(10); 1768c2ecf20Sopenharmony_ci stat = tp_ops->read_status(hwif); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (OK_STAT(stat, 0, ATA_BUSY)) 1798c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: ATAPI reset complete\n", drive->name); 1808c2ecf20Sopenharmony_ci else { 1818c2ecf20Sopenharmony_ci if (time_before(jiffies, hwif->poll_timeout)) { 1828c2ecf20Sopenharmony_ci ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20); 1838c2ecf20Sopenharmony_ci /* continue polling */ 1848c2ecf20Sopenharmony_ci return ide_started; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci /* end of polling */ 1878c2ecf20Sopenharmony_ci hwif->polling = 0; 1888c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: ATAPI reset timed-out, status=0x%02x\n", 1898c2ecf20Sopenharmony_ci drive->name, stat); 1908c2ecf20Sopenharmony_ci /* do it the old fashioned way */ 1918c2ecf20Sopenharmony_ci return do_reset1(drive, 1); 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci /* done polling */ 1948c2ecf20Sopenharmony_ci hwif->polling = 0; 1958c2ecf20Sopenharmony_ci ide_complete_drive_reset(drive, BLK_STS_OK); 1968c2ecf20Sopenharmony_ci return ide_stopped; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic void ide_reset_report_error(ide_hwif_t *hwif, u8 err) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci static const char *err_master_vals[] = 2028c2ecf20Sopenharmony_ci { NULL, "passed", "formatter device error", 2038c2ecf20Sopenharmony_ci "sector buffer error", "ECC circuitry error", 2048c2ecf20Sopenharmony_ci "controlling MPU error" }; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci u8 err_master = err & 0x7f; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: reset: master: ", hwif->name); 2098c2ecf20Sopenharmony_ci if (err_master && err_master < 6) 2108c2ecf20Sopenharmony_ci printk(KERN_CONT "%s", err_master_vals[err_master]); 2118c2ecf20Sopenharmony_ci else 2128c2ecf20Sopenharmony_ci printk(KERN_CONT "error (0x%02x?)", err); 2138c2ecf20Sopenharmony_ci if (err & 0x80) 2148c2ecf20Sopenharmony_ci printk(KERN_CONT "; slave: failed"); 2158c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* 2198c2ecf20Sopenharmony_ci * reset_pollfunc() gets invoked to poll the interface for completion every 50ms 2208c2ecf20Sopenharmony_ci * during an ide reset operation. If the drives have not yet responded, 2218c2ecf20Sopenharmony_ci * and we have not yet hit our maximum waiting time, then the timer is restarted 2228c2ecf20Sopenharmony_ci * for another 50ms. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_cistatic ide_startstop_t reset_pollfunc(ide_drive_t *drive) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 2278c2ecf20Sopenharmony_ci const struct ide_port_ops *port_ops = hwif->port_ops; 2288c2ecf20Sopenharmony_ci u8 tmp; 2298c2ecf20Sopenharmony_ci blk_status_t err = BLK_STS_OK; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (port_ops && port_ops->reset_poll) { 2328c2ecf20Sopenharmony_ci err = port_ops->reset_poll(drive); 2338c2ecf20Sopenharmony_ci if (err) { 2348c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: host reset_poll failure for %s.\n", 2358c2ecf20Sopenharmony_ci hwif->name, drive->name); 2368c2ecf20Sopenharmony_ci goto out; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci tmp = hwif->tp_ops->read_status(hwif); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (!OK_STAT(tmp, 0, ATA_BUSY)) { 2438c2ecf20Sopenharmony_ci if (time_before(jiffies, hwif->poll_timeout)) { 2448c2ecf20Sopenharmony_ci ide_set_handler(drive, &reset_pollfunc, HZ/20); 2458c2ecf20Sopenharmony_ci /* continue polling */ 2468c2ecf20Sopenharmony_ci return ide_started; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: reset timed-out, status=0x%02x\n", 2498c2ecf20Sopenharmony_ci hwif->name, tmp); 2508c2ecf20Sopenharmony_ci drive->failures++; 2518c2ecf20Sopenharmony_ci err = BLK_STS_IOERR; 2528c2ecf20Sopenharmony_ci } else { 2538c2ecf20Sopenharmony_ci tmp = ide_read_error(drive); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (tmp == 1) { 2568c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: reset: success\n", hwif->name); 2578c2ecf20Sopenharmony_ci drive->failures = 0; 2588c2ecf20Sopenharmony_ci } else { 2598c2ecf20Sopenharmony_ci ide_reset_report_error(hwif, tmp); 2608c2ecf20Sopenharmony_ci drive->failures++; 2618c2ecf20Sopenharmony_ci err = BLK_STS_IOERR; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ciout: 2658c2ecf20Sopenharmony_ci hwif->polling = 0; /* done polling */ 2668c2ecf20Sopenharmony_ci ide_complete_drive_reset(drive, err); 2678c2ecf20Sopenharmony_ci return ide_stopped; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void ide_disk_pre_reset(ide_drive_t *drive) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci drive->special_flags = 2758c2ecf20Sopenharmony_ci legacy ? (IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE) : 0; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci drive->mult_count = 0; 2788c2ecf20Sopenharmony_ci drive->dev_flags &= ~IDE_DFLAG_PARKED; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0 && 2818c2ecf20Sopenharmony_ci (drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) 2828c2ecf20Sopenharmony_ci drive->mult_req = 0; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (drive->mult_req != drive->mult_count) 2858c2ecf20Sopenharmony_ci drive->special_flags |= IDE_SFLAG_SET_MULTMODE; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic void pre_reset(ide_drive_t *drive) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci const struct ide_port_ops *port_ops = drive->hwif->port_ops; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (drive->media == ide_disk) 2938c2ecf20Sopenharmony_ci ide_disk_pre_reset(drive); 2948c2ecf20Sopenharmony_ci else 2958c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_POST_RESET; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (drive->dev_flags & IDE_DFLAG_USING_DMA) { 2988c2ecf20Sopenharmony_ci if (drive->crc_count) 2998c2ecf20Sopenharmony_ci ide_check_dma_crc(drive); 3008c2ecf20Sopenharmony_ci else 3018c2ecf20Sopenharmony_ci ide_dma_off(drive); 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0) { 3058c2ecf20Sopenharmony_ci if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) { 3068c2ecf20Sopenharmony_ci drive->dev_flags &= ~IDE_DFLAG_UNMASK; 3078c2ecf20Sopenharmony_ci drive->io_32bit = 0; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci return; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (port_ops && port_ops->pre_reset) 3138c2ecf20Sopenharmony_ci port_ops->pre_reset(drive); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (drive->current_speed != 0xff) 3168c2ecf20Sopenharmony_ci drive->desired_speed = drive->current_speed; 3178c2ecf20Sopenharmony_ci drive->current_speed = 0xff; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/* 3218c2ecf20Sopenharmony_ci * do_reset1() attempts to recover a confused drive by resetting it. 3228c2ecf20Sopenharmony_ci * Unfortunately, resetting a disk drive actually resets all devices on 3238c2ecf20Sopenharmony_ci * the same interface, so it can really be thought of as resetting the 3248c2ecf20Sopenharmony_ci * interface rather than resetting the drive. 3258c2ecf20Sopenharmony_ci * 3268c2ecf20Sopenharmony_ci * ATAPI devices have their own reset mechanism which allows them to be 3278c2ecf20Sopenharmony_ci * individually reset without clobbering other devices on the same interface. 3288c2ecf20Sopenharmony_ci * 3298c2ecf20Sopenharmony_ci * Unfortunately, the IDE interface does not generate an interrupt to let 3308c2ecf20Sopenharmony_ci * us know when the reset operation has finished, so we must poll for this. 3318c2ecf20Sopenharmony_ci * Equally poor, though, is the fact that this may a very long time to complete, 3328c2ecf20Sopenharmony_ci * (up to 30 seconds worstcase). So, instead of busy-waiting here for it, 3338c2ecf20Sopenharmony_ci * we set a timer to poll at 50ms intervals. 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_cistatic ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 3388c2ecf20Sopenharmony_ci struct ide_io_ports *io_ports = &hwif->io_ports; 3398c2ecf20Sopenharmony_ci const struct ide_tp_ops *tp_ops = hwif->tp_ops; 3408c2ecf20Sopenharmony_ci const struct ide_port_ops *port_ops; 3418c2ecf20Sopenharmony_ci ide_drive_t *tdrive; 3428c2ecf20Sopenharmony_ci unsigned long flags, timeout; 3438c2ecf20Sopenharmony_ci int i; 3448c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci spin_lock_irqsave(&hwif->lock, flags); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* We must not reset with running handlers */ 3498c2ecf20Sopenharmony_ci BUG_ON(hwif->handler != NULL); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* For an ATAPI device, first try an ATAPI SRST. */ 3528c2ecf20Sopenharmony_ci if (drive->media != ide_disk && !do_not_try_atapi) { 3538c2ecf20Sopenharmony_ci pre_reset(drive); 3548c2ecf20Sopenharmony_ci tp_ops->dev_select(drive); 3558c2ecf20Sopenharmony_ci udelay(20); 3568c2ecf20Sopenharmony_ci tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET); 3578c2ecf20Sopenharmony_ci ndelay(400); 3588c2ecf20Sopenharmony_ci hwif->poll_timeout = jiffies + WAIT_WORSTCASE; 3598c2ecf20Sopenharmony_ci hwif->polling = 1; 3608c2ecf20Sopenharmony_ci __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20); 3618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hwif->lock, flags); 3628c2ecf20Sopenharmony_ci return ide_started; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* We must not disturb devices in the IDE_DFLAG_PARKED state. */ 3668c2ecf20Sopenharmony_ci do { 3678c2ecf20Sopenharmony_ci unsigned long now; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci prepare_to_wait(&ide_park_wq, &wait, TASK_UNINTERRUPTIBLE); 3708c2ecf20Sopenharmony_ci timeout = jiffies; 3718c2ecf20Sopenharmony_ci ide_port_for_each_present_dev(i, tdrive, hwif) { 3728c2ecf20Sopenharmony_ci if ((tdrive->dev_flags & IDE_DFLAG_PARKED) && 3738c2ecf20Sopenharmony_ci time_after(tdrive->sleep, timeout)) 3748c2ecf20Sopenharmony_ci timeout = tdrive->sleep; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci now = jiffies; 3788c2ecf20Sopenharmony_ci if (time_before_eq(timeout, now)) 3798c2ecf20Sopenharmony_ci break; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hwif->lock, flags); 3828c2ecf20Sopenharmony_ci timeout = schedule_timeout_uninterruptible(timeout - now); 3838c2ecf20Sopenharmony_ci spin_lock_irqsave(&hwif->lock, flags); 3848c2ecf20Sopenharmony_ci } while (timeout); 3858c2ecf20Sopenharmony_ci finish_wait(&ide_park_wq, &wait); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* 3888c2ecf20Sopenharmony_ci * First, reset any device state data we were maintaining 3898c2ecf20Sopenharmony_ci * for any of the drives on this interface. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci ide_port_for_each_dev(i, tdrive, hwif) 3928c2ecf20Sopenharmony_ci pre_reset(tdrive); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (io_ports->ctl_addr == 0) { 3958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hwif->lock, flags); 3968c2ecf20Sopenharmony_ci ide_complete_drive_reset(drive, BLK_STS_IOERR); 3978c2ecf20Sopenharmony_ci return ide_stopped; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* 4018c2ecf20Sopenharmony_ci * Note that we also set nIEN while resetting the device, 4028c2ecf20Sopenharmony_ci * to mask unwanted interrupts from the interface during the reset. 4038c2ecf20Sopenharmony_ci * However, due to the design of PC hardware, this will cause an 4048c2ecf20Sopenharmony_ci * immediate interrupt due to the edge transition it produces. 4058c2ecf20Sopenharmony_ci * This single interrupt gives us a "fast poll" for drives that 4068c2ecf20Sopenharmony_ci * recover from reset very quickly, saving us the first 50ms wait time. 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_ci /* set SRST and nIEN */ 4098c2ecf20Sopenharmony_ci tp_ops->write_devctl(hwif, ATA_SRST | ATA_NIEN | ATA_DEVCTL_OBS); 4108c2ecf20Sopenharmony_ci /* more than enough time */ 4118c2ecf20Sopenharmony_ci udelay(10); 4128c2ecf20Sopenharmony_ci /* clear SRST, leave nIEN (unless device is on the quirk list) */ 4138c2ecf20Sopenharmony_ci tp_ops->write_devctl(hwif, 4148c2ecf20Sopenharmony_ci ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) ? 0 : ATA_NIEN) | 4158c2ecf20Sopenharmony_ci ATA_DEVCTL_OBS); 4168c2ecf20Sopenharmony_ci /* more than enough time */ 4178c2ecf20Sopenharmony_ci udelay(10); 4188c2ecf20Sopenharmony_ci hwif->poll_timeout = jiffies + WAIT_WORSTCASE; 4198c2ecf20Sopenharmony_ci hwif->polling = 1; 4208c2ecf20Sopenharmony_ci __ide_set_handler(drive, &reset_pollfunc, HZ/20); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* 4238c2ecf20Sopenharmony_ci * Some weird controller like resetting themselves to a strange 4248c2ecf20Sopenharmony_ci * state when the disks are reset this way. At least, the Winbond 4258c2ecf20Sopenharmony_ci * 553 documentation says that 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_ci port_ops = hwif->port_ops; 4288c2ecf20Sopenharmony_ci if (port_ops && port_ops->resetproc) 4298c2ecf20Sopenharmony_ci port_ops->resetproc(drive); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hwif->lock, flags); 4328c2ecf20Sopenharmony_ci return ide_started; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/* 4368c2ecf20Sopenharmony_ci * ide_do_reset() is the entry point to the drive/interface reset code. 4378c2ecf20Sopenharmony_ci */ 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ciide_startstop_t ide_do_reset(ide_drive_t *drive) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci return do_reset1(drive, 0); 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ide_do_reset); 444