2005-04-17 02:20:36 +04:00
|
|
|
/*
|
|
|
|
* Driver for the SWIM3 (Super Woz Integrated Machine 3)
|
|
|
|
* floppy controller found on Power Macintoshes.
|
|
|
|
*
|
|
|
|
* Copyright (C) 1996 Paul Mackerras.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO:
|
|
|
|
* handle 2 drives
|
|
|
|
* handle GCR disks
|
|
|
|
*/
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
#undef DEBUG
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
#include <linux/stddef.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/timer.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/fd.h>
|
|
|
|
#include <linux/ioctl.h>
|
|
|
|
#include <linux/blkdev.h>
|
|
|
|
#include <linux/interrupt.h>
|
2010-06-02 16:28:52 +04:00
|
|
|
#include <linux/mutex.h>
|
2005-04-17 02:20:36 +04:00
|
|
|
#include <linux/module.h>
|
2005-11-08 04:15:36 +03:00
|
|
|
#include <linux/spinlock.h>
|
2014-02-26 15:01:44 +04:00
|
|
|
#include <linux/wait.h>
|
2005-04-17 02:20:36 +04:00
|
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/dbdma.h>
|
|
|
|
#include <asm/prom.h>
|
|
|
|
#include <asm/uaccess.h>
|
|
|
|
#include <asm/mediabay.h>
|
|
|
|
#include <asm/machdep.h>
|
|
|
|
#include <asm/pmac_feature.h>
|
|
|
|
|
|
|
|
#define MAX_FLOPPIES 2
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
static DEFINE_MUTEX(swim3_mutex);
|
|
|
|
static struct gendisk *disks[MAX_FLOPPIES];
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
enum swim_state {
|
|
|
|
idle,
|
|
|
|
locating,
|
|
|
|
seeking,
|
|
|
|
settling,
|
|
|
|
do_transfer,
|
|
|
|
jogging,
|
|
|
|
available,
|
|
|
|
revalidating,
|
|
|
|
ejecting
|
|
|
|
};
|
|
|
|
|
|
|
|
#define REG(x) unsigned char x; char x ## _pad[15];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The names for these registers mostly represent speculation on my part.
|
|
|
|
* It will be interesting to see how close they are to the names Apple uses.
|
|
|
|
*/
|
|
|
|
struct swim3 {
|
|
|
|
REG(data);
|
|
|
|
REG(timer); /* counts down at 1MHz */
|
|
|
|
REG(error);
|
|
|
|
REG(mode);
|
|
|
|
REG(select); /* controls CA0, CA1, CA2 and LSTRB signals */
|
|
|
|
REG(setup);
|
|
|
|
REG(control); /* writing bits clears them */
|
|
|
|
REG(status); /* writing bits sets them in control */
|
|
|
|
REG(intr);
|
|
|
|
REG(nseek); /* # tracks to seek */
|
|
|
|
REG(ctrack); /* current track number */
|
|
|
|
REG(csect); /* current sector number */
|
|
|
|
REG(gap3); /* size of gap 3 in track format */
|
|
|
|
REG(sector); /* sector # to read or write */
|
|
|
|
REG(nsect); /* # sectors to read or write */
|
|
|
|
REG(intr_enable);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define control_bic control
|
|
|
|
#define control_bis status
|
|
|
|
|
|
|
|
/* Bits in select register */
|
|
|
|
#define CA_MASK 7
|
|
|
|
#define LSTRB 8
|
|
|
|
|
|
|
|
/* Bits in control register */
|
|
|
|
#define DO_SEEK 0x80
|
|
|
|
#define FORMAT 0x40
|
|
|
|
#define SELECT 0x20
|
|
|
|
#define WRITE_SECTORS 0x10
|
|
|
|
#define DO_ACTION 0x08
|
|
|
|
#define DRIVE2_ENABLE 0x04
|
|
|
|
#define DRIVE_ENABLE 0x02
|
|
|
|
#define INTR_ENABLE 0x01
|
|
|
|
|
|
|
|
/* Bits in status register */
|
|
|
|
#define FIFO_1BYTE 0x80
|
|
|
|
#define FIFO_2BYTE 0x40
|
|
|
|
#define ERROR 0x20
|
|
|
|
#define DATA 0x08
|
|
|
|
#define RDDATA 0x04
|
|
|
|
#define INTR_PENDING 0x02
|
|
|
|
#define MARK_BYTE 0x01
|
|
|
|
|
|
|
|
/* Bits in intr and intr_enable registers */
|
|
|
|
#define ERROR_INTR 0x20
|
|
|
|
#define DATA_CHANGED 0x10
|
|
|
|
#define TRANSFER_DONE 0x08
|
|
|
|
#define SEEN_SECTOR 0x04
|
|
|
|
#define SEEK_DONE 0x02
|
|
|
|
#define TIMER_DONE 0x01
|
|
|
|
|
|
|
|
/* Bits in error register */
|
|
|
|
#define ERR_DATA_CRC 0x80
|
|
|
|
#define ERR_ADDR_CRC 0x40
|
|
|
|
#define ERR_OVERRUN 0x04
|
|
|
|
#define ERR_UNDERRUN 0x01
|
|
|
|
|
|
|
|
/* Bits in setup register */
|
|
|
|
#define S_SW_RESET 0x80
|
|
|
|
#define S_GCR_WRITE 0x40
|
|
|
|
#define S_IBM_DRIVE 0x20
|
|
|
|
#define S_TEST_MODE 0x10
|
|
|
|
#define S_FCLK_DIV2 0x08
|
|
|
|
#define S_GCR 0x04
|
|
|
|
#define S_COPY_PROT 0x02
|
|
|
|
#define S_INV_WDATA 0x01
|
|
|
|
|
|
|
|
/* Select values for swim3_action */
|
|
|
|
#define SEEK_POSITIVE 0
|
|
|
|
#define SEEK_NEGATIVE 4
|
|
|
|
#define STEP 1
|
|
|
|
#define MOTOR_ON 2
|
|
|
|
#define MOTOR_OFF 6
|
|
|
|
#define INDEX 3
|
|
|
|
#define EJECT 7
|
|
|
|
#define SETMFM 9
|
|
|
|
#define SETGCR 13
|
|
|
|
|
|
|
|
/* Select values for swim3_select and swim3_readbit */
|
|
|
|
#define STEP_DIR 0
|
|
|
|
#define STEPPING 1
|
|
|
|
#define MOTOR_ON 2
|
|
|
|
#define RELAX 3 /* also eject in progress */
|
|
|
|
#define READ_DATA_0 4
|
|
|
|
#define TWOMEG_DRIVE 5
|
|
|
|
#define SINGLE_SIDED 6 /* drive or diskette is 4MB type? */
|
|
|
|
#define DRIVE_PRESENT 7
|
|
|
|
#define DISK_IN 8
|
|
|
|
#define WRITE_PROT 9
|
|
|
|
#define TRACK_ZERO 10
|
|
|
|
#define TACHO 11
|
|
|
|
#define READ_DATA_1 12
|
|
|
|
#define MFM_MODE 13
|
|
|
|
#define SEEK_COMPLETE 14
|
|
|
|
#define ONEMEG_MEDIA 15
|
|
|
|
|
|
|
|
/* Definitions of values used in writing and formatting */
|
|
|
|
#define DATA_ESCAPE 0x99
|
|
|
|
#define GCR_SYNC_EXC 0x3f
|
|
|
|
#define GCR_SYNC_CONV 0x80
|
|
|
|
#define GCR_FIRST_MARK 0xd5
|
|
|
|
#define GCR_SECOND_MARK 0xaa
|
|
|
|
#define GCR_ADDR_MARK "\xd5\xaa\x00"
|
|
|
|
#define GCR_DATA_MARK "\xd5\xaa\x0b"
|
|
|
|
#define GCR_SLIP_BYTE "\x27\xaa"
|
|
|
|
#define GCR_SELF_SYNC "\x3f\xbf\x1e\x34\x3c\x3f"
|
|
|
|
|
|
|
|
#define DATA_99 "\x99\x99"
|
|
|
|
#define MFM_ADDR_MARK "\x99\xa1\x99\xa1\x99\xa1\x99\xfe"
|
|
|
|
#define MFM_INDEX_MARK "\x99\xc2\x99\xc2\x99\xc2\x99\xfc"
|
|
|
|
#define MFM_GAP_LEN 12
|
|
|
|
|
|
|
|
struct floppy_state {
|
|
|
|
enum swim_state state;
|
|
|
|
struct swim3 __iomem *swim3; /* hardware registers */
|
|
|
|
struct dbdma_regs __iomem *dma; /* DMA controller registers */
|
|
|
|
int swim3_intr; /* interrupt number for SWIM3 */
|
|
|
|
int dma_intr; /* interrupt number for DMA channel */
|
|
|
|
int cur_cyl; /* cylinder head is on, or -1 */
|
|
|
|
int cur_sector; /* last sector we saw go past */
|
|
|
|
int req_cyl; /* the cylinder for the current r/w request */
|
|
|
|
int head; /* head number ditto */
|
|
|
|
int req_sector; /* sector number ditto */
|
|
|
|
int scount; /* # sectors we're transferring at present */
|
|
|
|
int retries;
|
|
|
|
int settle_time;
|
|
|
|
int secpercyl; /* disk geometry information */
|
|
|
|
int secpertrack;
|
|
|
|
int total_secs;
|
|
|
|
int write_prot; /* 1 if write-protected, 0 if not, -1 dunno */
|
|
|
|
struct dbdma_cmd *dma_cmd;
|
|
|
|
int ref_count;
|
|
|
|
int expect_cyl;
|
|
|
|
struct timer_list timeout;
|
|
|
|
int timeout_pending;
|
|
|
|
int ejected;
|
|
|
|
wait_queue_head_t wait;
|
|
|
|
int wanted;
|
2009-12-01 17:36:28 +03:00
|
|
|
struct macio_dev *mdev;
|
2005-04-17 02:20:36 +04:00
|
|
|
char dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)];
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
int index;
|
|
|
|
struct request *cur_req;
|
2005-04-17 02:20:36 +04:00
|
|
|
};
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
#define swim3_err(fmt, arg...) dev_err(&fs->mdev->ofdev.dev, "[fd%d] " fmt, fs->index, arg)
|
|
|
|
#define swim3_warn(fmt, arg...) dev_warn(&fs->mdev->ofdev.dev, "[fd%d] " fmt, fs->index, arg)
|
|
|
|
#define swim3_info(fmt, arg...) dev_info(&fs->mdev->ofdev.dev, "[fd%d] " fmt, fs->index, arg)
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
#define swim3_dbg(fmt, arg...) dev_dbg(&fs->mdev->ofdev.dev, "[fd%d] " fmt, fs->index, arg)
|
|
|
|
#else
|
|
|
|
#define swim3_dbg(fmt, arg...) do { } while(0)
|
|
|
|
#endif
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
static struct floppy_state floppy_states[MAX_FLOPPIES];
|
|
|
|
static int floppy_count = 0;
|
|
|
|
static DEFINE_SPINLOCK(swim3_lock);
|
|
|
|
|
|
|
|
static unsigned short write_preamble[] = {
|
|
|
|
0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, /* gap field */
|
|
|
|
0, 0, 0, 0, 0, 0, /* sync field */
|
|
|
|
0x99a1, 0x99a1, 0x99a1, 0x99fb, /* data address mark */
|
|
|
|
0x990f /* no escape for 512 bytes */
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned short write_postamble[] = {
|
|
|
|
0x9904, /* insert CRC */
|
|
|
|
0x4e4e, 0x4e4e,
|
|
|
|
0x9908, /* stop writing */
|
|
|
|
0, 0, 0, 0, 0, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
static void seek_track(struct floppy_state *fs, int n);
|
|
|
|
static void init_dma(struct dbdma_cmd *cp, int cmd, void *buf, int count);
|
|
|
|
static void act(struct floppy_state *fs);
|
|
|
|
static void scan_timeout(unsigned long data);
|
|
|
|
static void seek_timeout(unsigned long data);
|
|
|
|
static void settle_timeout(unsigned long data);
|
|
|
|
static void xfer_timeout(unsigned long data);
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 17:55:46 +04:00
|
|
|
static irqreturn_t swim3_interrupt(int irq, void *dev_id);
|
|
|
|
/*static void fd_dma_interrupt(int irq, void *dev_id);*/
|
2005-04-17 02:20:36 +04:00
|
|
|
static int grab_drive(struct floppy_state *fs, enum swim_state state,
|
|
|
|
int interruptible);
|
|
|
|
static void release_drive(struct floppy_state *fs);
|
|
|
|
static int fd_eject(struct floppy_state *fs);
|
2008-03-02 18:20:44 +03:00
|
|
|
static int floppy_ioctl(struct block_device *bdev, fmode_t mode,
|
2005-04-17 02:20:36 +04:00
|
|
|
unsigned int cmd, unsigned long param);
|
2008-03-02 18:20:44 +03:00
|
|
|
static int floppy_open(struct block_device *bdev, fmode_t mode);
|
2013-05-06 05:52:57 +04:00
|
|
|
static void floppy_release(struct gendisk *disk, fmode_t mode);
|
2011-03-09 21:54:28 +03:00
|
|
|
static unsigned int floppy_check_events(struct gendisk *disk,
|
|
|
|
unsigned int clearing);
|
2005-04-17 02:20:36 +04:00
|
|
|
static int floppy_revalidate(struct gendisk *disk);
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
static bool swim3_end_request(struct floppy_state *fs, int err, unsigned int nr_bytes)
|
2009-05-08 06:54:04 +04:00
|
|
|
{
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
struct request *req = fs->cur_req;
|
|
|
|
int rc;
|
2009-05-08 06:54:04 +04:00
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_dbg(" end request, err=%d nr_bytes=%d, cur_req=%p\n",
|
|
|
|
err, nr_bytes, req);
|
2009-05-08 06:54:04 +04:00
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
if (err)
|
|
|
|
nr_bytes = blk_rq_cur_bytes(req);
|
|
|
|
rc = __blk_end_request(req, err, nr_bytes);
|
|
|
|
if (rc)
|
|
|
|
return true;
|
|
|
|
fs->cur_req = NULL;
|
|
|
|
return false;
|
2009-05-08 06:54:04 +04:00
|
|
|
}
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
static void swim3_select(struct floppy_state *fs, int sel)
|
|
|
|
{
|
|
|
|
struct swim3 __iomem *sw = fs->swim3;
|
|
|
|
|
|
|
|
out_8(&sw->select, RELAX);
|
|
|
|
if (sel & 8)
|
|
|
|
out_8(&sw->control_bis, SELECT);
|
|
|
|
else
|
|
|
|
out_8(&sw->control_bic, SELECT);
|
|
|
|
out_8(&sw->select, sel & CA_MASK);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void swim3_action(struct floppy_state *fs, int action)
|
|
|
|
{
|
|
|
|
struct swim3 __iomem *sw = fs->swim3;
|
|
|
|
|
|
|
|
swim3_select(fs, action);
|
|
|
|
udelay(1);
|
|
|
|
out_8(&sw->select, sw->select | LSTRB);
|
|
|
|
udelay(2);
|
|
|
|
out_8(&sw->select, sw->select & ~LSTRB);
|
|
|
|
udelay(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int swim3_readbit(struct floppy_state *fs, int bit)
|
|
|
|
{
|
|
|
|
struct swim3 __iomem *sw = fs->swim3;
|
|
|
|
int stat;
|
|
|
|
|
|
|
|
swim3_select(fs, bit);
|
|
|
|
udelay(1);
|
|
|
|
stat = in_8(&sw->status);
|
|
|
|
return (stat & DATA) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void start_request(struct floppy_state *fs)
|
|
|
|
{
|
|
|
|
struct request *req;
|
|
|
|
unsigned long x;
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_dbg("start request, initial state=%d\n", fs->state);
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
if (fs->state == idle && fs->wanted) {
|
|
|
|
fs->state = available;
|
|
|
|
wake_up(&fs->wait);
|
|
|
|
return;
|
|
|
|
}
|
2009-05-08 06:54:04 +04:00
|
|
|
while (fs->state == idle) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_dbg("start request, idle loop, cur_req=%p\n", fs->cur_req);
|
|
|
|
if (!fs->cur_req) {
|
|
|
|
fs->cur_req = blk_fetch_request(disks[fs->index]->queue);
|
|
|
|
swim3_dbg(" fetched request %p\n", fs->cur_req);
|
|
|
|
if (!fs->cur_req)
|
2009-05-08 06:54:04 +04:00
|
|
|
break;
|
|
|
|
}
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
req = fs->cur_req;
|
|
|
|
|
|
|
|
if (fs->mdev->media_bay &&
|
|
|
|
check_media_bay(fs->mdev->media_bay) != MB_FD) {
|
|
|
|
swim3_dbg("%s", " media bay absent, dropping req\n");
|
|
|
|
swim3_end_request(fs, -ENODEV, 0);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0 /* This is really too verbose */
|
|
|
|
swim3_dbg("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n",
|
|
|
|
req->rq_disk->disk_name, req->cmd,
|
|
|
|
(long)blk_rq_pos(req), blk_rq_sectors(req),
|
|
|
|
req->buffer);
|
|
|
|
swim3_dbg(" errors=%d current_nr_sectors=%u\n",
|
|
|
|
req->errors, blk_rq_cur_sectors(req));
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif
|
|
|
|
|
2009-05-07 17:24:39 +04:00
|
|
|
if (blk_rq_pos(req) >= fs->total_secs) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_dbg(" pos out of bounds (%ld, max is %ld)\n",
|
|
|
|
(long)blk_rq_pos(req), (long)fs->total_secs);
|
|
|
|
swim3_end_request(fs, -EIO, 0);
|
2005-04-17 02:20:36 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (fs->ejected) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_dbg("%s", " disk ejected\n");
|
|
|
|
swim3_end_request(fs, -EIO, 0);
|
2005-04-17 02:20:36 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rq_data_dir(req) == WRITE) {
|
|
|
|
if (fs->write_prot < 0)
|
|
|
|
fs->write_prot = swim3_readbit(fs, WRITE_PROT);
|
|
|
|
if (fs->write_prot) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_dbg("%s", " try to write, disk write protected\n");
|
|
|
|
swim3_end_request(fs, -EIO, 0);
|
2005-04-17 02:20:36 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-07 17:24:39 +04:00
|
|
|
/* Do not remove the cast. blk_rq_pos(req) is now a
|
|
|
|
* sector_t and can be 64 bits, but it will never go
|
|
|
|
* past 32 bits for this driver anyway, so we can
|
|
|
|
* safely cast it down and not have to do a 64/32
|
|
|
|
* division
|
2005-04-17 02:20:36 +04:00
|
|
|
*/
|
2009-05-07 17:24:39 +04:00
|
|
|
fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl;
|
|
|
|
x = ((long)blk_rq_pos(req)) % fs->secpercyl;
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->head = x / fs->secpertrack;
|
|
|
|
fs->req_sector = x % fs->secpertrack + 1;
|
|
|
|
fs->state = do_transfer;
|
|
|
|
fs->retries = 0;
|
|
|
|
|
|
|
|
act(fs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
static void do_fd_request(struct request_queue * q)
|
|
|
|
{
|
|
|
|
start_request(q->queuedata);
|
|
|
|
}
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
static void set_timeout(struct floppy_state *fs, int nticks,
|
|
|
|
void (*proc)(unsigned long))
|
|
|
|
{
|
|
|
|
if (fs->timeout_pending)
|
|
|
|
del_timer(&fs->timeout);
|
|
|
|
fs->timeout.expires = jiffies + nticks;
|
|
|
|
fs->timeout.function = proc;
|
|
|
|
fs->timeout.data = (unsigned long) fs;
|
|
|
|
add_timer(&fs->timeout);
|
|
|
|
fs->timeout_pending = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void scan_track(struct floppy_state *fs)
|
|
|
|
{
|
|
|
|
struct swim3 __iomem *sw = fs->swim3;
|
|
|
|
|
|
|
|
swim3_select(fs, READ_DATA_0);
|
|
|
|
in_8(&sw->intr); /* clear SEEN_SECTOR bit */
|
|
|
|
in_8(&sw->error);
|
|
|
|
out_8(&sw->intr_enable, SEEN_SECTOR);
|
|
|
|
out_8(&sw->control_bis, DO_ACTION);
|
|
|
|
/* enable intr when track found */
|
|
|
|
set_timeout(fs, HZ, scan_timeout); /* enable timeout */
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void seek_track(struct floppy_state *fs, int n)
|
|
|
|
{
|
|
|
|
struct swim3 __iomem *sw = fs->swim3;
|
|
|
|
|
|
|
|
if (n >= 0) {
|
|
|
|
swim3_action(fs, SEEK_POSITIVE);
|
|
|
|
sw->nseek = n;
|
|
|
|
} else {
|
|
|
|
swim3_action(fs, SEEK_NEGATIVE);
|
|
|
|
sw->nseek = -n;
|
|
|
|
}
|
|
|
|
fs->expect_cyl = (fs->cur_cyl >= 0)? fs->cur_cyl + n: -1;
|
|
|
|
swim3_select(fs, STEP);
|
|
|
|
in_8(&sw->error);
|
|
|
|
/* enable intr when seek finished */
|
|
|
|
out_8(&sw->intr_enable, SEEK_DONE);
|
|
|
|
out_8(&sw->control_bis, DO_SEEK);
|
|
|
|
set_timeout(fs, 3*HZ, seek_timeout); /* enable timeout */
|
|
|
|
fs->settle_time = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void init_dma(struct dbdma_cmd *cp, int cmd,
|
|
|
|
void *buf, int count)
|
|
|
|
{
|
|
|
|
st_le16(&cp->req_count, count);
|
|
|
|
st_le16(&cp->command, cmd);
|
|
|
|
st_le32(&cp->phy_addr, virt_to_bus(buf));
|
|
|
|
cp->xfer_status = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void setup_transfer(struct floppy_state *fs)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
struct swim3 __iomem *sw = fs->swim3;
|
|
|
|
struct dbdma_cmd *cp = fs->dma_cmd;
|
|
|
|
struct dbdma_regs __iomem *dr = fs->dma;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
struct request *req = fs->cur_req;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
if (blk_rq_cur_sectors(req) <= 0) {
|
|
|
|
swim3_warn("%s", "Transfer 0 sectors ?\n");
|
2005-04-17 02:20:36 +04:00
|
|
|
return;
|
|
|
|
}
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
if (rq_data_dir(req) == WRITE)
|
2005-04-17 02:20:36 +04:00
|
|
|
n = 1;
|
|
|
|
else {
|
|
|
|
n = fs->secpertrack - fs->req_sector + 1;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
if (n > blk_rq_cur_sectors(req))
|
|
|
|
n = blk_rq_cur_sectors(req);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
|
|
|
|
swim3_dbg(" setup xfer at sect %d (of %d) head %d for %d\n",
|
|
|
|
fs->req_sector, fs->secpertrack, fs->head, n);
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->scount = n;
|
|
|
|
swim3_select(fs, fs->head? READ_DATA_1: READ_DATA_0);
|
|
|
|
out_8(&sw->sector, fs->req_sector);
|
|
|
|
out_8(&sw->nsect, n);
|
|
|
|
out_8(&sw->gap3, 0);
|
|
|
|
out_le32(&dr->cmdptr, virt_to_bus(cp));
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
if (rq_data_dir(req) == WRITE) {
|
2005-04-17 02:20:36 +04:00
|
|
|
/* Set up 3 dma commands: write preamble, data, postamble */
|
|
|
|
init_dma(cp, OUTPUT_MORE, write_preamble, sizeof(write_preamble));
|
|
|
|
++cp;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
init_dma(cp, OUTPUT_MORE, req->buffer, 512);
|
2005-04-17 02:20:36 +04:00
|
|
|
++cp;
|
|
|
|
init_dma(cp, OUTPUT_LAST, write_postamble, sizeof(write_postamble));
|
|
|
|
} else {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
init_dma(cp, INPUT_LAST, req->buffer, n * 512);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
++cp;
|
|
|
|
out_le16(&cp->command, DBDMA_STOP);
|
|
|
|
out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
|
|
|
|
in_8(&sw->error);
|
|
|
|
out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
if (rq_data_dir(req) == WRITE)
|
2005-04-17 02:20:36 +04:00
|
|
|
out_8(&sw->control_bis, WRITE_SECTORS);
|
|
|
|
in_8(&sw->intr);
|
|
|
|
out_le32(&dr->control, (RUN << 16) | RUN);
|
|
|
|
/* enable intr when transfer complete */
|
|
|
|
out_8(&sw->intr_enable, TRANSFER_DONE);
|
|
|
|
out_8(&sw->control_bis, DO_ACTION);
|
|
|
|
set_timeout(fs, 2*HZ, xfer_timeout); /* enable timeout */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void act(struct floppy_state *fs)
|
|
|
|
{
|
|
|
|
for (;;) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_dbg(" act loop, state=%d, req_cyl=%d, cur_cyl=%d\n",
|
|
|
|
fs->state, fs->req_cyl, fs->cur_cyl);
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
switch (fs->state) {
|
|
|
|
case idle:
|
|
|
|
return; /* XXX shouldn't get here */
|
|
|
|
|
|
|
|
case locating:
|
|
|
|
if (swim3_readbit(fs, TRACK_ZERO)) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_dbg("%s", " locate track 0\n");
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->cur_cyl = 0;
|
|
|
|
if (fs->req_cyl == 0)
|
|
|
|
fs->state = do_transfer;
|
|
|
|
else
|
|
|
|
fs->state = seeking;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
scan_track(fs);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case seeking:
|
|
|
|
if (fs->cur_cyl < 0) {
|
|
|
|
fs->expect_cyl = -1;
|
|
|
|
fs->state = locating;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (fs->req_cyl == fs->cur_cyl) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_warn("%s", "Whoops, seeking 0\n");
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->state = do_transfer;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
seek_track(fs, fs->req_cyl - fs->cur_cyl);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case settling:
|
|
|
|
/* check for SEEK_COMPLETE after 30ms */
|
|
|
|
fs->settle_time = (HZ + 32) / 33;
|
|
|
|
set_timeout(fs, fs->settle_time, settle_timeout);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case do_transfer:
|
|
|
|
if (fs->cur_cyl != fs->req_cyl) {
|
|
|
|
if (fs->retries > 5) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("Wrong cylinder in transfer, want: %d got %d\n",
|
|
|
|
fs->req_cyl, fs->cur_cyl);
|
|
|
|
swim3_end_request(fs, -EIO, 0);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->state = idle;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fs->state = seeking;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
setup_transfer(fs);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case jogging:
|
|
|
|
seek_track(fs, -5);
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("Unknown state %d\n", fs->state);
|
2005-04-17 02:20:36 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void scan_timeout(unsigned long data)
|
|
|
|
{
|
|
|
|
struct floppy_state *fs = (struct floppy_state *) data;
|
|
|
|
struct swim3 __iomem *sw = fs->swim3;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
swim3_dbg("* scan timeout, state=%d\n", fs->state);
|
2005-04-17 02:20:36 +04:00
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
spin_lock_irqsave(&swim3_lock, flags);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->timeout_pending = 0;
|
|
|
|
out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
|
|
|
|
out_8(&sw->select, RELAX);
|
|
|
|
out_8(&sw->intr_enable, 0);
|
|
|
|
fs->cur_cyl = -1;
|
|
|
|
if (fs->retries > 5) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_end_request(fs, -EIO, 0);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->state = idle;
|
|
|
|
start_request(fs);
|
|
|
|
} else {
|
|
|
|
fs->state = jogging;
|
|
|
|
act(fs);
|
|
|
|
}
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
spin_unlock_irqrestore(&swim3_lock, flags);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void seek_timeout(unsigned long data)
|
|
|
|
{
|
|
|
|
struct floppy_state *fs = (struct floppy_state *) data;
|
|
|
|
struct swim3 __iomem *sw = fs->swim3;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
swim3_dbg("* seek timeout, state=%d\n", fs->state);
|
2005-04-17 02:20:36 +04:00
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
spin_lock_irqsave(&swim3_lock, flags);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->timeout_pending = 0;
|
|
|
|
out_8(&sw->control_bic, DO_SEEK);
|
|
|
|
out_8(&sw->select, RELAX);
|
|
|
|
out_8(&sw->intr_enable, 0);
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("%s", "Seek timeout\n");
|
|
|
|
swim3_end_request(fs, -EIO, 0);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->state = idle;
|
|
|
|
start_request(fs);
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
spin_unlock_irqrestore(&swim3_lock, flags);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void settle_timeout(unsigned long data)
|
|
|
|
{
|
|
|
|
struct floppy_state *fs = (struct floppy_state *) data;
|
|
|
|
struct swim3 __iomem *sw = fs->swim3;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
swim3_dbg("* settle timeout, state=%d\n", fs->state);
|
2005-04-17 02:20:36 +04:00
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
spin_lock_irqsave(&swim3_lock, flags);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->timeout_pending = 0;
|
|
|
|
if (swim3_readbit(fs, SEEK_COMPLETE)) {
|
|
|
|
out_8(&sw->select, RELAX);
|
|
|
|
fs->state = locating;
|
|
|
|
act(fs);
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
goto unlock;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
out_8(&sw->select, RELAX);
|
|
|
|
if (fs->settle_time < 2*HZ) {
|
|
|
|
++fs->settle_time;
|
|
|
|
set_timeout(fs, 1, settle_timeout);
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
goto unlock;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("%s", "Seek settle timeout\n");
|
|
|
|
swim3_end_request(fs, -EIO, 0);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->state = idle;
|
|
|
|
start_request(fs);
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
unlock:
|
|
|
|
spin_unlock_irqrestore(&swim3_lock, flags);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void xfer_timeout(unsigned long data)
|
|
|
|
{
|
|
|
|
struct floppy_state *fs = (struct floppy_state *) data;
|
|
|
|
struct swim3 __iomem *sw = fs->swim3;
|
|
|
|
struct dbdma_regs __iomem *dr = fs->dma;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
unsigned long flags;
|
2005-04-17 02:20:36 +04:00
|
|
|
int n;
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_dbg("* xfer timeout, state=%d\n", fs->state);
|
|
|
|
|
|
|
|
spin_lock_irqsave(&swim3_lock, flags);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->timeout_pending = 0;
|
|
|
|
out_le32(&dr->control, RUN << 16);
|
|
|
|
/* We must wait a bit for dbdma to stop */
|
|
|
|
for (n = 0; (in_le32(&dr->status) & ACTIVE) && n < 1000; n++)
|
|
|
|
udelay(1);
|
|
|
|
out_8(&sw->intr_enable, 0);
|
|
|
|
out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION);
|
|
|
|
out_8(&sw->select, RELAX);
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("Timeout %sing sector %ld\n",
|
|
|
|
(rq_data_dir(fs->cur_req)==WRITE? "writ": "read"),
|
|
|
|
(long)blk_rq_pos(fs->cur_req));
|
|
|
|
swim3_end_request(fs, -EIO, 0);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->state = idle;
|
|
|
|
start_request(fs);
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
spin_unlock_irqrestore(&swim3_lock, flags);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 17:55:46 +04:00
|
|
|
static irqreturn_t swim3_interrupt(int irq, void *dev_id)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
|
|
|
struct floppy_state *fs = (struct floppy_state *) dev_id;
|
|
|
|
struct swim3 __iomem *sw = fs->swim3;
|
|
|
|
int intr, err, n;
|
|
|
|
int stat, resid;
|
|
|
|
struct dbdma_regs __iomem *dr;
|
|
|
|
struct dbdma_cmd *cp;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
unsigned long flags;
|
|
|
|
struct request *req = fs->cur_req;
|
|
|
|
|
|
|
|
swim3_dbg("* interrupt, state=%d\n", fs->state);
|
2005-04-17 02:20:36 +04:00
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
spin_lock_irqsave(&swim3_lock, flags);
|
2005-04-17 02:20:36 +04:00
|
|
|
intr = in_8(&sw->intr);
|
|
|
|
err = (intr & ERROR_INTR)? in_8(&sw->error): 0;
|
|
|
|
if ((intr & ERROR_INTR) && fs->state != do_transfer)
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("Non-transfer error interrupt: state=%d, dir=%x, intr=%x, err=%x\n",
|
|
|
|
fs->state, rq_data_dir(req), intr, err);
|
2005-04-17 02:20:36 +04:00
|
|
|
switch (fs->state) {
|
|
|
|
case locating:
|
|
|
|
if (intr & SEEN_SECTOR) {
|
|
|
|
out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
|
|
|
|
out_8(&sw->select, RELAX);
|
|
|
|
out_8(&sw->intr_enable, 0);
|
|
|
|
del_timer(&fs->timeout);
|
|
|
|
fs->timeout_pending = 0;
|
|
|
|
if (sw->ctrack == 0xff) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("%s", "Seen sector but cyl=ff?\n");
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->cur_cyl = -1;
|
|
|
|
if (fs->retries > 5) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_end_request(fs, -EIO, 0);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->state = idle;
|
|
|
|
start_request(fs);
|
|
|
|
} else {
|
|
|
|
fs->state = jogging;
|
|
|
|
act(fs);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fs->cur_cyl = sw->ctrack;
|
|
|
|
fs->cur_sector = sw->csect;
|
|
|
|
if (fs->expect_cyl != -1 && fs->expect_cyl != fs->cur_cyl)
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("Expected cyl %d, got %d\n",
|
|
|
|
fs->expect_cyl, fs->cur_cyl);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->state = do_transfer;
|
|
|
|
act(fs);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case seeking:
|
|
|
|
case jogging:
|
|
|
|
if (sw->nseek == 0) {
|
|
|
|
out_8(&sw->control_bic, DO_SEEK);
|
|
|
|
out_8(&sw->select, RELAX);
|
|
|
|
out_8(&sw->intr_enable, 0);
|
|
|
|
del_timer(&fs->timeout);
|
|
|
|
fs->timeout_pending = 0;
|
|
|
|
if (fs->state == seeking)
|
|
|
|
++fs->retries;
|
|
|
|
fs->state = settling;
|
|
|
|
act(fs);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case settling:
|
|
|
|
out_8(&sw->intr_enable, 0);
|
|
|
|
del_timer(&fs->timeout);
|
|
|
|
fs->timeout_pending = 0;
|
|
|
|
act(fs);
|
|
|
|
break;
|
|
|
|
case do_transfer:
|
|
|
|
if ((intr & (ERROR_INTR | TRANSFER_DONE)) == 0)
|
|
|
|
break;
|
|
|
|
out_8(&sw->intr_enable, 0);
|
|
|
|
out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION);
|
|
|
|
out_8(&sw->select, RELAX);
|
|
|
|
del_timer(&fs->timeout);
|
|
|
|
fs->timeout_pending = 0;
|
|
|
|
dr = fs->dma;
|
|
|
|
cp = fs->dma_cmd;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
if (rq_data_dir(req) == WRITE)
|
2005-04-17 02:20:36 +04:00
|
|
|
++cp;
|
|
|
|
/*
|
|
|
|
* Check that the main data transfer has finished.
|
|
|
|
* On writing, the swim3 sometimes doesn't use
|
|
|
|
* up all the bytes of the postamble, so we can still
|
|
|
|
* see DMA active here. That doesn't matter as long
|
|
|
|
* as all the sector data has been transferred.
|
|
|
|
*/
|
|
|
|
if ((intr & ERROR_INTR) == 0 && cp->xfer_status == 0) {
|
|
|
|
/* wait a little while for DMA to complete */
|
|
|
|
for (n = 0; n < 100; ++n) {
|
|
|
|
if (cp->xfer_status != 0)
|
|
|
|
break;
|
|
|
|
udelay(1);
|
|
|
|
barrier();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* turn off DMA */
|
|
|
|
out_le32(&dr->control, (RUN | PAUSE) << 16);
|
|
|
|
stat = ld_le16(&cp->xfer_status);
|
|
|
|
resid = ld_le16(&cp->res_count);
|
|
|
|
if (intr & ERROR_INTR) {
|
|
|
|
n = fs->scount - 1 - resid / 512;
|
|
|
|
if (n > 0) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
blk_update_request(req, 0, n << 9);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->req_sector += n;
|
|
|
|
}
|
|
|
|
if (fs->retries < 5) {
|
|
|
|
++fs->retries;
|
|
|
|
act(fs);
|
|
|
|
} else {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("Error %sing block %ld (err=%x)\n",
|
|
|
|
rq_data_dir(req) == WRITE? "writ": "read",
|
|
|
|
(long)blk_rq_pos(req), err);
|
|
|
|
swim3_end_request(fs, -EIO, 0);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->state = idle;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((stat & ACTIVE) == 0 || resid != 0) {
|
|
|
|
/* musta been an error */
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("fd dma error: stat=%x resid=%d\n", stat, resid);
|
|
|
|
swim3_err(" state=%d, dir=%x, intr=%x, err=%x\n",
|
|
|
|
fs->state, rq_data_dir(req), intr, err);
|
|
|
|
swim3_end_request(fs, -EIO, 0);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->state = idle;
|
|
|
|
start_request(fs);
|
|
|
|
break;
|
|
|
|
}
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
fs->retries = 0;
|
|
|
|
if (swim3_end_request(fs, 0, fs->scount << 9)) {
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->req_sector += fs->scount;
|
|
|
|
if (fs->req_sector > fs->secpertrack) {
|
|
|
|
fs->req_sector -= fs->secpertrack;
|
|
|
|
if (++fs->head > 1) {
|
|
|
|
fs->head = 0;
|
|
|
|
++fs->req_cyl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
act(fs);
|
2009-04-28 08:06:12 +04:00
|
|
|
} else
|
|
|
|
fs->state = idle;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
if (fs->state == idle)
|
|
|
|
start_request(fs);
|
|
|
|
break;
|
|
|
|
default:
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("Don't know what to do in state %d\n", fs->state);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
spin_unlock_irqrestore(&swim3_lock, flags);
|
2005-04-17 02:20:36 +04:00
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 17:55:46 +04:00
|
|
|
static void fd_dma_interrupt(int irq, void *dev_id)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
/* Called under the mutex to grab exclusive access to a drive */
|
2005-04-17 02:20:36 +04:00
|
|
|
static int grab_drive(struct floppy_state *fs, enum swim_state state,
|
|
|
|
int interruptible)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_dbg("%s", "-> grab drive\n");
|
|
|
|
|
|
|
|
spin_lock_irqsave(&swim3_lock, flags);
|
|
|
|
if (fs->state != idle && fs->state != available) {
|
2005-04-17 02:20:36 +04:00
|
|
|
++fs->wanted;
|
2014-02-26 15:01:44 +04:00
|
|
|
/* this will enable irqs in order to sleep */
|
|
|
|
if (!interruptible)
|
|
|
|
wait_event_lock_irq(fs->wait,
|
|
|
|
fs->state == available,
|
|
|
|
swim3_lock);
|
|
|
|
else if (wait_event_interruptible_lock_irq(fs->wait,
|
|
|
|
fs->state == available,
|
|
|
|
swim3_lock)) {
|
|
|
|
--fs->wanted;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
spin_unlock_irqrestore(&swim3_lock, flags);
|
2014-02-26 15:01:44 +04:00
|
|
|
return -EINTR;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
--fs->wanted;
|
|
|
|
}
|
|
|
|
fs->state = state;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
spin_unlock_irqrestore(&swim3_lock, flags);
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void release_drive(struct floppy_state *fs)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_dbg("%s", "-> release drive\n");
|
|
|
|
|
|
|
|
spin_lock_irqsave(&swim3_lock, flags);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->state = idle;
|
|
|
|
start_request(fs);
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
spin_unlock_irqrestore(&swim3_lock, flags);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int fd_eject(struct floppy_state *fs)
|
|
|
|
{
|
|
|
|
int err, n;
|
|
|
|
|
|
|
|
err = grab_drive(fs, ejecting, 1);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
swim3_action(fs, EJECT);
|
|
|
|
for (n = 20; n > 0; --n) {
|
|
|
|
if (signal_pending(current)) {
|
|
|
|
err = -EINTR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
swim3_select(fs, RELAX);
|
2005-09-10 11:27:28 +04:00
|
|
|
schedule_timeout_interruptible(1);
|
2005-04-17 02:20:36 +04:00
|
|
|
if (swim3_readbit(fs, DISK_IN) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
swim3_select(fs, RELAX);
|
|
|
|
udelay(150);
|
|
|
|
fs->ejected = 1;
|
|
|
|
release_drive(fs);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct floppy_struct floppy_type =
|
|
|
|
{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */
|
|
|
|
|
2010-07-08 12:18:46 +04:00
|
|
|
static int floppy_locked_ioctl(struct block_device *bdev, fmode_t mode,
|
2005-04-17 02:20:36 +04:00
|
|
|
unsigned int cmd, unsigned long param)
|
|
|
|
{
|
2008-03-02 18:20:44 +03:00
|
|
|
struct floppy_state *fs = bdev->bd_disk->private_data;
|
2005-04-17 02:20:36 +04:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
2009-12-01 17:36:28 +03:00
|
|
|
if (fs->mdev->media_bay &&
|
|
|
|
check_media_bay(fs->mdev->media_bay) != MB_FD)
|
2005-04-17 02:20:36 +04:00
|
|
|
return -ENXIO;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case FDEJECT:
|
|
|
|
if (fs->ref_count != 1)
|
|
|
|
return -EBUSY;
|
|
|
|
err = fd_eject(fs);
|
|
|
|
return err;
|
|
|
|
case FDGETPRM:
|
|
|
|
if (copy_to_user((void __user *) param, &floppy_type,
|
|
|
|
sizeof(struct floppy_struct)))
|
|
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -ENOTTY;
|
|
|
|
}
|
|
|
|
|
2010-07-08 12:18:46 +04:00
|
|
|
static int floppy_ioctl(struct block_device *bdev, fmode_t mode,
|
|
|
|
unsigned int cmd, unsigned long param)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2010-06-02 16:28:52 +04:00
|
|
|
mutex_lock(&swim3_mutex);
|
2010-07-08 12:18:46 +04:00
|
|
|
ret = floppy_locked_ioctl(bdev, mode, cmd, param);
|
2010-06-02 16:28:52 +04:00
|
|
|
mutex_unlock(&swim3_mutex);
|
2010-07-08 12:18:46 +04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-03-02 18:20:44 +03:00
|
|
|
static int floppy_open(struct block_device *bdev, fmode_t mode)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
2008-03-02 18:20:44 +03:00
|
|
|
struct floppy_state *fs = bdev->bd_disk->private_data;
|
2005-04-17 02:20:36 +04:00
|
|
|
struct swim3 __iomem *sw = fs->swim3;
|
|
|
|
int n, err = 0;
|
|
|
|
|
|
|
|
if (fs->ref_count == 0) {
|
2009-12-01 17:36:28 +03:00
|
|
|
if (fs->mdev->media_bay &&
|
|
|
|
check_media_bay(fs->mdev->media_bay) != MB_FD)
|
2005-04-17 02:20:36 +04:00
|
|
|
return -ENXIO;
|
|
|
|
out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2);
|
|
|
|
out_8(&sw->control_bic, 0xff);
|
|
|
|
out_8(&sw->mode, 0x95);
|
|
|
|
udelay(10);
|
|
|
|
out_8(&sw->intr_enable, 0);
|
|
|
|
out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE);
|
|
|
|
swim3_action(fs, MOTOR_ON);
|
|
|
|
fs->write_prot = -1;
|
|
|
|
fs->cur_cyl = -1;
|
|
|
|
for (n = 0; n < 2 * HZ; ++n) {
|
|
|
|
if (n >= HZ/30 && swim3_readbit(fs, SEEK_COMPLETE))
|
|
|
|
break;
|
|
|
|
if (signal_pending(current)) {
|
|
|
|
err = -EINTR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
swim3_select(fs, RELAX);
|
2005-09-10 11:27:28 +04:00
|
|
|
schedule_timeout_interruptible(1);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0
|
|
|
|
|| swim3_readbit(fs, DISK_IN) == 0))
|
|
|
|
err = -ENXIO;
|
|
|
|
swim3_action(fs, SETMFM);
|
|
|
|
swim3_select(fs, RELAX);
|
|
|
|
|
2008-03-02 18:20:44 +03:00
|
|
|
} else if (fs->ref_count == -1 || mode & FMODE_EXCL)
|
2005-04-17 02:20:36 +04:00
|
|
|
return -EBUSY;
|
|
|
|
|
2008-03-02 18:20:44 +03:00
|
|
|
if (err == 0 && (mode & FMODE_NDELAY) == 0
|
|
|
|
&& (mode & (FMODE_READ|FMODE_WRITE))) {
|
|
|
|
check_disk_change(bdev);
|
2005-04-17 02:20:36 +04:00
|
|
|
if (fs->ejected)
|
|
|
|
err = -ENXIO;
|
|
|
|
}
|
|
|
|
|
2008-03-02 18:20:44 +03:00
|
|
|
if (err == 0 && (mode & FMODE_WRITE)) {
|
2005-04-17 02:20:36 +04:00
|
|
|
if (fs->write_prot < 0)
|
|
|
|
fs->write_prot = swim3_readbit(fs, WRITE_PROT);
|
|
|
|
if (fs->write_prot)
|
|
|
|
err = -EROFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
if (fs->ref_count == 0) {
|
|
|
|
swim3_action(fs, MOTOR_OFF);
|
|
|
|
out_8(&sw->control_bic, DRIVE_ENABLE | INTR_ENABLE);
|
|
|
|
swim3_select(fs, RELAX);
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2008-03-02 18:20:44 +03:00
|
|
|
if (mode & FMODE_EXCL)
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->ref_count = -1;
|
|
|
|
else
|
|
|
|
++fs->ref_count;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-07 20:25:34 +04:00
|
|
|
static int floppy_unlocked_open(struct block_device *bdev, fmode_t mode)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2010-06-02 16:28:52 +04:00
|
|
|
mutex_lock(&swim3_mutex);
|
2010-08-07 20:25:34 +04:00
|
|
|
ret = floppy_open(bdev, mode);
|
2010-06-02 16:28:52 +04:00
|
|
|
mutex_unlock(&swim3_mutex);
|
2010-08-07 20:25:34 +04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-05-06 05:52:57 +04:00
|
|
|
static void floppy_release(struct gendisk *disk, fmode_t mode)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
2008-03-02 18:20:44 +03:00
|
|
|
struct floppy_state *fs = disk->private_data;
|
2005-04-17 02:20:36 +04:00
|
|
|
struct swim3 __iomem *sw = fs->swim3;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
|
2010-06-02 16:28:52 +04:00
|
|
|
mutex_lock(&swim3_mutex);
|
2005-04-17 02:20:36 +04:00
|
|
|
if (fs->ref_count > 0 && --fs->ref_count == 0) {
|
|
|
|
swim3_action(fs, MOTOR_OFF);
|
|
|
|
out_8(&sw->control_bic, 0xff);
|
|
|
|
swim3_select(fs, RELAX);
|
|
|
|
}
|
2010-06-02 16:28:52 +04:00
|
|
|
mutex_unlock(&swim3_mutex);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
2011-03-09 21:54:28 +03:00
|
|
|
static unsigned int floppy_check_events(struct gendisk *disk,
|
|
|
|
unsigned int clearing)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
|
|
|
struct floppy_state *fs = disk->private_data;
|
2011-03-09 21:54:28 +03:00
|
|
|
return fs->ejected ? DISK_EVENT_MEDIA_CHANGE : 0;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int floppy_revalidate(struct gendisk *disk)
|
|
|
|
{
|
|
|
|
struct floppy_state *fs = disk->private_data;
|
|
|
|
struct swim3 __iomem *sw;
|
|
|
|
int ret, n;
|
|
|
|
|
2009-12-01 17:36:28 +03:00
|
|
|
if (fs->mdev->media_bay &&
|
|
|
|
check_media_bay(fs->mdev->media_bay) != MB_FD)
|
2005-04-17 02:20:36 +04:00
|
|
|
return -ENXIO;
|
|
|
|
|
|
|
|
sw = fs->swim3;
|
|
|
|
grab_drive(fs, revalidating, 0);
|
|
|
|
out_8(&sw->intr_enable, 0);
|
|
|
|
out_8(&sw->control_bis, DRIVE_ENABLE);
|
|
|
|
swim3_action(fs, MOTOR_ON); /* necessary? */
|
|
|
|
fs->write_prot = -1;
|
|
|
|
fs->cur_cyl = -1;
|
|
|
|
mdelay(1);
|
|
|
|
for (n = HZ; n > 0; --n) {
|
|
|
|
if (swim3_readbit(fs, SEEK_COMPLETE))
|
|
|
|
break;
|
|
|
|
if (signal_pending(current))
|
|
|
|
break;
|
|
|
|
swim3_select(fs, RELAX);
|
2005-09-10 11:27:28 +04:00
|
|
|
schedule_timeout_interruptible(1);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
ret = swim3_readbit(fs, SEEK_COMPLETE) == 0
|
|
|
|
|| swim3_readbit(fs, DISK_IN) == 0;
|
|
|
|
if (ret)
|
|
|
|
swim3_action(fs, MOTOR_OFF);
|
|
|
|
else {
|
|
|
|
fs->ejected = 0;
|
|
|
|
swim3_action(fs, SETMFM);
|
|
|
|
}
|
|
|
|
swim3_select(fs, RELAX);
|
|
|
|
|
|
|
|
release_drive(fs);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-09-22 04:01:13 +04:00
|
|
|
static const struct block_device_operations floppy_fops = {
|
2010-08-07 20:25:34 +04:00
|
|
|
.open = floppy_unlocked_open,
|
2008-03-02 18:20:44 +03:00
|
|
|
.release = floppy_release,
|
2010-07-08 12:18:46 +04:00
|
|
|
.ioctl = floppy_ioctl,
|
2011-03-09 21:54:28 +03:00
|
|
|
.check_events = floppy_check_events,
|
2005-04-17 02:20:36 +04:00
|
|
|
.revalidate_disk= floppy_revalidate,
|
|
|
|
};
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
static void swim3_mb_event(struct macio_dev* mdev, int mb_state)
|
|
|
|
{
|
|
|
|
struct floppy_state *fs = macio_get_drvdata(mdev);
|
2013-02-22 03:16:40 +04:00
|
|
|
struct swim3 __iomem *sw;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
|
|
|
|
if (!fs)
|
|
|
|
return;
|
2013-02-22 03:16:40 +04:00
|
|
|
|
|
|
|
sw = fs->swim3;
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
if (mb_state != MB_FD)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Clear state */
|
|
|
|
out_8(&sw->intr_enable, 0);
|
|
|
|
in_8(&sw->intr);
|
|
|
|
in_8(&sw->error);
|
|
|
|
}
|
|
|
|
|
2006-07-03 11:25:26 +04:00
|
|
|
static int swim3_add_device(struct macio_dev *mdev, int index)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
2010-04-14 03:12:29 +04:00
|
|
|
struct device_node *swim = mdev->ofdev.dev.of_node;
|
2006-07-03 11:25:26 +04:00
|
|
|
struct floppy_state *fs = &floppy_states[index];
|
|
|
|
int rc = -EBUSY;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
/* Do this first for message macros */
|
|
|
|
memset(fs, 0, sizeof(*fs));
|
|
|
|
fs->mdev = mdev;
|
|
|
|
fs->index = index;
|
|
|
|
|
2006-07-03 11:25:26 +04:00
|
|
|
/* Check & Request resources */
|
|
|
|
if (macio_resource_count(mdev) < 2) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("%s", "No address in device-tree\n");
|
2006-07-03 11:25:26 +04:00
|
|
|
return -ENXIO;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
if (macio_irq_count(mdev) < 1) {
|
|
|
|
swim3_err("%s", "No interrupt in device-tree\n");
|
|
|
|
return -ENXIO;
|
2005-12-13 10:01:21 +03:00
|
|
|
}
|
2006-07-03 11:25:26 +04:00
|
|
|
if (macio_request_resource(mdev, 0, "swim3 (mmio)")) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("%s", "Can't request mmio resource\n");
|
2006-07-03 11:25:26 +04:00
|
|
|
return -EBUSY;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
2006-07-03 11:25:26 +04:00
|
|
|
if (macio_request_resource(mdev, 1, "swim3 (dma)")) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("%s", "Can't request dma resource\n");
|
2006-07-03 11:25:26 +04:00
|
|
|
macio_release_resource(mdev, 0);
|
|
|
|
return -EBUSY;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
2006-07-03 11:25:26 +04:00
|
|
|
dev_set_drvdata(&mdev->ofdev.dev, fs);
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2009-12-01 17:36:28 +03:00
|
|
|
if (mdev->media_bay == NULL)
|
2005-04-17 02:20:36 +04:00
|
|
|
pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1);
|
|
|
|
|
|
|
|
fs->state = idle;
|
2006-07-03 11:25:26 +04:00
|
|
|
fs->swim3 = (struct swim3 __iomem *)
|
|
|
|
ioremap(macio_resource_start(mdev, 0), 0x200);
|
|
|
|
if (fs->swim3 == NULL) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("%s", "Couldn't map mmio registers\n");
|
2006-07-03 11:25:26 +04:00
|
|
|
rc = -ENOMEM;
|
|
|
|
goto out_release;
|
|
|
|
}
|
|
|
|
fs->dma = (struct dbdma_regs __iomem *)
|
|
|
|
ioremap(macio_resource_start(mdev, 1), 0x200);
|
|
|
|
if (fs->dma == NULL) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("%s", "Couldn't map dma registers\n");
|
2006-07-03 11:25:26 +04:00
|
|
|
iounmap(fs->swim3);
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto out_release;
|
|
|
|
}
|
|
|
|
fs->swim3_intr = macio_irq(mdev, 0);
|
2009-08-18 22:18:35 +04:00
|
|
|
fs->dma_intr = macio_irq(mdev, 1);
|
2005-04-17 02:20:36 +04:00
|
|
|
fs->cur_cyl = -1;
|
|
|
|
fs->cur_sector = -1;
|
|
|
|
fs->secpercyl = 36;
|
|
|
|
fs->secpertrack = 18;
|
|
|
|
fs->total_secs = 2880;
|
|
|
|
init_waitqueue_head(&fs->wait);
|
|
|
|
|
|
|
|
fs->dma_cmd = (struct dbdma_cmd *) DBDMA_ALIGN(fs->dbdma_cmd_space);
|
|
|
|
memset(fs->dma_cmd, 0, 2 * sizeof(struct dbdma_cmd));
|
|
|
|
st_le16(&fs->dma_cmd[1].command, DBDMA_STOP);
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
if (mdev->media_bay == NULL || check_media_bay(mdev->media_bay) == MB_FD)
|
|
|
|
swim3_mb_event(mdev, MB_FD);
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) {
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_err("%s", "Couldn't request interrupt\n");
|
2005-04-17 02:20:36 +04:00
|
|
|
pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0);
|
2006-07-03 11:25:26 +04:00
|
|
|
goto out_unmap;
|
2005-04-17 02:20:36 +04:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
init_timer(&fs->timeout);
|
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
swim3_info("SWIM3 floppy controller %s\n",
|
2009-12-01 17:36:28 +03:00
|
|
|
mdev->media_bay ? "in media bay" : "");
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2006-07-03 11:25:26 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
out_unmap:
|
|
|
|
iounmap(fs->dma);
|
|
|
|
iounmap(fs->swim3);
|
|
|
|
|
|
|
|
out_release:
|
|
|
|
macio_release_resource(mdev, 0);
|
|
|
|
macio_release_resource(mdev, 1);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-12-22 03:13:49 +04:00
|
|
|
static int swim3_attach(struct macio_dev *mdev,
|
|
|
|
const struct of_device_id *match)
|
2006-07-03 11:25:26 +04:00
|
|
|
{
|
|
|
|
struct gendisk *disk;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
int index, rc;
|
|
|
|
|
|
|
|
index = floppy_count++;
|
|
|
|
if (index >= MAX_FLOPPIES)
|
|
|
|
return -ENXIO;
|
2006-07-03 11:25:26 +04:00
|
|
|
|
|
|
|
/* Add the drive */
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
rc = swim3_add_device(mdev, index);
|
2006-07-03 11:25:26 +04:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
/* Now register that disk. Same comment about failure handling */
|
|
|
|
disk = disks[index] = alloc_disk(1);
|
|
|
|
if (disk == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
disk->queue = blk_init_queue(do_fd_request, &swim3_lock);
|
|
|
|
if (disk->queue == NULL) {
|
|
|
|
put_disk(disk);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
disk->queue->queuedata = &floppy_states[index];
|
2006-07-03 11:25:26 +04:00
|
|
|
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
if (index == 0) {
|
2006-07-03 11:25:26 +04:00
|
|
|
/* If we failed, there isn't much we can do as the driver is still
|
|
|
|
* too dumb to remove the device, just bail out
|
|
|
|
*/
|
|
|
|
if (register_blkdev(FLOPPY_MAJOR, "fd"))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
disk->major = FLOPPY_MAJOR;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
disk->first_minor = index;
|
2006-07-03 11:25:26 +04:00
|
|
|
disk->fops = &floppy_fops;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
disk->private_data = &floppy_states[index];
|
2006-07-03 11:25:26 +04:00
|
|
|
disk->flags |= GENHD_FL_REMOVABLE;
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
sprintf(disk->disk_name, "fd%d", index);
|
2006-07-03 11:25:26 +04:00
|
|
|
set_capacity(disk, 2880);
|
|
|
|
add_disk(disk);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct of_device_id swim3_match[] =
|
|
|
|
{
|
|
|
|
{
|
|
|
|
.name = "swim3",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.compatible = "ohare-swim3"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.compatible = "swim3"
|
|
|
|
},
|
2011-08-03 17:02:55 +04:00
|
|
|
{ /* end of list */ }
|
2006-07-03 11:25:26 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct macio_driver swim3_driver =
|
|
|
|
{
|
2010-06-02 11:09:18 +04:00
|
|
|
.driver = {
|
|
|
|
.name = "swim3",
|
|
|
|
.of_match_table = swim3_match,
|
|
|
|
},
|
2006-07-03 11:25:26 +04:00
|
|
|
.probe = swim3_attach,
|
block/swim3: Locking fixes
The old PowerMac swim3 driver has some "interesting" locking issues,
using a private lock and failing to lock the queue before completing
requests, which triggered WARN_ONs among others.
This rips out the private lock, makes everything operate under the
block queue lock, and generally makes things simpler.
We used to also share a queue between the two possible instances which
was problematic since we might pick the wrong controller in some cases,
so make the queue and the current request per-instance and use
queuedata to point to our private data which is a lot cleaner.
We still share the queue lock but then, it's nearly impossible to actually
use 2 swim3's simultaneously: one would need to have a Wallstreet
PowerBook, the only machine afaik with two of these on the motherboard,
and populate both hotswap bays with a floppy drive (the machine ships
only with one), so nobody cares...
While at it, add a little fix to clear up stale interrupts when loading
the driver or plugging a floppy drive in a bay.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2011-12-12 15:42:12 +04:00
|
|
|
#ifdef CONFIG_PMAC_MEDIABAY
|
|
|
|
.mediabay_event = swim3_mb_event,
|
|
|
|
#endif
|
2006-07-03 11:25:26 +04:00
|
|
|
#if 0
|
|
|
|
.suspend = swim3_suspend,
|
|
|
|
.resume = swim3_resume,
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int swim3_init(void)
|
|
|
|
{
|
|
|
|
macio_register_driver(&swim3_driver);
|
2005-04-17 02:20:36 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(swim3_init)
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_AUTHOR("Paul Mackerras");
|
|
|
|
MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);
|