18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * IDE ATAPI floppy driver. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1996-1999 Gadi Oxman <gadio@netvision.net.il> 68c2ecf20Sopenharmony_ci * Copyright (C) 2000-2002 Paul Bristow <paul@paulbristow.net> 78c2ecf20Sopenharmony_ci * Copyright (C) 2005 Bartlomiej Zolnierkiewicz 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This driver supports the following IDE floppy drives: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * LS-120/240 SuperDisk 128c2ecf20Sopenharmony_ci * Iomega Zip 100/250 138c2ecf20Sopenharmony_ci * Iomega PC Card Clik!/PocketZip 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * For a historical changelog see 168c2ecf20Sopenharmony_ci * Documentation/ide/ChangeLog.ide-floppy.1996-2002 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/types.h> 208c2ecf20Sopenharmony_ci#include <linux/string.h> 218c2ecf20Sopenharmony_ci#include <linux/kernel.h> 228c2ecf20Sopenharmony_ci#include <linux/compat.h> 238c2ecf20Sopenharmony_ci#include <linux/delay.h> 248c2ecf20Sopenharmony_ci#include <linux/timer.h> 258c2ecf20Sopenharmony_ci#include <linux/mm.h> 268c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 278c2ecf20Sopenharmony_ci#include <linux/major.h> 288c2ecf20Sopenharmony_ci#include <linux/errno.h> 298c2ecf20Sopenharmony_ci#include <linux/genhd.h> 308c2ecf20Sopenharmony_ci#include <linux/cdrom.h> 318c2ecf20Sopenharmony_ci#include <linux/ide.h> 328c2ecf20Sopenharmony_ci#include <linux/hdreg.h> 338c2ecf20Sopenharmony_ci#include <linux/bitops.h> 348c2ecf20Sopenharmony_ci#include <linux/mutex.h> 358c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <scsi/scsi_ioctl.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 408c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 418c2ecf20Sopenharmony_ci#include <linux/io.h> 428c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include "ide-floppy.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* 478c2ecf20Sopenharmony_ci * After each failed packet command we issue a request sense command and retry 488c2ecf20Sopenharmony_ci * the packet command IDEFLOPPY_MAX_PC_RETRIES times. 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ci#define IDEFLOPPY_MAX_PC_RETRIES 3 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* format capacities descriptor codes */ 538c2ecf20Sopenharmony_ci#define CAPACITY_INVALID 0x00 548c2ecf20Sopenharmony_ci#define CAPACITY_UNFORMATTED 0x01 558c2ecf20Sopenharmony_ci#define CAPACITY_CURRENT 0x02 568c2ecf20Sopenharmony_ci#define CAPACITY_NO_CARTRIDGE 0x03 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci * The following delay solves a problem with ATAPI Zip 100 drive where BSY bit 608c2ecf20Sopenharmony_ci * was apparently being deasserted before the unit was ready to receive data. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci#define IDEFLOPPY_PC_DELAY (HZ/20) /* default delay for ZIP 100 (50ms) */ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int ide_floppy_callback(ide_drive_t *drive, int dsc) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct ide_disk_obj *floppy = drive->driver_data; 678c2ecf20Sopenharmony_ci struct ide_atapi_pc *pc = drive->pc; 688c2ecf20Sopenharmony_ci struct request *rq = pc->rq; 698c2ecf20Sopenharmony_ci int uptodate = pc->error ? 0 : 1; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci ide_debug_log(IDE_DBG_FUNC, "enter"); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (drive->failed_pc == pc) 748c2ecf20Sopenharmony_ci drive->failed_pc = NULL; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (pc->c[0] == GPCMD_READ_10 || pc->c[0] == GPCMD_WRITE_10 || 778c2ecf20Sopenharmony_ci blk_rq_is_scsi(rq)) 788c2ecf20Sopenharmony_ci uptodate = 1; /* FIXME */ 798c2ecf20Sopenharmony_ci else if (pc->c[0] == GPCMD_REQUEST_SENSE) { 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci u8 *buf = bio_data(rq->bio); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (!pc->error) { 848c2ecf20Sopenharmony_ci floppy->sense_key = buf[2] & 0x0F; 858c2ecf20Sopenharmony_ci floppy->asc = buf[12]; 868c2ecf20Sopenharmony_ci floppy->ascq = buf[13]; 878c2ecf20Sopenharmony_ci floppy->progress_indication = buf[15] & 0x80 ? 888c2ecf20Sopenharmony_ci (u16)get_unaligned((u16 *)&buf[16]) : 0x10000; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (drive->failed_pc) 918c2ecf20Sopenharmony_ci ide_debug_log(IDE_DBG_PC, "pc = %x", 928c2ecf20Sopenharmony_ci drive->failed_pc->c[0]); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci ide_debug_log(IDE_DBG_SENSE, "sense key = %x, asc = %x," 958c2ecf20Sopenharmony_ci "ascq = %x", floppy->sense_key, 968c2ecf20Sopenharmony_ci floppy->asc, floppy->ascq); 978c2ecf20Sopenharmony_ci } else 988c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Error in REQUEST SENSE itself - " 998c2ecf20Sopenharmony_ci "Aborting request!\n"); 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (ata_misc_request(rq)) 1038c2ecf20Sopenharmony_ci scsi_req(rq)->result = uptodate ? 0 : IDE_DRV_ERROR_GENERAL; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return uptodate; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic void ide_floppy_report_error(struct ide_disk_obj *floppy, 1098c2ecf20Sopenharmony_ci struct ide_atapi_pc *pc) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci /* suppress error messages resulting from Medium not present */ 1128c2ecf20Sopenharmony_ci if (floppy->sense_key == 0x02 && 1138c2ecf20Sopenharmony_ci floppy->asc == 0x3a && 1148c2ecf20Sopenharmony_ci floppy->ascq == 0x00) 1158c2ecf20Sopenharmony_ci return; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "%s: I/O error, pc = %2x, key = %2x, " 1188c2ecf20Sopenharmony_ci "asc = %2x, ascq = %2x\n", 1198c2ecf20Sopenharmony_ci floppy->drive->name, pc->c[0], floppy->sense_key, 1208c2ecf20Sopenharmony_ci floppy->asc, floppy->ascq); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic ide_startstop_t ide_floppy_issue_pc(ide_drive_t *drive, 1258c2ecf20Sopenharmony_ci struct ide_cmd *cmd, 1268c2ecf20Sopenharmony_ci struct ide_atapi_pc *pc) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct ide_disk_obj *floppy = drive->driver_data; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (drive->failed_pc == NULL && 1318c2ecf20Sopenharmony_ci pc->c[0] != GPCMD_REQUEST_SENSE) 1328c2ecf20Sopenharmony_ci drive->failed_pc = pc; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* Set the current packet command */ 1358c2ecf20Sopenharmony_ci drive->pc = pc; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) { 1388c2ecf20Sopenharmony_ci unsigned int done = blk_rq_bytes(drive->hwif->rq); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR)) 1418c2ecf20Sopenharmony_ci ide_floppy_report_error(floppy, pc); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* Giving up */ 1448c2ecf20Sopenharmony_ci pc->error = IDE_DRV_ERROR_GENERAL; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci drive->failed_pc = NULL; 1478c2ecf20Sopenharmony_ci drive->pc_callback(drive, 0); 1488c2ecf20Sopenharmony_ci ide_complete_rq(drive, BLK_STS_IOERR, done); 1498c2ecf20Sopenharmony_ci return ide_stopped; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci ide_debug_log(IDE_DBG_FUNC, "retry #%d", pc->retries); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci pc->retries++; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci return ide_issue_pc(drive, cmd); 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_civoid ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *pc) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci ide_init_pc(pc); 1628c2ecf20Sopenharmony_ci pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES; 1638c2ecf20Sopenharmony_ci pc->c[7] = 255; 1648c2ecf20Sopenharmony_ci pc->c[8] = 255; 1658c2ecf20Sopenharmony_ci pc->req_xfer = 255; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/* A mode sense command is used to "sense" floppy parameters. */ 1698c2ecf20Sopenharmony_civoid ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */ 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci ide_init_pc(pc); 1748c2ecf20Sopenharmony_ci pc->c[0] = GPCMD_MODE_SENSE_10; 1758c2ecf20Sopenharmony_ci pc->c[1] = 0; 1768c2ecf20Sopenharmony_ci pc->c[2] = page_code; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci switch (page_code) { 1798c2ecf20Sopenharmony_ci case IDEFLOPPY_CAPABILITIES_PAGE: 1808c2ecf20Sopenharmony_ci length += 12; 1818c2ecf20Sopenharmony_ci break; 1828c2ecf20Sopenharmony_ci case IDEFLOPPY_FLEXIBLE_DISK_PAGE: 1838c2ecf20Sopenharmony_ci length += 32; 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci default: 1868c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unsupported page code in %s\n", __func__); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci put_unaligned(cpu_to_be16(length), (u16 *) &pc->c[7]); 1898c2ecf20Sopenharmony_ci pc->req_xfer = length; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic void idefloppy_create_rw_cmd(ide_drive_t *drive, 1938c2ecf20Sopenharmony_ci struct ide_atapi_pc *pc, struct request *rq, 1948c2ecf20Sopenharmony_ci unsigned long sector) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct ide_disk_obj *floppy = drive->driver_data; 1978c2ecf20Sopenharmony_ci int block = sector / floppy->bs_factor; 1988c2ecf20Sopenharmony_ci int blocks = blk_rq_sectors(rq) / floppy->bs_factor; 1998c2ecf20Sopenharmony_ci int cmd = rq_data_dir(rq); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci ide_debug_log(IDE_DBG_FUNC, "block: %d, blocks: %d", block, blocks); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci ide_init_pc(pc); 2048c2ecf20Sopenharmony_ci pc->c[0] = cmd == READ ? GPCMD_READ_10 : GPCMD_WRITE_10; 2058c2ecf20Sopenharmony_ci put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]); 2068c2ecf20Sopenharmony_ci put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci memcpy(scsi_req(rq)->cmd, pc->c, 12); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci pc->rq = rq; 2118c2ecf20Sopenharmony_ci if (cmd == WRITE) 2128c2ecf20Sopenharmony_ci pc->flags |= PC_FLAG_WRITING; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci pc->flags |= PC_FLAG_DMA_OK; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy, 2188c2ecf20Sopenharmony_ci struct ide_atapi_pc *pc, struct request *rq) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci ide_init_pc(pc); 2218c2ecf20Sopenharmony_ci memcpy(pc->c, scsi_req(rq)->cmd, sizeof(pc->c)); 2228c2ecf20Sopenharmony_ci pc->rq = rq; 2238c2ecf20Sopenharmony_ci if (blk_rq_bytes(rq)) { 2248c2ecf20Sopenharmony_ci pc->flags |= PC_FLAG_DMA_OK; 2258c2ecf20Sopenharmony_ci if (rq_data_dir(rq) == WRITE) 2268c2ecf20Sopenharmony_ci pc->flags |= PC_FLAG_WRITING; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, 2318c2ecf20Sopenharmony_ci struct request *rq, sector_t block) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct ide_disk_obj *floppy = drive->driver_data; 2348c2ecf20Sopenharmony_ci struct ide_cmd cmd; 2358c2ecf20Sopenharmony_ci struct ide_atapi_pc *pc; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci ide_debug_log(IDE_DBG_FUNC, "enter, cmd: 0x%x\n", rq->cmd[0]); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (drive->debug_mask & IDE_DBG_RQ) 2408c2ecf20Sopenharmony_ci blk_dump_rq_flags(rq, (rq->rq_disk 2418c2ecf20Sopenharmony_ci ? rq->rq_disk->disk_name 2428c2ecf20Sopenharmony_ci : "dev?")); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (scsi_req(rq)->result >= ERROR_MAX) { 2458c2ecf20Sopenharmony_ci if (drive->failed_pc) { 2468c2ecf20Sopenharmony_ci ide_floppy_report_error(floppy, drive->failed_pc); 2478c2ecf20Sopenharmony_ci drive->failed_pc = NULL; 2488c2ecf20Sopenharmony_ci } else 2498c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "%s: I/O error\n", drive->name); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (ata_misc_request(rq)) { 2528c2ecf20Sopenharmony_ci scsi_req(rq)->result = 0; 2538c2ecf20Sopenharmony_ci ide_complete_rq(drive, BLK_STS_OK, blk_rq_bytes(rq)); 2548c2ecf20Sopenharmony_ci return ide_stopped; 2558c2ecf20Sopenharmony_ci } else 2568c2ecf20Sopenharmony_ci goto out_end; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci switch (req_op(rq)) { 2608c2ecf20Sopenharmony_ci default: 2618c2ecf20Sopenharmony_ci if (((long)blk_rq_pos(rq) % floppy->bs_factor) || 2628c2ecf20Sopenharmony_ci (blk_rq_sectors(rq) % floppy->bs_factor)) { 2638c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "%s: unsupported r/w rq size\n", 2648c2ecf20Sopenharmony_ci drive->name); 2658c2ecf20Sopenharmony_ci goto out_end; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci pc = &floppy->queued_pc; 2688c2ecf20Sopenharmony_ci idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block); 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci case REQ_OP_SCSI_IN: 2718c2ecf20Sopenharmony_ci case REQ_OP_SCSI_OUT: 2728c2ecf20Sopenharmony_ci pc = &floppy->queued_pc; 2738c2ecf20Sopenharmony_ci idefloppy_blockpc_cmd(floppy, pc, rq); 2748c2ecf20Sopenharmony_ci break; 2758c2ecf20Sopenharmony_ci case REQ_OP_DRV_IN: 2768c2ecf20Sopenharmony_ci case REQ_OP_DRV_OUT: 2778c2ecf20Sopenharmony_ci switch (ide_req(rq)->type) { 2788c2ecf20Sopenharmony_ci case ATA_PRIV_MISC: 2798c2ecf20Sopenharmony_ci case ATA_PRIV_SENSE: 2808c2ecf20Sopenharmony_ci pc = (struct ide_atapi_pc *)ide_req(rq)->special; 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci default: 2838c2ecf20Sopenharmony_ci BUG(); 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci ide_prep_sense(drive, rq); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (rq_data_dir(rq)) 2928c2ecf20Sopenharmony_ci cmd.tf_flags |= IDE_TFLAG_WRITE; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci cmd.rq = rq; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (!blk_rq_is_passthrough(rq) || blk_rq_bytes(rq)) { 2978c2ecf20Sopenharmony_ci ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); 2988c2ecf20Sopenharmony_ci ide_map_sg(drive, &cmd); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci pc->rq = rq; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return ide_floppy_issue_pc(drive, &cmd, pc); 3048c2ecf20Sopenharmony_ciout_end: 3058c2ecf20Sopenharmony_ci drive->failed_pc = NULL; 3068c2ecf20Sopenharmony_ci if (blk_rq_is_passthrough(rq) && scsi_req(rq)->result == 0) 3078c2ecf20Sopenharmony_ci scsi_req(rq)->result = -EIO; 3088c2ecf20Sopenharmony_ci ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(rq)); 3098c2ecf20Sopenharmony_ci return ide_stopped; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci/* 3138c2ecf20Sopenharmony_ci * Look at the flexible disk page parameters. We ignore the CHS capacity 3148c2ecf20Sopenharmony_ci * parameters and use the LBA parameters instead. 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_cistatic int ide_floppy_get_flexible_disk_page(ide_drive_t *drive, 3178c2ecf20Sopenharmony_ci struct ide_atapi_pc *pc) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct ide_disk_obj *floppy = drive->driver_data; 3208c2ecf20Sopenharmony_ci struct gendisk *disk = floppy->disk; 3218c2ecf20Sopenharmony_ci u8 *page, buf[40]; 3228c2ecf20Sopenharmony_ci int capacity, lba_capacity; 3238c2ecf20Sopenharmony_ci u16 transfer_rate, sector_size, cyls, rpm; 3248c2ecf20Sopenharmony_ci u8 heads, sectors; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (ide_queue_pc_tail(drive, disk, pc, buf, pc->req_xfer)) { 3298c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Can't get flexible disk page params\n"); 3308c2ecf20Sopenharmony_ci return 1; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (buf[3] & 0x80) 3348c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_WP; 3358c2ecf20Sopenharmony_ci else 3368c2ecf20Sopenharmony_ci drive->dev_flags &= ~IDE_DFLAG_WP; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci set_disk_ro(disk, !!(drive->dev_flags & IDE_DFLAG_WP)); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci page = &buf[8]; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci transfer_rate = be16_to_cpup((__be16 *)&buf[8 + 2]); 3438c2ecf20Sopenharmony_ci sector_size = be16_to_cpup((__be16 *)&buf[8 + 6]); 3448c2ecf20Sopenharmony_ci cyls = be16_to_cpup((__be16 *)&buf[8 + 8]); 3458c2ecf20Sopenharmony_ci rpm = be16_to_cpup((__be16 *)&buf[8 + 28]); 3468c2ecf20Sopenharmony_ci heads = buf[8 + 4]; 3478c2ecf20Sopenharmony_ci sectors = buf[8 + 5]; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci capacity = cyls * heads * sectors * sector_size; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (memcmp(page, &floppy->flexible_disk_page, 32)) 3528c2ecf20Sopenharmony_ci printk(KERN_INFO PFX "%s: %dkB, %d/%d/%d CHS, %d kBps, " 3538c2ecf20Sopenharmony_ci "%d sector size, %d rpm\n", 3548c2ecf20Sopenharmony_ci drive->name, capacity / 1024, cyls, heads, 3558c2ecf20Sopenharmony_ci sectors, transfer_rate / 8, sector_size, rpm); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci memcpy(&floppy->flexible_disk_page, page, 32); 3588c2ecf20Sopenharmony_ci drive->bios_cyl = cyls; 3598c2ecf20Sopenharmony_ci drive->bios_head = heads; 3608c2ecf20Sopenharmony_ci drive->bios_sect = sectors; 3618c2ecf20Sopenharmony_ci lba_capacity = floppy->blocks * floppy->block_size; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (capacity < lba_capacity) { 3648c2ecf20Sopenharmony_ci printk(KERN_NOTICE PFX "%s: The disk reports a capacity of %d " 3658c2ecf20Sopenharmony_ci "bytes, but the drive only handles %d\n", 3668c2ecf20Sopenharmony_ci drive->name, lba_capacity, capacity); 3678c2ecf20Sopenharmony_ci floppy->blocks = floppy->block_size ? 3688c2ecf20Sopenharmony_ci capacity / floppy->block_size : 0; 3698c2ecf20Sopenharmony_ci drive->capacity64 = floppy->blocks * floppy->bs_factor; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return 0; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci/* 3768c2ecf20Sopenharmony_ci * Determine if a media is present in the floppy drive, and if so, its LBA 3778c2ecf20Sopenharmony_ci * capacity. 3788c2ecf20Sopenharmony_ci */ 3798c2ecf20Sopenharmony_cistatic int ide_floppy_get_capacity(ide_drive_t *drive) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct ide_disk_obj *floppy = drive->driver_data; 3828c2ecf20Sopenharmony_ci struct gendisk *disk = floppy->disk; 3838c2ecf20Sopenharmony_ci struct ide_atapi_pc pc; 3848c2ecf20Sopenharmony_ci u8 *cap_desc; 3858c2ecf20Sopenharmony_ci u8 pc_buf[256], header_len, desc_cnt; 3868c2ecf20Sopenharmony_ci int i, rc = 1, blocks, length; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci ide_debug_log(IDE_DBG_FUNC, "enter"); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci drive->bios_cyl = 0; 3918c2ecf20Sopenharmony_ci drive->bios_head = drive->bios_sect = 0; 3928c2ecf20Sopenharmony_ci floppy->blocks = 0; 3938c2ecf20Sopenharmony_ci floppy->bs_factor = 1; 3948c2ecf20Sopenharmony_ci drive->capacity64 = 0; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci ide_floppy_create_read_capacity_cmd(&pc); 3978c2ecf20Sopenharmony_ci if (ide_queue_pc_tail(drive, disk, &pc, pc_buf, pc.req_xfer)) { 3988c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Can't get floppy parameters\n"); 3998c2ecf20Sopenharmony_ci return 1; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci header_len = pc_buf[3]; 4028c2ecf20Sopenharmony_ci cap_desc = &pc_buf[4]; 4038c2ecf20Sopenharmony_ci desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */ 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci for (i = 0; i < desc_cnt; i++) { 4068c2ecf20Sopenharmony_ci unsigned int desc_start = 4 + i*8; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]); 4098c2ecf20Sopenharmony_ci length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci ide_debug_log(IDE_DBG_PROBE, "Descriptor %d: %dkB, %d blocks, " 4128c2ecf20Sopenharmony_ci "%d sector size", 4138c2ecf20Sopenharmony_ci i, blocks * length / 1024, 4148c2ecf20Sopenharmony_ci blocks, length); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (i) 4178c2ecf20Sopenharmony_ci continue; 4188c2ecf20Sopenharmony_ci /* 4198c2ecf20Sopenharmony_ci * the code below is valid only for the 1st descriptor, ie i=0 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci switch (pc_buf[desc_start + 4] & 0x03) { 4238c2ecf20Sopenharmony_ci /* Clik! drive returns this instead of CAPACITY_CURRENT */ 4248c2ecf20Sopenharmony_ci case CAPACITY_UNFORMATTED: 4258c2ecf20Sopenharmony_ci if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) 4268c2ecf20Sopenharmony_ci /* 4278c2ecf20Sopenharmony_ci * If it is not a clik drive, break out 4288c2ecf20Sopenharmony_ci * (maintains previous driver behaviour) 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_ci break; 4318c2ecf20Sopenharmony_ci fallthrough; 4328c2ecf20Sopenharmony_ci case CAPACITY_CURRENT: 4338c2ecf20Sopenharmony_ci /* Normal Zip/LS-120 disks */ 4348c2ecf20Sopenharmony_ci if (memcmp(cap_desc, &floppy->cap_desc, 8)) 4358c2ecf20Sopenharmony_ci printk(KERN_INFO PFX "%s: %dkB, %d blocks, %d " 4368c2ecf20Sopenharmony_ci "sector size\n", 4378c2ecf20Sopenharmony_ci drive->name, blocks * length / 1024, 4388c2ecf20Sopenharmony_ci blocks, length); 4398c2ecf20Sopenharmony_ci memcpy(&floppy->cap_desc, cap_desc, 8); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (!length || length % 512) { 4428c2ecf20Sopenharmony_ci printk(KERN_NOTICE PFX "%s: %d bytes block size" 4438c2ecf20Sopenharmony_ci " not supported\n", drive->name, length); 4448c2ecf20Sopenharmony_ci } else { 4458c2ecf20Sopenharmony_ci floppy->blocks = blocks; 4468c2ecf20Sopenharmony_ci floppy->block_size = length; 4478c2ecf20Sopenharmony_ci floppy->bs_factor = length / 512; 4488c2ecf20Sopenharmony_ci if (floppy->bs_factor != 1) 4498c2ecf20Sopenharmony_ci printk(KERN_NOTICE PFX "%s: Warning: " 4508c2ecf20Sopenharmony_ci "non 512 bytes block size not " 4518c2ecf20Sopenharmony_ci "fully supported\n", 4528c2ecf20Sopenharmony_ci drive->name); 4538c2ecf20Sopenharmony_ci drive->capacity64 = 4548c2ecf20Sopenharmony_ci floppy->blocks * floppy->bs_factor; 4558c2ecf20Sopenharmony_ci rc = 0; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci break; 4588c2ecf20Sopenharmony_ci case CAPACITY_NO_CARTRIDGE: 4598c2ecf20Sopenharmony_ci /* 4608c2ecf20Sopenharmony_ci * This is a KERN_ERR so it appears on screen 4618c2ecf20Sopenharmony_ci * for the user to see 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "%s: No disk in drive\n", 4648c2ecf20Sopenharmony_ci drive->name); 4658c2ecf20Sopenharmony_ci break; 4668c2ecf20Sopenharmony_ci case CAPACITY_INVALID: 4678c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "%s: Invalid capacity for disk " 4688c2ecf20Sopenharmony_ci "in drive\n", drive->name); 4698c2ecf20Sopenharmony_ci break; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci ide_debug_log(IDE_DBG_PROBE, "Descriptor 0 Code: %d", 4728c2ecf20Sopenharmony_ci pc_buf[desc_start + 4] & 0x03); 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* Clik! disk does not support get_flexible_disk_page */ 4768c2ecf20Sopenharmony_ci if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) 4778c2ecf20Sopenharmony_ci (void) ide_floppy_get_flexible_disk_page(drive, &pc); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return rc; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic void ide_floppy_setup(ide_drive_t *drive) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct ide_disk_obj *floppy = drive->driver_data; 4858c2ecf20Sopenharmony_ci u16 *id = drive->id; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci drive->pc_callback = ide_floppy_callback; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* 4908c2ecf20Sopenharmony_ci * We used to check revisions here. At this point however I'm giving up. 4918c2ecf20Sopenharmony_ci * Just assume they are all broken, its easier. 4928c2ecf20Sopenharmony_ci * 4938c2ecf20Sopenharmony_ci * The actual reason for the workarounds was likely a driver bug after 4948c2ecf20Sopenharmony_ci * all rather than a firmware bug, and the workaround below used to hide 4958c2ecf20Sopenharmony_ci * it. It should be fixed as of version 1.9, but to be on the safe side 4968c2ecf20Sopenharmony_ci * we'll leave the limitation below for the 2.2.x tree. 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_ci if (strstarts((char *)&id[ATA_ID_PROD], "IOMEGA ZIP 100 ATAPI")) { 4998c2ecf20Sopenharmony_ci drive->atapi_flags |= IDE_AFLAG_ZIP_DRIVE; 5008c2ecf20Sopenharmony_ci /* This value will be visible in the /proc/ide/hdx/settings */ 5018c2ecf20Sopenharmony_ci drive->pc_delay = IDEFLOPPY_PC_DELAY; 5028c2ecf20Sopenharmony_ci blk_queue_max_hw_sectors(drive->queue, 64); 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* 5068c2ecf20Sopenharmony_ci * Guess what? The IOMEGA Clik! drive also needs the above fix. It makes 5078c2ecf20Sopenharmony_ci * nasty clicking noises without it, so please don't remove this. 5088c2ecf20Sopenharmony_ci */ 5098c2ecf20Sopenharmony_ci if (strstarts((char *)&id[ATA_ID_PROD], "IOMEGA Clik!")) { 5108c2ecf20Sopenharmony_ci blk_queue_max_hw_sectors(drive->queue, 64); 5118c2ecf20Sopenharmony_ci drive->atapi_flags |= IDE_AFLAG_CLIK_DRIVE; 5128c2ecf20Sopenharmony_ci /* IOMEGA Clik! drives do not support lock/unlock commands */ 5138c2ecf20Sopenharmony_ci drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci (void) ide_floppy_get_capacity(drive); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci ide_proc_register_driver(drive, floppy->driver); 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic void ide_floppy_flush(ide_drive_t *drive) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic int ide_floppy_init_media(ide_drive_t *drive, struct gendisk *disk) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci int ret = 0; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (ide_do_test_unit_ready(drive, disk)) 5308c2ecf20Sopenharmony_ci ide_do_start_stop(drive, disk, 1); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci ret = ide_floppy_get_capacity(drive); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci set_capacity(disk, ide_gd_capacity(drive)); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return ret; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ciconst struct ide_disk_ops ide_atapi_disk_ops = { 5408c2ecf20Sopenharmony_ci .check = ide_check_atapi_device, 5418c2ecf20Sopenharmony_ci .get_capacity = ide_floppy_get_capacity, 5428c2ecf20Sopenharmony_ci .setup = ide_floppy_setup, 5438c2ecf20Sopenharmony_ci .flush = ide_floppy_flush, 5448c2ecf20Sopenharmony_ci .init_media = ide_floppy_init_media, 5458c2ecf20Sopenharmony_ci .set_doorlock = ide_set_media_lock, 5468c2ecf20Sopenharmony_ci .do_request = ide_floppy_do_request, 5478c2ecf20Sopenharmony_ci .ioctl = ide_floppy_ioctl, 5488c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 5498c2ecf20Sopenharmony_ci .compat_ioctl = ide_floppy_compat_ioctl, 5508c2ecf20Sopenharmony_ci#endif 5518c2ecf20Sopenharmony_ci}; 552