/drivers/scsi/in2000.c
C | 2337 lines | 1360 code | 388 blank | 589 comment | 283 complexity | 5f7d74d39b73bd2c3f2fd10b3c42579a MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
Large files files are truncated, but you can click here to view the full file
- /*
- * in2000.c - Linux device driver for the
- * Always IN2000 ISA SCSI card.
- *
- * Copyright (c) 1996 John Shifflett, GeoLog Consulting
- * john@geolog.com
- * jshiffle@netcom.com
- *
- * 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.
- *
- * For the avoidance of doubt the "preferred form" of this code is one which
- * is in an open non patent encumbered format. Where cryptographic key signing
- * forms part of the process of creating an executable the information
- * including keys needed to generate an equivalently functional executable
- * are deemed to be part of the source code.
- *
- * Drew Eckhardt's excellent 'Generic NCR5380' sources provided
- * much of the inspiration and some of the code for this driver.
- * The Linux IN2000 driver distributed in the Linux kernels through
- * version 1.2.13 was an extremely valuable reference on the arcane
- * (and still mysterious) workings of the IN2000's fifo. It also
- * is where I lifted in2000_biosparam(), the gist of the card
- * detection scheme, and other bits of code. Many thanks to the
- * talented and courageous people who wrote, contributed to, and
- * maintained that driver (including Brad McLean, Shaun Savage,
- * Bill Earnest, Larry Doolittle, Roger Sunshine, John Luckey,
- * Matt Postiff, Peter Lu, zerucha@shell.portal.com, and Eric
- * Youngdale). I should also mention the driver written by
- * Hamish Macdonald for the (GASP!) Amiga A2091 card, included
- * in the Linux-m68k distribution; it gave me a good initial
- * understanding of the proper way to run a WD33c93 chip, and I
- * ended up stealing lots of code from it.
- *
- * _This_ driver is (I feel) an improvement over the old one in
- * several respects:
- * - All problems relating to the data size of a SCSI request are
- * gone (as far as I know). The old driver couldn't handle
- * swapping to partitions because that involved 4k blocks, nor
- * could it deal with the st.c tape driver unmodified, because
- * that usually involved 4k - 32k blocks. The old driver never
- * quite got away from a morbid dependence on 2k block sizes -
- * which of course is the size of the card's fifo.
- *
- * - Target Disconnection/Reconnection is now supported. Any
- * system with more than one device active on the SCSI bus
- * will benefit from this. The driver defaults to what I'm
- * calling 'adaptive disconnect' - meaning that each command
- * is evaluated individually as to whether or not it should
- * be run with the option to disconnect/reselect (if the
- * device chooses), or as a "SCSI-bus-hog".
- *
- * - Synchronous data transfers are now supported. Because there
- * are a few devices (and many improperly terminated systems)
- * that choke when doing sync, the default is sync DISABLED
- * for all devices. This faster protocol can (and should!)
- * be enabled on selected devices via the command-line.
- *
- * - Runtime operating parameters can now be specified through
- * either the LILO or the 'insmod' command line. For LILO do:
- * "in2000=blah,blah,blah"
- * and with insmod go like:
- * "insmod /usr/src/linux/modules/in2000.o setup_strings=blah,blah"
- * The defaults should be good for most people. See the comment
- * for 'setup_strings' below for more details.
- *
- * - The old driver relied exclusively on what the Western Digital
- * docs call "Combination Level 2 Commands", which are a great
- * idea in that the CPU is relieved of a lot of interrupt
- * overhead. However, by accepting a certain (user-settable)
- * amount of additional interrupts, this driver achieves
- * better control over the SCSI bus, and data transfers are
- * almost as fast while being much easier to define, track,
- * and debug.
- *
- * - You can force detection of a card whose BIOS has been disabled.
- *
- * - Multiple IN2000 cards might almost be supported. I've tried to
- * keep it in mind, but have no way to test...
- *
- *
- * TODO:
- * tagged queuing. multiple cards.
- *
- *
- * NOTE:
- * When using this or any other SCSI driver as a module, you'll
- * find that with the stock kernel, at most _two_ SCSI hard
- * drives will be linked into the device list (ie, usable).
- * If your IN2000 card has more than 2 disks on its bus, you
- * might want to change the define of 'SD_EXTRA_DEVS' in the
- * 'hosts.h' file from 2 to whatever is appropriate. It took
- * me a while to track down this surprisingly obscure and
- * undocumented little "feature".
- *
- *
- * People with bug reports, wish-lists, complaints, comments,
- * or improvements are asked to pah-leeez email me (John Shifflett)
- * at john@geolog.com or jshiffle@netcom.com! I'm anxious to get
- * this thing into as good a shape as possible, and I'm positive
- * there are lots of lurking bugs and "Stupid Places".
- *
- * Updated for Linux 2.5 by Alan Cox <alan@lxorguk.ukuu.org.uk>
- * - Using new_eh handler
- * - Hopefully got all the locking right again
- * See "FIXME" notes for items that could do with more work
- */
- #include <linux/module.h>
- #include <linux/blkdev.h>
- #include <linux/interrupt.h>
- #include <linux/string.h>
- #include <linux/delay.h>
- #include <linux/proc_fs.h>
- #include <linux/ioport.h>
- #include <linux/stat.h>
- #include <asm/io.h>
- #include <asm/system.h>
- #include "scsi.h"
- #include <scsi/scsi_host.h>
- #define IN2000_VERSION "1.33-2.5"
- #define IN2000_DATE "2002/11/03"
- #include "in2000.h"
- /*
- * 'setup_strings' is a single string used to pass operating parameters and
- * settings from the kernel/module command-line to the driver. 'setup_args[]'
- * is an array of strings that define the compile-time default values for
- * these settings. If Linux boots with a LILO or insmod command-line, those
- * settings are combined with 'setup_args[]'. Note that LILO command-lines
- * are prefixed with "in2000=" while insmod uses a "setup_strings=" prefix.
- * The driver recognizes the following keywords (lower case required) and
- * arguments:
- *
- * - ioport:addr -Where addr is IO address of a (usually ROM-less) card.
- * - noreset -No optional args. Prevents SCSI bus reset at boot time.
- * - nosync:x -x is a bitmask where the 1st 7 bits correspond with
- * the 7 possible SCSI devices (bit 0 for device #0, etc).
- * Set a bit to PREVENT sync negotiation on that device.
- * The driver default is sync DISABLED on all devices.
- * - period:ns -ns is the minimum # of nanoseconds in a SCSI data transfer
- * period. Default is 500; acceptable values are 250 - 1000.
- * - disconnect:x -x = 0 to never allow disconnects, 2 to always allow them.
- * x = 1 does 'adaptive' disconnects, which is the default
- * and generally the best choice.
- * - debug:x -If 'DEBUGGING_ON' is defined, x is a bitmask that causes
- * various types of debug output to printed - see the DB_xxx
- * defines in in2000.h
- * - proc:x -If 'PROC_INTERFACE' is defined, x is a bitmask that
- * determines how the /proc interface works and what it
- * does - see the PR_xxx defines in in2000.h
- *
- * Syntax Notes:
- * - Numeric arguments can be decimal or the '0x' form of hex notation. There
- * _must_ be a colon between a keyword and its numeric argument, with no
- * spaces.
- * - Keywords are separated by commas, no spaces, in the standard kernel
- * command-line manner.
- * - A keyword in the 'nth' comma-separated command-line member will overwrite
- * the 'nth' element of setup_args[]. A blank command-line member (in
- * other words, a comma with no preceding keyword) will _not_ overwrite
- * the corresponding setup_args[] element.
- *
- * A few LILO examples (for insmod, use 'setup_strings' instead of 'in2000'):
- * - in2000=ioport:0x220,noreset
- * - in2000=period:250,disconnect:2,nosync:0x03
- * - in2000=debug:0x1e
- * - in2000=proc:3
- */
- /* Normally, no defaults are specified... */
- static char *setup_args[] = { "", "", "", "", "", "", "", "", "" };
- /* filled in by 'insmod' */
- static char *setup_strings;
- module_param(setup_strings, charp, 0);
- static inline uchar read_3393(struct IN2000_hostdata *hostdata, uchar reg_num)
- {
- write1_io(reg_num, IO_WD_ADDR);
- return read1_io(IO_WD_DATA);
- }
- #define READ_AUX_STAT() read1_io(IO_WD_ASR)
- static inline void write_3393(struct IN2000_hostdata *hostdata, uchar reg_num, uchar value)
- {
- write1_io(reg_num, IO_WD_ADDR);
- write1_io(value, IO_WD_DATA);
- }
- static inline void write_3393_cmd(struct IN2000_hostdata *hostdata, uchar cmd)
- {
- /* while (READ_AUX_STAT() & ASR_CIP)
- printk("|");*/
- write1_io(WD_COMMAND, IO_WD_ADDR);
- write1_io(cmd, IO_WD_DATA);
- }
- static uchar read_1_byte(struct IN2000_hostdata *hostdata)
- {
- uchar asr, x = 0;
- write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
- write_3393_cmd(hostdata, WD_CMD_TRANS_INFO | 0x80);
- do {
- asr = READ_AUX_STAT();
- if (asr & ASR_DBR)
- x = read_3393(hostdata, WD_DATA);
- } while (!(asr & ASR_INT));
- return x;
- }
- static void write_3393_count(struct IN2000_hostdata *hostdata, unsigned long value)
- {
- write1_io(WD_TRANSFER_COUNT_MSB, IO_WD_ADDR);
- write1_io((value >> 16), IO_WD_DATA);
- write1_io((value >> 8), IO_WD_DATA);
- write1_io(value, IO_WD_DATA);
- }
- static unsigned long read_3393_count(struct IN2000_hostdata *hostdata)
- {
- unsigned long value;
- write1_io(WD_TRANSFER_COUNT_MSB, IO_WD_ADDR);
- value = read1_io(IO_WD_DATA) << 16;
- value |= read1_io(IO_WD_DATA) << 8;
-