blob: a0a8ad3a3038ca3d1050edc3d86d6ad98f07d8ff [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Borislav Petkovd3f20842008-02-01 23:09:33 +01002 * IDE ATAPI floppy driver.
3 *
Bartlomiej Zolnierkiewicz59bca8c2008-02-01 23:09:33 +01004 * Copyright (C) 1996-1999 Gadi Oxman <gadio@netvision.net.il>
5 * Copyright (C) 2000-2002 Paul Bristow <paul@paulbristow.net>
6 * Copyright (C) 2005 Bartlomiej Zolnierkiewicz
Borislav Petkov0571c7a2008-02-02 19:56:38 +01007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * This driver supports the following IDE floppy drives:
9 *
10 * LS-120/240 SuperDisk
11 * Iomega Zip 100/250
12 * Iomega PC Card Clik!/PocketZip
13 *
Borislav Petkovd3f20842008-02-01 23:09:33 +010014 * For a historical changelog see
15 * Documentation/ide/ChangeLog.ide-floppy.1996-2002
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 */
17
Bartlomiej Zolnierkiewicz51509ee2008-10-10 22:39:34 +020018#define DRV_NAME "ide-floppy"
19
Borislav Petkovfc6c5bc2008-02-02 19:56:38 +010020#define IDEFLOPPY_VERSION "1.00"
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/module.h>
23#include <linux/types.h>
24#include <linux/string.h>
25#include <linux/kernel.h>
26#include <linux/delay.h>
27#include <linux/timer.h>
28#include <linux/mm.h>
29#include <linux/interrupt.h>
30#include <linux/major.h>
31#include <linux/errno.h>
32#include <linux/genhd.h>
33#include <linux/slab.h>
34#include <linux/cdrom.h>
35#include <linux/ide.h>
Bartlomiej Zolnierkiewicz3ceca722008-10-10 22:39:27 +020036#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/bitops.h>
Arjan van de Vencf8b8972006-03-23 03:00:45 -080038#include <linux/mutex.h>
Borislav Petkovb98b3402008-10-10 22:39:35 +020039#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
Bartlomiej Zolnierkiewicz89636af2007-07-20 01:11:59 +020041#include <scsi/scsi_ioctl.h>
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <asm/byteorder.h>
Borislav Petkov7e8b1632008-02-02 19:56:34 +010044#include <linux/irq.h>
45#include <linux/uaccess.h>
46#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <asm/unaligned.h>
48
Borislav Petkovf373bd82008-02-02 19:56:36 +010049/* define to see debug info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#define IDEFLOPPY_DEBUG_LOG 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52/* #define IDEFLOPPY_DEBUG(fmt, args...) printk(KERN_INFO fmt, ## args) */
Borislav Petkov0571c7a2008-02-02 19:56:38 +010053#define IDEFLOPPY_DEBUG(fmt, args...)
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55#if IDEFLOPPY_DEBUG_LOG
Borislav Petkovbcc77d92008-02-02 19:56:34 +010056#define debug_log(fmt, args...) \
57 printk(KERN_INFO "ide-floppy: " fmt, ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#else
Borislav Petkov0571c7a2008-02-02 19:56:38 +010059#define debug_log(fmt, args...) do {} while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#endif
61
62
Borislav Petkov0571c7a2008-02-02 19:56:38 +010063/* Some drives require a longer irq timeout. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#define IDEFLOPPY_WAIT_CMD (5 * WAIT_CMD)
65
66/*
Borislav Petkov0571c7a2008-02-02 19:56:38 +010067 * After each failed packet command we issue a request sense command and retry
68 * the packet command IDEFLOPPY_MAX_PC_RETRIES times.
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 */
70#define IDEFLOPPY_MAX_PC_RETRIES 3
71
72/*
Borislav Petkov0571c7a2008-02-02 19:56:38 +010073 * With each packet command, we allocate a buffer of IDEFLOPPY_PC_BUFFER_SIZE
74 * bytes.
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 */
76#define IDEFLOPPY_PC_BUFFER_SIZE 256
77
Borislav Petkov194ec0c2008-02-02 19:56:35 +010078/* format capacities descriptor codes */
Linus Torvalds1da177e2005-04-16 15:20:36 -070079#define CAPACITY_INVALID 0x00
80#define CAPACITY_UNFORMATTED 0x01
81#define CAPACITY_CURRENT 0x02
82#define CAPACITY_NO_CARTRIDGE 0x03
83
84/*
Borislav Petkov0571c7a2008-02-02 19:56:38 +010085 * Most of our global data which we need to save even as we leave the driver
86 * due to an interrupt or a timer event is stored in a variable of type
87 * idefloppy_floppy_t, defined below.
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 */
89typedef struct ide_floppy_obj {
90 ide_drive_t *drive;
91 ide_driver_t *driver;
92 struct gendisk *disk;
93 struct kref kref;
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +010094 unsigned int openers; /* protected by BKL for now */
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96 /* Current packet command */
Borislav Petkov8e555122008-04-18 00:46:27 +020097 struct ide_atapi_pc *pc;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 /* Last failed packet command */
Borislav Petkov8e555122008-04-18 00:46:27 +020099 struct ide_atapi_pc *failed_pc;
Bartlomiej Zolnierkiewicz2e8a6f82008-10-10 22:39:36 +0200100 /* used for blk_{fs,pc}_request() requests */
101 struct ide_atapi_pc queued_pc;
Bartlomiej Zolnierkiewicz394a4c22008-10-10 22:39:35 +0200102
Bartlomiej Zolnierkiewicz2e8a6f82008-10-10 22:39:36 +0200103 struct ide_atapi_pc request_sense_pc;
Bartlomiej Zolnierkiewicz394a4c22008-10-10 22:39:35 +0200104 struct request request_sense_rq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100106 /* Last error information */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 u8 sense_key, asc, ascq;
108 /* delay this long before sending packet command */
109 u8 ticks;
110 int progress_indication;
111
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100112 /* Device information */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 /* Current format */
114 int blocks, block_size, bs_factor;
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100115 /* Last format capacity descriptor */
116 u8 cap_desc[8];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 /* Copy of the flexible disk page */
Borislav Petkov8e81bbb2008-02-02 19:56:35 +0100118 u8 flexible_disk_page[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 /* Write protect */
120 int wp;
121 /* Supports format progress report */
122 int srfp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123} idefloppy_floppy_t;
124
Bartlomiej Zolnierkiewiczc40d3d32005-08-18 22:09:21 +0200125#define IDEFLOPPY_TICKS_DELAY HZ/20 /* default delay for ZIP 100 (50ms) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100127/* IOCTLs used in low-level formatting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128#define IDEFLOPPY_IOCTL_FORMAT_SUPPORTED 0x4600
129#define IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY 0x4601
130#define IDEFLOPPY_IOCTL_FORMAT_START 0x4602
131#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603
132
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100133/* Error code returned in rq->errors to the higher part of the driver. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134#define IDEFLOPPY_ERROR_GENERAL 101
135
136/*
Borislav Petkov948391d2008-02-02 19:56:34 +0100137 * Pages of the SELECT SENSE / MODE SENSE packet commands.
138 * See SFF-8070i spec.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 */
140#define IDEFLOPPY_CAPABILITIES_PAGE 0x1b
141#define IDEFLOPPY_FLEXIBLE_DISK_PAGE 0x05
142
Arjan van de Vencf8b8972006-03-23 03:00:45 -0800143static DEFINE_MUTEX(idefloppy_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145#define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref)
146
147#define ide_floppy_g(disk) \
148 container_of((disk)->private_data, struct ide_floppy_obj, driver)
149
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +0200150static void idefloppy_cleanup_obj(struct kref *);
151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk)
153{
154 struct ide_floppy_obj *floppy = NULL;
155
Arjan van de Vencf8b8972006-03-23 03:00:45 -0800156 mutex_lock(&idefloppy_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 floppy = ide_floppy_g(disk);
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +0200158 if (floppy) {
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +0200159 if (ide_device_get(floppy->drive))
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +0200160 floppy = NULL;
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +0200161 else
162 kref_get(&floppy->kref);
Bartlomiej Zolnierkiewicz08da5912008-07-24 22:53:15 +0200163 }
Arjan van de Vencf8b8972006-03-23 03:00:45 -0800164 mutex_unlock(&idefloppy_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 return floppy;
166}
167
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168static void ide_floppy_put(struct ide_floppy_obj *floppy)
169{
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +0200170 ide_drive_t *drive = floppy->drive;
171
Arjan van de Vencf8b8972006-03-23 03:00:45 -0800172 mutex_lock(&idefloppy_ref_mutex);
Borislav Petkov9a24b632008-02-02 19:56:33 +0100173 kref_put(&floppy->kref, idefloppy_cleanup_obj);
Bartlomiej Zolnierkiewiczd3e33ff2008-08-05 18:16:59 +0200174 ide_device_put(drive);
Arjan van de Vencf8b8972006-03-23 03:00:45 -0800175 mutex_unlock(&idefloppy_ref_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176}
177
178/*
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100179 * Used to finish servicing a request. For read/write requests, we will call
180 * ide_end_request to pass to the next buffer.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 */
Borislav Petkovc2b2b292008-04-18 00:46:27 +0200182static int idefloppy_end_request(ide_drive_t *drive, int uptodate, int nsecs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183{
184 idefloppy_floppy_t *floppy = drive->driver_data;
185 struct request *rq = HWGROUP(drive)->rq;
186 int error;
187
Borislav Petkovbcc77d92008-02-02 19:56:34 +0100188 debug_log("Reached %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190 switch (uptodate) {
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100191 case 0: error = IDEFLOPPY_ERROR_GENERAL; break;
192 case 1: error = 0; break;
193 default: error = uptodate;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 }
195 if (error)
196 floppy->failed_pc = NULL;
197 /* Why does this happen? */
198 if (!rq)
199 return 0;
Jens Axboe4aff5e22006-08-10 08:44:47 +0200200 if (!blk_special_request(rq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 /* our real local end request function */
202 ide_end_request(drive, uptodate, nsecs);
203 return 0;
204 }
205 rq->errors = error;
206 /* fixme: need to move this local also */
207 ide_end_drive_cmd(drive, 0, 0);
208 return 0;
209}
210
Borislav Petkov8e555122008-04-18 00:46:27 +0200211static void ide_floppy_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
Borislav Petkov32925e12008-02-02 19:56:36 +0100212 unsigned int bcount, int direction)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213{
Bartlomiej Zolnierkiewicz9567b342008-04-28 23:44:36 +0200214 ide_hwif_t *hwif = drive->hwif;
Borislav Petkovb98b3402008-10-10 22:39:35 +0200215 const struct ide_tp_ops *tp_ops = hwif->tp_ops;
216 xfer_func_t *xf = direction ? tp_ops->output_data : tp_ops->input_data;
217 struct scatterlist *sg = pc->sg;
218 char *buf;
NeilBrown5705f702007-09-25 12:35:59 +0200219 int count, done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Borislav Petkovb98b3402008-10-10 22:39:35 +0200221 while (bcount) {
222 count = min(sg->length - pc->b_count, bcount);
223 if (PageHighMem(sg_page(sg))) {
224 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
Borislav Petkovb98b3402008-10-10 22:39:35 +0200226 local_irq_save(flags);
227 buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
228 xf(drive, NULL, buf + pc->b_count, count);
229 kunmap_atomic(buf - sg->offset, KM_IRQ0);
230 local_irq_restore(flags);
231 } else {
232 buf = sg_virt(sg);
233 xf(drive, NULL, buf + pc->b_count, count);
234 }
Jens Axboe6c92e692007-08-16 13:43:12 +0200235 bcount -= count;
236 pc->b_count += count;
237 done += count;
Borislav Petkovb98b3402008-10-10 22:39:35 +0200238
239 if (pc->b_count == sg->length) {
240 if (!--pc->sg_cnt)
241 break;
242 pc->sg = sg = sg_next(sg);
243 pc->b_count = 0;
244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 }
246
Borislav Petkovc2b2b292008-04-18 00:46:27 +0200247 idefloppy_end_request(drive, 1, done >> 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
249 if (bcount) {
Borislav Petkov32925e12008-02-02 19:56:36 +0100250 printk(KERN_ERR "%s: leftover data in %s, bcount == %d\n",
251 drive->name, __func__, bcount);
Bartlomiej Zolnierkiewicz9f87abe2008-04-28 23:44:41 +0200252 ide_pad_transfer(drive, direction, bcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 }
254}
255
Borislav Petkov8e555122008-04-18 00:46:27 +0200256static void idefloppy_update_buffers(ide_drive_t *drive,
257 struct ide_atapi_pc *pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258{
259 struct request *rq = pc->rq;
260 struct bio *bio = rq->bio;
261
262 while ((bio = rq->bio) != NULL)
Borislav Petkovc2b2b292008-04-18 00:46:27 +0200263 idefloppy_end_request(drive, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264}
265
266/*
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100267 * Generate a new packet command request in front of the request queue, before
268 * the current request so that it will be processed immediately, on the next
269 * pass through the driver.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 */
Borislav Petkov8e555122008-04-18 00:46:27 +0200271static void idefloppy_queue_pc_head(ide_drive_t *drive, struct ide_atapi_pc *pc,
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100272 struct request *rq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273{
274 struct ide_floppy_obj *floppy = drive->driver_data;
275
FUJITA Tomonori124cafc2008-07-15 21:21:44 +0200276 blk_rq_init(NULL, rq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 rq->buffer = (char *) pc;
Jens Axboe4aff5e22006-08-10 08:44:47 +0200278 rq->cmd_type = REQ_TYPE_SPECIAL;
Bartlomiej Zolnierkiewicze8a96aa2008-07-15 21:21:41 +0200279 rq->cmd_flags |= REQ_PREEMPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 rq->rq_disk = floppy->disk;
Borislav Petkov20cd93b2008-07-23 19:56:00 +0200281 memcpy(rq->cmd, pc->c, 12);
FUJITA Tomonori63f5abb2008-07-15 21:21:51 +0200282 ide_do_drive_cmd(drive, rq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283}
284
Borislav Petkov81f49382008-07-15 21:21:56 +0200285static void ide_floppy_callback(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286{
287 idefloppy_floppy_t *floppy = drive->driver_data;
Borislav Petkov81f49382008-07-15 21:21:56 +0200288 struct ide_atapi_pc *pc = floppy->pc;
289 int uptodate = pc->error ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Borislav Petkovbcc77d92008-02-02 19:56:34 +0100291 debug_log("Reached %s\n", __func__);
292
Bartlomiej Zolnierkiewiczdd2e9a02008-07-15 21:22:01 +0200293 if (floppy->failed_pc == pc)
294 floppy->failed_pc = NULL;
295
Borislav Petkov81f49382008-07-15 21:21:56 +0200296 if (pc->c[0] == GPCMD_READ_10 || pc->c[0] == GPCMD_WRITE_10 ||
297 (pc->rq && blk_pc_request(pc->rq)))
298 uptodate = 1; /* FIXME */
299 else if (pc->c[0] == GPCMD_REQUEST_SENSE) {
300 u8 *buf = floppy->pc->buf;
Borislav Petkova6ff2d32008-02-02 19:56:34 +0100301
Borislav Petkov81f49382008-07-15 21:21:56 +0200302 if (!pc->error) {
303 floppy->sense_key = buf[2] & 0x0F;
304 floppy->asc = buf[12];
305 floppy->ascq = buf[13];
306 floppy->progress_indication = buf[15] & 0x80 ?
307 (u16)get_unaligned((u16 *)&buf[16]) : 0x10000;
308
309 if (floppy->failed_pc)
310 debug_log("pc = %x, ", floppy->failed_pc->c[0]);
311
Borislav Petkova6ff2d32008-02-02 19:56:34 +0100312 debug_log("sense key = %x, asc = %x, ascq = %x\n",
Borislav Petkov81f49382008-07-15 21:21:56 +0200313 floppy->sense_key, floppy->asc, floppy->ascq);
314 } else
315 printk(KERN_ERR "Error in REQUEST SENSE itself - "
316 "Aborting request!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Borislav Petkov81f49382008-07-15 21:21:56 +0200319 idefloppy_end_request(drive, uptodate, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320}
321
Borislav Petkov8e555122008-04-18 00:46:27 +0200322static void idefloppy_init_pc(struct ide_atapi_pc *pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323{
Borislav Petkov68dc3572008-07-16 20:33:47 +0200324 memset(pc, 0, sizeof(*pc));
Borislav Petkov8e555122008-04-18 00:46:27 +0200325 pc->buf = pc->pc_buf;
326 pc->buf_size = IDEFLOPPY_PC_BUFFER_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
Borislav Petkov8e555122008-04-18 00:46:27 +0200329static void idefloppy_create_request_sense_cmd(struct ide_atapi_pc *pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330{
Borislav Petkov30d67092008-02-02 19:56:33 +0100331 idefloppy_init_pc(pc);
332 pc->c[0] = GPCMD_REQUEST_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 pc->c[4] = 255;
Borislav Petkov8e555122008-04-18 00:46:27 +0200334 pc->req_xfer = 18;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335}
336
337/*
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100338 * Called when an error was detected during the last packet command. We queue a
339 * request sense packet command in the head of the request list.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 */
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100341static void idefloppy_retry_pc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342{
Bartlomiej Zolnierkiewicz394a4c22008-10-10 22:39:35 +0200343 struct ide_floppy_obj *floppy = drive->driver_data;
344 struct request *rq = &floppy->request_sense_rq;
Bartlomiej Zolnierkiewicz2e8a6f82008-10-10 22:39:36 +0200345 struct ide_atapi_pc *pc = &floppy->request_sense_pc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Bartlomiej Zolnierkiewicz64a57fe2008-02-06 02:57:51 +0100347 (void)ide_read_error(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 idefloppy_create_request_sense_cmd(pc);
349 idefloppy_queue_pc_head(drive, pc, rq);
350}
351
Borislav Petkov0eea6452008-02-02 19:56:36 +0100352/* The usual interrupt handler called during a packet command. */
Paolo Ciarrocchi52d3ccf2008-04-26 17:36:41 +0200353static ide_startstop_t idefloppy_pc_intr(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
355 idefloppy_floppy_t *floppy = drive->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Bartlomiej Zolnierkiewicz646c0cb2008-07-15 21:22:03 +0200357 return ide_pc_intr(drive, floppy->pc, idefloppy_pc_intr,
358 IDEFLOPPY_WAIT_CMD, NULL, idefloppy_update_buffers,
359 idefloppy_retry_pc, NULL, ide_floppy_io_buffers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
362/*
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100363 * What we have here is a classic case of a top half / bottom half interrupt
364 * service routine. In interrupt mode, the device sends an interrupt to signal
365 * that it is ready to receive a packet. However, we need to delay about 2-3
366 * ticks before issuing the packet or we gets in trouble.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 */
Borislav Petkovcbbc4e82008-07-15 21:22:03 +0200368static int idefloppy_transfer_pc(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
370 idefloppy_floppy_t *floppy = drive->driver_data;
371
372 /* Send the actual packet */
Bartlomiej Zolnierkiewicz374e0422008-07-23 19:55:56 +0200373 drive->hwif->tp_ops->output_data(drive, NULL, floppy->pc->c, 12);
Bartlomiej Zolnierkiewicz9567b342008-04-28 23:44:36 +0200374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 /* Timeout for the packet command */
376 return IDEFLOPPY_WAIT_CMD;
377}
378
Borislav Petkovcbbc4e82008-07-15 21:22:03 +0200379
380/*
381 * Called as an interrupt (or directly). When the device says it's ready for a
382 * packet, we schedule the packet transfer to occur about 2-3 ticks later in
383 * transfer_pc.
384 */
385static ide_startstop_t idefloppy_start_pc_transfer(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386{
387 idefloppy_floppy_t *floppy = drive->driver_data;
Bartlomiej Zolnierkiewicz6ffb6642008-07-15 21:21:56 +0200388 struct ide_atapi_pc *pc = floppy->pc;
Bartlomiej Zolnierkiewicz0b2eea42008-07-15 21:21:54 +0200389 ide_expiry_t *expiry;
390 unsigned int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100392 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 * The following delay solves a problem with ATAPI Zip 100 drives
394 * where the Busy flag was apparently being deasserted before the
395 * unit was ready to receive data. This was happening on a
396 * 1200 MHz Athlon system. 10/26/01 25msec is too short,
397 * 40 and 50msec work well. idefloppy_pc_intr will not be actually
398 * used until after the packet is moved in about 50 msec.
399 */
Borislav Petkovea68d272008-07-23 19:56:01 +0200400 if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) {
Bartlomiej Zolnierkiewicz0b2eea42008-07-15 21:21:54 +0200401 timeout = floppy->ticks;
Borislav Petkovcbbc4e82008-07-15 21:22:03 +0200402 expiry = &idefloppy_transfer_pc;
Bartlomiej Zolnierkiewicz0b2eea42008-07-15 21:21:54 +0200403 } else {
404 timeout = IDEFLOPPY_WAIT_CMD;
405 expiry = NULL;
406 }
Borislav Petkov0078df22008-02-02 19:56:33 +0100407
Bartlomiej Zolnierkiewicz594c16d2008-07-15 21:21:58 +0200408 return ide_transfer_pc(drive, pc, idefloppy_pc_intr, timeout, expiry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409}
410
Borislav Petkovd652c132008-02-02 19:56:35 +0100411static void ide_floppy_report_error(idefloppy_floppy_t *floppy,
Borislav Petkov8e555122008-04-18 00:46:27 +0200412 struct ide_atapi_pc *pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
Borislav Petkovd652c132008-02-02 19:56:35 +0100414 /* supress error messages resulting from Medium not present */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 if (floppy->sense_key == 0x02 &&
416 floppy->asc == 0x3a &&
417 floppy->ascq == 0x00)
Borislav Petkovd652c132008-02-02 19:56:35 +0100418 return;
419
420 printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, "
421 "asc = %2x, ascq = %2x\n",
422 floppy->drive->name, pc->c[0], floppy->sense_key,
423 floppy->asc, floppy->ascq);
424
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425}
426
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100427static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
Borislav Petkov8e555122008-04-18 00:46:27 +0200428 struct ide_atapi_pc *pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429{
430 idefloppy_floppy_t *floppy = drive->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 if (floppy->failed_pc == NULL &&
Borislav Petkov30d67092008-02-02 19:56:33 +0100433 pc->c[0] != GPCMD_REQUEST_SENSE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 floppy->failed_pc = pc;
435 /* Set the current packet command */
436 floppy->pc = pc;
437
Borislav Petkov757ced82008-02-02 19:56:37 +0100438 if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) {
Borislav Petkov6e5fa7b2008-02-02 19:56:37 +0100439 if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR))
Borislav Petkov757ced82008-02-02 19:56:37 +0100440 ide_floppy_report_error(floppy, pc);
441 /* Giving up */
442 pc->error = IDEFLOPPY_ERROR_GENERAL;
443
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 floppy->failed_pc = NULL;
Borislav Petkov2207fa52008-07-23 19:55:59 +0200445 drive->pc_callback(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 return ide_stopped;
447 }
448
Borislav Petkovbcc77d92008-02-02 19:56:34 +0100449 debug_log("Retry number - %d\n", pc->retries);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 pc->retries++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
Borislav Petkovcbbc4e82008-07-15 21:22:03 +0200453 return ide_issue_pc(drive, pc, idefloppy_start_pc_transfer,
Bartlomiej Zolnierkiewicz6bf16412008-07-15 21:22:00 +0200454 IDEFLOPPY_WAIT_CMD, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455}
456
Borislav Petkov8e555122008-04-18 00:46:27 +0200457static void idefloppy_create_prevent_cmd(struct ide_atapi_pc *pc, int prevent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
Borislav Petkovbcc77d92008-02-02 19:56:34 +0100459 debug_log("creating prevent removal command, prevent = %d\n", prevent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461 idefloppy_init_pc(pc);
Borislav Petkov30d67092008-02-02 19:56:33 +0100462 pc->c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 pc->c[4] = prevent;
464}
465
Borislav Petkov8e555122008-04-18 00:46:27 +0200466static void idefloppy_create_read_capacity_cmd(struct ide_atapi_pc *pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467{
468 idefloppy_init_pc(pc);
Borislav Petkov30d67092008-02-02 19:56:33 +0100469 pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 pc->c[7] = 255;
471 pc->c[8] = 255;
Borislav Petkov8e555122008-04-18 00:46:27 +0200472 pc->req_xfer = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473}
474
Borislav Petkov8e555122008-04-18 00:46:27 +0200475static void idefloppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b,
476 int l, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477{
478 idefloppy_init_pc(pc);
Borislav Petkov30d67092008-02-02 19:56:33 +0100479 pc->c[0] = GPCMD_FORMAT_UNIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 pc->c[1] = 0x17;
481
Borislav Petkov8e555122008-04-18 00:46:27 +0200482 memset(pc->buf, 0, 12);
483 pc->buf[1] = 0xA2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 /* Default format list header, u8 1: FOV/DCRT/IMM bits set */
485
486 if (flags & 1) /* Verify bit on... */
Borislav Petkov8e555122008-04-18 00:46:27 +0200487 pc->buf[1] ^= 0x20; /* ... turn off DCRT bit */
488 pc->buf[3] = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Borislav Petkov8e555122008-04-18 00:46:27 +0200490 put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buf[4]));
491 put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buf[8]));
492 pc->buf_size = 12;
Borislav Petkov6e5fa7b2008-02-02 19:56:37 +0100493 pc->flags |= PC_FLAG_WRITING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494}
495
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100496/* A mode sense command is used to "sense" floppy parameters. */
Borislav Petkov8e555122008-04-18 00:46:27 +0200497static void idefloppy_create_mode_sense_cmd(struct ide_atapi_pc *pc,
Bartlomiej Zolnierkiewicz4de4b9e2008-10-10 22:39:36 +0200498 u8 page_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
Borislav Petkov24a5d702008-02-02 19:56:34 +0100500 u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100501
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 idefloppy_init_pc(pc);
Borislav Petkov30d67092008-02-02 19:56:33 +0100503 pc->c[0] = GPCMD_MODE_SENSE_10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 pc->c[1] = 0;
Bartlomiej Zolnierkiewicz4de4b9e2008-10-10 22:39:36 +0200505 pc->c[2] = page_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507 switch (page_code) {
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100508 case IDEFLOPPY_CAPABILITIES_PAGE:
509 length += 12;
510 break;
511 case IDEFLOPPY_FLEXIBLE_DISK_PAGE:
512 length += 32;
513 break;
514 default:
515 printk(KERN_ERR "ide-floppy: unsupported page code "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 "in create_mode_sense_cmd\n");
517 }
Borislav Petkov8f622432008-02-02 19:56:33 +0100518 put_unaligned(cpu_to_be16(length), (u16 *) &pc->c[7]);
Borislav Petkov8e555122008-04-18 00:46:27 +0200519 pc->req_xfer = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520}
521
Borislav Petkov8e555122008-04-18 00:46:27 +0200522static void idefloppy_create_start_stop_cmd(struct ide_atapi_pc *pc, int start)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523{
524 idefloppy_init_pc(pc);
Borislav Petkov30d67092008-02-02 19:56:33 +0100525 pc->c[0] = GPCMD_START_STOP_UNIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 pc->c[4] = start;
527}
528
Borislav Petkovae7e8dd2008-02-02 19:56:36 +0100529static void idefloppy_create_rw_cmd(idefloppy_floppy_t *floppy,
Borislav Petkov8e555122008-04-18 00:46:27 +0200530 struct ide_atapi_pc *pc, struct request *rq,
Borislav Petkovae7e8dd2008-02-02 19:56:36 +0100531 unsigned long sector)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532{
533 int block = sector / floppy->bs_factor;
534 int blocks = rq->nr_sectors / floppy->bs_factor;
535 int cmd = rq_data_dir(rq);
536
Borislav Petkovae7e8dd2008-02-02 19:56:36 +0100537 debug_log("create_rw10_cmd: block == %d, blocks == %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 block, blocks);
539
540 idefloppy_init_pc(pc);
Borislav Petkovae7e8dd2008-02-02 19:56:36 +0100541 pc->c[0] = cmd == READ ? GPCMD_READ_10 : GPCMD_WRITE_10;
542 put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]);
Borislav Petkov8f622432008-02-02 19:56:33 +0100543 put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]);
Borislav Petkovae7e8dd2008-02-02 19:56:36 +0100544
Borislav Petkov20cd93b2008-07-23 19:56:00 +0200545 memcpy(rq->cmd, pc->c, 12);
546
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 pc->rq = rq;
Borislav Petkovb98b3402008-10-10 22:39:35 +0200548 pc->b_count = 0;
Jens Axboe4aff5e22006-08-10 08:44:47 +0200549 if (rq->cmd_flags & REQ_RW)
Borislav Petkov6e5fa7b2008-02-02 19:56:37 +0100550 pc->flags |= PC_FLAG_WRITING;
Borislav Petkov8e555122008-04-18 00:46:27 +0200551 pc->buf = NULL;
552 pc->req_xfer = pc->buf_size = blocks * floppy->block_size;
Bartlomiej Zolnierkiewicz5e331092008-07-15 21:21:56 +0200553 pc->flags |= PC_FLAG_DMA_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554}
555
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100556static void idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy,
Borislav Petkov8e555122008-04-18 00:46:27 +0200557 struct ide_atapi_pc *pc, struct request *rq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 idefloppy_init_pc(pc);
560 memcpy(pc->c, rq->cmd, sizeof(pc->c));
Jens Axboe3d6392c2007-07-09 12:38:05 +0200561 pc->rq = rq;
Borislav Petkovb98b3402008-10-10 22:39:35 +0200562 pc->b_count = 0;
Jens Axboe3d6392c2007-07-09 12:38:05 +0200563 if (rq->data_len && rq_data_dir(rq) == WRITE)
Borislav Petkov6e5fa7b2008-02-02 19:56:37 +0100564 pc->flags |= PC_FLAG_WRITING;
Borislav Petkov8e555122008-04-18 00:46:27 +0200565 pc->buf = rq->data;
Jens Axboe3d6392c2007-07-09 12:38:05 +0200566 if (rq->bio)
Bartlomiej Zolnierkiewicz5e331092008-07-15 21:21:56 +0200567 pc->flags |= PC_FLAG_DMA_OK;
Jens Axboe3d6392c2007-07-09 12:38:05 +0200568 /*
569 * possibly problematic, doesn't look like ide-floppy correctly
570 * handled scattered requests if dma fails...
571 */
Borislav Petkov8e555122008-04-18 00:46:27 +0200572 pc->req_xfer = pc->buf_size = rq->data_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573}
574
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100575static ide_startstop_t idefloppy_do_request(ide_drive_t *drive,
576 struct request *rq, sector_t block_s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
578 idefloppy_floppy_t *floppy = drive->driver_data;
Borislav Petkovb98b3402008-10-10 22:39:35 +0200579 ide_hwif_t *hwif = drive->hwif;
Borislav Petkov8e555122008-04-18 00:46:27 +0200580 struct ide_atapi_pc *pc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 unsigned long block = (unsigned long)block_s;
582
Borislav Petkovb98b3402008-10-10 22:39:35 +0200583 debug_log("%s: dev: %s, cmd: 0x%x, cmd_type: %x, errors: %d\n",
584 __func__, rq->rq_disk ? rq->rq_disk->disk_name : "?",
585 rq->cmd[0], rq->cmd_type, rq->errors);
586
587 debug_log("%s: sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",
588 __func__, (long)rq->sector, rq->nr_sectors,
589 rq->current_nr_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
591 if (rq->errors >= ERROR_MAX) {
Borislav Petkovd652c132008-02-02 19:56:35 +0100592 if (floppy->failed_pc)
593 ide_floppy_report_error(floppy, floppy->failed_pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 else
595 printk(KERN_ERR "ide-floppy: %s: I/O error\n",
596 drive->name);
Borislav Petkovc2b2b292008-04-18 00:46:27 +0200597 idefloppy_end_request(drive, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 return ide_stopped;
599 }
Jens Axboe4aff5e22006-08-10 08:44:47 +0200600 if (blk_fs_request(rq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 if (((long)rq->sector % floppy->bs_factor) ||
602 (rq->nr_sectors % floppy->bs_factor)) {
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100603 printk(KERN_ERR "%s: unsupported r/w request size\n",
604 drive->name);
Borislav Petkovc2b2b292008-04-18 00:46:27 +0200605 idefloppy_end_request(drive, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 return ide_stopped;
607 }
Bartlomiej Zolnierkiewicz2e8a6f82008-10-10 22:39:36 +0200608 pc = &floppy->queued_pc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 idefloppy_create_rw_cmd(floppy, pc, rq, block);
Jens Axboe4aff5e22006-08-10 08:44:47 +0200610 } else if (blk_special_request(rq)) {
Borislav Petkov8e555122008-04-18 00:46:27 +0200611 pc = (struct ide_atapi_pc *) rq->buffer;
Jens Axboe4aff5e22006-08-10 08:44:47 +0200612 } else if (blk_pc_request(rq)) {
Bartlomiej Zolnierkiewicz2e8a6f82008-10-10 22:39:36 +0200613 pc = &floppy->queued_pc;
Jens Axboe3d6392c2007-07-09 12:38:05 +0200614 idefloppy_blockpc_cmd(floppy, pc, rq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 } else {
616 blk_dump_rq_flags(rq,
617 "ide-floppy: unsupported command in queue");
Borislav Petkovc2b2b292008-04-18 00:46:27 +0200618 idefloppy_end_request(drive, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 return ide_stopped;
620 }
621
Borislav Petkovb98b3402008-10-10 22:39:35 +0200622 ide_init_sg_cmd(drive, rq);
623 ide_map_sg(drive, rq);
624
625 pc->sg = hwif->sg_table;
626 pc->sg_cnt = hwif->sg_nents;
627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 pc->rq = rq;
Bartlomiej Zolnierkiewicz5d418932008-07-15 21:21:57 +0200629
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 return idefloppy_issue_pc(drive, pc);
631}
632
633/*
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100634 * Add a special packet command request to the tail of the request queue,
635 * and wait for it to be serviced.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 */
Borislav Petkov8e555122008-04-18 00:46:27 +0200637static int idefloppy_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638{
639 struct ide_floppy_obj *floppy = drive->driver_data;
FUJITA Tomonori6fe16232008-07-15 21:21:43 +0200640 struct request *rq;
641 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
FUJITA Tomonori6fe16232008-07-15 21:21:43 +0200643 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
644 rq->buffer = (char *) pc;
645 rq->cmd_type = REQ_TYPE_SPECIAL;
Borislav Petkov20cd93b2008-07-23 19:56:00 +0200646 memcpy(rq->cmd, pc->c, 12);
FUJITA Tomonori6fe16232008-07-15 21:21:43 +0200647 error = blk_execute_rq(drive->queue, floppy->disk, rq, 0);
648 blk_put_request(rq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
FUJITA Tomonori6fe16232008-07-15 21:21:43 +0200650 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651}
652
653/*
Borislav Petkov8e81bbb2008-02-02 19:56:35 +0100654 * Look at the flexible disk page parameters. We ignore the CHS capacity
655 * parameters and use the LBA parameters instead.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 */
Borislav Petkov8e81bbb2008-02-02 19:56:35 +0100657static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658{
659 idefloppy_floppy_t *floppy = drive->driver_data;
Borislav Petkov8e555122008-04-18 00:46:27 +0200660 struct ide_atapi_pc pc;
Borislav Petkov8e81bbb2008-02-02 19:56:35 +0100661 u8 *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 int capacity, lba_capacity;
Borislav Petkov8e81bbb2008-02-02 19:56:35 +0100663 u16 transfer_rate, sector_size, cyls, rpm;
664 u8 heads, sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
Bartlomiej Zolnierkiewicz4de4b9e2008-10-10 22:39:36 +0200666 idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE);
Borislav Petkov8e81bbb2008-02-02 19:56:35 +0100667
668 if (idefloppy_queue_pc_tail(drive, &pc)) {
669 printk(KERN_ERR "ide-floppy: Can't get flexible disk page"
670 " parameters\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 return 1;
672 }
Borislav Petkov8e555122008-04-18 00:46:27 +0200673 floppy->wp = !!(pc.buf[3] & 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 set_disk_ro(floppy->disk, floppy->wp);
Borislav Petkov8e555122008-04-18 00:46:27 +0200675 page = &pc.buf[8];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
Harvey Harrison85ae98a2008-07-16 20:33:47 +0200677 transfer_rate = be16_to_cpup((__be16 *)&pc.buf[8 + 2]);
678 sector_size = be16_to_cpup((__be16 *)&pc.buf[8 + 6]);
679 cyls = be16_to_cpup((__be16 *)&pc.buf[8 + 8]);
680 rpm = be16_to_cpup((__be16 *)&pc.buf[8 + 28]);
Borislav Petkov8e555122008-04-18 00:46:27 +0200681 heads = pc.buf[8 + 4];
682 sectors = pc.buf[8 + 5];
Borislav Petkov8e81bbb2008-02-02 19:56:35 +0100683
684 capacity = cyls * heads * sectors * sector_size;
685
686 if (memcmp(page, &floppy->flexible_disk_page, 32))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
688 "%d sector size, %d rpm\n",
Borislav Petkov8e81bbb2008-02-02 19:56:35 +0100689 drive->name, capacity / 1024, cyls, heads,
690 sectors, transfer_rate / 8, sector_size, rpm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Borislav Petkov8e81bbb2008-02-02 19:56:35 +0100692 memcpy(&floppy->flexible_disk_page, page, 32);
693 drive->bios_cyl = cyls;
694 drive->bios_head = heads;
695 drive->bios_sect = sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 lba_capacity = floppy->blocks * floppy->block_size;
Borislav Petkov8e81bbb2008-02-02 19:56:35 +0100697
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 if (capacity < lba_capacity) {
699 printk(KERN_NOTICE "%s: The disk reports a capacity of %d "
700 "bytes, but the drive only handles %d\n",
701 drive->name, lba_capacity, capacity);
Borislav Petkov8e81bbb2008-02-02 19:56:35 +0100702 floppy->blocks = floppy->block_size ?
703 capacity / floppy->block_size : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 }
705 return 0;
706}
707
Borislav Petkov948391d2008-02-02 19:56:34 +0100708static int idefloppy_get_sfrp_bit(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709{
710 idefloppy_floppy_t *floppy = drive->driver_data;
Borislav Petkov8e555122008-04-18 00:46:27 +0200711 struct ide_atapi_pc pc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
713 floppy->srfp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
Bartlomiej Zolnierkiewicz4de4b9e2008-10-10 22:39:36 +0200715 idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE);
Borislav Petkov6e5fa7b2008-02-02 19:56:37 +0100716 pc.flags |= PC_FLAG_SUPPRESS_ERROR;
Bartlomiej Zolnierkiewicz4de4b9e2008-10-10 22:39:36 +0200717
Borislav Petkov948391d2008-02-02 19:56:34 +0100718 if (idefloppy_queue_pc_tail(drive, &pc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Borislav Petkov8e555122008-04-18 00:46:27 +0200721 floppy->srfp = pc.buf[8 + 2] & 0x40;
Bartlomiej Zolnierkiewicze3faa242008-10-10 22:39:34 +0200722 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723}
724
725/*
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100726 * Determine if a media is present in the floppy drive, and if so, its LBA
727 * capacity.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 */
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100729static int ide_floppy_get_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730{
731 idefloppy_floppy_t *floppy = drive->driver_data;
Borislav Petkov8e555122008-04-18 00:46:27 +0200732 struct ide_atapi_pc pc;
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100733 u8 *cap_desc;
734 u8 header_len, desc_cnt;
735 int i, rc = 1, blocks, length;
736
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 drive->bios_cyl = 0;
738 drive->bios_head = drive->bios_sect = 0;
Alan Coxfdb77da2007-02-17 02:40:20 +0100739 floppy->blocks = 0;
740 floppy->bs_factor = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 set_capacity(floppy->disk, 0);
742
743 idefloppy_create_read_capacity_cmd(&pc);
744 if (idefloppy_queue_pc_tail(drive, &pc)) {
745 printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
746 return 1;
747 }
Borislav Petkov8e555122008-04-18 00:46:27 +0200748 header_len = pc.buf[3];
749 cap_desc = &pc.buf[4];
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100750 desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100752 for (i = 0; i < desc_cnt; i++) {
753 unsigned int desc_start = 4 + i*8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Harvey Harrison85ae98a2008-07-16 20:33:47 +0200755 blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]);
756 length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]);
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100757
758 debug_log("Descriptor %d: %dkB, %d blocks, %d sector size\n",
759 i, blocks * length / 1024, blocks, length);
760
761 if (i)
762 continue;
763 /*
764 * the code below is valid only for the 1st descriptor, ie i=0
765 */
766
Borislav Petkov8e555122008-04-18 00:46:27 +0200767 switch (pc.buf[desc_start + 4] & 0x03) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 /* Clik! drive returns this instead of CAPACITY_CURRENT */
769 case CAPACITY_UNFORMATTED:
Borislav Petkovea68d272008-07-23 19:56:01 +0200770 if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE))
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100771 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 * If it is not a clik drive, break out
773 * (maintains previous driver behaviour)
774 */
775 break;
776 case CAPACITY_CURRENT:
777 /* Normal Zip/LS-120 disks */
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100778 if (memcmp(cap_desc, &floppy->cap_desc, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 printk(KERN_INFO "%s: %dkB, %d blocks, %d "
780 "sector size\n", drive->name,
781 blocks * length / 1024, blocks, length);
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100782 memcpy(&floppy->cap_desc, cap_desc, 8);
783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 if (!length || length % 512) {
785 printk(KERN_NOTICE "%s: %d bytes block size "
786 "not supported\n", drive->name, length);
787 } else {
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100788 floppy->blocks = blocks;
789 floppy->block_size = length;
790 floppy->bs_factor = length / 512;
791 if (floppy->bs_factor != 1)
792 printk(KERN_NOTICE "%s: warning: non "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 "512 bytes block size not "
794 "fully supported\n",
795 drive->name);
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100796 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 }
798 break;
799 case CAPACITY_NO_CARTRIDGE:
800 /*
801 * This is a KERN_ERR so it appears on screen
802 * for the user to see
803 */
804 printk(KERN_ERR "%s: No disk in drive\n", drive->name);
805 break;
806 case CAPACITY_INVALID:
807 printk(KERN_ERR "%s: Invalid capacity for disk "
808 "in drive\n", drive->name);
809 break;
810 }
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100811 debug_log("Descriptor 0 Code: %d\n",
Borislav Petkov8e555122008-04-18 00:46:27 +0200812 pc.buf[desc_start + 4] & 0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 }
814
815 /* Clik! disk does not support get_flexible_disk_page */
Borislav Petkovea68d272008-07-23 19:56:01 +0200816 if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE))
Borislav Petkov8e81bbb2008-02-02 19:56:35 +0100817 (void) ide_floppy_get_flexible_disk_page(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
819 set_capacity(floppy->disk, floppy->blocks * floppy->bs_factor);
820 return rc;
821}
822
823/*
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100824 * Obtain the list of formattable capacities.
825 * Very similar to ide_floppy_get_capacity, except that we push the capacity
826 * descriptors to userland, instead of our own structures.
827 *
828 * Userland gives us the following structure:
829 *
830 * struct idefloppy_format_capacities {
831 * int nformats;
832 * struct {
833 * int nblocks;
834 * int blocksize;
835 * } formats[];
836 * };
837 *
838 * userland initializes nformats to the number of allocated formats[] records.
839 * On exit we set nformats to the number of records we've actually initialized.
840 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100842static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843{
Borislav Petkov8e555122008-04-18 00:46:27 +0200844 struct ide_atapi_pc pc;
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100845 u8 header_len, desc_cnt;
846 int i, blocks, length, u_array_size, u_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 int __user *argp;
848
849 if (get_user(u_array_size, arg))
Bartlomiej Zolnierkiewicze3faa242008-10-10 22:39:34 +0200850 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
852 if (u_array_size <= 0)
Bartlomiej Zolnierkiewicze3faa242008-10-10 22:39:34 +0200853 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
855 idefloppy_create_read_capacity_cmd(&pc);
856 if (idefloppy_queue_pc_tail(drive, &pc)) {
857 printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
Bartlomiej Zolnierkiewicze3faa242008-10-10 22:39:34 +0200858 return -EIO;
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100859 }
Bartlomiej Zolnierkiewicze3faa242008-10-10 22:39:34 +0200860
Borislav Petkov8e555122008-04-18 00:46:27 +0200861 header_len = pc.buf[3];
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100862 desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863
864 u_index = 0;
865 argp = arg + 1;
866
867 /*
Borislav Petkov194ec0c2008-02-02 19:56:35 +0100868 * We always skip the first capacity descriptor. That's the current
869 * capacity. We are interested in the remaining descriptors, the
870 * formattable capacities.
871 */
872 for (i = 1; i < desc_cnt; i++) {
873 unsigned int desc_start = 4 + i*8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 if (u_index >= u_array_size)
876 break; /* User-supplied buffer too small */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
Harvey Harrison85ae98a2008-07-16 20:33:47 +0200878 blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]);
879 length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
881 if (put_user(blocks, argp))
Bartlomiej Zolnierkiewicze3faa242008-10-10 22:39:34 +0200882 return -EFAULT;
883
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 ++argp;
885
886 if (put_user(length, argp))
Bartlomiej Zolnierkiewicze3faa242008-10-10 22:39:34 +0200887 return -EFAULT;
888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 ++argp;
890
891 ++u_index;
892 }
893
894 if (put_user(u_index, arg))
Bartlomiej Zolnierkiewicze3faa242008-10-10 22:39:34 +0200895 return -EFAULT;
896
897 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898}
899
900/*
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100901 * Get ATAPI_FORMAT_UNIT progress indication.
902 *
903 * Userland gives a pointer to an int. The int is set to a progress
904 * indicator 0-65536, with 65536=100%.
905 *
906 * If the drive does not support format progress indication, we just check
907 * the dsc bit, and return either 0 or 65536.
908 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
Bartlomiej Zolnierkiewiczd56c99e2008-10-10 22:39:34 +0200910static int ide_floppy_get_format_progress(ide_drive_t *drive, int __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
912 idefloppy_floppy_t *floppy = drive->driver_data;
Borislav Petkov8e555122008-04-18 00:46:27 +0200913 struct ide_atapi_pc pc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 int progress_indication = 0x10000;
915
916 if (floppy->srfp) {
917 idefloppy_create_request_sense_cmd(&pc);
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100918 if (idefloppy_queue_pc_tail(drive, &pc))
Bartlomiej Zolnierkiewicze3faa242008-10-10 22:39:34 +0200919 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
921 if (floppy->sense_key == 2 &&
922 floppy->asc == 4 &&
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100923 floppy->ascq == 4)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 progress_indication = floppy->progress_indication;
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100925
926 /* Else assume format_unit has finished, and we're at 0x10000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 } else {
Bartlomiej Zolnierkiewiczb73c7ee2008-07-23 19:55:52 +0200928 ide_hwif_t *hwif = drive->hwif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 unsigned long flags;
Bartlomiej Zolnierkiewicz22c525b2008-01-25 22:17:11 +0100930 u8 stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
932 local_irq_save(flags);
Bartlomiej Zolnierkiewicz374e0422008-07-23 19:55:56 +0200933 stat = hwif->tp_ops->read_status(hwif);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 local_irq_restore(flags);
935
Bartlomiej Zolnierkiewicz3a7d2482008-10-10 22:39:21 +0200936 progress_indication = ((stat & ATA_DSC) == 0) ? 0 : 0x10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Bartlomiej Zolnierkiewicze3faa242008-10-10 22:39:34 +0200939 if (put_user(progress_indication, arg))
940 return -EFAULT;
941
942 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943}
944
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100945static sector_t idefloppy_capacity(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946{
947 idefloppy_floppy_t *floppy = drive->driver_data;
948 unsigned long capacity = floppy->blocks * floppy->bs_factor;
949
950 return capacity;
951}
952
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200953#ifdef CONFIG_IDE_PROC_FS
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200954ide_devset_rw(bios_cyl, 0, 1023, bios_cyl);
955ide_devset_rw(bios_head, 0, 255, bios_head);
956ide_devset_rw(bios_sect, 0, 63, bios_sect);
957
958static int get_ticks(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959{
960 idefloppy_floppy_t *floppy = drive->driver_data;
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200961 return floppy->ticks;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962}
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +0200963
964static int set_ticks(ide_drive_t *drive, int arg)
965{
966 idefloppy_floppy_t *floppy = drive->driver_data;
967 floppy->ticks = arg;
968 return 0;
969}
970
971IDE_DEVSET(ticks, S_RW, 0, 255, get_ticks, set_ticks);
972
973static const struct ide_devset *idefloppy_settings[] = {
974 &ide_devset_bios_cyl,
975 &ide_devset_bios_head,
976 &ide_devset_bios_sect,
977 &ide_devset_ticks,
978 NULL
979};
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +0200980#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100982static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983{
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200984 u16 *id = drive->id;
Borislav Petkov3ad67762008-04-18 00:46:25 +0200985 u8 gcw[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +0200987 *((u16 *)&gcw) = id[ATA_ID_CONFIG];
Bartlomiej Zolnierkiewicz2e8a6f82008-10-10 22:39:36 +0200988
Borislav Petkov2207fa52008-07-23 19:55:59 +0200989 drive->pc_callback = ide_floppy_callback;
Borislav Petkov3ad67762008-04-18 00:46:25 +0200990
991 if (((gcw[0] & 0x60) >> 5) == 1)
Borislav Petkovea68d272008-07-23 19:56:01 +0200992 drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 /*
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100994 * We used to check revisions here. At this point however I'm giving up.
995 * Just assume they are all broken, its easier.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 *
Borislav Petkov0571c7a2008-02-02 19:56:38 +0100997 * The actual reason for the workarounds was likely a driver bug after
998 * all rather than a firmware bug, and the workaround below used to hide
999 * it. It should be fixed as of version 1.9, but to be on the safe side
1000 * we'll leave the limitation below for the 2.2.x tree.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +02001002 if (!strncmp((char *)&id[ATA_ID_PROD], "IOMEGA ZIP 100 ATAPI", 20)) {
Borislav Petkovea68d272008-07-23 19:56:01 +02001003 drive->atapi_flags |= IDE_AFLAG_ZIP_DRIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 /* This value will be visible in the /proc/ide/hdx/settings */
1005 floppy->ticks = IDEFLOPPY_TICKS_DELAY;
1006 blk_queue_max_sectors(drive->queue, 64);
1007 }
1008
1009 /*
Borislav Petkov0571c7a2008-02-02 19:56:38 +01001010 * Guess what? The IOMEGA Clik! drive also needs the above fix. It makes
1011 * nasty clicking noises without it, so please don't remove this.
1012 */
Bartlomiej Zolnierkiewicz4dde4492008-10-10 22:39:19 +02001013 if (strncmp((char *)&id[ATA_ID_PROD], "IOMEGA Clik!", 11) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 blk_queue_max_sectors(drive->queue, 64);
Borislav Petkovea68d272008-07-23 19:56:01 +02001015 drive->atapi_flags |= IDE_AFLAG_CLIK_DRIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 }
1017
Borislav Petkov194ec0c2008-02-02 19:56:35 +01001018 (void) ide_floppy_get_capacity(drive);
Bartlomiej Zolnierkiewicz1e874f42008-10-10 22:39:27 +02001019
1020 ide_proc_register_driver(drive, floppy->driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021}
1022
Russell King4031bbe2006-01-06 11:41:00 +00001023static void ide_floppy_remove(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
1025 idefloppy_floppy_t *floppy = drive->driver_data;
1026 struct gendisk *g = floppy->disk;
1027
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +02001028 ide_proc_unregister_driver(drive, floppy->driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
1030 del_gendisk(g);
1031
1032 ide_floppy_put(floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033}
1034
Borislav Petkov9a24b632008-02-02 19:56:33 +01001035static void idefloppy_cleanup_obj(struct kref *kref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036{
1037 struct ide_floppy_obj *floppy = to_ide_floppy(kref);
1038 ide_drive_t *drive = floppy->drive;
1039 struct gendisk *g = floppy->disk;
1040
1041 drive->driver_data = NULL;
1042 g->private_data = NULL;
1043 put_disk(g);
1044 kfree(floppy);
1045}
1046
Bartlomiej Zolnierkiewiczecfd80e2007-05-10 00:01:09 +02001047#ifdef CONFIG_IDE_PROC_FS
Borislav Petkov0571c7a2008-02-02 19:56:38 +01001048static int proc_idefloppy_read_capacity(char *page, char **start, off_t off,
1049 int count, int *eof, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050{
1051 ide_drive_t*drive = (ide_drive_t *)data;
1052 int len;
1053
Borislav Petkov0571c7a2008-02-02 19:56:38 +01001054 len = sprintf(page, "%llu\n", (long long)idefloppy_capacity(drive));
1055 PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056}
1057
1058static ide_proc_entry_t idefloppy_proc[] = {
Borislav Petkov0571c7a2008-02-02 19:56:38 +01001059 { "capacity", S_IFREG|S_IRUGO, proc_idefloppy_read_capacity, NULL },
1060 { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 { NULL, 0, NULL, NULL }
1062};
Bartlomiej Zolnierkiewiczecfd80e2007-05-10 00:01:09 +02001063#endif /* CONFIG_IDE_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
Russell King4031bbe2006-01-06 11:41:00 +00001065static int ide_floppy_probe(ide_drive_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067static ide_driver_t idefloppy_driver = {
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001068 .gen_driver = {
Laurent Riffard4ef3b8f2005-11-18 22:15:40 +01001069 .owner = THIS_MODULE,
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001070 .name = "ide-floppy",
1071 .bus = &ide_bus_type,
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001072 },
Russell King4031bbe2006-01-06 11:41:00 +00001073 .probe = ide_floppy_probe,
1074 .remove = ide_floppy_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 .version = IDEFLOPPY_VERSION,
1076 .media = ide_floppy,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 .do_request = idefloppy_do_request,
Borislav Petkovc2b2b292008-04-18 00:46:27 +02001078 .end_request = idefloppy_end_request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 .error = __ide_error,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +02001080#ifdef CONFIG_IDE_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 .proc = idefloppy_proc,
Bartlomiej Zolnierkiewicz8185d5a2008-10-10 22:39:28 +02001082 .settings = idefloppy_settings,
Bartlomiej Zolnierkiewicz7662d042007-05-10 00:01:10 +02001083#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084};
1085
1086static int idefloppy_open(struct inode *inode, struct file *filp)
1087{
1088 struct gendisk *disk = inode->i_bdev->bd_disk;
1089 struct ide_floppy_obj *floppy;
1090 ide_drive_t *drive;
Borislav Petkov8e555122008-04-18 00:46:27 +02001091 struct ide_atapi_pc pc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 int ret = 0;
1093
Borislav Petkovbcc77d92008-02-02 19:56:34 +01001094 debug_log("Reached %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
Borislav Petkov0571c7a2008-02-02 19:56:38 +01001096 floppy = ide_floppy_get(disk);
1097 if (!floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 return -ENXIO;
1099
1100 drive = floppy->drive;
1101
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001102 floppy->openers++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001104 if (floppy->openers == 1) {
Borislav Petkovea68d272008-07-23 19:56:01 +02001105 drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 /* Just in case */
1107
Borislav Petkovc96a7df2008-07-16 20:33:46 +02001108 idefloppy_init_pc(&pc);
1109 pc.c[0] = GPCMD_TEST_UNIT_READY;
1110
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 if (idefloppy_queue_pc_tail(drive, &pc)) {
1112 idefloppy_create_start_stop_cmd(&pc, 1);
1113 (void) idefloppy_queue_pc_tail(drive, &pc);
1114 }
1115
Borislav Petkov194ec0c2008-02-02 19:56:35 +01001116 if (ide_floppy_get_capacity(drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 && (filp->f_flags & O_NDELAY) == 0
1118 /*
Borislav Petkov0571c7a2008-02-02 19:56:38 +01001119 * Allow O_NDELAY to open a drive without a disk, or with an
1120 * unreadable disk, so that we can get the format capacity
1121 * of the drive or begin the format - Sam
1122 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 ret = -EIO;
1125 goto out_put_floppy;
1126 }
1127
1128 if (floppy->wp && (filp->f_mode & 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 ret = -EROFS;
1130 goto out_put_floppy;
1131 }
Borislav Petkovea68d272008-07-23 19:56:01 +02001132 drive->atapi_flags |= IDE_AFLAG_MEDIA_CHANGED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 /* IOMEGA Clik! drives do not support lock/unlock commands */
Borislav Petkovea68d272008-07-23 19:56:01 +02001134 if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 idefloppy_create_prevent_cmd(&pc, 1);
1136 (void) idefloppy_queue_pc_tail(drive, &pc);
1137 }
1138 check_disk_change(inode->i_bdev);
Borislav Petkovea68d272008-07-23 19:56:01 +02001139 } else if (drive->atapi_flags & IDE_AFLAG_FORMAT_IN_PROGRESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 ret = -EBUSY;
1141 goto out_put_floppy;
1142 }
1143 return 0;
1144
1145out_put_floppy:
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001146 floppy->openers--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 ide_floppy_put(floppy);
1148 return ret;
1149}
1150
1151static int idefloppy_release(struct inode *inode, struct file *filp)
1152{
1153 struct gendisk *disk = inode->i_bdev->bd_disk;
1154 struct ide_floppy_obj *floppy = ide_floppy_g(disk);
1155 ide_drive_t *drive = floppy->drive;
Borislav Petkov8e555122008-04-18 00:46:27 +02001156 struct ide_atapi_pc pc;
Borislav Petkovbcc77d92008-02-02 19:56:34 +01001157
1158 debug_log("Reached %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001160 if (floppy->openers == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 /* IOMEGA Clik! drives do not support lock/unlock commands */
Borislav Petkovea68d272008-07-23 19:56:01 +02001162 if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 idefloppy_create_prevent_cmd(&pc, 0);
1164 (void) idefloppy_queue_pc_tail(drive, &pc);
1165 }
1166
Borislav Petkovea68d272008-07-23 19:56:01 +02001167 drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 }
Bartlomiej Zolnierkiewiczc94964a2007-02-17 02:40:24 +01001169
1170 floppy->openers--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171
1172 ide_floppy_put(floppy);
1173
1174 return 0;
1175}
1176
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001177static int idefloppy_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1178{
1179 struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
1180 ide_drive_t *drive = floppy->drive;
1181
1182 geo->heads = drive->bios_head;
1183 geo->sectors = drive->bios_sect;
1184 geo->cylinders = (u16)drive->bios_cyl; /* truncate */
1185 return 0;
1186}
1187
Borislav Petkovea68d272008-07-23 19:56:01 +02001188static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
1189 unsigned long arg, unsigned int cmd)
Borislav Petkov20bf7bd2008-02-02 19:56:35 +01001190{
Borislav Petkovea68d272008-07-23 19:56:01 +02001191 idefloppy_floppy_t *floppy = drive->driver_data;
1192
Borislav Petkov20bf7bd2008-02-02 19:56:35 +01001193 if (floppy->openers > 1)
1194 return -EBUSY;
1195
1196 /* The IOMEGA Clik! Drive doesn't support this command -
1197 * no room for an eject mechanism */
Borislav Petkovea68d272008-07-23 19:56:01 +02001198 if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) {
Borislav Petkov20bf7bd2008-02-02 19:56:35 +01001199 int prevent = arg ? 1 : 0;
1200
1201 if (cmd == CDROMEJECT)
1202 prevent = 0;
1203
1204 idefloppy_create_prevent_cmd(pc, prevent);
1205 (void) idefloppy_queue_pc_tail(floppy->drive, pc);
1206 }
1207
1208 if (cmd == CDROMEJECT) {
1209 idefloppy_create_start_stop_cmd(pc, 2);
1210 (void) idefloppy_queue_pc_tail(floppy->drive, pc);
1211 }
1212
1213 return 0;
1214}
1215
Bartlomiej Zolnierkiewiczd56c99e2008-10-10 22:39:34 +02001216static int ide_floppy_format_unit(ide_drive_t *drive, int __user *arg)
Borislav Petkov20bf7bd2008-02-02 19:56:35 +01001217{
Bartlomiej Zolnierkiewiczd56c99e2008-10-10 22:39:34 +02001218 idefloppy_floppy_t *floppy = drive->driver_data;
Borislav Petkov8e555122008-04-18 00:46:27 +02001219 struct ide_atapi_pc pc;
Borislav Petkovea68d272008-07-23 19:56:01 +02001220 int blocks, length, flags, err = 0;
Borislav Petkov20bf7bd2008-02-02 19:56:35 +01001221
1222 if (floppy->openers > 1) {
1223 /* Don't format if someone is using the disk */
Borislav Petkovea68d272008-07-23 19:56:01 +02001224 drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
Borislav Petkov20bf7bd2008-02-02 19:56:35 +01001225 return -EBUSY;
1226 }
1227
Borislav Petkovea68d272008-07-23 19:56:01 +02001228 drive->atapi_flags |= IDE_AFLAG_FORMAT_IN_PROGRESS;
Borislav Petkov20bf7bd2008-02-02 19:56:35 +01001229
1230 /*
1231 * Send ATAPI_FORMAT_UNIT to the drive.
1232 *
1233 * Userland gives us the following structure:
1234 *
1235 * struct idefloppy_format_command {
1236 * int nblocks;
1237 * int blocksize;
1238 * int flags;
1239 * } ;
1240 *
1241 * flags is a bitmask, currently, the only defined flag is:
1242 *
1243 * 0x01 - verify media after format.
1244 */
1245 if (get_user(blocks, arg) ||
1246 get_user(length, arg+1) ||
1247 get_user(flags, arg+2)) {
1248 err = -EFAULT;
1249 goto out;
1250 }
1251
Borislav Petkovea68d272008-07-23 19:56:01 +02001252 (void) idefloppy_get_sfrp_bit(drive);
Borislav Petkov20bf7bd2008-02-02 19:56:35 +01001253 idefloppy_create_format_unit_cmd(&pc, blocks, length, flags);
1254
Borislav Petkovea68d272008-07-23 19:56:01 +02001255 if (idefloppy_queue_pc_tail(drive, &pc))
Borislav Petkov20bf7bd2008-02-02 19:56:35 +01001256 err = -EIO;
1257
1258out:
1259 if (err)
Borislav Petkovea68d272008-07-23 19:56:01 +02001260 drive->atapi_flags &= ~IDE_AFLAG_FORMAT_IN_PROGRESS;
Borislav Petkov20bf7bd2008-02-02 19:56:35 +01001261 return err;
1262}
1263
Bartlomiej Zolnierkiewiczd56c99e2008-10-10 22:39:34 +02001264static int ide_floppy_format_ioctl(ide_drive_t *drive, struct file *file,
1265 unsigned int cmd, void __user *argp)
1266{
1267 switch (cmd) {
1268 case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
1269 return 0;
1270 case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
1271 return ide_floppy_get_format_capacities(drive, argp);
1272 case IDEFLOPPY_IOCTL_FORMAT_START:
1273 if (!(file->f_mode & 2))
1274 return -EPERM;
1275 return ide_floppy_format_unit(drive, (int __user *)argp);
1276 case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
1277 return ide_floppy_get_format_progress(drive, argp);
1278 default:
1279 return -ENOTTY;
1280 }
1281}
Borislav Petkov20bf7bd2008-02-02 19:56:35 +01001282
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283static int idefloppy_ioctl(struct inode *inode, struct file *file,
1284 unsigned int cmd, unsigned long arg)
1285{
1286 struct block_device *bdev = inode->i_bdev;
1287 struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
1288 ide_drive_t *drive = floppy->drive;
Borislav Petkov8e555122008-04-18 00:46:27 +02001289 struct ide_atapi_pc pc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 void __user *argp = (void __user *)arg;
Ondrej Zary07203f62005-11-10 00:25:15 +01001291 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292
Bartlomiej Zolnierkiewiczd56c99e2008-10-10 22:39:34 +02001293 if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR)
Borislav Petkovea68d272008-07-23 19:56:01 +02001294 return ide_floppy_lockdoor(drive, &pc, arg, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
Bartlomiej Zolnierkiewiczd56c99e2008-10-10 22:39:34 +02001296 err = ide_floppy_format_ioctl(drive, file, cmd, argp);
1297 if (err != -ENOTTY)
1298 return err;
Bartlomiej Zolnierkiewicz89636af2007-07-20 01:11:59 +02001299
1300 /*
1301 * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
1302 * and CDROM_SEND_PACKET (legacy) ioctls
1303 */
1304 if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
1305 err = scsi_cmd_ioctl(file, bdev->bd_disk->queue,
1306 bdev->bd_disk, cmd, argp);
Bartlomiej Zolnierkiewicz89636af2007-07-20 01:11:59 +02001307
1308 if (err == -ENOTTY)
1309 err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
1310
1311 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312}
1313
1314static int idefloppy_media_changed(struct gendisk *disk)
1315{
1316 struct ide_floppy_obj *floppy = ide_floppy_g(disk);
1317 ide_drive_t *drive = floppy->drive;
Borislav Petkov6e5fa7b2008-02-02 19:56:37 +01001318 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
1320 /* do not scan partitions twice if this is a removable device */
1321 if (drive->attach) {
1322 drive->attach = 0;
1323 return 0;
1324 }
Borislav Petkovea68d272008-07-23 19:56:01 +02001325 ret = !!(drive->atapi_flags & IDE_AFLAG_MEDIA_CHANGED);
1326 drive->atapi_flags &= ~IDE_AFLAG_MEDIA_CHANGED;
Borislav Petkov6e5fa7b2008-02-02 19:56:37 +01001327 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328}
1329
1330static int idefloppy_revalidate_disk(struct gendisk *disk)
1331{
1332 struct ide_floppy_obj *floppy = ide_floppy_g(disk);
1333 set_capacity(disk, idefloppy_capacity(floppy->drive));
1334 return 0;
1335}
1336
1337static struct block_device_operations idefloppy_ops = {
Paolo Ciarrocchi52d3ccf2008-04-26 17:36:41 +02001338 .owner = THIS_MODULE,
1339 .open = idefloppy_open,
1340 .release = idefloppy_release,
1341 .ioctl = idefloppy_ioctl,
1342 .getgeo = idefloppy_getgeo,
1343 .media_changed = idefloppy_media_changed,
1344 .revalidate_disk = idefloppy_revalidate_disk
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345};
1346
Russell King4031bbe2006-01-06 11:41:00 +00001347static int ide_floppy_probe(ide_drive_t *drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348{
1349 idefloppy_floppy_t *floppy;
1350 struct gendisk *g;
1351
1352 if (!strstr("ide-floppy", drive->driver_req))
1353 goto failed;
Bartlomiej Zolnierkiewicz2a924662008-10-10 22:39:24 +02001354
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 if (drive->media != ide_floppy)
1356 goto failed;
Bartlomiej Zolnierkiewicz2a924662008-10-10 22:39:24 +02001357
Bartlomiej Zolnierkiewicz51509ee2008-10-10 22:39:34 +02001358 if (!ide_check_atapi_device(drive, DRV_NAME)) {
Borislav Petkov0571c7a2008-02-02 19:56:38 +01001359 printk(KERN_ERR "ide-floppy: %s: not supported by this version"
1360 " of ide-floppy\n", drive->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 goto failed;
1362 }
Borislav Petkov0571c7a2008-02-02 19:56:38 +01001363 floppy = kzalloc(sizeof(idefloppy_floppy_t), GFP_KERNEL);
1364 if (!floppy) {
1365 printk(KERN_ERR "ide-floppy: %s: Can't allocate a floppy"
1366 " structure\n", drive->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 goto failed;
1368 }
1369
1370 g = alloc_disk(1 << PARTN_BITS);
1371 if (!g)
1372 goto out_free_floppy;
1373
1374 ide_init_disk(g, drive);
1375
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 kref_init(&floppy->kref);
1377
1378 floppy->drive = drive;
1379 floppy->driver = &idefloppy_driver;
1380 floppy->disk = g;
1381
1382 g->private_data = &floppy->driver;
1383
1384 drive->driver_data = floppy;
1385
Borislav Petkov0571c7a2008-02-02 19:56:38 +01001386 idefloppy_setup(drive, floppy);
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001387
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 g->minors = 1 << PARTN_BITS;
1389 g->driverfs_dev = &drive->gendev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
1391 g->fops = &idefloppy_ops;
1392 drive->attach = 1;
1393 add_disk(g);
1394 return 0;
1395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396out_free_floppy:
1397 kfree(floppy);
1398failed:
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001399 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400}
1401
Borislav Petkov0571c7a2008-02-02 19:56:38 +01001402static void __exit idefloppy_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403{
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001404 driver_unregister(&idefloppy_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405}
1406
Bartlomiej Zolnierkiewicz17514e82005-11-19 22:24:35 +01001407static int __init idefloppy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408{
1409 printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
Bartlomiej Zolnierkiewicz8604aff2005-05-26 14:55:34 +02001410 return driver_register(&idefloppy_driver.gen_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411}
1412
Kay Sievers263756e2005-12-12 18:03:44 +01001413MODULE_ALIAS("ide:*m-floppy*");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414module_init(idefloppy_init);
1415module_exit(idefloppy_exit);
1416MODULE_LICENSE("GPL");
Borislav Petkov0571c7a2008-02-02 19:56:38 +01001417MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
1418