* Re: [PATCH] sym53c500_cs PCMCIA SCSI driver (new)
@ 2004-04-16 22:42 P. Christeas
2004-04-17 2:12 ` Bob Tracy
0 siblings, 1 reply; 8+ messages in thread
From: P. Christeas @ 2004-04-16 22:42 UTC (permalink / raw)
To: Bob Tracy; +Cc: lkml
<crap>
Its me!
I'm the second person in our solar system that has such a card!
I do have the New Media *Basics SCSI* card! I remember back in the kernel 2.2
days that I had found that code, hacked it and used it.. Since then, I hadn't
tried to use it again. Actually, I lost (hd failure) the system together with
the patch I had for that code..
Anyway, I believe that support for such hw is another Linux success story and
reserves a sticker at major distros saying "Linux: Supports all hardware;
even New Media's SCSI cards!".
</crap>
I cleanly compiled and run your module. Looks OK. I haven't yet attached any
peripheral, though. It's of no use to me, but I will be glad to help you by
testing that code (w. devices as well).
Thanks for resurrecting the dead!
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] sym53c500_cs PCMCIA SCSI driver (new)
2004-04-16 22:42 [PATCH] sym53c500_cs PCMCIA SCSI driver (new) P. Christeas
@ 2004-04-17 2:12 ` Bob Tracy
0 siblings, 0 replies; 8+ messages in thread
From: Bob Tracy @ 2004-04-17 2:12 UTC (permalink / raw)
To: P. Christeas; +Cc: linux-kernel
P. Christeas wrote:
> I'm the second person in our solar system that has such a card!
>
> I cleanly compiled and run your module. Looks OK. I haven't yet attached any
> peripheral, though. It's of no use to me, but I will be glad to help you by
> testing that code (w. devices as well).
> Thanks for resurrecting the dead!
Bravo! You've made my day :-). What kind of devices do you have
available? When I repair the #$%@! capstan on my Archive cartridge
tape unit, I need to test with that... The need for tape backup was
the reason I bought my card in the first place. At the moment, the
only device I've got that's even halfway convenient to use in testing
is an Olympus optical disk unit (removable media). The driver works
reliably with that, but I've got a sneaking suspicion that a tape unit
would stress things a bit more (error handling and such).
Per Christoph's critique, I've successfully combined the three driver
source files into a single source file, and eliminated all the
deprecated includes as well as the structure typedefs. Still to do:
add support for multiple HBAs, and eliminate distasteful hacks in
detection code. Dunno how I'm going to test the multiple HBA code...
--
-----------------------------------------------------------------------
Bob Tracy WTO + WIPO = DMCA? http://www.anti-dmca.org
rct@frus.com
-----------------------------------------------------------------------
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] sym53c500_cs PCMCIA SCSI driver (new)
2004-04-22 19:38 ` Bill Davidsen
@ 2004-04-22 20:48 ` Bob Tracy
0 siblings, 0 replies; 8+ messages in thread
From: Bob Tracy @ 2004-04-22 20:48 UTC (permalink / raw)
To: Bill Davidsen; +Cc: Christoph Hellwig, linux-kernel, linux-scsi
Bill Davidsen wrote:
> WRT the split of code... if there is some reason why there will never be
> another type of card then the split is unnessessary. But otherwise,
> you've done the work, and it matches the way other drivers were split,
> so why scrap it?
>
> As you guessed I don't feel strongly one way or the other, just thought
> you could use a little support for having made the effort to design for
> the future.
You give me too much credit :-). I inherited the split design from the
original author and simply preserved it. As far as maintaining the
split design, the only evidence I've seen of non-PCMCIA cards using the
Symbios/NCR 53c500 controller is the existence of a driver in the FreeBSD
tree. In any event, I don't have the hardware to test anything other
than the PCMCIA case, and if there's someone out there who needs support
for the non-PCMCIA case, I expect the Linux driver would have been written
before now. Christoph suggested in an earlier posting that the split to
support other hardware would probably be accomplished differently these
days anyway, so we (the community) probably haven't lost all that much by
concentrating on producing a well-written PCMCIA-only driver.
I saved my first attempt at a 2.6 driver (in case someone wants to
revisit the issue). Otherwise, although I appreciate your support,
it's OBE. I'm waiting to hear back from Christoph on a few design
issues (questions asked off-line) before submitting a third 2.6 driver.
The main issue I'm wrestling with at the moment is support for the
improbable case of multiple HBAs... I agree in principle with the
objective as long as I don't do something stupid that kills performance
for the normal case of a single HBA. As I see it, there are essentially
two approaches:
(1) Calculate all the needed hardware register offsets up front at HBA
init time, and carry them as part of the per-instance data. This
approach has a few things going for it -- the in-core memory
requirement is essentially identical for the single HBA case, and
dereferencing a structure pointer to get a register address is
barely worse than accessing the equivalent global variable in the
driver.
(2) Calculate a particular register offset each time that register is
accessed, using something like shost->io_port + offset, which, it
is claimed, is normal Linux driver practice. Although this
approach is extremely attractive from the standpoint of code
simplicity, I'm concerned about the arithmetic overhead. If it
turns out most of the hardware register accesses occur during
initialization, my concerns are pretty well meaningless. Obviously
I need to look at this more closely.
You may safely assume I'm learning more about this than I originally
anticipated :-).
--
-----------------------------------------------------------------------
Bob Tracy WTO + WIPO = DMCA? http://www.anti-dmca.org
rct@frus.com
-----------------------------------------------------------------------
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] sym53c500_cs PCMCIA SCSI driver (new)
2004-04-16 14:17 ` Bob Tracy
2004-04-17 9:45 ` Christoph Hellwig
@ 2004-04-22 19:38 ` Bill Davidsen
2004-04-22 20:48 ` Bob Tracy
1 sibling, 1 reply; 8+ messages in thread
From: Bill Davidsen @ 2004-04-22 19:38 UTC (permalink / raw)
To: Bob Tracy; +Cc: Christoph Hellwig, linux-kernel, linux-scsi
Bob Tracy wrote:
> Christoph Hellwig wrote:
>
>>I've given it a short spin and here's a bunch of comments:
>
>
> Thank you for taking the time and trouble to review it.
>
>
>> - the split into three source files is supserflous, one file should do it
>
>
> Given that the driver currently supports only PCMCIA implementations,
> I agree. My thinking was if someone comes up with a host adapter that
> isn't PCMCIA, the SYM53C500.c file is to the sym53c500_cs driver what
> the qlogicfas.c file is to the qlogic_cs driver, that is, core functions
> that could support multiple types of host adapters. The logic to
> handle the different types of adapters isn't there, and I don't know
> that it ever will be (else, it's probable that someone would have
> written the Linux driver long before now). However, after baring my
> ignorance to the world and saying I was unaware of non-PCMCIA
> implementations, I found a FreeBSD driver for the NCR 53c500. Never
> say "never," I guess... Your opinion counts for much, but you're the
> only person I've heard from. Is there a consensus I should forget
> about the non-PCMCIA cases?
>
>
>> - please don't use host.h or scsi.h from drivers/scsi/. The defintions
>> not present in include/scsi/ are deprecated and shall not be used (the
>> most prominent example in your driver are the Scsi_<Foo> typedefs that
>> have been replaced by struct scsi_foo
>
>
> I caught that in the coding style guidelines (and in the mentioned
> include files), and will fix for the next submission.
>
>
>> - the driver doesn't even try to deal with multiple HBAs
>
>
> Guilty as charged. Functionally, there's nothing in the driver I
> submitted that wasn't in the original. Suggestions welcome... Which
> of the existing PCMCIA SCSI drivers do a proper job of handling
> multiple host adapters in your opinion? I'll try to adapt that code to
> fit this driver. If I have to "roll my own" from scratch, I'm probably
> in over my head.
>
>
>> - your detection logic could be streamlined a little, e.g. the request/release
>> resource mess
>
>
> I'll see what I can do.
>
> Although I touched on it above, by way of apology/explanation, the goal
> for the initial port was to replicate the functionality I already had in
> older kernel versions. It appears I faithfully replicated the
> deficiencies of the old driver as well :-). Again, thank you for the
> feedback.
>
> Anyone else have input before I act on the recommendations I've been
> given? Unless I hear otherwise, I'll start work on the code
> consolidation and removal of dependencies on deprecated include files.
> The detection logic and handling multiple HBAs will take a bit more
> effort...
>
WRT the split of code... if there is some reason why there will never be
another type of card then the split is unnessessary. But otherwise,
you've done the work, and it matches the way other drivers were split,
so why scrap it?
As you guessed I don't feel strongly one way or the other, just thought
you could use a little support for having made the effort to design for
the future.
--
-bill davidsen (davidsen@tmr.com)
"The secret to procrastination is to put things off until the
last possible moment - but no longer" -me
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] sym53c500_cs PCMCIA SCSI driver (new)
2004-04-16 14:17 ` Bob Tracy
@ 2004-04-17 9:45 ` Christoph Hellwig
2004-04-22 19:38 ` Bill Davidsen
1 sibling, 0 replies; 8+ messages in thread
From: Christoph Hellwig @ 2004-04-17 9:45 UTC (permalink / raw)
To: Bob Tracy; +Cc: linux-kernel, linux-scsi
On Fri, Apr 16, 2004 at 09:17:20AM -0500, Bob Tracy wrote:
> Given that the driver currently supports only PCMCIA implementations,
> I agree. My thinking was if someone comes up with a host adapter that
> isn't PCMCIA, the SYM53C500.c file is to the sym53c500_cs driver what
> the qlogicfas.c file is to the qlogic_cs driver, that is, core functions
> that could support multiple types of host adapters. The logic to
> handle the different types of adapters isn't there, and I don't know
> that it ever will be (else, it's probable that someone would have
> written the Linux driver long before now). However, after baring my
> ignorance to the world and saying I was unaware of non-PCMCIA
> implementations, I found a FreeBSD driver for the NCR 53c500. Never
> say "never," I guess... Your opinion counts for much, but you're the
> only person I've heard from. Is there a consensus I should forget
> about the non-PCMCIA cases?
I'd suggest to keep it as simple as you can for the time beeing. If we
ever find a user with a ISA or whatever variant he can split it out. And
such a split would work a little different from what you did now.
> > - the driver doesn't even try to deal with multiple HBAs
>
> Guilty as charged. Functionally, there's nothing in the driver I
> submitted that wasn't in the original. Suggestions welcome... Which
> of the existing PCMCIA SCSI drivers do a proper job of handling
> multiple host adapters in your opinion? I'll try to adapt that code to
> fit this driver. If I have to "roll my own" from scratch, I'm probably
> in over my head.
It looks like nsp_cs at least tries to :-)
> > - your detection logic could be streamlined a little, e.g. the request/release
> > resource mess
>
> I'll see what I can do.
>
> Although I touched on it above, by way of apology/explanation, the goal
> for the initial port was to replicate the functionality I already had in
> older kernel versions. It appears I faithfully replicated the
> deficiencies of the old driver as well :-). Again, thank you for the
> feedback.
Hey, you don't need to apologize. Anyt 2.6 driver is better than none and
your looks quite okay from the functional standpoint. We just need to have
a little higher bars for new drivers as we already have lots of maintaince
overhead for old and sloppy written drivers.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] sym53c500_cs PCMCIA SCSI driver (new)
2004-04-16 12:05 ` Christoph Hellwig
@ 2004-04-16 14:17 ` Bob Tracy
2004-04-17 9:45 ` Christoph Hellwig
2004-04-22 19:38 ` Bill Davidsen
0 siblings, 2 replies; 8+ messages in thread
From: Bob Tracy @ 2004-04-16 14:17 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: linux-kernel, linux-scsi
Christoph Hellwig wrote:
> I've given it a short spin and here's a bunch of comments:
Thank you for taking the time and trouble to review it.
> - the split into three source files is supserflous, one file should do it
Given that the driver currently supports only PCMCIA implementations,
I agree. My thinking was if someone comes up with a host adapter that
isn't PCMCIA, the SYM53C500.c file is to the sym53c500_cs driver what
the qlogicfas.c file is to the qlogic_cs driver, that is, core functions
that could support multiple types of host adapters. The logic to
handle the different types of adapters isn't there, and I don't know
that it ever will be (else, it's probable that someone would have
written the Linux driver long before now). However, after baring my
ignorance to the world and saying I was unaware of non-PCMCIA
implementations, I found a FreeBSD driver for the NCR 53c500. Never
say "never," I guess... Your opinion counts for much, but you're the
only person I've heard from. Is there a consensus I should forget
about the non-PCMCIA cases?
> - please don't use host.h or scsi.h from drivers/scsi/. The defintions
> not present in include/scsi/ are deprecated and shall not be used (the
> most prominent example in your driver are the Scsi_<Foo> typedefs that
> have been replaced by struct scsi_foo
I caught that in the coding style guidelines (and in the mentioned
include files), and will fix for the next submission.
> - the driver doesn't even try to deal with multiple HBAs
Guilty as charged. Functionally, there's nothing in the driver I
submitted that wasn't in the original. Suggestions welcome... Which
of the existing PCMCIA SCSI drivers do a proper job of handling
multiple host adapters in your opinion? I'll try to adapt that code to
fit this driver. If I have to "roll my own" from scratch, I'm probably
in over my head.
> - your detection logic could be streamlined a little, e.g. the request/release
> resource mess
I'll see what I can do.
Although I touched on it above, by way of apology/explanation, the goal
for the initial port was to replicate the functionality I already had in
older kernel versions. It appears I faithfully replicated the
deficiencies of the old driver as well :-). Again, thank you for the
feedback.
Anyone else have input before I act on the recommendations I've been
given? Unless I hear otherwise, I'll start work on the code
consolidation and removal of dependencies on deprecated include files.
The detection logic and handling multiple HBAs will take a bit more
effort...
--
-----------------------------------------------------------------------
Bob Tracy WTO + WIPO = DMCA? http://www.anti-dmca.org
rct@frus.com
-----------------------------------------------------------------------
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] sym53c500_cs PCMCIA SCSI driver (new)
2004-04-10 2:17 Bob Tracy
@ 2004-04-16 12:05 ` Christoph Hellwig
2004-04-16 14:17 ` Bob Tracy
0 siblings, 1 reply; 8+ messages in thread
From: Christoph Hellwig @ 2004-04-16 12:05 UTC (permalink / raw)
To: Bob Tracy; +Cc: linux-kernel, linux-scsi
On Fri, Apr 09, 2004 at 09:17:03PM -0500, Bob Tracy wrote:
> The attached patch set implements a PCMCIA SCSI driver for host adapters
> based on the Symbios 53c500 chip. The original driver for this chip was
> written by Thomas Corner and available only as an add-on to the
> pcmcia-cs package. I've been maintaining the add-on driver on an
> infrequent basis for the past several years, and the release of the 2.6
> kernel "forced" a long overdue update.
>
> The only host adapter I'm aware of that uses the sym53c500 controller
> chip is the "new" version of the New Media Bus Toaster (circa 1996),
> and the attached driver has been tested using this particular adapter
> on a 2.6.4 kernel. The patch set applies cleanly to 2.6.4 and 2.6.5.
>
> Comments / feedback / cheers / jeers accepted...
I've given it a short spin and here's a bunch of comments:
- the split into three source files is supserflous, one file should do it
- please don't use host.h or scsi.h from drivers/scsi/. The defintions
not present in include/scsi/ are deprecated and shall not be used (the
most prominent example in your driver are the Scsi_<Foo> typedefs that
have been replaced by struct scsi_foo
- the driver doesn't even try to deal with multiple HBAs
- your detection logic could be streamlined a little, e.g. the request/release
resource mess
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] sym53c500_cs PCMCIA SCSI driver (new)
@ 2004-04-10 2:17 Bob Tracy
2004-04-16 12:05 ` Christoph Hellwig
0 siblings, 1 reply; 8+ messages in thread
From: Bob Tracy @ 2004-04-10 2:17 UTC (permalink / raw)
To: linux-kernel; +Cc: linux-scsi
[-- Attachment #1: Type: text/plain, Size: 951 bytes --]
The attached patch set implements a PCMCIA SCSI driver for host adapters
based on the Symbios 53c500 chip. The original driver for this chip was
written by Thomas Corner and available only as an add-on to the
pcmcia-cs package. I've been maintaining the add-on driver on an
infrequent basis for the past several years, and the release of the 2.6
kernel "forced" a long overdue update.
The only host adapter I'm aware of that uses the sym53c500 controller
chip is the "new" version of the New Media Bus Toaster (circa 1996),
and the attached driver has been tested using this particular adapter
on a 2.6.4 kernel. The patch set applies cleanly to 2.6.4 and 2.6.5.
Comments / feedback / cheers / jeers accepted...
--
-----------------------------------------------------------------------
Bob Tracy WTO + WIPO = DMCA? http://www.anti-dmca.org
rct@frus.com
-----------------------------------------------------------------------
[-- Attachment #2: patch05_sym53c500 --]
[-- Type: text/plain, Size: 39062 bytes --]
--- linux/drivers/scsi/pcmcia/Kconfig.orig Thu Apr 1 13:53:55 2004
+++ linux/drivers/scsi/pcmcia/Kconfig Thu Apr 1 14:00:42 2004
@@ -69,4 +69,14 @@
To compile this driver as a module, choose M here: the
module will be called qlogic_cs.
+config PCMCIA_SYM53C500
+ tristate "Symbios 53c500 PCMCIA support"
+ depends on m
+ help
+ Say Y here if you have a New Media Bus Toaster or other PCMCIA
+ SCSI adapter based on the Symbios 53c500 controller.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sym53c500_cs.
+
endmenu
--- linux/drivers/scsi/pcmcia/Makefile.orig Sat Mar 29 21:39:31 2003
+++ linux/drivers/scsi/pcmcia/Makefile Thu Apr 1 13:51:01 2004
@@ -6,7 +6,9 @@
obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o
obj-$(CONFIG_PCMCIA_AHA152X) += aha152x_cs.o
obj-$(CONFIG_PCMCIA_NINJA_SCSI) += nsp_cs.o
+obj-$(CONFIG_PCMCIA_SYM53C500) += sym53c500_cs.o
aha152x_cs-objs := aha152x_stub.o aha152x_core.o
fdomain_cs-objs := fdomain_stub.o fdomain_core.o
qlogic_cs-objs := qlogic_stub.o qlogic_core.o
+sym53c500_cs-objs := sym53c500.o SYM53C500.o
--- linux/drivers/scsi/pcmcia/SYM53C500.c.orig Mon Apr 5 14:51:07 2004
+++ linux/drivers/scsi/pcmcia/SYM53C500.c Fri Apr 9 14:44:32 2004
@@ -0,0 +1,860 @@
+/*
+* SYM53C500.c
+*
+* Low-level SCSI driver for SYM53C500 chip - Bob Tracy (rct@frus.com)
+*
+* Original driver by Tom Corner (tcorner@via.at) was adapted from
+* NCR53c406a.c which is Copyrighted (C) 1994, 1995, 1996
+* Normunds Saumanis (normunds@fi.ibm.com)
+*
+* A rewrite has been long overdue, and the 2.6 kernel forced the issue.
+* All the USE_BIOS code has been ripped out. It was never used, and
+* could not have worked anyway. USE_DMA has gone bye-bye too.
+*
+* 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, or (at your option) any
+* later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*/
+
+#define SYM53C500_DEBUG 0
+#define VERBOSE_SYM53C500_DEBUG 0
+
+/* Set this to 0 if you encounter kernel lockups while transferring
+ * data in PIO mode */
+#define USE_FAST_PIO 1
+
+/* ============= End of user configurable parameters ============= */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/bitops.h>
+#include <asm/irq.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+
+#include "scsi.h"
+#include "hosts.h"
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/ciscode.h>
+
+#include "SYM53C500.h"
+
+/* ============================================================= */
+
+#define WATCHDOG 5000000
+
+#define SYNC_MODE 0 /* Synchronous transfer mode */
+
+#if DEBUG
+#undef SYM53C500_DEBUG
+#define SYM53C500_DEBUG 1
+#endif
+
+/* Default configuration */
+#define C1_IMG 0x07 /* ID=7 */
+#define C2_IMG 0x48 /* FE SCSI2 */
+#define C3_IMG 0x20 /* CDB */
+#define C4_IMG 0x04 /* ANE */
+#define C5_IMG 0xa4 /*? changed from b6= AA PI SIE POL */
+#define C7_IMG 0x80 /* added for SYM53C500 t. corner */
+
+#define REG0 (outb(C4_IMG, CONFIG4)) /* select register set 0 */
+#define REG1 outb(C7_IMG, CONFIG7); outb(C5_IMG, CONFIG5) /* select register set 1 */
+
+#if SYM53C500_DEBUG
+#define DEB(x) x
+#else
+#define DEB(x)
+#endif
+
+#if VERBOSE_SYM53C500_DEBUG
+#define VDEB(x) x
+#else
+#define VDEB(x)
+#endif
+
+#define LOAD_DMA_COUNT(count) \
+ outb(count & 0xff, TC_LSB); \
+ outb((count >> 8) & 0xff, TC_MSB); \
+ outb((count >> 16) & 0xff, TC_HIGH);
+
+/* Chip commands */
+#define DMA_OP 0x80
+
+#define SCSI_NOP 0x00
+#define FLUSH_FIFO 0x01
+#define CHIP_RESET 0x02
+#define SCSI_RESET 0x03
+#define RESELECT 0x40
+#define SELECT_NO_ATN 0x41
+#define SELECT_ATN 0x42
+#define SELECT_ATN_STOP 0x43
+#define ENABLE_SEL 0x44
+#define DISABLE_SEL 0x45
+#define SELECT_ATN3 0x46
+#define RESELECT3 0x47
+#define TRANSFER_INFO 0x10
+#define INIT_CMD_COMPLETE 0x11
+#define MSG_ACCEPT 0x12
+#define TRANSFER_PAD 0x18
+#define SET_ATN 0x1a
+#define RESET_ATN 0x1b
+#define SEND_MSG 0x20
+#define SEND_STATUS 0x21
+#define SEND_DATA 0x22
+#define DISCONN_SEQ 0x23
+#define TERMINATE_SEQ 0x24
+#define TARG_CMD_COMPLETE 0x25
+#define DISCONN 0x27
+#define RECV_MSG 0x28
+#define RECV_CMD 0x29
+#define RECV_DATA 0x2a
+#define RECV_CMD_SEQ 0x2b
+#define TARGET_ABORT_DMA 0x04
+
+/*----------------------------------------------------------------*/
+/* the following will set the monitor border color (useful to find
+ where something crashed or gets stuck at */
+/* 1 = blue
+ 2 = green
+ 3 = cyan
+ 4 = red
+ 5 = magenta
+ 6 = yellow
+ 7 = white
+*/
+
+#if SYM53C500_DEBUG
+#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
+#else
+#define rtrc(i) {}
+#endif
+/*----------------------------------------------------------------*/
+
+enum Phase {
+ idle,
+ data_out,
+ data_in,
+ command_ph,
+ status_ph,
+ message_out,
+ message_in
+};
+
+/* Static function prototypes */
+static void SYM53C500_intr(int, void *, struct pt_regs *);
+static irqreturn_t do_SYM53C500_intr(int, void *, struct pt_regs *);
+static void chip_init(void);
+static void calc_port_addr(void);
+static int irq_probe(void);
+
+/* ================================================================= */
+
+static int port_base = 0;
+static int irq_level = -1; /* 0 is 'no irq', so use -1 for 'uninitialized'*/
+
+static int fast_pio = USE_FAST_PIO;
+
+static Scsi_Cmnd *current_SC;
+static char info_msg[256];
+
+/* ================================================================= */
+
+/* possible i/o port addresses */
+static unsigned short ports[] = { 0x130, 0x230, 0x280, 0x290, 0x320, 0x330, 0x340, 0x350 };
+#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
+
+/* ============================================================ */
+
+/* Control Register Set 0 */
+static int TC_LSB; /* transfer counter lsb */
+static int TC_MSB; /* transfer counter msb */
+static int SCSI_FIFO; /* scsi fifo register */
+static int CMD_REG; /* command register */
+static int STAT_REG; /* status register */
+static int DEST_ID; /* selection/reselection bus id */
+static int INT_REG; /* interrupt status register */
+static int SRTIMOUT; /* select/reselect timeout reg */
+static int SEQ_REG; /* sequence step register */
+static int SYNCPRD; /* synchronous transfer period */
+static int FIFO_FLAGS; /* indicates # of bytes in fifo */
+static int SYNCOFF; /* synchronous offset register */
+static int CONFIG1; /* configuration register */
+static int CLKCONV; /* clock conversion reg */
+/*static int TESTREG;*/ /* test mode register */
+static int CONFIG2; /* Configuration 2 Register */
+static int CONFIG3; /* Configuration 3 Register */
+static int CONFIG4; /* Configuration 4 Register */
+static int TC_HIGH; /* Transfer Counter High */
+/*static int FIFO_BOTTOM;*/ /* Reserve FIFO byte register */
+
+/* Control Register Set 1 */
+/*static int JUMPER_SENSE;*/ /* Jumper sense port reg (r/w) */
+/*static int SRAM_PTR;*/ /* SRAM address pointer reg (r/w) */
+/*static int SRAM_DATA;*/ /* SRAM data register (r/w) */
+static int PIO_FIFO; /* PIO FIFO registers (r/w) */
+/*static int PIO_FIFO1;*/ /* */
+/*static int PIO_FIFO2;*/ /* */
+/*static int PIO_FIFO3;*/ /* */
+static int PIO_STATUS; /* PIO status (r/w) */
+/*static int ATA_CMD;*/ /* ATA command/status reg (r/w) */
+/*static int ATA_ERR;*/ /* ATA features/error register (r/w)*/
+static int PIO_FLAG; /* PIO flag interrupt enable (r/w) */
+static int CONFIG5; /* Configuration 5 register (r/w) */
+/*static int SIGNATURE;*/ /* Signature Register (r) */
+/*static int CONFIG6;*/ /* Configuration 6 register (r) */
+static int CONFIG7;
+
+/* ============================================================== */
+
+/*
+* SYM53C500_proc_info is basically a stub function for now. It
+* wouldn't exist except for the fact there were /proc entries for
+* this driver under 2.4 and earlier kernels, and the author (sole
+* user?) expects to see them.
+*
+* buffer: I/O buffer
+* start: if inout == FALSE, pointer into buffer where user
+* read should start
+* offset: current offset
+* length: length of buffer
+* hostno: Scsi_Host host_no
+* inout: 1 --> user is writing; 0 --> user is reading
+*/
+
+#undef SPRINTF
+#define SPRINTF(args...) \
+ do { \
+ if (length > (pos - buffer)) \
+ pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \
+ } while (0)
+
+int
+SYM53C500_proc_info(struct Scsi_Host *shost, char *buffer,
+ char **start, off_t offset, int length, int inout)
+{
+ char *pos = buffer;
+ int thislength;
+
+ if (inout)
+ return(-ENOSYS); /* look, but don't touch */
+
+ /*
+ * Cheesy, but it's what we had before.
+ */
+ SPRINTF("%s\n", info_msg);
+
+ thislength = pos - (buffer + offset);
+
+ if (thislength < 0) {
+ *start = 0;
+ return 0;
+ }
+
+ thislength = MIN(thislength, length);
+ *start = buffer + offset;
+
+ return thislength;
+}
+
+static __inline__ int
+SYM53C500_pio_read(unsigned char *request, unsigned int reqlen)
+{
+ int i;
+ int len; /* current scsi fifo size */
+
+ REG1;
+ while (reqlen) {
+ i = inb(PIO_STATUS);
+ /* VDEB(printk("pio_status=%x\n", i)); */
+ if (i & 0x80)
+ return 0;
+
+ switch (i & 0x1e) {
+ default:
+ case 0x10: /* fifo empty */
+ len = 0;
+ break;
+ case 0x0:
+ len = 1;
+ break;
+ case 0x8: /* fifo 1/3 full */
+ len = 42;
+ break;
+ case 0xc: /* fifo 2/3 full */
+ len = 84;
+ break;
+ case 0xe: /* fifo full */
+ len = 128;
+ break;
+ }
+
+ if ((i & 0x40) && len == 0) { /* fifo empty and interrupt occurred */
+ return 0;
+ }
+
+ if (len) {
+ if (len > reqlen)
+ len = reqlen;
+
+ if (fast_pio && len > 3) {
+ insl(PIO_FIFO, request, len >> 2);
+ request += len & 0xfc;
+ reqlen -= len & 0xfc;
+ } else {
+ while (len--) {
+ *request++ = inb(PIO_FIFO);
+ reqlen--;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static __inline__ int
+SYM53C500_pio_write(unsigned char *request, unsigned int reqlen)
+{
+ int i = 0;
+ int len; /* current scsi fifo size */
+
+ REG1;
+ while (reqlen && !(i & 0x40)) {
+ i = inb(PIO_STATUS);
+ /* VDEB(printk("pio_status=%x\n", i)); */
+ if (i & 0x80) /* error */
+ return 0;
+
+ switch (i & 0x1e) {
+ case 0x10:
+ len = 128;
+ break;
+ case 0x0:
+ len = 84;
+ break;
+ case 0x8:
+ len = 42;
+ break;
+ case 0xc:
+ len = 1;
+ break;
+ default:
+ case 0xe:
+ len = 0;
+ break;
+ }
+
+ if (len) {
+ if (len > reqlen)
+ len = reqlen;
+
+ if (fast_pio && len > 3) {
+ outsl(PIO_FIFO, request, len >> 2);
+ request += len & 0xfc;
+ reqlen -= len & 0xfc;
+ } else {
+ while (len--) {
+ outb(*request++, PIO_FIFO);
+ reqlen--;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+struct Scsi_Host *
+__SYM53C500_detect(struct scsi_host_template *tpnt)
+{
+ struct Scsi_Host *shpnt;
+ int i;
+
+ if (port_base) {
+ if (!request_region(port_base, 0x10, "SYM53C500"))
+ port_base = 0;
+ } else {
+ for (i = 0; i < PORT_COUNT && !port_base; i++) {
+ if (!request_region(ports[i], 0x10, "SYM53C500")) {
+ DEB(printk("SYM53C500: port %x in use\n", ports[i]));
+ } else {
+ VDEB(printk("SYM53C500: port %x available\n", ports[i]));
+ outb(C5_IMG, ports[i] + 0x0d); /* reg set 1 */
+ if ((inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7 && (inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7 && (inb(ports[i] + 0x0e) & 0xf8) == 0x58) {
+ port_base = ports[i];
+ VDEB(printk("SYM53C500: Sig register valid\n"));
+ VDEB(printk("port_base=%x\n", port_base));
+ break;
+ }
+ release_region(ports[i], 0x10);
+ }
+ }
+ }
+
+ if (!port_base) { /* no ports found */
+ printk("SYM53C500: no available ports found\n");
+ return NULL;
+ }
+
+ DEB(printk("SYM53C500 detected at 0x%x\n", port_base));
+
+ calc_port_addr();
+ chip_init();
+
+ if (irq_level < 0) {
+ irq_level = irq_probe();
+ if (irq_level < 0) { /* Trouble */
+ printk("SYM53C500: IRQ problem, irq_level=%d, giving up\n", irq_level);
+ goto err_release;
+ }
+ }
+
+ shpnt = scsi_host_alloc(tpnt, 0);
+ if (!shpnt) {
+ printk("SYM53C500: Unable to register host, giving up.\n");
+ goto err_release;
+ }
+
+ if (irq_level > 0) {
+ if (request_irq(irq_level, do_SYM53C500_intr, 0, "SYM53C500", shpnt)) {
+ printk("SYM53C500: unable to allocate IRQ %d\n", irq_level);
+ goto err_free_scsi;
+ }
+ tpnt->can_queue = 1;
+ DEB(printk("SYM53C500: allocated IRQ %d\n", irq_level));
+ } else if (irq_level == 0) {
+ tpnt->can_queue = 0;
+ DEB(printk("SYM53C500: No interrupts detected\n"));
+ goto err_free_scsi;
+ } else {
+ DEB(printk("SYM53C500: Shouldn't get here!\n"));
+ goto err_free_scsi;
+ }
+
+ shpnt->irq = irq_level;
+ shpnt->io_port = port_base;
+ shpnt->n_io_port = 0x10;
+ shpnt->dma_channel = -1;
+
+ sprintf(info_msg, "SYM53C500 at 0x%x, IRQ %d, %s PIO mode.",
+ port_base, irq_level, fast_pio ? "fast" : "slow");
+
+ return (shpnt);
+
+err_free_scsi:
+ scsi_host_put(shpnt);
+err_release:
+ release_region(port_base, 0x10);
+ return NULL;
+}
+
+int
+SYM53C500_detect(struct scsi_host_template *sht)
+{
+ return (__SYM53C500_detect(sht) != NULL);
+}
+
+/*
+* Note fast_pio is global and set at compile time.
+*/
+void
+SYM53C500_preset(int port, int irq)
+{
+ port_base = port;
+ irq_level = irq;
+
+ DEB(printk("SYM53C500: port_base=0x%X, irq=%d, fast_pio=%d\n",
+ port_base, irq_level, fast_pio);)
+}
+
+const char*
+SYM53C500_info(struct Scsi_Host *SChost)
+{
+ DEB(printk("SYM53C500_info called\n"));
+ return (info_msg);
+}
+
+int
+SYM53C500_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+ int i;
+
+ VDEB(printk("SYM53C500_queue called\n"));
+/*
+* target and lun members no longer exist.
+*
+ DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n",
+ SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->target,
+ SCpnt->lun, SCpnt->request_bufflen));
+*/
+
+ VDEB(for (i = 0; i < SCpnt->cmd_len; i++)
+ printk("cmd[%d]=%02x ", i, SCpnt->cmnd[i]));
+ VDEB(printk("\n"));
+
+ current_SC = SCpnt;
+ current_SC->scsi_done = done;
+ current_SC->SCp.phase = command_ph;
+ current_SC->SCp.Status = 0;
+ current_SC->SCp.Message = 0;
+
+ /* We are locked here already by the mid layer */
+ REG0;
+ outb(SCpnt->device->id, DEST_ID); /* set destination */
+ outb(FLUSH_FIFO, CMD_REG); /* reset the fifos */
+
+ for (i = 0; i < SCpnt->cmd_len; i++) {
+ outb(SCpnt->cmnd[i], SCSI_FIFO);
+ }
+ outb(SELECT_NO_ATN, CMD_REG);
+
+ rtrc(1);
+ return 0;
+}
+
+int
+SYM53C500_abort(Scsi_Cmnd *SCpnt)
+{
+ DEB(printk("SYM53C500_abort called\n"));
+ return FAILED; /* Don't know how to abort */
+}
+
+int
+SYM53C500_host_reset(Scsi_Cmnd *SCpnt)
+{
+ DEB(printk("SYM53C500_host_reset called\n"));
+ outb(C4_IMG, CONFIG4); /* Select reg set 0 */
+ outb(CHIP_RESET, CMD_REG);
+ outb(SCSI_NOP, CMD_REG); /* required after reset */
+ outb(SCSI_RESET, CMD_REG);
+ chip_init();
+
+ rtrc(2);
+ return SUCCESS;
+}
+
+int
+SYM53C500_device_reset(Scsi_Cmnd *SCpnt)
+{
+ return FAILED;
+}
+
+int
+SYM53C500_bus_reset(Scsi_Cmnd *SCpnt)
+{
+ return FAILED;
+}
+
+int
+SYM53C500_biosparm(struct scsi_device *disk,
+ struct block_device *dev,
+ sector_t capacity, int *info_array)
+{
+ int size;
+
+ DEB(printk("SYM53C500_biosparm called\n"));
+
+ size = capacity;
+ info_array[0] = 64; /* heads */
+ info_array[1] = 32; /* sectors */
+ info_array[2] = size >> 11; /* cylinders */
+ if (info_array[2] > 1024) { /* big disk */
+ info_array[0] = 255;
+ info_array[1] = 63;
+ info_array[2] = size / (255 * 63);
+ }
+ return 0;
+}
+
+static irqreturn_t
+do_SYM53C500_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+ struct Scsi_Host *dev = dev_id;
+
+ spin_lock_irqsave(dev->host_lock, flags);
+ SYM53C500_intr(irq, dev_id, regs);
+ spin_unlock_irqrestore(dev->host_lock, flags);
+ return IRQ_HANDLED;
+}
+
+static void
+SYM53C500_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ DEB(unsigned char fifo_size;)
+ DEB(unsigned char seq_reg;)
+ unsigned char status, int_reg;
+ unsigned char pio_status;
+ struct scatterlist *sglist;
+ unsigned int sgcount;
+
+ VDEB(printk("SYM53C500_intr called\n"));
+
+ REG1;
+ pio_status = inb(PIO_STATUS);
+ REG0;
+ status = inb(STAT_REG);
+ DEB(seq_reg = inb(SEQ_REG));
+ int_reg = inb(INT_REG);
+ DEB(fifo_size = inb(FIFO_FLAGS) & 0x1f);
+
+#if SYM53C500_DEBUG
+ printk("status=%02x, seq_reg=%02x, int_reg=%02x, fifo_size=%02x",
+ status, seq_reg, int_reg, fifo_size);
+ printk(", pio=%02x\n", pio_status);
+#endif /* SYM53C500_DEBUG */
+
+ if (int_reg & 0x80) { /* SCSI reset intr */
+ rtrc(3);
+ DEB(printk("SYM53C500: reset intr received\n"));
+ current_SC->SCp.phase = idle;
+ current_SC->result = DID_RESET << 16;
+ current_SC->scsi_done(current_SC);
+ return;
+ }
+
+ if (pio_status & 0x80) {
+ printk("SYM53C500: Warning: PIO error!\n");
+ current_SC->SCp.phase = idle;
+ current_SC->result = DID_ERROR << 16;
+ current_SC->scsi_done(current_SC);
+ return;
+ }
+
+ if (status & 0x20) { /* Parity error */
+ printk("SYM53C500: Warning: parity error!\n");
+ current_SC->SCp.phase = idle;
+ current_SC->result = DID_PARITY << 16;
+ current_SC->scsi_done(current_SC);
+ return;
+ }
+
+ if (status & 0x40) { /* Gross error */
+ printk("SYM53C500: Warning: gross error!\n");
+ current_SC->SCp.phase = idle;
+ current_SC->result = DID_ERROR << 16;
+ current_SC->scsi_done(current_SC);
+ return;
+ }
+
+ if (int_reg & 0x20) { /* Disconnect */
+ DEB(printk("SYM53C500: disconnect intr received\n"));
+ if (current_SC->SCp.phase != message_in) { /* Unexpected disconnect */
+ current_SC->result = DID_NO_CONNECT << 16;
+ } else { /* Command complete, return status and message */
+ current_SC->result = (current_SC->SCp.Status & 0xff)
+ | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16);
+ }
+
+ rtrc(0);
+ current_SC->SCp.phase = idle;
+ current_SC->scsi_done(current_SC);
+ return;
+ }
+
+ switch (status & 0x07) { /* scsi phase */
+ case 0x00: /* DATA-OUT */
+ if (int_reg & 0x10) { /* Target requesting info transfer */
+ rtrc(5);
+ current_SC->SCp.phase = data_out;
+ VDEB(printk("SYM53C500: Data-Out phase\n"));
+ outb(FLUSH_FIFO, CMD_REG);
+ LOAD_DMA_COUNT(current_SC->request_bufflen); /* Max transfer size */
+ outb(TRANSFER_INFO | DMA_OP, CMD_REG);
+ if (!current_SC->use_sg) /* Don't use scatter-gather */
+ SYM53C500_pio_write(current_SC->request_buffer, current_SC->request_bufflen);
+ else { /* use scatter-gather */
+ sgcount = current_SC->use_sg;
+ sglist = current_SC->request_buffer;
+ while (sgcount--) {
+ SYM53C500_pio_write(page_address(sglist->page) + sglist->offset, sglist->length);
+ sglist++;
+ }
+ }
+ REG0;
+ }
+ break;
+
+ case 0x01: /* DATA-IN */
+ if (int_reg & 0x10) { /* Target requesting info transfer */
+ rtrc(6);
+ current_SC->SCp.phase = data_in;
+ VDEB(printk("SYM53C500: Data-In phase\n"));
+ outb(FLUSH_FIFO, CMD_REG);
+ LOAD_DMA_COUNT(current_SC->request_bufflen); /* Max transfer size */
+ outb(TRANSFER_INFO | DMA_OP, CMD_REG);
+ if (!current_SC->use_sg) /* Don't use scatter-gather */
+ SYM53C500_pio_read(current_SC->request_buffer, current_SC->request_bufflen);
+ else { /* Use scatter-gather */
+ sgcount = current_SC->use_sg;
+ sglist = current_SC->request_buffer;
+ while (sgcount--) {
+ SYM53C500_pio_read(page_address(sglist->page) + sglist->offset, sglist->length);
+ sglist++;
+ }
+ }
+ REG0;
+ }
+ break;
+
+ case 0x02: /* COMMAND */
+ current_SC->SCp.phase = command_ph;
+ printk("SYM53C500: Warning: Unknown interrupt occurred in command phase!\n");
+ break;
+
+ case 0x03: /* STATUS */
+ rtrc(7);
+ current_SC->SCp.phase = status_ph;
+ VDEB(printk("SYM53C500: Status phase\n"));
+ outb(FLUSH_FIFO, CMD_REG);
+ outb(INIT_CMD_COMPLETE, CMD_REG);
+ break;
+
+ case 0x04: /* Reserved */
+ case 0x05: /* Reserved */
+ printk("SYM53C500: WARNING: Reserved phase!!!\n");
+ break;
+
+ case 0x06: /* MESSAGE-OUT */
+ DEB(printk("SYM53C500: Message-Out phase\n"));
+ current_SC->SCp.phase = message_out;
+ outb(SET_ATN, CMD_REG); /* Reject the message */
+ outb(MSG_ACCEPT, CMD_REG);
+ break;
+
+ case 0x07: /* MESSAGE-IN */
+ rtrc(4);
+ VDEB(printk("SYM53C500: Message-In phase\n"));
+ current_SC->SCp.phase = message_in;
+
+ current_SC->SCp.Status = inb(SCSI_FIFO);
+ current_SC->SCp.Message = inb(SCSI_FIFO);
+
+ VDEB(printk("SCSI FIFO size=%d\n", inb(FIFO_FLAGS) & 0x1f));
+ DEB(printk("Status = %02x Message = %02x\n", current_SC->SCp.Status, current_SC->SCp.Message));
+
+ if (current_SC->SCp.Message == SAVE_POINTERS || current_SC->SCp.Message == DISCONNECT) {
+ outb(SET_ATN, CMD_REG); /* Reject message */
+ DEB(printk("Discarding SAVE_POINTERS message\n"));
+ }
+ outb(MSG_ACCEPT, CMD_REG);
+ break;
+ }
+}
+
+static int
+irq_probe(void)
+{
+ int irqs, irq;
+ unsigned long i;
+
+ inb(INT_REG); /* clear the interrupt register */
+ irqs = probe_irq_on();
+
+ /* Invalid command will cause an interrupt */
+ REG0;
+ outb(0xff, CMD_REG);
+
+ /* Wait for the interrupt to occur */
+ i = jiffies + WATCHDOG;
+ while (time_after(i, jiffies) && !(inb(STAT_REG) & 0x80))
+ barrier();
+ if (time_before_eq(i, jiffies)) { /* Timed out, must be hardware trouble */
+ probe_irq_off(irqs);
+ return -1;
+ }
+
+ irq = probe_irq_off(irqs);
+
+ /* Kick the chip */
+ outb(CHIP_RESET, CMD_REG);
+ outb(SCSI_NOP, CMD_REG);
+ chip_init();
+
+ return irq;
+}
+
+static void
+chip_init(void)
+{
+ REG1;
+ outb(0x01, PIO_STATUS);
+ outb(0x00, PIO_FLAG);
+
+ outb(C4_IMG, CONFIG4); /* REG0; */
+ outb(C3_IMG, CONFIG3);
+ outb(C2_IMG, CONFIG2);
+ outb(C1_IMG, CONFIG1);
+
+ outb(0x05, CLKCONV); /* clock conversion factor */
+ outb(0x9C, SRTIMOUT); /* Selection timeout */
+ outb(0x05, SYNCPRD); /* Synchronous transfer period */
+ outb(SYNC_MODE, SYNCOFF); /* synchronous mode */
+}
+
+void
+calc_port_addr(void)
+{
+ /* Control Register Set 0 */
+ TC_LSB = (port_base + 0x00);
+ TC_MSB = (port_base + 0x01);
+ SCSI_FIFO = (port_base + 0x02);
+ CMD_REG = (port_base + 0x03);
+ STAT_REG = (port_base + 0x04);
+ DEST_ID = (port_base + 0x04);
+ INT_REG = (port_base + 0x05);
+ SRTIMOUT = (port_base + 0x05);
+ SEQ_REG = (port_base + 0x06);
+ SYNCPRD = (port_base + 0x06);
+ FIFO_FLAGS = (port_base + 0x07);
+ SYNCOFF = (port_base + 0x07);
+ CONFIG1 = (port_base + 0x08);
+ CLKCONV = (port_base + 0x09);
+ /* TESTREG = (port_base + 0x0A); */
+ CONFIG2 = (port_base + 0x0B);
+ CONFIG3 = (port_base + 0x0C);
+ CONFIG4 = (port_base + 0x0D);
+ TC_HIGH = (port_base + 0x0E);
+ /* FIFO_BOTTOM = (port_base + 0x0F); */
+
+ /* Control Register Set 1 */
+ /* JUMPER_SENSE = (port_base + 0x00); */
+ /* SRAM_PTR = (port_base + 0x01); */
+ /* SRAM_DATA = (port_base + 0x02); */
+ PIO_FIFO = (port_base + 0x04);
+ /* PIO_FIFO1 = (port_base + 0x05); */
+ /* PIO_FIFO2 = (port_base + 0x06); */
+ /* PIO_FIFO3 = (port_base + 0x07); */
+ PIO_STATUS = (port_base + 0x08);
+ /* ATA_CMD = (port_base + 0x09); */
+ /* ATA_ERR = (port_base + 0x0A); */
+ PIO_FLAG = (port_base + 0x0B);
+ CONFIG5 = (port_base + 0x09);
+ /* SIGNATURE = (port_base + 0x0E); */
+ /* CONFIG6 = (port_base +0x0F); */
+ CONFIG7 = (port_base + 0x0d);
+}
+
+MODULE_AUTHOR("Bob Tracy <rct@frus.com>");
+MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver");
+MODULE_LICENSE("GPL");
+
+struct scsi_host_template sym53c500_driver_template = SYM53C500;
--- linux/drivers/scsi/pcmcia/SYM53C500.h.orig Mon Apr 5 14:51:11 2004
+++ linux/drivers/scsi/pcmcia/SYM53C500.h Fri Apr 9 15:05:37 2004
@@ -0,0 +1,69 @@
+#ifndef _SYM53C500_H
+#define _SYM53C500_H
+
+/*
+* SYM53C500.h
+*
+* Bob Tracy (rct@frus.com)
+* Original by Tom Corner (tcorner@via.at)
+*
+* Adapted from NCR53c406a.h which is Copyrighted (C) 1994
+* Normunds Saumanis (normunds@rx.tech.swh.lv)
+*
+* 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, or (at your option) any
+* later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*/
+
+/* A useful macro... */
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+
+int SYM53C500_detect(struct scsi_host_template *);
+struct Scsi_Host *__SYM53C500_detect(struct scsi_host_template *);
+const char *SYM53C500_info(struct Scsi_Host *);
+int SYM53C500_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int SYM53C500_abort(Scsi_Cmnd *);
+int SYM53C500_device_reset(Scsi_Cmnd *);
+int SYM53C500_bus_reset(Scsi_Cmnd *);
+int SYM53C500_host_reset(Scsi_Cmnd *);
+int SYM53C500_biosparm(struct scsi_device *, struct block_device *, sector_t, int *);
+int SYM53C500_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/*
+* scsi_host_template initializer
+*
+* Include file defining structure implies proc_info is optional.
+* Trouble is, directory for host adapter won't get created unless
+* there's a proc_info routine, i.e., nothing will appear in /proc.
+* This is different from the 2.4 implementation.
+*/
+#define SYM53C500 { \
+ .module = THIS_MODULE, \
+ .name = "SYM53C500", \
+ .info = SYM53C500_info, \
+ .queuecommand = SYM53C500_queue, \
+ .eh_abort_handler = SYM53C500_abort, \
+ .eh_device_reset_handler = SYM53C500_device_reset,\
+ .eh_bus_reset_handler = SYM53C500_bus_reset, \
+ .eh_host_reset_handler = SYM53C500_host_reset, \
+ .bios_param = SYM53C500_biosparm, \
+ .proc_info = SYM53C500_proc_info, \
+ .proc_name = "SYM53C500", \
+ .can_queue = 1, \
+ .this_id = 7, \
+ .sg_tablesize = 32, \
+ .cmd_per_lun = 1, \
+ .use_clustering = ENABLE_CLUSTERING \
+}
+
+#endif /* _SYM5C500_H */
--- linux/drivers/scsi/pcmcia/sym53c500.c.orig Mon Apr 5 14:51:19 2004
+++ linux/drivers/scsi/pcmcia/sym53c500.c Thu Apr 8 15:12:18 2004
@@ -0,0 +1,377 @@
+/*
+* sym53c500.c
+*
+* A driver for newer Bus Toaster SCSI cards using the SYM53C500 chip
+* adapted by Tom Corner (tcorner@via.at) from a driver for the Qlogic
+* SCSI card written by David Hinds (dhinds@allegro.stanford.edu).
+*
+* Rewritten by Bob Tracy (rct@frus.com) for inclusion in the 2.6 and later
+* kernel source trees. The pcmcia-cs add-on version of this driver is not
+* supported beyond 2.4.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_ioctl.h>
+
+#include "scsi.h"
+#include "hosts.h"
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/ciscode.h>
+
+#include "SYM53C500.h"
+
+extern struct scsi_host_template sym53c500_driver_template;
+/* extern void SYM53C500_setup(char *str, int *ints); */
+extern void SYM53C500_preset(int port, int irq);
+extern struct Scsi_Host *__SYM53C500_detect(struct scsi_host_template *);
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"sym53c500_cs.c 0.7 2004/04/01 14:15:58 (Bob Tracy)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static unsigned int irq_mask = 0xdeb8; /* 3, 6, 7, 9-12, 14, 15 */
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+ dev_link_t link;
+ dev_node_t node;
+ struct Scsi_Host *host;
+ unsigned short manf_id;
+} scsi_info_t;
+
+static void SYM53C500_release(dev_link_t *link);
+static int SYM53C500_event(event_t event, int priority, event_callback_args_t *args);
+static dev_link_t *SYM53C500_attach(void);
+static void SYM53C500_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+static dev_info_t dev_info = "sym53c500_cs";
+
+static dev_link_t *
+SYM53C500_attach(void)
+{
+ scsi_info_t *info;
+ client_reg_t client_reg;
+ dev_link_t *link;
+ int i, ret;
+
+ DEBUG(0, "SYM53C500_attach()\n");
+
+ /* Create new SCSI device */
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return NULL;
+ memset(info, 0, sizeof(*info));
+ link = &info->link;
+ link->priv = info;
+ link->io.NumPorts1 = 16;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ link->io.IOAddrLines = 10;
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+ if (irq_list[0] == -1)
+ link->irq.IRQInfo2 = irq_mask;
+ else
+ for (i = 0; i < 4; i++)
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.Present = PRESENT_OPTION;
+
+ /* Register with Card Services */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.event_handler = &SYM53C500_event;
+ client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = pcmcia_register_client(&link->handle, &client_reg);
+ if (ret != 0) {
+ cs_error(link->handle, RegisterClient, ret);
+ SYM53C500_detach(link);
+ return NULL;
+ }
+
+ return link;
+} /* SYM53C500_attach */
+
+/*====================================================================*/
+
+static void
+SYM53C500_detach(dev_link_t *link)
+{
+ dev_link_t **linkp;
+
+ DEBUG(0, "SYM53C500_detach(0x%p)\n", link);
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link)
+ break;
+ if (*linkp == NULL)
+ return;
+
+ if (link->state & DEV_CONFIG)
+ SYM53C500_release(link);
+
+ if (link->handle)
+ pcmcia_deregister_client(link->handle);
+
+ /* Unlink device structure, free bits. */
+ *linkp = link->next;
+ kfree(link->priv);
+ link->priv = NULL;
+} /* SYM53C500_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+static void
+SYM53C500_config(dev_link_t *link)
+{
+ client_handle_t handle = link->handle;
+ scsi_info_t *info = link->priv;
+ tuple_t tuple;
+ cisparse_t parse;
+ int i, last_ret, last_fn;
+ unsigned short tuple_data[32];
+ struct Scsi_Host *host;
+
+ DEBUG(0, "SYM53C500_config(0x%p)\n", link);
+
+ tuple.TupleData = (cisdata_t *)tuple_data;
+ tuple.TupleDataMax = 64;
+ tuple.TupleOffset = 0;
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+ CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+ link->conf.ConfigBase = parse.config.base;
+
+ tuple.DesiredTuple = CISTPL_MANFID;
+ if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) &&
+ (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS))
+ info->manf_id = le16_to_cpu(tuple.TupleData[0]);
+
+ /* Configure card */
+ link->state |= DEV_CONFIG;
+
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ while (1) {
+ if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
+ pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+ goto next_entry;
+ link->conf.ConfigIndex = parse.cftable_entry.index;
+ link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+ link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
+
+ if (link->io.BasePort1 != 0) {
+ i = pcmcia_request_io(handle, &link->io);
+ if (i == CS_SUCCESS)
+ break;
+ }
+next_entry:
+ CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+ }
+
+ CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
+ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+
+ /*
+ * That's the trouble with copying liberally from another driver.
+ * Some things probably aren't relevant, and I suspect this entire
+ * section dealing with manufacturer IDs can be scrapped. --rct
+ */
+ if ((info->manf_id == MANFID_MACNICA) ||
+ (info->manf_id == MANFID_PIONEER) ||
+ (info->manf_id == 0x0098)) {
+ /* set ATAcmd */
+ outb(0xb4, link->io.BasePort1 + 0xd);
+ outb(0x24, link->io.BasePort1 + 0x9);
+ outb(0x04, link->io.BasePort1 + 0xd);
+ }
+
+ /*
+ * A bad hack: __SYM53C500_detect() will do a request_region(),
+ * so we have to get out of the way first.
+ */
+ release_region(link->io.BasePort1, link->io.NumPorts1);
+
+ SYM53C500_preset(link->io.BasePort1, link->irq.AssignedIRQ);
+
+ host = __SYM53C500_detect(&sym53c500_driver_template);
+ if (!host) {
+ printk(KERN_INFO "sym53c500_cs: no SCSI devices found\n");
+ goto out;
+ }
+
+ sprintf(info->node.dev_name, "scsi%d", host->host_no);
+ link->dev = &info->node;
+ info->host = host;
+
+ scsi_add_host(host, NULL); /* XXX handle failure */
+ scsi_scan_host(host);
+
+out:
+ link->state &= ~DEV_CONFIG_PENDING;
+ return;
+
+cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+ SYM53C500_release(link);
+ return;
+} /* SYM53C500_config */
+
+/*====================================================================*/
+
+static void
+SYM53C500_release(dev_link_t *link)
+{
+ scsi_info_t *info = link->priv;
+ struct Scsi_Host *shost = info->host;
+
+ DEBUG(0, "SYM53C500_release(0x%p)\n", link);
+
+ /*
+ * Interrupts getting hosed on card removal. Try
+ * the following code, mostly from qlogicfas.c.
+ */
+ if (shost->irq)
+ free_irq(shost->irq, shost);
+ if (shost->dma_channel != 0xff)
+ free_dma(shost->dma_channel);
+ if (shost->io_port && shost->n_io_port)
+ release_region(shost->io_port, shost->n_io_port);
+
+ scsi_remove_host(shost);
+ link->dev = NULL;
+
+ pcmcia_release_configuration(link->handle);
+ pcmcia_release_io(link->handle, &link->io);
+ pcmcia_release_irq(link->handle, &link->irq);
+
+ link->state &= ~DEV_CONFIG;
+
+ scsi_host_put(shost);
+} /* SYM53C500_release */
+
+/*====================================================================*/
+
+static int
+SYM53C500_event(event_t event, int priority, event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+ scsi_info_t *info = link->priv;
+
+ DEBUG(1, "SYM53C500_event(0x%06x)\n", event);
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG)
+ SYM53C500_release(link);
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ SYM53C500_config(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if (link->state & DEV_CONFIG)
+ pcmcia_release_configuration(link->handle);
+ break;
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (link->state & DEV_CONFIG) {
+ pcmcia_request_configuration(link->handle, &link->conf);
+ /* See earlier comment about manufacturer IDs. */
+ if ((info->manf_id == MANFID_MACNICA) ||
+ (info->manf_id == MANFID_PIONEER) ||
+ (info->manf_id == 0x0098)) {
+ outb(0x80, link->io.BasePort1 + 0xd);
+ outb(0x24, link->io.BasePort1 + 0x9);
+ outb(0x04, link->io.BasePort1 + 0xd);
+ }
+ /* Fugly! */
+ SYM53C500_bus_reset(NULL);
+ }
+ break;
+ }
+ return 0;
+} /* SYM53C500_event */
+
+/*====================================================================*/
+
+static struct pcmcia_driver sym53c500_cs_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "sym53c500_cs",
+ },
+ .attach = SYM53C500_attach,
+ .detach = SYM53C500_detach,
+};
+
+static int __init
+init_sym53c500_cs(void)
+{
+ return pcmcia_register_driver(&sym53c500_cs_driver);
+}
+
+static void __exit
+exit_sym53c500_cs(void)
+{
+ pcmcia_unregister_driver(&sym53c500_cs_driver);
+
+ /* XXX: this really needs to move into generic code... */
+ while (dev_list != NULL)
+ SYM53C500_detach(dev_list);
+}
+
+module_init(init_sym53c500_cs);
+module_exit(exit_sym53c500_cs);
--- linux/Documentation/scsi/sym53c500_cs.txt.orig Thu Apr 1 16:42:23 2004
+++ linux/Documentation/scsi/sym53c500_cs.txt Mon Apr 5 16:00:24 2004
@@ -0,0 +1,16 @@
+The sym53c500_cs driver originated as an add-on to David Hinds' pcmcia-cs
+package, and was written by Tom Corner (tcorner@via.at). This rewrite
+addresses the following concerns:
+
+ (1) extensive kernel changes between 2.4 and 2.6.
+ (2) deprecated PCMCIA support outside the kernel.
+
+The Symbios Logic 53c500 chip was used in the "new" (circa 1997) version
+of the New Media Bus Toaster PCMCIA SCSI controller. I am unaware of any
+other products using this chip.
+
+Through the years, there have been a number of downloads of the pcmcia-cs
+version of this driver, and I guess it worked for those users. It worked
+for Tom Corner, and it works for me. Your mileage will probably vary.
+
+--Bob Tracy (rct@frus.com)
--- linux/Documentation/scsi/00-INDEX.orig Sat Mar 29 21:17:08 2003
+++ linux/Documentation/scsi/00-INDEX Thu Apr 1 16:44:34 2004
@@ -62,6 +62,8 @@
- info on API between SCSI layer and low level drivers
st.txt
- info on scsi tape driver
+sym53c500_cs.txt
+ - info on PCMCIA driver for Symbios Logic 53c500 based adapters
sym53c8xx_2.txt
- info on second generation driver for sym53c8xx based adapters
tmscsim.txt
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2004-04-22 20:48 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-04-16 22:42 [PATCH] sym53c500_cs PCMCIA SCSI driver (new) P. Christeas
2004-04-17 2:12 ` Bob Tracy
-- strict thread matches above, loose matches on Subject: below --
2004-04-10 2:17 Bob Tracy
2004-04-16 12:05 ` Christoph Hellwig
2004-04-16 14:17 ` Bob Tracy
2004-04-17 9:45 ` Christoph Hellwig
2004-04-22 19:38 ` Bill Davidsen
2004-04-22 20:48 ` Bob Tracy
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®