18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) 48c2ecf20Sopenharmony_ci * Copyright (C) 1998-2002 Linux ATA Development 58c2ecf20Sopenharmony_ci * Andre Hedrick <andre@linux-ide.org> 68c2ecf20Sopenharmony_ci * Copyright (C) 2003 Red Hat 78c2ecf20Sopenharmony_ci * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * Mostly written by Mark Lord <mlord@pobox.com> 128c2ecf20Sopenharmony_ci * and Gadi Oxman <gadio@netvision.net.il> 138c2ecf20Sopenharmony_ci * and Andre Hedrick <andre@linux-ide.org> 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/types.h> 198c2ecf20Sopenharmony_ci#include <linux/string.h> 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/timer.h> 228c2ecf20Sopenharmony_ci#include <linux/mm.h> 238c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 248c2ecf20Sopenharmony_ci#include <linux/major.h> 258c2ecf20Sopenharmony_ci#include <linux/errno.h> 268c2ecf20Sopenharmony_ci#include <linux/genhd.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci#include <linux/delay.h> 298c2ecf20Sopenharmony_ci#include <linux/mutex.h> 308c2ecf20Sopenharmony_ci#include <linux/leds.h> 318c2ecf20Sopenharmony_ci#include <linux/ide.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 348c2ecf20Sopenharmony_ci#include <asm/irq.h> 358c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 368c2ecf20Sopenharmony_ci#include <asm/io.h> 378c2ecf20Sopenharmony_ci#include <asm/div64.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include "ide-disk.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic const u8 ide_rw_cmds[] = { 428c2ecf20Sopenharmony_ci ATA_CMD_READ_MULTI, 438c2ecf20Sopenharmony_ci ATA_CMD_WRITE_MULTI, 448c2ecf20Sopenharmony_ci ATA_CMD_READ_MULTI_EXT, 458c2ecf20Sopenharmony_ci ATA_CMD_WRITE_MULTI_EXT, 468c2ecf20Sopenharmony_ci ATA_CMD_PIO_READ, 478c2ecf20Sopenharmony_ci ATA_CMD_PIO_WRITE, 488c2ecf20Sopenharmony_ci ATA_CMD_PIO_READ_EXT, 498c2ecf20Sopenharmony_ci ATA_CMD_PIO_WRITE_EXT, 508c2ecf20Sopenharmony_ci ATA_CMD_READ, 518c2ecf20Sopenharmony_ci ATA_CMD_WRITE, 528c2ecf20Sopenharmony_ci ATA_CMD_READ_EXT, 538c2ecf20Sopenharmony_ci ATA_CMD_WRITE_EXT, 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void ide_tf_set_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 dma) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci u8 index, lba48, write; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci lba48 = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0; 618c2ecf20Sopenharmony_ci write = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (dma) { 648c2ecf20Sopenharmony_ci cmd->protocol = ATA_PROT_DMA; 658c2ecf20Sopenharmony_ci index = 8; 668c2ecf20Sopenharmony_ci } else { 678c2ecf20Sopenharmony_ci cmd->protocol = ATA_PROT_PIO; 688c2ecf20Sopenharmony_ci if (drive->mult_count) { 698c2ecf20Sopenharmony_ci cmd->tf_flags |= IDE_TFLAG_MULTI_PIO; 708c2ecf20Sopenharmony_ci index = 0; 718c2ecf20Sopenharmony_ci } else 728c2ecf20Sopenharmony_ci index = 4; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci cmd->tf.command = ide_rw_cmds[index + lba48 + write]; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * __ide_do_rw_disk() issues READ and WRITE commands to a disk, 808c2ecf20Sopenharmony_ci * using LBA if supported, or CHS otherwise, to address sectors. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_cistatic ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, 838c2ecf20Sopenharmony_ci sector_t block) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 868c2ecf20Sopenharmony_ci u16 nsectors = (u16)blk_rq_sectors(rq); 878c2ecf20Sopenharmony_ci u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48); 888c2ecf20Sopenharmony_ci u8 dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); 898c2ecf20Sopenharmony_ci struct ide_cmd cmd; 908c2ecf20Sopenharmony_ci struct ide_taskfile *tf = &cmd.tf; 918c2ecf20Sopenharmony_ci ide_startstop_t rc; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) { 948c2ecf20Sopenharmony_ci if (block + blk_rq_sectors(rq) > 1ULL << 28) 958c2ecf20Sopenharmony_ci dma = 0; 968c2ecf20Sopenharmony_ci else 978c2ecf20Sopenharmony_ci lba48 = 0; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 1018c2ecf20Sopenharmony_ci cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; 1028c2ecf20Sopenharmony_ci cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (drive->dev_flags & IDE_DFLAG_LBA) { 1058c2ecf20Sopenharmony_ci if (lba48) { 1068c2ecf20Sopenharmony_ci pr_debug("%s: LBA=0x%012llx\n", drive->name, 1078c2ecf20Sopenharmony_ci (unsigned long long)block); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci tf->nsect = nsectors & 0xff; 1108c2ecf20Sopenharmony_ci tf->lbal = (u8) block; 1118c2ecf20Sopenharmony_ci tf->lbam = (u8)(block >> 8); 1128c2ecf20Sopenharmony_ci tf->lbah = (u8)(block >> 16); 1138c2ecf20Sopenharmony_ci tf->device = ATA_LBA; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci tf = &cmd.hob; 1168c2ecf20Sopenharmony_ci tf->nsect = (nsectors >> 8) & 0xff; 1178c2ecf20Sopenharmony_ci tf->lbal = (u8)(block >> 24); 1188c2ecf20Sopenharmony_ci if (sizeof(block) != 4) { 1198c2ecf20Sopenharmony_ci tf->lbam = (u8)((u64)block >> 32); 1208c2ecf20Sopenharmony_ci tf->lbah = (u8)((u64)block >> 40); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci cmd.valid.out.hob = IDE_VALID_OUT_HOB; 1248c2ecf20Sopenharmony_ci cmd.valid.in.hob = IDE_VALID_IN_HOB; 1258c2ecf20Sopenharmony_ci cmd.tf_flags |= IDE_TFLAG_LBA48; 1268c2ecf20Sopenharmony_ci } else { 1278c2ecf20Sopenharmony_ci tf->nsect = nsectors & 0xff; 1288c2ecf20Sopenharmony_ci tf->lbal = block; 1298c2ecf20Sopenharmony_ci tf->lbam = block >>= 8; 1308c2ecf20Sopenharmony_ci tf->lbah = block >>= 8; 1318c2ecf20Sopenharmony_ci tf->device = ((block >> 8) & 0xf) | ATA_LBA; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci } else { 1348c2ecf20Sopenharmony_ci unsigned int sect, head, cyl, track; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci track = (int)block / drive->sect; 1378c2ecf20Sopenharmony_ci sect = (int)block % drive->sect + 1; 1388c2ecf20Sopenharmony_ci head = track % drive->head; 1398c2ecf20Sopenharmony_ci cyl = track / drive->head; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci tf->nsect = nsectors & 0xff; 1448c2ecf20Sopenharmony_ci tf->lbal = sect; 1458c2ecf20Sopenharmony_ci tf->lbam = cyl; 1468c2ecf20Sopenharmony_ci tf->lbah = cyl >> 8; 1478c2ecf20Sopenharmony_ci tf->device = head; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci cmd.tf_flags |= IDE_TFLAG_FS; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (rq_data_dir(rq)) 1538c2ecf20Sopenharmony_ci cmd.tf_flags |= IDE_TFLAG_WRITE; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci ide_tf_set_cmd(drive, &cmd, dma); 1568c2ecf20Sopenharmony_ci cmd.rq = rq; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (dma == 0) { 1598c2ecf20Sopenharmony_ci ide_init_sg_cmd(&cmd, nsectors << 9); 1608c2ecf20Sopenharmony_ci ide_map_sg(drive, &cmd); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci rc = do_rw_taskfile(drive, &cmd); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (rc == ide_stopped && dma) { 1668c2ecf20Sopenharmony_ci /* fallback to PIO */ 1678c2ecf20Sopenharmony_ci cmd.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK; 1688c2ecf20Sopenharmony_ci ide_tf_set_cmd(drive, &cmd, 0); 1698c2ecf20Sopenharmony_ci ide_init_sg_cmd(&cmd, nsectors << 9); 1708c2ecf20Sopenharmony_ci rc = do_rw_taskfile(drive, &cmd); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return rc; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* 1778c2ecf20Sopenharmony_ci * 268435455 == 137439 MB or 28bit limit 1788c2ecf20Sopenharmony_ci * 320173056 == 163929 MB or 48bit addressing 1798c2ecf20Sopenharmony_ci * 1073741822 == 549756 MB or 48bit addressing fake drive 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, 1838c2ecf20Sopenharmony_ci sector_t block) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED); 1888c2ecf20Sopenharmony_ci BUG_ON(blk_rq_is_passthrough(rq)); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ledtrig_disk_activity(rq_data_dir(rq) == WRITE); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci pr_debug("%s: %sing: block=%llu, sectors=%u\n", 1938c2ecf20Sopenharmony_ci drive->name, rq_data_dir(rq) == READ ? "read" : "writ", 1948c2ecf20Sopenharmony_ci (unsigned long long)block, blk_rq_sectors(rq)); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (hwif->rw_disk) 1978c2ecf20Sopenharmony_ci hwif->rw_disk(drive, rq); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return __ide_do_rw_disk(drive, rq, block); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* 2038c2ecf20Sopenharmony_ci * Queries for true maximum capacity of the drive. 2048c2ecf20Sopenharmony_ci * Returns maximum LBA address (> 0) of the drive, 0 if failed. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_cistatic u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct ide_cmd cmd; 2098c2ecf20Sopenharmony_ci struct ide_taskfile *tf = &cmd.tf; 2108c2ecf20Sopenharmony_ci u64 addr = 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 2138c2ecf20Sopenharmony_ci if (lba48) 2148c2ecf20Sopenharmony_ci tf->command = ATA_CMD_READ_NATIVE_MAX_EXT; 2158c2ecf20Sopenharmony_ci else 2168c2ecf20Sopenharmony_ci tf->command = ATA_CMD_READ_NATIVE_MAX; 2178c2ecf20Sopenharmony_ci tf->device = ATA_LBA; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; 2208c2ecf20Sopenharmony_ci cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; 2218c2ecf20Sopenharmony_ci if (lba48) { 2228c2ecf20Sopenharmony_ci cmd.valid.out.hob = IDE_VALID_OUT_HOB; 2238c2ecf20Sopenharmony_ci cmd.valid.in.hob = IDE_VALID_IN_HOB; 2248c2ecf20Sopenharmony_ci cmd.tf_flags = IDE_TFLAG_LBA48; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci ide_no_data_taskfile(drive, &cmd); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* if OK, compute maximum address value */ 2308c2ecf20Sopenharmony_ci if (!(tf->status & ATA_ERR)) 2318c2ecf20Sopenharmony_ci addr = ide_get_lba_addr(&cmd, lba48) + 1; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return addr; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci/* 2378c2ecf20Sopenharmony_ci * Sets maximum virtual LBA address of the drive. 2388c2ecf20Sopenharmony_ci * Returns new maximum virtual LBA address (> 0) or 0 on failure. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_cistatic u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct ide_cmd cmd; 2438c2ecf20Sopenharmony_ci struct ide_taskfile *tf = &cmd.tf; 2448c2ecf20Sopenharmony_ci u64 addr_set = 0; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci addr_req--; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 2498c2ecf20Sopenharmony_ci tf->lbal = (addr_req >> 0) & 0xff; 2508c2ecf20Sopenharmony_ci tf->lbam = (addr_req >>= 8) & 0xff; 2518c2ecf20Sopenharmony_ci tf->lbah = (addr_req >>= 8) & 0xff; 2528c2ecf20Sopenharmony_ci if (lba48) { 2538c2ecf20Sopenharmony_ci cmd.hob.lbal = (addr_req >>= 8) & 0xff; 2548c2ecf20Sopenharmony_ci cmd.hob.lbam = (addr_req >>= 8) & 0xff; 2558c2ecf20Sopenharmony_ci cmd.hob.lbah = (addr_req >>= 8) & 0xff; 2568c2ecf20Sopenharmony_ci tf->command = ATA_CMD_SET_MAX_EXT; 2578c2ecf20Sopenharmony_ci } else { 2588c2ecf20Sopenharmony_ci tf->device = (addr_req >>= 8) & 0x0f; 2598c2ecf20Sopenharmony_ci tf->command = ATA_CMD_SET_MAX; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci tf->device |= ATA_LBA; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; 2648c2ecf20Sopenharmony_ci cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; 2658c2ecf20Sopenharmony_ci if (lba48) { 2668c2ecf20Sopenharmony_ci cmd.valid.out.hob = IDE_VALID_OUT_HOB; 2678c2ecf20Sopenharmony_ci cmd.valid.in.hob = IDE_VALID_IN_HOB; 2688c2ecf20Sopenharmony_ci cmd.tf_flags = IDE_TFLAG_LBA48; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci ide_no_data_taskfile(drive, &cmd); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* if OK, compute maximum address value */ 2748c2ecf20Sopenharmony_ci if (!(tf->status & ATA_ERR)) 2758c2ecf20Sopenharmony_ci addr_set = ide_get_lba_addr(&cmd, lba48) + 1; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return addr_set; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic unsigned long long sectors_to_MB(unsigned long long n) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci n <<= 9; /* make it bytes */ 2838c2ecf20Sopenharmony_ci do_div(n, 1000000); /* make it MB */ 2848c2ecf20Sopenharmony_ci return n; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/* 2888c2ecf20Sopenharmony_ci * Some disks report total number of sectors instead of 2898c2ecf20Sopenharmony_ci * maximum sector address. We list them here. 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_cistatic const struct drive_list_entry hpa_list[] = { 2928c2ecf20Sopenharmony_ci { "ST340823A", NULL }, 2938c2ecf20Sopenharmony_ci { "ST320413A", NULL }, 2948c2ecf20Sopenharmony_ci { "ST310211A", NULL }, 2958c2ecf20Sopenharmony_ci { NULL, NULL } 2968c2ecf20Sopenharmony_ci}; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic u64 ide_disk_hpa_get_native_capacity(ide_drive_t *drive, int lba48) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci u64 capacity, set_max; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci capacity = drive->capacity64; 3038c2ecf20Sopenharmony_ci set_max = idedisk_read_native_max_address(drive, lba48); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (ide_in_drive_list(drive->id, hpa_list)) { 3068c2ecf20Sopenharmony_ci /* 3078c2ecf20Sopenharmony_ci * Since we are inclusive wrt to firmware revisions do this 3088c2ecf20Sopenharmony_ci * extra check and apply the workaround only when needed. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci if (set_max == capacity + 1) 3118c2ecf20Sopenharmony_ci set_max--; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return set_max; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic u64 ide_disk_hpa_set_capacity(ide_drive_t *drive, u64 set_max, int lba48) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci set_max = idedisk_set_max_address(drive, set_max, lba48); 3208c2ecf20Sopenharmony_ci if (set_max) 3218c2ecf20Sopenharmony_ci drive->capacity64 = set_max; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return set_max; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic void idedisk_check_hpa(ide_drive_t *drive) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci u64 capacity, set_max; 3298c2ecf20Sopenharmony_ci int lba48 = ata_id_lba48_enabled(drive->id); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci capacity = drive->capacity64; 3328c2ecf20Sopenharmony_ci set_max = ide_disk_hpa_get_native_capacity(drive, lba48); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (set_max <= capacity) 3358c2ecf20Sopenharmony_ci return; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci drive->probed_capacity = set_max; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Host Protected Area detected.\n" 3408c2ecf20Sopenharmony_ci "\tcurrent capacity is %llu sectors (%llu MB)\n" 3418c2ecf20Sopenharmony_ci "\tnative capacity is %llu sectors (%llu MB)\n", 3428c2ecf20Sopenharmony_ci drive->name, 3438c2ecf20Sopenharmony_ci capacity, sectors_to_MB(capacity), 3448c2ecf20Sopenharmony_ci set_max, sectors_to_MB(set_max)); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if ((drive->dev_flags & IDE_DFLAG_NOHPA) == 0) 3478c2ecf20Sopenharmony_ci return; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci set_max = ide_disk_hpa_set_capacity(drive, set_max, lba48); 3508c2ecf20Sopenharmony_ci if (set_max) 3518c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Host Protected Area disabled.\n", 3528c2ecf20Sopenharmony_ci drive->name); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic int ide_disk_get_capacity(ide_drive_t *drive) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci u16 *id = drive->id; 3588c2ecf20Sopenharmony_ci int lba; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (ata_id_lba48_enabled(id)) { 3618c2ecf20Sopenharmony_ci /* drive speaks 48-bit LBA */ 3628c2ecf20Sopenharmony_ci lba = 1; 3638c2ecf20Sopenharmony_ci drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2); 3648c2ecf20Sopenharmony_ci } else if (ata_id_has_lba(id) && ata_id_is_lba_capacity_ok(id)) { 3658c2ecf20Sopenharmony_ci /* drive speaks 28-bit LBA */ 3668c2ecf20Sopenharmony_ci lba = 1; 3678c2ecf20Sopenharmony_ci drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY); 3688c2ecf20Sopenharmony_ci } else { 3698c2ecf20Sopenharmony_ci /* drive speaks boring old 28-bit CHS */ 3708c2ecf20Sopenharmony_ci lba = 0; 3718c2ecf20Sopenharmony_ci drive->capacity64 = drive->cyl * drive->head * drive->sect; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci drive->probed_capacity = drive->capacity64; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (lba) { 3778c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_LBA; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* 3808c2ecf20Sopenharmony_ci * If this device supports the Host Protected Area feature set, 3818c2ecf20Sopenharmony_ci * then we may need to change our opinion about its capacity. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci if (ata_id_hpa_enabled(id)) 3848c2ecf20Sopenharmony_ci idedisk_check_hpa(drive); 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* limit drive capacity to 137GB if LBA48 cannot be used */ 3888c2ecf20Sopenharmony_ci if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 && 3898c2ecf20Sopenharmony_ci drive->capacity64 > 1ULL << 28) { 3908c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: cannot use LBA48 - full capacity " 3918c2ecf20Sopenharmony_ci "%llu sectors (%llu MB)\n", 3928c2ecf20Sopenharmony_ci drive->name, (unsigned long long)drive->capacity64, 3938c2ecf20Sopenharmony_ci sectors_to_MB(drive->capacity64)); 3948c2ecf20Sopenharmony_ci drive->probed_capacity = drive->capacity64 = 1ULL << 28; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && 3988c2ecf20Sopenharmony_ci (drive->dev_flags & IDE_DFLAG_LBA48)) { 3998c2ecf20Sopenharmony_ci if (drive->capacity64 > 1ULL << 28) { 4008c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode" 4018c2ecf20Sopenharmony_ci " will be used for accessing sectors " 4028c2ecf20Sopenharmony_ci "> %u\n", drive->name, 1 << 28); 4038c2ecf20Sopenharmony_ci } else 4048c2ecf20Sopenharmony_ci drive->dev_flags &= ~IDE_DFLAG_LBA48; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci return 0; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic void ide_disk_unlock_native_capacity(ide_drive_t *drive) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci u16 *id = drive->id; 4138c2ecf20Sopenharmony_ci int lba48 = ata_id_lba48_enabled(id); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 || 4168c2ecf20Sopenharmony_ci ata_id_hpa_enabled(id) == 0) 4178c2ecf20Sopenharmony_ci return; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* 4208c2ecf20Sopenharmony_ci * according to the spec the SET MAX ADDRESS command shall be 4218c2ecf20Sopenharmony_ci * immediately preceded by a READ NATIVE MAX ADDRESS command 4228c2ecf20Sopenharmony_ci */ 4238c2ecf20Sopenharmony_ci if (!ide_disk_hpa_get_native_capacity(drive, lba48)) 4248c2ecf20Sopenharmony_ci return; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (ide_disk_hpa_set_capacity(drive, drive->probed_capacity, lba48)) 4278c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_NOHPA; /* disable HPA on resume */ 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic bool idedisk_prep_rq(ide_drive_t *drive, struct request *rq) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct ide_cmd *cmd; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (req_op(rq) != REQ_OP_FLUSH) 4358c2ecf20Sopenharmony_ci return true; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (ide_req(rq)->special) { 4388c2ecf20Sopenharmony_ci cmd = ide_req(rq)->special; 4398c2ecf20Sopenharmony_ci memset(cmd, 0, sizeof(*cmd)); 4408c2ecf20Sopenharmony_ci } else { 4418c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* FIXME: map struct ide_taskfile on rq->cmd[] */ 4458c2ecf20Sopenharmony_ci BUG_ON(cmd == NULL); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (ata_id_flush_ext_enabled(drive->id) && 4488c2ecf20Sopenharmony_ci (drive->capacity64 >= (1UL << 28))) 4498c2ecf20Sopenharmony_ci cmd->tf.command = ATA_CMD_FLUSH_EXT; 4508c2ecf20Sopenharmony_ci else 4518c2ecf20Sopenharmony_ci cmd->tf.command = ATA_CMD_FLUSH; 4528c2ecf20Sopenharmony_ci cmd->valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; 4538c2ecf20Sopenharmony_ci cmd->tf_flags = IDE_TFLAG_DYN; 4548c2ecf20Sopenharmony_ci cmd->protocol = ATA_PROT_NODATA; 4558c2ecf20Sopenharmony_ci rq->cmd_flags &= ~REQ_OP_MASK; 4568c2ecf20Sopenharmony_ci rq->cmd_flags |= REQ_OP_DRV_OUT; 4578c2ecf20Sopenharmony_ci ide_req(rq)->type = ATA_PRIV_TASKFILE; 4588c2ecf20Sopenharmony_ci ide_req(rq)->special = cmd; 4598c2ecf20Sopenharmony_ci cmd->rq = rq; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return true; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ciide_devset_get(multcount, mult_count); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci/* 4678c2ecf20Sopenharmony_ci * This is tightly woven into the driver->do_special can not touch. 4688c2ecf20Sopenharmony_ci * DON'T do it again until a total personality rewrite is committed. 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_cistatic int set_multcount(ide_drive_t *drive, int arg) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct request *rq; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff)) 4758c2ecf20Sopenharmony_ci return -EINVAL; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (drive->special_flags & IDE_SFLAG_SET_MULTMODE) 4788c2ecf20Sopenharmony_ci return -EBUSY; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); 4818c2ecf20Sopenharmony_ci ide_req(rq)->type = ATA_PRIV_TASKFILE; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci drive->mult_req = arg; 4848c2ecf20Sopenharmony_ci drive->special_flags |= IDE_SFLAG_SET_MULTMODE; 4858c2ecf20Sopenharmony_ci blk_execute_rq(drive->queue, NULL, rq, 0); 4868c2ecf20Sopenharmony_ci blk_put_request(rq); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci return (drive->mult_count == arg) ? 0 : -EIO; 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ciide_devset_get_flag(nowerr, IDE_DFLAG_NOWERR); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic int set_nowerr(ide_drive_t *drive, int arg) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci if (arg < 0 || arg > 1) 4968c2ecf20Sopenharmony_ci return -EINVAL; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (arg) 4998c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_NOWERR; 5008c2ecf20Sopenharmony_ci else 5018c2ecf20Sopenharmony_ci drive->dev_flags &= ~IDE_DFLAG_NOWERR; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return 0; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci struct ide_cmd cmd; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 5138c2ecf20Sopenharmony_ci cmd.tf.feature = feature; 5148c2ecf20Sopenharmony_ci cmd.tf.nsect = nsect; 5158c2ecf20Sopenharmony_ci cmd.tf.command = ATA_CMD_SET_FEATURES; 5168c2ecf20Sopenharmony_ci cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; 5178c2ecf20Sopenharmony_ci cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci return ide_no_data_taskfile(drive, &cmd); 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic void update_flush(ide_drive_t *drive) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci u16 *id = drive->id; 5258c2ecf20Sopenharmony_ci bool wc = false; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (drive->dev_flags & IDE_DFLAG_WCACHE) { 5288c2ecf20Sopenharmony_ci unsigned long long capacity; 5298c2ecf20Sopenharmony_ci int barrier; 5308c2ecf20Sopenharmony_ci /* 5318c2ecf20Sopenharmony_ci * We must avoid issuing commands a drive does not 5328c2ecf20Sopenharmony_ci * understand or we may crash it. We check flush cache 5338c2ecf20Sopenharmony_ci * is supported. We also check we have the LBA48 flush 5348c2ecf20Sopenharmony_ci * cache if the drive capacity is too large. By this 5358c2ecf20Sopenharmony_ci * time we have trimmed the drive capacity if LBA48 is 5368c2ecf20Sopenharmony_ci * not available so we don't need to recheck that. 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_ci capacity = ide_gd_capacity(drive); 5398c2ecf20Sopenharmony_ci barrier = ata_id_flush_enabled(id) && 5408c2ecf20Sopenharmony_ci (drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 && 5418c2ecf20Sopenharmony_ci ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 || 5428c2ecf20Sopenharmony_ci capacity <= (1ULL << 28) || 5438c2ecf20Sopenharmony_ci ata_id_flush_ext_enabled(id)); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: cache flushes %ssupported\n", 5468c2ecf20Sopenharmony_ci drive->name, barrier ? "" : "not "); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (barrier) { 5498c2ecf20Sopenharmony_ci wc = true; 5508c2ecf20Sopenharmony_ci drive->prep_rq = idedisk_prep_rq; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci blk_queue_write_cache(drive->queue, wc, false); 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ciide_devset_get_flag(wcache, IDE_DFLAG_WCACHE); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic int set_wcache(ide_drive_t *drive, int arg) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci int err = 1; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (arg < 0 || arg > 1) 5648c2ecf20Sopenharmony_ci return -EINVAL; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (ata_id_flush_enabled(drive->id)) { 5678c2ecf20Sopenharmony_ci err = ide_do_setfeature(drive, 5688c2ecf20Sopenharmony_ci arg ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF, 0); 5698c2ecf20Sopenharmony_ci if (err == 0) { 5708c2ecf20Sopenharmony_ci if (arg) 5718c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_WCACHE; 5728c2ecf20Sopenharmony_ci else 5738c2ecf20Sopenharmony_ci drive->dev_flags &= ~IDE_DFLAG_WCACHE; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci update_flush(drive); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci return err; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic int do_idedisk_flushcache(ide_drive_t *drive) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct ide_cmd cmd; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 5878c2ecf20Sopenharmony_ci if (ata_id_flush_ext_enabled(drive->id)) 5888c2ecf20Sopenharmony_ci cmd.tf.command = ATA_CMD_FLUSH_EXT; 5898c2ecf20Sopenharmony_ci else 5908c2ecf20Sopenharmony_ci cmd.tf.command = ATA_CMD_FLUSH; 5918c2ecf20Sopenharmony_ci cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; 5928c2ecf20Sopenharmony_ci cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return ide_no_data_taskfile(drive, &cmd); 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ciide_devset_get(acoustic, acoustic); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic int set_acoustic(ide_drive_t *drive, int arg) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci if (arg < 0 || arg > 254) 6028c2ecf20Sopenharmony_ci return -EINVAL; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci ide_do_setfeature(drive, 6058c2ecf20Sopenharmony_ci arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF, arg); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci drive->acoustic = arg; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci return 0; 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ciide_devset_get_flag(addressing, IDE_DFLAG_LBA48); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci/* 6158c2ecf20Sopenharmony_ci * drive->addressing: 6168c2ecf20Sopenharmony_ci * 0: 28-bit 6178c2ecf20Sopenharmony_ci * 1: 48-bit 6188c2ecf20Sopenharmony_ci * 2: 48-bit capable doing 28-bit 6198c2ecf20Sopenharmony_ci */ 6208c2ecf20Sopenharmony_cistatic int set_addressing(ide_drive_t *drive, int arg) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci if (arg < 0 || arg > 2) 6238c2ecf20Sopenharmony_ci return -EINVAL; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (arg && ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) || 6268c2ecf20Sopenharmony_ci ata_id_lba48_enabled(drive->id) == 0)) 6278c2ecf20Sopenharmony_ci return -EIO; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (arg == 2) 6308c2ecf20Sopenharmony_ci arg = 0; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (arg) 6338c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_LBA48; 6348c2ecf20Sopenharmony_ci else 6358c2ecf20Sopenharmony_ci drive->dev_flags &= ~IDE_DFLAG_LBA48; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci return 0; 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ciide_ext_devset_rw(acoustic, acoustic); 6418c2ecf20Sopenharmony_ciide_ext_devset_rw(address, addressing); 6428c2ecf20Sopenharmony_ciide_ext_devset_rw(multcount, multcount); 6438c2ecf20Sopenharmony_ciide_ext_devset_rw(wcache, wcache); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ciide_ext_devset_rw_sync(nowerr, nowerr); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic int ide_disk_check(ide_drive_t *drive, const char *s) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci return 1; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic void ide_disk_setup(ide_drive_t *drive) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci struct ide_disk_obj *idkp = drive->driver_data; 6558c2ecf20Sopenharmony_ci struct request_queue *q = drive->queue; 6568c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 6578c2ecf20Sopenharmony_ci u16 *id = drive->id; 6588c2ecf20Sopenharmony_ci char *m = (char *)&id[ATA_ID_PROD]; 6598c2ecf20Sopenharmony_ci unsigned long long capacity; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci ide_proc_register_driver(drive, idkp->driver); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) 6648c2ecf20Sopenharmony_ci return; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (drive->dev_flags & IDE_DFLAG_REMOVABLE) { 6678c2ecf20Sopenharmony_ci /* 6688c2ecf20Sopenharmony_ci * Removable disks (eg. SYQUEST); ignore 'WD' drives 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_ci if (m[0] != 'W' || m[1] != 'D') 6718c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_DOORLOCKING; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci (void)set_addressing(drive, 1); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (drive->dev_flags & IDE_DFLAG_LBA48) { 6778c2ecf20Sopenharmony_ci int max_s = 2048; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (max_s > hwif->rqsize) 6808c2ecf20Sopenharmony_ci max_s = hwif->rqsize; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci blk_queue_max_hw_sectors(q, max_s); 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, 6868c2ecf20Sopenharmony_ci queue_max_sectors(q) / 2); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (ata_id_is_ssd(id)) { 6898c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_NONROT, q); 6908c2ecf20Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q); 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci /* calculate drive capacity, and select LBA if possible */ 6948c2ecf20Sopenharmony_ci ide_disk_get_capacity(drive); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* 6978c2ecf20Sopenharmony_ci * if possible, give fdisk access to more of the drive, 6988c2ecf20Sopenharmony_ci * by correcting bios_cyls: 6998c2ecf20Sopenharmony_ci */ 7008c2ecf20Sopenharmony_ci capacity = ide_gd_capacity(drive); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) { 7038c2ecf20Sopenharmony_ci if (ata_id_lba48_enabled(drive->id)) { 7048c2ecf20Sopenharmony_ci /* compatibility */ 7058c2ecf20Sopenharmony_ci drive->bios_sect = 63; 7068c2ecf20Sopenharmony_ci drive->bios_head = 255; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (drive->bios_sect && drive->bios_head) { 7108c2ecf20Sopenharmony_ci unsigned int cap0 = capacity; /* truncate to 32 bits */ 7118c2ecf20Sopenharmony_ci unsigned int cylsz, cyl; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (cap0 != capacity) 7148c2ecf20Sopenharmony_ci drive->bios_cyl = 65535; 7158c2ecf20Sopenharmony_ci else { 7168c2ecf20Sopenharmony_ci cylsz = drive->bios_sect * drive->bios_head; 7178c2ecf20Sopenharmony_ci cyl = cap0 / cylsz; 7188c2ecf20Sopenharmony_ci if (cyl > 65535) 7198c2ecf20Sopenharmony_ci cyl = 65535; 7208c2ecf20Sopenharmony_ci if (cyl > drive->bios_cyl) 7218c2ecf20Sopenharmony_ci drive->bios_cyl = cyl; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: %llu sectors (%llu MB)", 7268c2ecf20Sopenharmony_ci drive->name, capacity, sectors_to_MB(capacity)); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci /* Only print cache size when it was specified */ 7298c2ecf20Sopenharmony_ci if (id[ATA_ID_BUF_SIZE]) 7308c2ecf20Sopenharmony_ci printk(KERN_CONT " w/%dKiB Cache", id[ATA_ID_BUF_SIZE] / 2); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci printk(KERN_CONT ", CHS=%d/%d/%d\n", 7338c2ecf20Sopenharmony_ci drive->bios_cyl, drive->bios_head, drive->bios_sect); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* write cache enabled? */ 7368c2ecf20Sopenharmony_ci if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id)) 7378c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_WCACHE; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci set_wcache(drive, 1); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 && 7428c2ecf20Sopenharmony_ci (drive->head == 0 || drive->head > 16)) 7438c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: invalid geometry: %d physical heads?\n", 7448c2ecf20Sopenharmony_ci drive->name, drive->head); 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic void ide_disk_flush(ide_drive_t *drive) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci if (ata_id_flush_enabled(drive->id) == 0 || 7508c2ecf20Sopenharmony_ci (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) 7518c2ecf20Sopenharmony_ci return; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (do_idedisk_flushcache(drive)) 7548c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: wcache flush failed!\n", drive->name); 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic int ide_disk_init_media(ide_drive_t *drive, struct gendisk *disk) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci return 0; 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk, 7638c2ecf20Sopenharmony_ci int on) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci struct ide_cmd cmd; 7668c2ecf20Sopenharmony_ci int ret; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0) 7698c2ecf20Sopenharmony_ci return 0; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 7728c2ecf20Sopenharmony_ci cmd.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK; 7738c2ecf20Sopenharmony_ci cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; 7748c2ecf20Sopenharmony_ci cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci ret = ide_no_data_taskfile(drive, &cmd); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (ret) 7798c2ecf20Sopenharmony_ci drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci return ret; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ciconst struct ide_disk_ops ide_ata_disk_ops = { 7858c2ecf20Sopenharmony_ci .check = ide_disk_check, 7868c2ecf20Sopenharmony_ci .unlock_native_capacity = ide_disk_unlock_native_capacity, 7878c2ecf20Sopenharmony_ci .get_capacity = ide_disk_get_capacity, 7888c2ecf20Sopenharmony_ci .setup = ide_disk_setup, 7898c2ecf20Sopenharmony_ci .flush = ide_disk_flush, 7908c2ecf20Sopenharmony_ci .init_media = ide_disk_init_media, 7918c2ecf20Sopenharmony_ci .set_doorlock = ide_disk_set_doorlock, 7928c2ecf20Sopenharmony_ci .do_request = ide_do_rw_disk, 7938c2ecf20Sopenharmony_ci .ioctl = ide_disk_ioctl, 7948c2ecf20Sopenharmony_ci .compat_ioctl = ide_disk_ioctl, 7958c2ecf20Sopenharmony_ci}; 796