Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
32d9ad84
Commit
32d9ad84
authored
Feb 02, 2004
by
James Bottomley
Committed by
James Bottomley
Feb 02, 2004
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
SCSI: Remove AM53c974 driver
It hasn't compiled for ages and no-one seems to care ...
parent
5cd7327e
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
0 additions
and
2788 deletions
+0
-2788
Documentation/scsi/AM53C974.txt
Documentation/scsi/AM53C974.txt
+0
-246
drivers/scsi/AM53C974.c
drivers/scsi/AM53C974.c
+0
-2463
drivers/scsi/AM53C974.h
drivers/scsi/AM53C974.h
+0
-61
drivers/scsi/Kconfig
drivers/scsi/Kconfig
+0
-17
drivers/scsi/Makefile
drivers/scsi/Makefile
+0
-1
No files found.
Documentation/scsi/AM53C974.txt
deleted
100644 → 0
View file @
5cd7327e
SUBJECT
-------
AM53/79C974 PC-SCSI Driver
DISCLAIMER
----------
*** THIS SHOULD BE CONSIDERED AS BETA SOFTWARE ***
*** USE AT YOUR OWN RISK! ***
Copyright
---------
The architecture and much of the code of this device driver was
originally developed by Drew Eckhardt for the NCR5380. The
following copyrights apply:
For the architecture and all pieces of code which can also be found
in the NCR5380 device driver:
Copyright 1993, Drew Eckhardt
Visionary Computing
(Unix and Linux consulting and custom programming)
drew@colorado.edu
+1 (303) 666-5836
The AM53C974_nobios_detect code was originally developed by
Robin Cutshaw (robin@xfree86.org) and is used here in a
slightly modified form.
For the remaining code:
Copyright 1994, D. Frieauff
EMail: fri@rsx42sun0.dofn.de
Phone: x49-7545-8-2256 , x49-7541-42305
Version
-------
AM53/79C974 (PC-SCSI) Linux driver ALPHA release 0.5, 19 November 1995
Changelog
---------
0.1 -> 0.2:
- Extended message handling re-written to eliminate 'invalid message 17' bug
- Parameters of AM53C974_intr adapted
- Debug messages structured
- Spelling improved
0.2 -> 0.3:
- README file updated -- please read this file up to the end!
- Automatic scanning of io_port and irq implemented; no need for BIOS32
anymore
- Improved configuration (now via LILO parameter string)
- Cleanup of probing and initialization code
- Improved sync. negotiation (can be setup individually for every device)
- Improved/ debugged code for reception of ext. messages
0.3 -> 0.4:
- Improved PCI probing and initialization code
- Compatibility changes for Linux 1.3.x
0.4 -> 0.5:
- Compatibility changes for Linux 1.3.42
Bugs & Todo
-----------
- Add proc info function
- Support SCSI-2 tagged queuing
- Finalize abort code
Features
--------
This driver supports asynchronous and synchronous SCSI-I and SCSI-II
devices. It is capable of transfer rate and synchronous negotiation
(see below). The driver supports scatter-gather. Transfers are DMA
based, but do not (yet) make use of the AM53/79C974 MDL mode.
Max. transfer rate is 10MHz (whatever this is in real life). The
transfer rate is negotiated with each device (see dmesg output). The
AM53/79C974 has a 96-byte DMA FIFO to the PCI bus and a 16-byte SCSI
FIFO. It provides active negation and glitch suppression functions.
Burst DMA transfer rate is 132 MBytes/sec.
Configuration
-------------
The following communication characteristics can be set individually
for every SCSI device on the bus:
- enable/disable sync. negotiation
- transfer rate
- asynchronous or synchronous communication
- in case of sync. communication, the sync. offset
The sync. offset specifies the number of bytes that can be sent or
received from the SCSI bus without ACK resp. REQ signal.
CAUTION: USING SYNCHRONOUS MODE ON LONG SCSI CABLES MAY CAUSE
COMMUNICATION PROBLEMS LEADING TO LOSS OF DATA.
The default setting of the SCSI communication parameters is as follows:
- no negotiation
- 5.0 MHz transfer rate
- asynchronous mode
- zero offset
The parameters can be modified by passing a string with the following
syntax to the kernel:
AM53C974=host-scsi-id,target-scsi-id,max-rate,max-offset
The parameters will be used by the driver as negotiation basis. The
range of the rate parameter is 3 to 10 MHz. The range of the
sync. offset parameter is 0 to 15 bytes. A value of 0 denotes
asynchronous comm. mode. If the target cannot cope with the specified
transfer rate, sync. mode or sync. offset, the negotiation result
will differ from the specified values. The negotiation result is
printed out at the end of the negotiation process (to read it, use the
dmesg program or the appropriate syslog). The parameter strings
(blank separated) can be passed to the kernel at the LILO prompt, or
as part of the LILO configuration file.
For example, the string "AM53C974=7,2,8,15" would be interpreted as
follows:
For communication between the controller with SCSI-ID 7 and the
device with SCSI-ID 2 a transfer rate of 8MHz in synchronous mode with
max. 15 bytes offset should be negotiated.
As an example, here my LILO configuration file:
boot = /dev/sda
compact
#prompt
delay = 50 # optional, for systems that boot very quickly
vga = normal # force sane state
ramdisk = 0 # paranoia setting
root = current # use "current" root
image = /usr/src/linux/arch/i386/boot/zImage
label = linux
append = "AM53C974=7,0,10,0 AM53C974=7,1,10,0 AM53C974=7,2,10,15 AM53C974=7,4,10,0 AM53C974=7,5,10,0"
read-only
other = /dev/sda4
label = os2
other = /dev/sdb3
loader = /boot/any_d.b
table = /dev/sdb
label = setup
The same parameters at the LILO prompt:
LILO boot: linux AM53C974=7,0,10,0 AM53C974=7,1,10,0 AM53C974=7,2,10,15 AM53C974=7,4,10,0 AM53C974=7,5,10,0
You can override parameters specified in the LILO configuration file
by parameters specified on the LILO command line.
BIOS usage
----------
Version 0.4 of the driver will use the BIOS, if available. Otherwise
it will try its internal PCI scan and access routines. The driver
assumes that the controller's SCSI-ID (usually 7) has been correctly
loaded by the BIOS into the controller's register during system
boot. If the driver detects that the controller's SCSI ID is not '7'
it will print out a warning. If this happens to you please correct
setting of the controller's SCSI-ID. If it is wrong, then edit the
AM53C974_SCSI_ID definition in file AM53C974.h accordingly.
Test environment
----------------
This driver was tested on a Compaq XL566 with the following SCSI configuration:
2 x HP C2247 fixed disk (internal, rate=10MHz, async.)
1 x Micropolis 1624 fixed disk (external, rate=8MHz, sync., offset=15 bytes)
1 x Wangtek W5525ES cartridge streamer (internal, rate=5MHz, async.)
1 x Toshiba XM-3301B CD-ROM (external, rate=5MHz, async.)
Known problems
--------------
- Compaq/Matsushita CD-ROM:
Use of this device with AM53C974 driver version 0.2 caused the kernel to
hang during Linux boot. If you encounter the problem, don't enable sync.
negotiation with the CD-ROM, i.e. simply don't specify comm. parameters
for this device on the LILO command line or configuration file.
The driver will thus use its default for the CD-ROM, which is 5MHz
transfer rate async and no sync. negotiation.
- Some disks cause problems.
What to do if there is a SCSI problem possibly related to the driver
--------------------------------------------------------------------
Read Klaus Liedl's WWW page (http://www-c724.uibk.ac.at/XL/). In case
this does not help: Send me a complete description of the problem,
including your SCSI configuration plus as much debugging information
as possible. Don't wait until I ask you for this information. To
enable the generation of debugging output, remove the comments from
the following definitions in the AM53C974.h file:
AM53C974_DEBUG
AM53C974_DEBUG_MSG
AM53C974_DEBUG_KEYWAIT
AM53C974_DEBUG_INFO
AM53C974_DEBUG_INTR
With these definitions enabled, the driver will enter single-step mode
during Linux boot. Use the spacebar for stepping. Take note of at
least the last 10 printout sections (marked by dashes) before the
crash/hangup or whatever happens and send me all of this information
via email. If the system can boot, use the syslogd daemon to record
the debugging output. Maybe you can use the ramdisk for this purpose
too (if necessary, kindly ask K. Liedl (Klaus.Liedl@uibk.ac.at) for
support, he knows how to do it -- I never tried). Stay in email
contact with me. Be aware that the following weeks/months could be the
worst of your life. Note: If single-stepping takes up too much time,
you can try to let the driver catch the problem by pressing the 'r'
key. The driver will automatically enter single-step mode if it has
detected something weird.
Author's Contact Address
-----------------------
Email: fri@rsx42sun0.dofn.de
Phone: x49-7545-2256 (office), x49-7541-42305 (home)
Home address: D. Frieauff, Stockerholzstr. 27, 88048 Friedrichshafen, Germany
!!!! Important Notice !!!!
-----------------------------
- Klaus Liedl maintains an excellent WWW page about Linux on Compaq XL.
It includes an FAQ, lots of tips & tricks as well as downloadable
boot disk images. The URL is: http://www-c724.uibk.ac.at/XL/
- Volunteer wanted for further maintenance of this driver software. I
don't have the time anymore to do serious support as some of you will know.
Literature
----------
- AMD AM53C974 PC-SCSI Technical Manual, publication #18624B
- Amendment to the AMD AM53C974 PC-SCSI Technical Manual
- AMD AM79C974 PC-NET Datasheet, publication #18681
- Amendment to the AMD AM79C974 PC-NET Datasheet
THANKS to
---------
- Drew Eckhardt, Robin Cutshaw, K. Liedl, Robert J. Pappas, A. Grenier,
Mark Stockton, David C. Niemi, Ben Craft, and many others who have helped
drivers/scsi/AM53C974.c
deleted
100644 → 0
View file @
5cd7327e
#error Please convert me to Documentation/DMA-mapping.txt
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/system.h>
#include "scsi.h"
#include "hosts.h"
#include "AM53C974.h"
/* AM53/79C974 (PCscsi) driver release 0.5
* The architecture and much of the code of this device
* driver was originally developed by Drew Eckhardt for
* the NCR5380. The following copyrights apply:
* For the architecture and all pieces of code which can also be found
* in the NCR5380 device driver:
* Copyright 1993, Drew Eckhardt
* Visionary Computing
* (Unix and Linux consulting and custom programming)
* drew@colorado.edu
* +1 (303) 666-5836
*
* The AM53C974_nobios_detect code was originally developed by
* Robin Cutshaw (robin@xfree86.org) and is used here in a
* slightly modified form.
*
* PCI detection rewritten by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*
* For the remaining code:
* Copyright 1994, D. Frieauff
* EMail: fri@rsx42sun0.dofn.de
* Phone: x49-7545-8-2256 , x49-7541-42305
*/
/*
* $Log: AM53C974.c,v $
*/
#ifdef AM53C974_DEBUG
#define DEB(x) x
#ifdef AM53C974_DEBUG_KEYWAIT
#define KEYWAIT() AM53C974_keywait()
#else
#define KEYWAIT()
#endif
#ifdef AM53C974_DEBUG_INIT
#define DEB_INIT(x) x
#else
#define DEB_INIT(x)
#endif
#ifdef AM53C974_DEBUG_MSG
#define DEB_MSG(x) x
#else
#define DEB_MSG(x)
#endif
#ifdef AM53C974_DEB_RESEL
#define DEB_RESEL(x) x
#else
#define DEB_RESEL(x)
#endif
#ifdef AM53C974_DEBUG_QUEUE
#define DEB_QUEUE(x) x
#define LIST(x,y) {printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); if ((x)==(y)) udelay(5); }
#define REMOVE(w,x,y,z) {printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, (void*)(w), (void*)(x), (void*)(y), (void*)(z)); if ((x)==(y)) udelay(5); }
#else
#define DEB_QUEUE(x)
#define LIST(x,y)
#define REMOVE(w,x,y,z)
#endif
#ifdef AM53C974_DEBUG_INFO
#define DEB_INFO(x) x
#else
#define DEB_INFO(x)
#endif
#ifdef AM53C974_DEBUG_LINKED
#define DEB_LINKED(x) x
#else
#define DEB_LINKED(x)
#endif
#ifdef AM53C974_DEBUG_INTR
#define DEB_INTR(x) x
#else
#define DEB_INTR(x)
#endif
#else
#define DEB_INIT(x)
#define DEB(x)
#define DEB_QUEUE(x)
#define LIST(x,y)
#define REMOVE(w,x,y,z)
#define DEB_INFO(x)
#define DEB_LINKED(x)
#define DEB_INTR(x)
#define DEB_MSG(x)
#define DEB_RESEL(x)
#define KEYWAIT()
#endif
#ifdef AM53C974_DEBUG_ABORT
#define DEB_ABORT(x) x
#else
#define DEB_ABORT(x)
#endif
#ifdef VERBOSE_AM53C974_DEBUG
#define VDEB(x) x
#else
#define VDEB(x)
#endif
#define INSIDE(x,l,h) ( ((x) >= (l)) && ((x) <= (h)) )
#include <scsi/scsicam.h>
/***************************************************************************************
* Default setting of the controller's SCSI id. Edit and uncomment this only if your *
* BIOS does not correctly initialize the controller's SCSI id. *
* If you don't get a warning during boot, it is correctly initialized. *
****************************************************************************************/
/* #define AM53C974_SCSI_ID 7 */
/***************************************************************************************
* Default settings for sync. negotiation enable, transfer rate and sync. offset. *
* These settings can be replaced by LILO overrides (append) with the following syntax: *
* AM53C974=host-scsi-id, target-scsi-id, max-rate, max-offset *
* Sync. negotiation is disabled by default and will be enabled for those targets which *
* are specified in the LILO override *
****************************************************************************************/
#define DEFAULT_SYNC_NEGOTIATION_ENABLED 0
/* 0 or 1 */
#define DEFAULT_RATE 5
/* MHz, min: 3; max: 10 */
#define DEFAULT_SYNC_OFFSET 0
/* bytes, min: 0; max: 15; use 0 for async. mode */
/***************************************************************************************
* If defined, don't allow targets to disconnect during commands. This will reduce *
* performance, but may be worthwhile if you suspect the driver of corrupting data when *
* a disconnect happens. *
***************************************************************************************/
#define AM53C974_PROHIBIT_DISCONNECT
/* --------------------- don't edit below here --------------------- */
#define AM53C974_DRIVER_REVISION_MAJOR 0
#define AM53C974_DRIVER_REVISION_MINOR 5
#define SEPARATOR_LINE \
"--------------------------------------------------------------------------\n"
/* debug control */
/* #define AM53C974_DEBUG */
/* #define AM53C974_DEBUG_MSG */
/* #define AM53C974_DEBUG_KEYWAIT */
/* #define AM53C974_DEBUG_INIT */
/* #define AM53C974_DEBUG_QUEUE */
/* #define AM53C974_DEBUG_INFO */
/* #define AM53C974_DEBUG_LINKED */
/* #define VERBOSE_AM53C974_DEBUG */
/* #define AM53C974_DEBUG_INTR */
/* #define AM53C974_DEB_RESEL */
#define AM53C974_DEBUG_ABORT
/* #define AM53C974_OPTION_DEBUG_PROBE_ONLY */
/* special options/constants */
#define DEF_CLK 40
/* chip clock freq. in MHz */
#define MIN_PERIOD 4
/* for negotiation: min. number of clocks per cycle */
#define MAX_PERIOD 13
/* for negotiation: max. number of clocks per cycle */
#define MAX_OFFSET 15
/* for negotiation: max. offset (0=async) */
#define DEF_SCSI_TIMEOUT 245
/* STIMREG value, 40 Mhz */
#define DEF_STP 8
/* STPREG value assuming 5.0 MB/sec, FASTCLK, FASTSCSI */
#define DEF_SOF_RAD 0
/* REQ/ACK deassertion delay */
#define DEF_SOF_RAA 0
/* REQ/ACK assertion delay */
#define DEF_ETM 0
/* CNTLREG1, ext. timing mode */
#define DEF_PERE 1
/* CNTLREG1, parity error reporting */
#define DEF_CLKF 0
/* CLKFREG, 0=40 Mhz */
#define DEF_ENF 1
/* CNTLREG2, enable features */
#define DEF_ADIDCHK 0
/* CNTLREG3, additional ID check */
#define DEF_FASTSCSI 1
/* CNTLREG3, fast SCSI */
#define DEF_FASTCLK 1
/* CNTLREG3, fast clocking, 5 MB/sec at 40MHz chip clk */
#define DEF_GLITCH 1
/* CNTLREG4, glitch eater, 0=12ns, 1=35ns, 2=25ns, 3=off */
#define DEF_PWD 0
/* CNTLREG4, reduced power feature */
#define DEF_RAE 0
/* CNTLREG4, RAE active negation on REQ, ACK only */
#define DEF_RADE 1
/* 1CNTLREG4, active negation on REQ, ACK and data */
/*** SCSI block ***/
#define CTCLREG 0x00
/* r current transf. count, low byte */
#define CTCMREG 0x04
/* r current transf. count, middle byte */
#define CTCHREG 0x38
/* r current transf. count, high byte */
#define STCLREG 0x00
/* w start transf. count, low byte */
#define STCMREG 0x04
/* w start transf. count, middle byte */
#define STCHREG 0x38
/* w start transf. count, high byte */
#define FFREG 0x08
/* rw SCSI FIFO reg. */
#define STIMREG 0x14
/* w SCSI timeout reg. */
#define SDIDREG 0x10
/* w SCSI destination ID reg. */
#define SDIREG_MASK 0x07
/* mask */
#define STPREG 0x18
/* w synchronous transf. period reg. */
#define STPREG_STP 0x1F
/* synchr. transfer period */
#define CLKFREG 0x24
/* w clock factor reg. */
#define CLKFREG_MASK 0x07
/* mask */
#define CMDREG 0x0C
/* rw SCSI command reg. */
#define CMDREG_DMA 0x80
/* set DMA mode (set together with opcodes below) */
#define CMDREG_IT 0x10
/* information transfer */
#define CMDREG_ICCS 0x11
/* initiator command complete steps */
#define CMDREG_MA 0x12
/* message accepted */
#define CMDREG_TPB 0x98
/* transfer pad bytes, DMA mode only */
#define CMDREG_SATN 0x1A
/* set ATN */
#define CMDREG_RATN 0x1B
/* reset ATN */
#define CMDREG_SOAS 0x41
/* select without ATN steps */
#define CMDREG_SAS 0x42
/* select with ATN steps (1 msg byte) */
#define CMDREG_SASS 0x43
/* select with ATN and stop steps */
#define CMDREG_ESR 0x44
/* enable selection/reselection */
#define CMDREG_DSR 0x45
/* disable selection/reselection */
#define CMDREG_SA3S 0x46
/* select with ATN 3 steps (3 msg bytes) */
#define CMDREG_NOP 0x00
/* no operation */
#define CMDREG_CFIFO 0x01
/* clear FIFO */
#define CMDREG_RDEV 0x02
/* reset device */
#define CMDREG_RBUS 0x03
/* reset SCSI bus */
#define STATREG 0x10
/* r SCSI status reg. */
#define STATREG_INT 0x80
/* SCSI interrupt condition detected */
#define STATREG_IOE 0x40
/* SCSI illegal operation error detected */
#define STATREG_PE 0x20
/* SCSI parity error detected */
#define STATREG_CTZ 0x10
/* CTC reg decremented to zero */
#define STATREG_MSG 0x04
/* SCSI MSG phase (latched?) */
#define STATREG_CD 0x02
/* SCSI C/D phase (latched?) */
#define STATREG_IO 0x01
/* SCSI I/O phase (latched?) */
#define STATREG_PHASE 0x07
/* SCSI phase mask */
#define INSTREG 0x14
/* r interrupt status reg. */
#define INSTREG_SRST 0x80
/* SCSI reset detected */
#define INSTREG_ICMD 0x40
/* SCSI invalid command detected */
#define INSTREG_DIS 0x20
/* target disconnected or sel/resel timeout */
#define INSTREG_SR 0x10
/* device on bus has service request */
#define INSTREG_SO 0x08
/* successful operation */
#define INSTREG_RESEL 0x04
/* device reselected as initiator */
#define ISREG 0x18
/* r internal state reg. */
#define ISREG_SOF 0x08
/* synchronous offset flag (act. low) */
#define ISREG_IS 0x07
/* status of intermediate op. */
#define ISREG_OK_NO_STOP 0x04
/* selection successful */
#define ISREG_OK_STOP 0x01
/* selection successful */
#define CFIREG 0x1C
/* r current FIFO/internal state reg. */
#define CFIREG_IS 0xE0
/* status of intermediate op. */
#define CFIREG_CF 0x1F
/* number of bytes in SCSI FIFO */
#define SOFREG 0x1C
/* w synchr. offset reg. */
#define SOFREG_RAD 0xC0
/* REQ/ACK deassertion delay (sync.) */
#define SOFREG_RAA 0x30
/* REQ/ACK assertion delay (sync.) */
#define SOFREG_SO 0x0F
/* synch. offset (sync.) */
#define CNTLREG1 0x20
/* rw control register one */
#define CNTLREG1_ETM 0x80
/* set extended timing mode */
#define CNTLREG1_DISR 0x40
/* disable interrupt on SCSI reset */
#define CNTLREG1_PERE 0x10
/* enable parity error reporting */
#define CNTLREG1_SID 0x07
/* host adapter SCSI ID */
#define CNTLREG2 0x2C
/* rw control register two */
#define CNTLREG2_ENF 0x40
/* enable features */
#define CNTLREG3 0x30
/* rw control register three */
#define CNTLREG3_ADIDCHK 0x80
/* additional ID check */
#define CNTLREG3_FASTSCSI 0x10
/* fast SCSI */
#define CNTLREG3_FASTCLK 0x08
/* fast SCSI clocking */
#define CNTLREG4 0x34
/* rw control register four */
#define CNTLREG4_GLITCH 0xC0
/* glitch eater */
#define CNTLREG4_PWD 0x20
/* reduced power feature */
#define CNTLREG4_RAE 0x08
/* write only, active negot. ctrl. */
#define CNTLREG4_RADE 0x04
/* active negot. ctrl. */
#define CNTLREG4_RES 0x10
/* reserved bit, must be 1 */
/*** DMA block ***/
#define DMACMD 0x40
/* rw command */
#define DMACMD_DIR 0x80
/* transfer direction (1=read from device) */
#define DMACMD_INTE_D 0x40
/* DMA transfer interrupt enable */
#define DMACMD_INTE_P 0x20
/* page transfer interrupt enable */
#define DMACMD_MDL 0x10
/* map to memory descriptor list */
#define DMACMD_DIAG 0x04
/* diagnostics, set to 0 */
#define DMACMD_IDLE 0x00
/* idle cmd */
#define DMACMD_BLAST 0x01
/* flush FIFO to memory */
#define DMACMD_ABORT 0x02
/* terminate DMA */
#define DMACMD_START 0x03
/* start DMA */
#define DMASTATUS 0x54
/* r status register */
#define DMASTATUS_BCMPLT 0x20
/* BLAST complete */
#define DMASTATUS_SCSIINT 0x10
/* SCSI interrupt pending */
#define DMASTATUS_DONE 0x08
/* DMA transfer terminated */
#define DMASTATUS_ABORT 0x04
/* DMA transfer aborted */
#define DMASTATUS_ERROR 0x02
/* DMA transfer error */
#define DMASTATUS_PWDN 0x02
/* power down indicator */
#define DMASTC 0x44
/* rw starting transfer count */
#define DMASPA 0x48
/* rw starting physical address */
#define DMAWBC 0x4C
/* r working byte counter */
#define DMAWAC 0x50
/* r working address counter */
#define DMASMDLA 0x58
/* rw starting MDL address */
#define DMAWMAC 0x5C
/* r working MDL counter */
/*** SCSI phases ***/
#define PHASE_MSGIN 0x07
#define PHASE_MSGOUT 0x06
#define PHASE_RES_1 0x05
#define PHASE_RES_0 0x04
#define PHASE_STATIN 0x03
#define PHASE_CMDOUT 0x02
#define PHASE_DATAIN 0x01
#define PHASE_DATAOUT 0x00
#define AM53C974_local_declare() unsigned long io_port
#define AM53C974_setio(instance) io_port = instance->io_port
#define AM53C974_read_8(addr) inb(io_port + (addr))
#define AM53C974_write_8(addr,x) outb((x), io_port + (addr))
#define AM53C974_read_16(addr) inw(io_port + (addr))
#define AM53C974_write_16(addr,x) outw((x), io_port + (addr))
#define AM53C974_read_32(addr) inl(io_port + (addr))
#define AM53C974_write_32(addr,x) outl((x), io_port + (addr))
#define AM53C974_poll_int() { do { statreg = AM53C974_read_8(STATREG); } \
while (!(statreg & STATREG_INT)) ; \
AM53C974_read_8(INSTREG) ; }
/* clear int */
#define AM53C974_cfifo() (AM53C974_read_8(CFIREG) & CFIREG_CF)
/* These are "special" values for the tag parameter passed to AM53C974_select. */
#define TAG_NEXT -1
/* Use next free tag */
#define TAG_NONE -2
/* Establish I_T_L nexus instead of I_T_L_Q
* even on SCSI-II devices */
/************ LILO overrides *************/
typedef
struct
_override_t
{
int
host_scsi_id
;
/* SCSI id of the bus controller */
int
target_scsi_id
;
/* SCSI id of target */
int
max_rate
;
/* max. transfer rate */
int
max_offset
;
/* max. sync. offset, 0 = asynchronous */
}
override_t
;
#ifdef AM53C974_DEBUG
static
void
AM53C974_print_phase
(
struct
Scsi_Host
*
instance
);
static
void
AM53C974_print_queues
(
struct
Scsi_Host
*
instance
);
#endif
/* AM53C974_DEBUG */
static
void
AM53C974_print
(
struct
Scsi_Host
*
instance
);
static
void
AM53C974_keywait
(
void
);
static
__inline__
int
AM53C974_pci_detect
(
Scsi_Host_Template
*
tpnt
);
static
int
AM53C974_init
(
Scsi_Host_Template
*
tpnt
,
struct
pci_dev
*
pdev
);
static
void
AM53C974_config_after_reset
(
struct
Scsi_Host
*
instance
);
static
__inline__
void
initialize_SCp
(
Scsi_Cmnd
*
cmd
);
static
__inline__
void
run_main
(
void
);
static
void
AM53C974_main
(
void
);
static
void
AM53C974_intr
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
);
static
void
do_AM53C974_intr
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
);
static
void
AM53C974_intr_disconnect
(
struct
Scsi_Host
*
instance
);
static
int
AM53C974_sync_neg
(
struct
Scsi_Host
*
instance
,
int
target
,
unsigned
char
*
msg
);
static
__inline__
void
AM53C974_set_async
(
struct
Scsi_Host
*
instance
,
int
target
);
static
__inline__
void
AM53C974_set_sync
(
struct
Scsi_Host
*
instance
,
int
target
);
static
void
AM53C974_information_transfer
(
struct
Scsi_Host
*
instance
,
unsigned
char
statreg
,
unsigned
char
isreg
,
unsigned
char
instreg
,
unsigned
char
cfifo
,
unsigned
char
dmastatus
);
static
int
AM53C974_message
(
struct
Scsi_Host
*
instance
,
Scsi_Cmnd
*
cmd
,
unsigned
char
msg
);
static
void
AM53C974_select
(
struct
Scsi_Host
*
instance
,
Scsi_Cmnd
*
cmd
,
int
tag
);
static
void
AM53C974_intr_reselect
(
struct
Scsi_Host
*
instance
,
unsigned
char
statreg
);
static
__inline__
void
AM53C974_transfer_dma
(
struct
Scsi_Host
*
instance
,
short
dir
,
unsigned
long
length
,
char
*
data
);
static
void
AM53C974_dma_blast
(
struct
Scsi_Host
*
instance
,
unsigned
char
dmastatus
,
unsigned
char
statreg
);
static
void
AM53C974_intr_bus_reset
(
struct
Scsi_Host
*
instance
);
static
struct
Scsi_Host
*
first_instance
;
static
Scsi_Host_Template
*
the_template
;
static
struct
Scsi_Host
*
first_host
;
/* Head of list of AMD boards */
static
volatile
int
main_running
;
static
int
commandline_current
;
override_t
overrides
[
7
]
=
{
{
-
1
,
0
,
0
,
0
},};
/* LILO overrides */
#ifdef AM53C974_DEBUG
static
int
deb_stop
=
1
;
static
struct
{
unsigned
char
value
;
char
*
name
;
}
phases
[]
=
{
{
PHASE_DATAOUT
,
"DATAOUT"
},
{
PHASE_DATAIN
,
"DATAIN"
},
{
PHASE_CMDOUT
,
"CMDOUT"
},
{
PHASE_STATIN
,
"STATIN"
},
{
PHASE_MSGOUT
,
"MSGOUT"
},
{
PHASE_MSGIN
,
"MSGIN"
},
{
PHASE_RES_0
,
"RESERVED 0"
},
{
PHASE_RES_1
,
"RESERVED 1"
}
};
/**************************************************************************
* Function : void AM53C974_print_phase(struct Scsi_Host *instance)
*
* Purpose : print the current SCSI phase for debugging purposes
*
* Input : instance - which AM53C974
**************************************************************************/
static
void
AM53C974_print_phase
(
struct
Scsi_Host
*
instance
)
{
AM53C974_local_declare
();
unsigned
char
statreg
,
latched
;
int
i
;
AM53C974_setio
(
instance
);
latched
=
(
AM53C974_read_8
(
CNTLREG2
))
&
CNTLREG2_ENF
;
statreg
=
AM53C974_read_8
(
STATREG
);
for
(
i
=
0
;
(
phases
[
i
].
value
!=
PHASE_RES_1
)
&&
(
phases
[
i
].
value
!=
(
statreg
&
STATREG_PHASE
));
++
i
);
if
(
latched
)
printk
(
"scsi%d : phase %s, latched at end of last command
\n
"
,
instance
->
host_no
,
phases
[
i
].
name
);
else
printk
(
"scsi%d : phase %s, real time
\n
"
,
instance
->
host_no
,
phases
[
i
].
name
);
}
/**************************************************************************
* Function : void AM53C974_print_queues(struct Scsi_Host *instance)
*
* Purpose : print commands in the various queues
*
* Inputs : instance - which AM53C974
**************************************************************************/
static
void
AM53C974_print_queues
(
struct
Scsi_Host
*
instance
)
{
unsigned
long
flags
;
struct
AM53C974_hostdata
*
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
Scsi_Cmnd
*
ptr
;
printk
(
"AM53C974: coroutine is%s running.
\n
"
,
main_running
?
""
:
"n't"
);
save_flags
(
flags
);
cli
();
if
(
!
hostdata
->
connected
)
{
printk
(
"scsi%d: no currently connected command
\n
"
,
instance
->
host_no
);
}
else
{
print_Scsi_Cmnd
((
Scsi_Cmnd
*
)
hostdata
->
connected
);
}
if
(
!
hostdata
->
sel_cmd
)
{
printk
(
"scsi%d: no currently arbitrating command
\n
"
,
instance
->
host_no
);
}
else
{
print_Scsi_Cmnd
((
Scsi_Cmnd
*
)
hostdata
->
sel_cmd
);
}
printk
(
"scsi%d: issue_queue "
,
instance
->
host_no
);
if
(
!
hostdata
->
issue_queue
)
printk
(
"empty
\n
"
);
else
{
printk
(
":
\n
"
);
for
(
ptr
=
(
Scsi_Cmnd
*
)
hostdata
->
issue_queue
;
ptr
;
ptr
=
(
Scsi_Cmnd
*
)
ptr
->
host_scribble
)
print_Scsi_Cmnd
(
ptr
);
}
printk
(
"scsi%d: disconnected_queue "
,
instance
->
host_no
);
if
(
!
hostdata
->
disconnected_queue
)
printk
(
"empty
\n
"
);
else
{
printk
(
":
\n
"
);
for
(
ptr
=
(
Scsi_Cmnd
*
)
hostdata
->
disconnected_queue
;
ptr
;
ptr
=
(
Scsi_Cmnd
*
)
ptr
->
host_scribble
)
print_Scsi_Cmnd
(
ptr
);
}
restore_flags
(
flags
);
}
#endif
/* AM53C974_DEBUG */
/**************************************************************************
* Function : void AM53C974_print(struct Scsi_Host *instance)
*
* Purpose : dump the chip registers for debugging purposes
*
* Input : instance - which AM53C974
**************************************************************************/
static
void
AM53C974_print
(
struct
Scsi_Host
*
instance
)
{
AM53C974_local_declare
();
unsigned
long
flags
;
unsigned
long
ctcreg
,
dmastc
,
dmaspa
,
dmawbc
,
dmawac
;
unsigned
char
cmdreg
,
statreg
,
isreg
,
cfireg
,
cntlreg
[
4
],
dmacmd
,
dmastatus
;
AM53C974_setio
(
instance
);
save_flags
(
flags
);
cli
();
ctcreg
=
AM53C974_read_8
(
CTCHREG
)
<<
16
;
ctcreg
|=
AM53C974_read_8
(
CTCMREG
)
<<
8
;
ctcreg
|=
AM53C974_read_8
(
CTCLREG
);
cmdreg
=
AM53C974_read_8
(
CMDREG
);
statreg
=
AM53C974_read_8
(
STATREG
);
isreg
=
AM53C974_read_8
(
ISREG
);
cfireg
=
AM53C974_read_8
(
CFIREG
);
cntlreg
[
0
]
=
AM53C974_read_8
(
CNTLREG1
);
cntlreg
[
1
]
=
AM53C974_read_8
(
CNTLREG2
);
cntlreg
[
2
]
=
AM53C974_read_8
(
CNTLREG3
);
cntlreg
[
3
]
=
AM53C974_read_8
(
CNTLREG4
);
dmacmd
=
AM53C974_read_8
(
DMACMD
);
dmastc
=
AM53C974_read_32
(
DMASTC
);
dmaspa
=
AM53C974_read_32
(
DMASPA
);
dmawbc
=
AM53C974_read_32
(
DMAWBC
);
dmawac
=
AM53C974_read_32
(
DMAWAC
);
dmastatus
=
AM53C974_read_8
(
DMASTATUS
);
restore_flags
(
flags
);
printk
(
"AM53C974 register dump:
\n
"
);
printk
(
"IO base: 0x%04lx; CTCREG: 0x%04lx; CMDREG: 0x%02x; STATREG: 0x%02x; ISREG: 0x%02x
\n
"
,
io_port
,
ctcreg
,
cmdreg
,
statreg
,
isreg
);
printk
(
"CFIREG: 0x%02x; CNTLREG1-4: 0x%02x; 0x%02x; 0x%02x; 0x%02x
\n
"
,
cfireg
,
cntlreg
[
0
],
cntlreg
[
1
],
cntlreg
[
2
],
cntlreg
[
3
]);
printk
(
"DMACMD: 0x%02x; DMASTC: 0x%04lx; DMASPA: 0x%04lx
\n
"
,
dmacmd
,
dmastc
,
dmaspa
);
printk
(
"DMAWBC: 0x%04lx; DMAWAC: 0x%04lx; DMASTATUS: 0x%02x
\n
"
,
dmawbc
,
dmawac
,
dmastatus
);
printk
(
"---------------------------------------------------------
\n
"
);
}
/**************************************************************************
* Function : void AM53C974_keywait(void)
*
* Purpose : wait until a key is pressed, if it was the 'r' key leave singlestep mode;
* this function is used for debugging only
*
* Input : none
**************************************************************************/
static
void
AM53C974_keywait
(
void
)
{
unsigned
long
flags
;
#ifdef AM53C974_DEBUG
int
key
;
if
(
!
deb_stop
)
return
;
#endif
save_flags
(
flags
);
cli
();
while
((
inb_p
(
0x64
)
&
0x01
)
!=
0x01
);
#ifdef AM53C974_DEBUG
key
=
inb
(
0x60
);
if
(
key
==
0x93
)
deb_stop
=
0
;
/* don't stop if 'r' was pressed */
#endif
restore_flags
(
flags
);
}
#ifndef MODULE
/**************************************************************************
* Function : AM53C974_setup(char *str)
*
* Purpose : LILO command line initialization of the overrides array,
*
* Input : str - parameter string.
*
* Returns : 1.
*
* NOTE : this function needs to be declared as an external function
* in init/main.c and included there in the bootsetups list
***************************************************************************/
static
int
AM53C974_setup
(
char
*
str
)
{
int
ints
[
5
];
get_options
(
str
,
ARRAY_SIZE
(
ints
),
ints
);
if
(
ints
[
0
]
<
4
)
printk
(
"AM53C974_setup: wrong number of parameters;
\n
correct syntax is: AM53C974=host-scsi-id, target-scsi-id, max-rate, max-offset
\n
"
);
else
{
if
(
commandline_current
<
(
sizeof
(
overrides
)
/
sizeof
(
override_t
)))
{
if
((
ints
[
1
]
<
0
)
||
(
ints
[
1
]
>
7
)
||
(
ints
[
2
]
<
0
)
||
(
ints
[
2
]
>
7
)
||
(
ints
[
1
]
==
ints
[
2
])
||
(
ints
[
3
]
<
(
DEF_CLK
/
MAX_PERIOD
))
||
(
ints
[
3
]
>
(
DEF_CLK
/
MIN_PERIOD
))
||
(
ints
[
4
]
<
0
)
||
(
ints
[
4
]
>
MAX_OFFSET
))
printk
(
"AM53C974_setup: invalid parameter
\n
"
);
else
{
overrides
[
commandline_current
].
host_scsi_id
=
ints
[
1
];
overrides
[
commandline_current
].
target_scsi_id
=
ints
[
2
];
overrides
[
commandline_current
].
max_rate
=
ints
[
3
];
overrides
[
commandline_current
].
max_offset
=
ints
[
4
];
commandline_current
++
;
}
}
else
printk
(
"AM53C974_setup: too many overrides
\n
"
);
}
return
1
;
}
__setup
(
"AM53C974="
,
AM53C974_setup
);
#endif
/* !MODULE */
/**************************************************************************
* Function : int AM53C974_pci_detect(Scsi_Host_Template *tpnt)
*
* Purpose : detects and initializes AM53C974 SCSI chips with PCI Bios
*
* Inputs : tpnt - host template
*
* Returns : number of host adapters detected
**************************************************************************/
static
int
__init
AM53C974_pci_detect
(
Scsi_Host_Template
*
tpnt
)
{
int
count
=
0
;
/* number of boards detected */
struct
pci_dev
*
pdev
=
NULL
;
unsigned
short
command
;
while
((
pdev
=
pci_find_device
(
PCI_VENDOR_ID_AMD
,
PCI_DEVICE_ID_AMD_SCSI
,
pdev
)))
{
if
(
pci_enable_device
(
pdev
))
continue
;
pci_read_config_word
(
pdev
,
PCI_COMMAND
,
&
command
);
/* check whether device is I/O mapped -- should be */
if
(
!
(
command
&
PCI_COMMAND_IO
))
continue
;
pci_set_master
(
pdev
);
/* everything seems OK now, so initialize */
if
(
AM53C974_init
(
tpnt
,
pdev
))
count
++
;
}
return
(
count
);
}
/**************************************************************************
* Function : int AM53C974_init(Scsi_Host_Template *tpnt, struct pci_dev *pdev)
*
* Purpose : initializes instance and corresponding AM53/79C974 chip,
*
* Inputs : tpnt - template, pci_config - PCI configuration,
*
* Returns : 1 on success, 0 on failure.
*
* NOTE: If no override for the controller's SCSI id is given and AM53C974_SCSI_ID
* is not defined we assume that the SCSI address of this controller is correctly
* set up by the BIOS (as reflected by contents of register CNTLREG1).
* This is the only BIOS assistance we need.
**************************************************************************/
static
int
__init
AM53C974_init
(
Scsi_Host_Template
*
tpnt
,
struct
pci_dev
*
pdev
)
{
AM53C974_local_declare
();
int
i
,
j
;
struct
Scsi_Host
*
instance
,
*
search
;
struct
AM53C974_hostdata
*
hostdata
;
#ifdef AM53C974_OPTION_DEBUG_PROBE_ONLY
printk
(
"AM53C974: probe only enabled, aborting initialization
\n
"
);
return
0
;
#endif
instance
=
scsi_register
(
tpnt
,
sizeof
(
struct
AM53C974_hostdata
));
if
(
!
instance
)
{
printk
(
KERN_WARNING
"AM53C974: Unable to register host, aborting.
\n
"
);
return
0
;
}
scsi_set_device
(
instance
,
&
pdev
->
dev
);
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
instance
->
base
=
0
;
instance
->
io_port
=
pci_resource_start
(
pdev
,
0
);
instance
->
irq
=
pdev
->
irq
;
instance
->
dma_channel
=
-
1
;
AM53C974_setio
(
instance
);
#ifdef AM53C974_SCSI_ID
instance
->
this_id
=
AM53C974_SCSI_ID
;
AM53C974_write_8
(
CNTLREG1
,
instance
->
this_id
&
CNTLREG1_SID
);
#else
instance
->
this_id
=
AM53C974_read_8
(
CNTLREG1
)
&
CNTLREG1_SID
;
if
(
instance
->
this_id
!=
7
)
printk
(
"scsi%d: WARNING: unusual hostadapter SCSI id %d; please verify!
\n
"
,
instance
->
host_no
,
instance
->
this_id
);
#endif
for
(
i
=
0
;
i
<
sizeof
(
hostdata
->
msgout
);
i
++
)
{
hostdata
->
msgout
[
i
]
=
NOP
;
hostdata
->
last_message
[
i
]
=
NOP
;
}
for
(
i
=
0
;
i
<
8
;
i
++
)
{
hostdata
->
busy
[
i
]
=
0
;
hostdata
->
sync_per
[
i
]
=
DEF_STP
;
hostdata
->
sync_off
[
i
]
=
0
;
hostdata
->
sync_neg
[
i
]
=
0
;
hostdata
->
sync_en
[
i
]
=
DEFAULT_SYNC_NEGOTIATION_ENABLED
;
hostdata
->
max_rate
[
i
]
=
DEFAULT_RATE
;
hostdata
->
max_offset
[
i
]
=
DEFAULT_SYNC_OFFSET
;
}
/* overwrite defaults by LILO overrides */
for
(
i
=
0
;
i
<
commandline_current
;
i
++
)
{
if
(
overrides
[
i
].
host_scsi_id
==
instance
->
this_id
)
{
j
=
overrides
[
i
].
target_scsi_id
;
hostdata
->
sync_en
[
j
]
=
1
;
hostdata
->
max_rate
[
j
]
=
overrides
[
i
].
max_rate
;
hostdata
->
max_offset
[
j
]
=
overrides
[
i
].
max_offset
;
}
}
hostdata
->
sel_cmd
=
NULL
;
hostdata
->
connected
=
NULL
;
hostdata
->
issue_queue
=
NULL
;
hostdata
->
disconnected_queue
=
NULL
;
hostdata
->
in_reset
=
0
;
hostdata
->
aborted
=
0
;
hostdata
->
selecting
=
0
;
hostdata
->
disconnecting
=
0
;
hostdata
->
dma_busy
=
0
;
if
(
!
request_region
(
instance
->
io_port
,
128
,
"AM53C974"
))
{
printk
(
"AM53C974 (scsi%d): Could not get IO region %04lx.
\n
"
,
instance
->
host_no
,
instance
->
io_port
);
scsi_unregister
(
instance
);
return
0
;
}
/* Set up an interrupt handler if we aren't already sharing an IRQ with another board */
for
(
search
=
first_host
;
search
&&
(((
the_template
!=
NULL
)
&&
(
search
->
hostt
!=
the_template
))
||
(
search
->
irq
!=
instance
->
irq
)
||
(
search
==
instance
));
search
=
search
->
next
);
if
(
!
search
)
{
if
(
request_irq
(
instance
->
irq
,
do_AM53C974_intr
,
SA_SHIRQ
,
"AM53C974"
,
instance
))
{
printk
(
"scsi%d: IRQ%d not free, detaching
\n
"
,
instance
->
host_no
,
instance
->
irq
);
scsi_unregister
(
instance
);
return
0
;
}
}
else
{
printk
(
"scsi%d: using interrupt handler previously installed for scsi%d
\n
"
,
instance
->
host_no
,
search
->
host_no
);
}
if
(
!
the_template
)
{
the_template
=
instance
->
hostt
;
first_instance
=
instance
;
}
/* do hard reset */
AM53C974_write_8
(
CMDREG
,
CMDREG_RDEV
);
/* reset device */
udelay
(
5
);
AM53C974_write_8
(
CMDREG
,
CMDREG_NOP
);
AM53C974_write_8
(
CNTLREG1
,
CNTLREG1_DISR
|
instance
->
this_id
);
AM53C974_write_8
(
CMDREG
,
CMDREG_RBUS
);
/* reset SCSI bus */
udelay
(
10
);
AM53C974_config_after_reset
(
instance
);
mdelay
(
500
);
return
(
1
);
}
/*********************************************************************
* Function : AM53C974_config_after_reset(struct Scsi_Host *instance) *
* *
* Purpose : initializes chip registers after reset *
* *
* Inputs : instance - which AM53C974 *
* *
* Returns : nothing *
**********************************************************************/
static
void
AM53C974_config_after_reset
(
struct
Scsi_Host
*
instance
)
{
AM53C974_local_declare
();
AM53C974_setio
(
instance
);
/* clear SCSI FIFO */
AM53C974_write_8
(
CMDREG
,
CMDREG_CFIFO
);
/* configure device */
AM53C974_write_8
(
STIMREG
,
DEF_SCSI_TIMEOUT
);
AM53C974_write_8
(
STPREG
,
DEF_STP
&
STPREG_STP
);
AM53C974_write_8
(
SOFREG
,
(
DEF_SOF_RAD
<<
6
)
|
(
DEF_SOF_RAA
<<
4
));
AM53C974_write_8
(
CLKFREG
,
DEF_CLKF
&
CLKFREG_MASK
);
AM53C974_write_8
(
CNTLREG1
,
(
DEF_ETM
<<
7
)
|
CNTLREG1_DISR
|
(
DEF_PERE
<<
4
)
|
instance
->
this_id
);
AM53C974_write_8
(
CNTLREG2
,
(
DEF_ENF
<<
6
));
AM53C974_write_8
(
CNTLREG3
,
(
DEF_ADIDCHK
<<
7
)
|
(
DEF_FASTSCSI
<<
4
)
|
(
DEF_FASTCLK
<<
3
));
AM53C974_write_8
(
CNTLREG4
,
(
DEF_GLITCH
<<
6
)
|
(
DEF_PWD
<<
5
)
|
(
DEF_RAE
<<
3
)
|
(
DEF_RADE
<<
2
)
|
CNTLREG4_RES
);
}
/***********************************************************************
* Function : const char *AM53C974_info(struct Scsi_Host *instance) *
* *
* Purpose : return device driver information *
* *
* Inputs : instance - which AM53C974 *
* *
* Returns : info string *
************************************************************************/
static
const
char
*
AM53C974_info
(
struct
Scsi_Host
*
instance
)
{
static
char
info
[
100
];
sprintf
(
info
,
"AM53/79C974 PCscsi driver rev. %d.%d; host I/O address: 0x%lx; irq: %d
\n
"
,
AM53C974_DRIVER_REVISION_MAJOR
,
AM53C974_DRIVER_REVISION_MINOR
,
instance
->
io_port
,
instance
->
irq
);
return
(
info
);
}
/**************************************************************************
* Function : void initialize_SCp(Scsi_Cmnd *cmd) *
* *
* Purpose : initialize the saved data pointers for cmd to point to the *
* start of the buffer. *
* *
* Inputs : cmd - Scsi_Cmnd structure to have pointers reset. *
* *
* Returns : nothing *
**************************************************************************/
static
__inline__
void
initialize_SCp
(
Scsi_Cmnd
*
cmd
)
{
if
(
cmd
->
use_sg
)
{
cmd
->
SCp
.
buffer
=
(
struct
scatterlist
*
)
cmd
->
buffer
;
cmd
->
SCp
.
buffers_residual
=
cmd
->
use_sg
-
1
;
cmd
->
SCp
.
ptr
=
(
char
*
)
cmd
->
SCp
.
buffer
->
address
;
cmd
->
SCp
.
this_residual
=
cmd
->
SCp
.
buffer
->
length
;
}
else
{
cmd
->
SCp
.
buffer
=
NULL
;
cmd
->
SCp
.
buffers_residual
=
0
;
cmd
->
SCp
.
ptr
=
(
char
*
)
cmd
->
request_buffer
;
cmd
->
SCp
.
this_residual
=
cmd
->
request_bufflen
;
}
}
/**************************************************************************
* Function : run_main(void) *
* *
* Purpose : insure that the coroutine is running and will process our *
* request. main_running is checked/set here (in an inline *
* function rather than in AM53C974_main itself to reduce the *
* chances of stack overflow. *
* *
* *
* Inputs : none *
* *
* Returns : nothing *
**************************************************************************/
static
__inline__
void
run_main
(
void
)
{
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
if
(
!
main_running
)
{
/* main_running is cleared in AM53C974_main once it can't do
more work, and AM53C974_main exits with interrupts disabled. */
main_running
=
1
;
AM53C974_main
();
}
restore_flags
(
flags
);
}
/**************************************************************************
* Function : int AM53C974_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
*
* Purpose : writes SCSI command into AM53C974 FIFO
*
* Inputs : cmd - SCSI command, done - function called on completion, with
* a pointer to the command descriptor.
*
* Returns : status, see hosts.h for details
*
* Side effects :
* cmd is added to the per instance issue_queue, with minor
* twiddling done to the host specific fields of cmd. If the
* main coroutine is not running, it is restarted.
**************************************************************************/
static
int
AM53C974_queue_command
(
Scsi_Cmnd
*
cmd
,
void
(
*
done
)
(
Scsi_Cmnd
*
))
{
unsigned
long
flags
;
struct
Scsi_Host
*
instance
=
cmd
->
device
->
host
;
struct
AM53C974_hostdata
*
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
Scsi_Cmnd
*
tmp
;
save_flags
(
flags
);
cli
();
DEB_QUEUE
(
printk
(
SEPARATOR_LINE
));
DEB_QUEUE
(
printk
(
"scsi%d: AM53C974_queue_command called
\n
"
,
instance
->
host_no
));
DEB_QUEUE
(
printk
(
"cmd=%02x target=%02x lun=%02x bufflen=%d use_sg = %02x
\n
"
,
cmd
->
cmnd
[
0
],
cmd
->
target
,
cmd
->
device
->
lun
,
cmd
->
request_bufflen
,
cmd
->
use_sg
));
/* We use the host_scribble field as a pointer to the next command in a queue */
cmd
->
host_scribble
=
NULL
;
cmd
->
scsi_done
=
done
;
cmd
->
result
=
0
;
cmd
->
device
->
disconnect
=
0
;
/* Insert the cmd into the issue queue. Note that REQUEST SENSE
* commands are added to the head of the queue since any command will
* clear the contingent allegiance condition that exists and the
* sense data is only guaranteed to be valid while the condition exists. */
if
(
!
(
hostdata
->
issue_queue
)
||
(
cmd
->
cmnd
[
0
]
==
REQUEST_SENSE
))
{
LIST
(
cmd
,
hostdata
->
issue_queue
);
cmd
->
host_scribble
=
(
unsigned
char
*
)
hostdata
->
issue_queue
;
hostdata
->
issue_queue
=
cmd
;
}
else
{
for
(
tmp
=
(
Scsi_Cmnd
*
)
hostdata
->
issue_queue
;
tmp
->
host_scribble
;
tmp
=
(
Scsi_Cmnd
*
)
tmp
->
host_scribble
);
LIST
(
cmd
,
tmp
);
tmp
->
host_scribble
=
(
unsigned
char
*
)
cmd
;
}
DEB_QUEUE
(
printk
(
"scsi%d : command added to %s of queue
\n
"
,
instance
->
host_no
,
(
cmd
->
cmnd
[
0
]
==
REQUEST_SENSE
)
?
"head"
:
"tail"
));
/* Run the coroutine if it isn't already running. */
run_main
();
restore_flags
(
flags
);
return
0
;
}
/**************************************************************************
* Function : AM53C974_main (void)
*
* Purpose : AM53C974_main is a coroutine that runs as long as more work can
* be done on the AM53C974 host adapters in a system. Both
* AM53C974_queue_command() and AM53C974_intr() will try to start it
* in case it is not running.
*
* NOTE : AM53C974_main exits with interrupts *disabled*, the caller should
* reenable them. This prevents reentrancy and kernel stack overflow.
**************************************************************************/
static
void
AM53C974_main
(
void
)
{
AM53C974_local_declare
();
unsigned
long
flags
;
Scsi_Cmnd
*
tmp
,
*
prev
;
struct
Scsi_Host
*
instance
;
struct
AM53C974_hostdata
*
hostdata
;
int
done
;
/* We run (with interrupts disabled) until we're sure that none of
* the host adapters have anything that can be done, at which point
* we set main_running to 0 and exit. */
save_flags
(
flags
);
cli
();
/* Freeze request queues */
do
{
done
=
1
;
for
(
instance
=
first_instance
;
instance
&&
instance
->
hostt
==
the_template
;
instance
=
instance
->
next
)
{
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
AM53C974_setio
(
instance
);
/* start to select target if we are not connected and not in the
selection process */
if
(
!
hostdata
->
connected
&&
!
hostdata
->
sel_cmd
)
{
/* Search through the issue_queue for a command destined for a target
that is not busy. */
for
(
tmp
=
(
Scsi_Cmnd
*
)
hostdata
->
issue_queue
,
prev
=
NULL
;
tmp
;
prev
=
tmp
,
tmp
=
(
Scsi_Cmnd
*
)
tmp
->
host_scribble
)
{
/* When we find one, remove it from the issue queue. */
if
(
!
(
hostdata
->
busy
[
tmp
->
device
->
id
]
&
(
1
<<
tmp
->
device
->
lun
)))
{
if
(
prev
)
{
REMOVE
(
prev
,
(
Scsi_Cmnd
*
)
(
prev
->
host_scribble
),
tmp
,
(
Scsi_Cmnd
*
)
(
tmp
->
host_scribble
));
prev
->
host_scribble
=
tmp
->
host_scribble
;
}
else
{
REMOVE
(
-
1
,
hostdata
->
issue_queue
,
tmp
,
tmp
->
host_scribble
);
hostdata
->
issue_queue
=
(
Scsi_Cmnd
*
)
tmp
->
host_scribble
;
}
tmp
->
host_scribble
=
NULL
;
/* go into selection mode, disable reselection and wait for
SO interrupt which will continue with the selection process */
hostdata
->
selecting
=
1
;
hostdata
->
sel_cmd
=
tmp
;
AM53C974_write_8
(
CMDREG
,
CMDREG_DSR
);
break
;
}
/* if target/lun is not busy */
}
/* for */
}
/* if (!hostdata->connected) */
else
{
DEB
(
printk
(
"main: connected; cmd = 0x%lx, sel_cmd = 0x%lx
\n
"
,
(
long
)
hostdata
->
connected
,
(
long
)
hostdata
->
sel_cmd
));
}
}
/* for instance */
}
while
(
!
done
);
main_running
=
0
;
restore_flags
(
flags
);
}
/************************************************************************
* Function : AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs) *
* *
* Purpose : interrupt handler *
* *
* Inputs : irq - interrupt line, regs - ? *
* *
* Returns : nothing *
************************************************************************/
static
void
do_AM53C974_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
);
AM53C974_intr
(
irq
,
dev_id
,
regs
);
spin_unlock_irqrestore
(
dev
->
host_lock
,
flags
);
}
/************************************************************************
* Function : AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs) *
* *
* Purpose : interrupt handler *
* *
* Inputs : irq - interrupt line, regs - ? *
* *
* Returns : nothing *
************************************************************************/
static
void
AM53C974_intr
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
AM53C974_local_declare
();
struct
Scsi_Host
*
instance
;
struct
AM53C974_hostdata
*
hostdata
;
unsigned
char
cmdreg
,
dmastatus
,
statreg
,
isreg
,
instreg
,
cfifo
;
/* find AM53C974 hostadapter responsible for this interrupt */
for
(
instance
=
first_instance
;
instance
;
instance
=
instance
->
next
)
if
((
instance
->
irq
==
irq
)
&&
(
instance
->
hostt
==
the_template
))
goto
FOUND
;
return
;
/* found; now decode and process */
FOUND:
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
AM53C974_setio
(
instance
);
dmastatus
=
AM53C974_read_8
(
DMASTATUS
);
DEB_INTR
(
printk
(
SEPARATOR_LINE
));
DEB_INTR
(
printk
(
"AM53C974 interrupt; dmastatus=0x%02x
\n
"
,
dmastatus
));
KEYWAIT
();
/*** DMA related interrupts ***/
if
(
hostdata
->
connected
&&
(
dmastatus
&
(
DMASTATUS_ERROR
|
DMASTATUS_PWDN
|
DMASTATUS_ABORT
)))
{
/* DMA error or POWERDOWN */
printk
(
"scsi%d: DMA error or powerdown; dmastatus: 0x%02x
\n
"
,
instance
->
host_no
,
dmastatus
);
#ifdef AM53C974_DEBUG
deb_stop
=
1
;
#endif
panic
(
"scsi%d: cannot recover
\n
"
,
instance
->
host_no
);
}
if
(
hostdata
->
connected
&&
(
dmastatus
&
DMASTATUS_DONE
))
{
/* DMA transfer done */
unsigned
long
residual
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
if
(
!
(
AM53C974_read_8
(
DMACMD
)
&
DMACMD_DIR
))
{
do
{
dmastatus
=
AM53C974_read_8
(
DMASTATUS
);
residual
=
AM53C974_read_8
(
CTCLREG
)
|
(
AM53C974_read_8
(
CTCMREG
)
<<
8
)
|
(
AM53C974_read_8
(
CTCHREG
)
<<
16
);
residual
+=
AM53C974_read_8
(
CFIREG
)
&
CFIREG_CF
;
}
while
(
!
(
dmastatus
&
DMASTATUS_SCSIINT
)
&&
residual
);
residual
=
AM53C974_read_8
(
CTCLREG
)
|
(
AM53C974_read_8
(
CTCMREG
)
<<
8
)
|
(
AM53C974_read_8
(
CTCHREG
)
<<
16
);
residual
+=
AM53C974_read_8
(
CFIREG
)
&
CFIREG_CF
;
}
else
residual
=
0
;
hostdata
->
connected
->
SCp
.
ptr
+=
hostdata
->
connected
->
SCp
.
this_residual
-
residual
;
hostdata
->
connected
->
SCp
.
this_residual
=
residual
;
AM53C974_write_8
(
DMACMD
,
DMACMD_IDLE
);
/* if service request missed before, process it now (ugly) */
if
(
hostdata
->
dma_busy
)
{
hostdata
->
dma_busy
=
0
;
cmdreg
=
AM53C974_read_8
(
CMDREG
);
statreg
=
AM53C974_read_8
(
STATREG
);
isreg
=
AM53C974_read_8
(
ISREG
);
instreg
=
AM53C974_read_8
(
INSTREG
);
cfifo
=
AM53C974_cfifo
();
AM53C974_information_transfer
(
instance
,
statreg
,
isreg
,
instreg
,
cfifo
,
dmastatus
);
}
restore_flags
(
flags
);
}
if
(
!
(
dmastatus
&
DMASTATUS_SCSIINT
))
{
return
;
}
/*** SCSI related interrupts ***/
cmdreg
=
AM53C974_read_8
(
CMDREG
);
statreg
=
AM53C974_read_8
(
STATREG
);
isreg
=
AM53C974_read_8
(
ISREG
);
instreg
=
AM53C974_read_8
(
INSTREG
);
cfifo
=
AM53C974_cfifo
();
DEB_INTR
(
printk
(
"scsi%d: statreg: 0x%02x; isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02x
\n
"
,
instance
->
host_no
,
statreg
,
isreg
,
instreg
,
cfifo
));
if
(
statreg
&
STATREG_PE
)
{
/* parity error */
#ifdef AM53C974_DEBUG
deb_stop
=
1
;
#endif
printk
(
"scsi%d : PARITY error
\n
"
,
instance
->
host_no
);
if
(
hostdata
->
connected
)
hostdata
->
sync_off
[
hostdata
->
connected
->
device
->
id
]
=
0
;
/* setup asynchronous transfer */
hostdata
->
aborted
=
1
;
}
if
(
statreg
&
STATREG_IOE
)
{
/* illegal operation error */
#ifdef AM53C974_DEBUG
deb_stop
=
1
;
#endif
printk
(
"scsi%d : ILLEGAL OPERATION error
\n
"
,
instance
->
host_no
);
printk
(
"cmdreg: 0x%02x; dmacmd: 0x%02x; statreg: 0x%02x;
\n
"
"isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02x
\n
"
,
cmdreg
,
AM53C974_read_8
(
DMACMD
),
statreg
,
isreg
,
instreg
,
cfifo
);
}
if
(
hostdata
->
in_reset
&&
(
instreg
&
INSTREG_SRST
))
{
unsigned
long
flags
;
/* RESET INTERRUPT */
#ifdef AM53C974_DEBUG
deb_stop
=
1
;
#endif
DEB
(
printk
(
"Bus reset interrupt received
\n
"
));
AM53C974_intr_bus_reset
(
instance
);
save_flags
(
flags
);
cli
();
if
(
hostdata
->
connected
)
{
hostdata
->
connected
->
result
=
DID_RESET
<<
16
;
hostdata
->
connected
->
scsi_done
((
Scsi_Cmnd
*
)
hostdata
->
connected
);
hostdata
->
connected
=
NULL
;
}
else
{
if
(
hostdata
->
sel_cmd
)
{
hostdata
->
sel_cmd
->
result
=
DID_RESET
<<
16
;
hostdata
->
sel_cmd
->
scsi_done
((
Scsi_Cmnd
*
)
hostdata
->
sel_cmd
);
hostdata
->
sel_cmd
=
NULL
;
}
}
restore_flags
(
flags
);
if
(
hostdata
->
in_reset
==
1
)
goto
EXIT
;
else
return
;
}
if
(
instreg
&
INSTREG_ICMD
)
{
/* INVALID COMMAND INTERRUPT */
#ifdef AM53C974_DEBUG
deb_stop
=
1
;
#endif
printk
(
"scsi%d: Invalid command interrupt
\n
"
,
instance
->
host_no
);
printk
(
"cmdreg: 0x%02x; dmacmd: 0x%02x; statreg: 0x%02x; dmastatus: 0x%02x;
\n
"
"isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02x
\n
"
,
cmdreg
,
AM53C974_read_8
(
DMACMD
),
statreg
,
dmastatus
,
isreg
,
instreg
,
cfifo
);
panic
(
"scsi%d: cannot recover
\n
"
,
instance
->
host_no
);
}
if
(
instreg
&
INSTREG_DIS
)
{
unsigned
long
flags
;
/* DISCONNECT INTERRUPT */
DEB_INTR
(
printk
(
"Disconnect interrupt received; "
));
save_flags
(
flags
);
cli
();
AM53C974_intr_disconnect
(
instance
);
restore_flags
(
flags
);
goto
EXIT
;
}
if
(
instreg
&
INSTREG_RESEL
)
{
unsigned
long
flags
;
/* RESELECTION INTERRUPT */
DEB_INTR
(
printk
(
"Reselection interrupt received
\n
"
));
save_flags
(
flags
);
cli
();
AM53C974_intr_reselect
(
instance
,
statreg
);
restore_flags
(
flags
);
goto
EXIT
;
}
if
(
instreg
&
INSTREG_SO
)
{
DEB_INTR
(
printk
(
"Successful operation interrupt received
\n
"
));
if
(
hostdata
->
selecting
)
{
unsigned
long
flags
;
DEB_INTR
(
printk
(
"DSR completed, starting select
\n
"
));
save_flags
(
flags
);
cli
();
AM53C974_select
(
instance
,
(
Scsi_Cmnd
*
)
hostdata
->
sel_cmd
,
(
hostdata
->
sel_cmd
->
cmnd
[
0
]
==
REQUEST_SENSE
)
?
TAG_NONE
:
TAG_NEXT
);
hostdata
->
selecting
=
0
;
AM53C974_set_sync
(
instance
,
hostdata
->
sel_cmd
->
device
->
id
);
restore_flags
(
flags
);
return
;
}
if
(
hostdata
->
sel_cmd
!=
NULL
)
{
if
(((
isreg
&
ISREG_IS
)
!=
ISREG_OK_NO_STOP
)
&&
((
isreg
&
ISREG_IS
)
!=
ISREG_OK_STOP
))
{
unsigned
long
flags
;
/* UNSUCCESSFUL SELECTION */
DEB_INTR
(
printk
(
"unsuccessful selection
\n
"
));
save_flags
(
flags
);
cli
();
hostdata
->
dma_busy
=
0
;
LIST
(
hostdata
->
sel_cmd
,
hostdata
->
issue_queue
);
hostdata
->
sel_cmd
->
host_scribble
=
(
unsigned
char
*
)
hostdata
->
issue_queue
;
hostdata
->
issue_queue
=
hostdata
->
sel_cmd
;
hostdata
->
sel_cmd
=
NULL
;
hostdata
->
selecting
=
0
;
restore_flags
(
flags
);
goto
EXIT
;
}
else
{
unsigned
long
flags
;
/* SUCCESSFUL SELECTION */
DEB
(
printk
(
"successful selection; cmd=0x%02lx
\n
"
,
(
long
)
hostdata
->
sel_cmd
));
save_flags
(
flags
);
cli
();
hostdata
->
dma_busy
=
0
;
hostdata
->
disconnecting
=
0
;
hostdata
->
connected
=
hostdata
->
sel_cmd
;
hostdata
->
sel_cmd
=
NULL
;
hostdata
->
selecting
=
0
;
#ifdef SCSI2
if
(
!
hostdata
->
conneted
->
device
->
simple_tags
)
#else
hostdata
->
busy
[
hostdata
->
connected
->
device
->
id
]
|=
(
1
<<
hostdata
->
connected
->
device
->
lun
);
/* very strange -- use_sg is sometimes nonzero for request sense commands !! */
if
((
hostdata
->
connected
->
cmnd
[
0
]
==
REQUEST_SENSE
)
&&
hostdata
->
connected
->
use_sg
)
{
DEB
(
printk
(
"scsi%d: REQUEST_SENSE command with nonzero use_sg
\n
"
,
instance
->
host_no
));
KEYWAIT
();
hostdata
->
connected
->
use_sg
=
0
;
}
initialize_SCp
((
Scsi_Cmnd
*
)
hostdata
->
connected
);
hostdata
->
connected
->
SCp
.
phase
=
PHASE_CMDOUT
;
AM53C974_information_transfer
(
instance
,
statreg
,
isreg
,
instreg
,
cfifo
,
dmastatus
);
restore_flags
(
flags
);
return
;
}
}
else
{
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
AM53C974_information_transfer
(
instance
,
statreg
,
isreg
,
instreg
,
cfifo
,
dmastatus
);
restore_flags
(
flags
);
return
;
}
}
if
(
instreg
&
INSTREG_SR
)
{
DEB_INTR
(
printk
(
"Service request interrupt received, "
));
if
(
hostdata
->
connected
)
{
unsigned
long
flags
;
DEB_INTR
(
printk
(
"calling information_transfer
\n
"
));
save_flags
(
flags
);
cli
();
AM53C974_information_transfer
(
instance
,
statreg
,
isreg
,
instreg
,
cfifo
,
dmastatus
);
restore_flags
(
flags
);
}
else
{
printk
(
"scsi%d: weird: service request when no command connected
\n
"
,
instance
->
host_no
);
AM53C974_write_8
(
CMDREG
,
CMDREG_CFIFO
);
}
/* clear FIFO */
return
;
}
EXIT:
DEB_INTR
(
printk
(
"intr: starting main
\n
"
));
run_main
();
DEB_INTR
(
printk
(
"end of intr
\n
"
));
}
/**************************************************************************
* Function : AM53C974_intr_disconnect(struct Scsi_Host *instance)
*
* Purpose : manage target disconnection
*
* Inputs : instance -- which AM53C974
*
* Returns : nothing
**************************************************************************/
static
void
AM53C974_intr_disconnect
(
struct
Scsi_Host
*
instance
)
{
AM53C974_local_declare
();
struct
AM53C974_hostdata
*
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
Scsi_Cmnd
*
cmd
;
AM53C974_setio
(
instance
);
if
(
hostdata
->
sel_cmd
!=
NULL
)
{
/* normal selection timeout, typical for nonexisting targets */
cmd
=
(
Scsi_Cmnd
*
)
hostdata
->
sel_cmd
;
DEB_INTR
(
printk
(
"bad target
\n
"
));
cmd
->
result
=
DID_BAD_TARGET
<<
16
;
goto
EXIT_FINISHED
;
}
if
(
!
hostdata
->
connected
)
{
/* can happen if controller was reset, a device tried to reconnect,
failed and disconnects now */
AM53C974_write_8
(
CMDREG
,
CMDREG_CFIFO
);
return
;
}
if
(
hostdata
->
disconnecting
)
{
/* target sent disconnect message, so we are prepared */
cmd
=
(
Scsi_Cmnd
*
)
hostdata
->
connected
;
AM53C974_set_async
(
instance
,
cmd
->
device
->
id
);
DEB_INTR
(
printk
(
"scsi%d : disc. from cmnd %d for ta %d, lun %d
\n
"
,
instance
->
host_no
,
cmd
->
cmnd
[
0
],
cmd
->
target
,
cmd
->
device
->
lun
));
if
(
cmd
->
device
->
disconnect
)
{
/* target wants to reselect later */
DEB_INTR
(
printk
(
"ok, re-enabling selection
\n
"
));
LIST
(
cmd
,
hostdata
->
disconnected_queue
);
cmd
->
host_scribble
=
(
unsigned
char
*
)
hostdata
->
disconnected_queue
;
hostdata
->
disconnected_queue
=
cmd
;
DEB_QUEUE
(
printk
(
"scsi%d : command for target %d lun %d this %d was moved from connected to"
" the disconnected_queue
\n
"
,
instance
->
host_no
,
cmd
->
target
,
cmd
->
device
->
lun
,
hostdata
->
disconnected_queue
->
SCp
.
this_residual
));
DEB_QUEUE
(
AM53C974_print_queues
(
instance
));
goto
EXIT_UNFINISHED
;
}
else
{
/* target does not want to reselect later, we are really finished */
#ifdef AM53C974_DEBUG
if
(
cmd
->
cmnd
[
0
]
==
REQUEST_SENSE
)
{
int
i
;
printk
(
"Request sense data dump:
\n
"
);
for
(
i
=
0
;
i
<
cmd
->
request_bufflen
;
i
++
)
{
printk
(
"%02x "
,
*
((
char
*
)
(
cmd
->
request_buffer
)
+
i
));
if
(
i
&&
!
(
i
%
16
))
printk
(
"
\n
"
);
}
printk
(
"
\n
"
);
}
#endif
goto
EXIT_FINISHED
;
}
/* !cmd->device->disconnect */
}
/* if (hostdata->disconnecting) */
/* no disconnect message received; unexpected disconnection */
cmd
=
(
Scsi_Cmnd
*
)
hostdata
->
connected
;
if
(
cmd
)
{
#ifdef AM53C974_DEBUG
deb_stop
=
1
;
#endif
AM53C974_set_async
(
instance
,
cmd
->
device
->
id
);
printk
(
"scsi%d: Unexpected disconnect; phase: %d; target: %d; this_residual: %d; buffers_residual: %d; message: %d
\n
"
,
instance
->
host_no
,
cmd
->
SCp
.
phase
,
cmd
->
device
->
id
,
cmd
->
SCp
.
this_residual
,
cmd
->
SCp
.
buffers_residual
,
cmd
->
SCp
.
Message
);
printk
(
"cmdreg: 0x%02x; statreg: 0x%02x; isreg: 0x%02x; cfifo: 0x%02x
\n
"
,
AM53C974_read_8
(
CMDREG
),
AM53C974_read_8
(
STATREG
),
AM53C974_read_8
(
ISREG
),
AM53C974_read_8
(
CFIREG
)
&
CFIREG_CF
);
if
((
hostdata
->
last_message
[
0
]
==
EXTENDED_MESSAGE
)
&&
(
hostdata
->
last_message
[
2
]
==
EXTENDED_SDTR
))
{
/* sync. negotiation was aborted, setup asynchronous transfer with target */
hostdata
->
sync_off
[
cmd
->
device
->
id
]
=
0
;
}
if
(
hostdata
->
aborted
||
hostdata
->
msgout
[
0
]
==
ABORT
)
cmd
->
result
=
DID_ABORT
<<
16
;
else
cmd
->
result
=
DID_ERROR
<<
16
;
goto
EXIT_FINISHED
;
}
EXIT_FINISHED:
hostdata
->
aborted
=
0
;
hostdata
->
msgout
[
0
]
=
NOP
;
hostdata
->
sel_cmd
=
NULL
;
hostdata
->
connected
=
NULL
;
hostdata
->
selecting
=
0
;
hostdata
->
disconnecting
=
0
;
hostdata
->
dma_busy
=
0
;
hostdata
->
busy
[
cmd
->
device
->
id
]
&=
~
(
1
<<
cmd
->
device
->
lun
);
AM53C974_write_8
(
CMDREG
,
CMDREG_CFIFO
);
DEB
(
printk
(
"disconnect; issue_queue: 0x%lx, disconnected_queue: 0x%lx
\n
"
,
(
long
)
hostdata
->
issue_queue
,
(
long
)
hostdata
->
disconnected_queue
));
cmd
->
scsi_done
(
cmd
);
if
(
!
hostdata
->
selecting
)
{
AM53C974_set_async
(
instance
,
cmd
->
device
->
id
);
AM53C974_write_8
(
CMDREG
,
CMDREG_ESR
);
}
/* allow reselect */
return
;
EXIT_UNFINISHED:
hostdata
->
msgout
[
0
]
=
NOP
;
hostdata
->
sel_cmd
=
NULL
;
hostdata
->
connected
=
NULL
;
hostdata
->
aborted
=
0
;
hostdata
->
selecting
=
0
;
hostdata
->
disconnecting
=
0
;
hostdata
->
dma_busy
=
0
;
DEB
(
printk
(
"disconnect; issue_queue: 0x%lx, disconnected_queue: 0x%lx
\n
"
,
(
long
)
hostdata
->
issue_queue
,
(
long
)
hostdata
->
disconnected_queue
));
if
(
!
hostdata
->
selecting
)
{
AM53C974_set_async
(
instance
,
cmd
->
device
->
id
);
AM53C974_write_8
(
CMDREG
,
CMDREG_ESR
);
}
/* allow reselect */
return
;
}
/**************************************************************************
* Function : int AM53C974_sync_neg(struct Scsi_Host *instance, int target, unsigned char *msg)
*
* Purpose : setup message string for sync. negotiation
*
* Inputs : instance -- which AM53C974
* target -- which SCSI target to deal with
* msg -- input message string
*
* Returns : 0 if parameters accepted or 1 if not accepted
*
* Side effects: hostdata is changed
*
* Note: we assume here that fastclk is enabled
**************************************************************************/
static
int
AM53C974_sync_neg
(
struct
Scsi_Host
*
instance
,
int
target
,
unsigned
char
*
msg
)
{
AM53C974_local_declare
();
struct
AM53C974_hostdata
*
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
int
period
,
offset
,
i
,
rate
,
rate_rem
;
AM53C974_setio
(
instance
);
period
=
(
DEF_CLK
*
msg
[
3
]
*
8
+
1000
)
/
2000
;
if
(
period
<
MIN_PERIOD
)
{
period
=
MIN_PERIOD
;
hostdata
->
msgout
[
3
]
=
period
/
4
;
}
else
if
(
period
>
MAX_PERIOD
)
{
period
=
MAX_PERIOD
;
hostdata
->
msgout
[
3
]
=
period
/
4
;
}
else
hostdata
->
msgout
[
3
]
=
msg
[
3
];
offset
=
msg
[
4
];
if
(
offset
>
MAX_OFFSET
)
offset
=
MAX_OFFSET
;
hostdata
->
msgout
[
4
]
=
offset
;
hostdata
->
sync_per
[
target
]
=
period
;
hostdata
->
sync_off
[
target
]
=
offset
;
for
(
i
=
0
;
i
<
3
;
i
++
)
hostdata
->
msgout
[
i
]
=
msg
[
i
];
if
((
hostdata
->
msgout
[
3
]
!=
msg
[
3
])
||
(
msg
[
4
]
!=
offset
))
return
(
1
);
rate
=
DEF_CLK
/
period
;
rate_rem
=
10
*
(
DEF_CLK
-
period
*
rate
)
/
period
;
if
(
offset
)
printk
(
"
\n
target %d: rate=%d.%d Mhz, synchronous, sync offset=%d bytes
\n
"
,
target
,
rate
,
rate_rem
,
offset
);
else
printk
(
"
\n
target %d: rate=%d.%d Mhz, asynchronous
\n
"
,
target
,
rate
,
rate_rem
);
return
(
0
);
}
/**************************************************************************
* Function : AM53C974_set_async(struct Scsi_Host *instance, int target)
*
* Purpose : put controller into async. mode
*
* Inputs : instance -- which AM53C974
* target -- which SCSI target to deal with
*
* Returns : nothing
**************************************************************************/
static
__inline__
void
AM53C974_set_async
(
struct
Scsi_Host
*
instance
,
int
target
)
{
AM53C974_local_declare
();
struct
AM53C974_hostdata
*
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
AM53C974_setio
(
instance
);
AM53C974_write_8
(
STPREG
,
hostdata
->
sync_per
[
target
]);
AM53C974_write_8
(
SOFREG
,
(
DEF_SOF_RAD
<<
6
)
|
(
DEF_SOF_RAA
<<
4
));
}
/**************************************************************************
* Function : AM53C974_set_sync(struct Scsi_Host *instance, int target)
*
* Purpose : put controller into sync. mode
*
* Inputs : instance -- which AM53C974
* target -- which SCSI target to deal with
*
* Returns : nothing
**************************************************************************/
static
__inline__
void
AM53C974_set_sync
(
struct
Scsi_Host
*
instance
,
int
target
)
{
AM53C974_local_declare
();
struct
AM53C974_hostdata
*
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
AM53C974_setio
(
instance
);
AM53C974_write_8
(
STPREG
,
hostdata
->
sync_per
[
target
]);
AM53C974_write_8
(
SOFREG
,
(
SOFREG_SO
&
hostdata
->
sync_off
[
target
])
|
(
DEF_SOF_RAD
<<
6
)
|
(
DEF_SOF_RAA
<<
4
));
}
/***********************************************************************
* Function : AM53C974_information_transfer(struct Scsi_Host *instance, *
* unsigned char statreg, unsigned char isreg, *
* unsigned char instreg, unsigned char cfifo, *
* unsigned char dmastatus) *
* *
* Purpose : handle phase changes *
* *
* Inputs : instance - which AM53C974 *
* statreg - status register *
* isreg - internal state register *
* instreg - interrupt status register *
* cfifo - number of bytes in FIFO *
* dmastatus - dma status register *
* *
* Returns : nothing *
************************************************************************/
static
void
AM53C974_information_transfer
(
struct
Scsi_Host
*
instance
,
unsigned
char
statreg
,
unsigned
char
isreg
,
unsigned
char
instreg
,
unsigned
char
cfifo
,
unsigned
char
dmastatus
)
{
AM53C974_local_declare
();
struct
AM53C974_hostdata
*
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
Scsi_Cmnd
*
cmd
=
(
Scsi_Cmnd
*
)
hostdata
->
connected
;
int
ret
,
i
,
len
,
residual
=
-
1
;
AM53C974_setio
(
instance
);
DEB_INFO
(
printk
(
SEPARATOR_LINE
));
switch
(
statreg
&
STATREG_PHASE
)
{
/* scsi phase */
case
PHASE_DATAOUT
:
DEB_INFO
(
printk
(
"Dataout phase; cmd=0x%lx, sel_cmd=0x%lx, this_residual=%d, buffers_residual=%d
\n
"
,
(
long
)
hostdata
->
connected
,
(
long
)
hostdata
->
sel_cmd
,
cmd
->
SCp
.
this_residual
,
cmd
->
SCp
.
buffers_residual
));
cmd
->
SCp
.
phase
=
PHASE_DATAOUT
;
goto
PHASE_DATA_IO
;
case
PHASE_DATAIN
:
DEB_INFO
(
printk
(
"Datain phase; cmd=0x%lx, sel_cmd=0x%lx, this_residual=%d, buffers_residual=%d
\n
"
,
(
long
)
hostdata
->
connected
,
(
long
)
hostdata
->
sel_cmd
,
cmd
->
SCp
.
this_residual
,
cmd
->
SCp
.
buffers_residual
));
cmd
->
SCp
.
phase
=
PHASE_DATAIN
;
PHASE_DATA_IO:
if
(
hostdata
->
aborted
)
{
AM53C974_write_8
(
DMACMD
,
DMACMD_IDLE
);
AM53C974_write_8
(
CMDREG
,
CMDREG_CFIFO
);
AM53C974_write_8
(
CMDREG
,
CMDREG_SATN
);
return
;
}
if
((
!
cmd
->
SCp
.
this_residual
)
&&
cmd
->
SCp
.
buffers_residual
)
{
cmd
->
SCp
.
buffer
++
;
cmd
->
SCp
.
buffers_residual
--
;
cmd
->
SCp
.
ptr
=
(
unsigned
char
*
)
cmd
->
SCp
.
buffer
->
address
;
cmd
->
SCp
.
this_residual
=
cmd
->
SCp
.
buffer
->
length
;
}
if
(
cmd
->
SCp
.
this_residual
)
{
if
(
!
(
AM53C974_read_8
(
DMACMD
)
&
DMACMD_START
))
{
hostdata
->
dma_busy
=
0
;
AM53C974_transfer_dma
(
instance
,
statreg
&
STATREG_IO
,
(
unsigned
long
)
cmd
->
SCp
.
this_residual
,
cmd
->
SCp
.
ptr
);
}
else
hostdata
->
dma_busy
=
1
;
}
return
;
case
PHASE_MSGIN
:
DEB_INFO
(
printk
(
"Message-In phase; cmd=0x%lx, sel_cmd=0x%lx
\n
"
,
(
long
)
hostdata
->
connected
,
(
long
)
hostdata
->
sel_cmd
));
AM53C974_set_async
(
instance
,
cmd
->
device
->
id
);
if
(
cmd
->
SCp
.
phase
==
PHASE_DATAIN
)
AM53C974_dma_blast
(
instance
,
dmastatus
,
statreg
);
if
((
cmd
->
SCp
.
phase
==
PHASE_DATAOUT
)
&&
(
AM53C974_read_8
(
DMACMD
)
&
DMACMD_START
))
{
AM53C974_write_8
(
DMACMD
,
DMACMD_IDLE
);
residual
=
cfifo
+
(
AM53C974_read_8
(
CTCLREG
)
|
(
AM53C974_read_8
(
CTCMREG
)
<<
8
)
|
(
AM53C974_read_8
(
CTCHREG
)
<<
16
));
cmd
->
SCp
.
ptr
+=
cmd
->
SCp
.
this_residual
-
residual
;
cmd
->
SCp
.
this_residual
=
residual
;
if
(
cfifo
)
{
AM53C974_write_8
(
CMDREG
,
CMDREG_CFIFO
);
cfifo
=
0
;
}
}
if
(
cmd
->
SCp
.
phase
==
PHASE_STATIN
)
{
while
((
AM53C974_read_8
(
CFIREG
)
&
CFIREG_CF
)
<
2
);
cmd
->
SCp
.
Status
=
AM53C974_read_8
(
FFREG
);
cmd
->
SCp
.
Message
=
AM53C974_read_8
(
FFREG
);
DEB_INFO
(
printk
(
"Message-In phase; status=0x%02x, message=0x%02x
\n
"
,
cmd
->
SCp
.
Status
,
cmd
->
SCp
.
Message
));
ret
=
AM53C974_message
(
instance
,
cmd
,
cmd
->
SCp
.
Message
);
}
else
{
if
(
!
cfifo
)
{
AM53C974_write_8
(
CMDREG
,
CMDREG_IT
);
AM53C974_poll_int
();
cmd
->
SCp
.
Message
=
AM53C974_read_8
(
FFREG
);
}
ret
=
AM53C974_message
(
instance
,
cmd
,
cmd
->
SCp
.
Message
);
}
cmd
->
SCp
.
phase
=
PHASE_MSGIN
;
AM53C974_set_sync
(
instance
,
cmd
->
device
->
id
);
break
;
case
PHASE_MSGOUT
:
DEB_INFO
(
printk
(
"Message-Out phase; cfifo=%d; msgout[0]=0x%02x
\n
"
,
AM53C974_read_8
(
CFIREG
)
&
CFIREG_CF
,
hostdata
->
msgout
[
0
]));
AM53C974_write_8
(
DMACMD
,
DMACMD_IDLE
);
AM53C974_set_async
(
instance
,
cmd
->
device
->
id
);
for
(
i
=
0
;
i
<
sizeof
(
hostdata
->
last_message
);
i
++
)
hostdata
->
last_message
[
i
]
=
hostdata
->
msgout
[
i
];
if
((
hostdata
->
msgout
[
0
]
==
0
)
||
INSIDE
(
hostdata
->
msgout
[
0
],
0x02
,
0x1F
)
||
INSIDE
(
hostdata
->
msgout
[
0
],
0x80
,
0xFF
))
len
=
1
;
else
{
if
(
hostdata
->
msgout
[
0
]
==
EXTENDED_MESSAGE
)
{
#ifdef AM53C974_DEBUG_INFO
printk
(
"Extended message dump:
\n
"
);
for
(
i
=
0
;
i
<
hostdata
->
msgout
[
1
]
+
2
;
i
++
)
{
printk
(
"%02x "
,
hostdata
->
msgout
[
i
]);
if
(
i
&&
!
(
i
%
16
))
printk
(
"
\n
"
);
}
printk
(
"
\n
"
);
#endif
len
=
hostdata
->
msgout
[
1
]
+
2
;
}
else
len
=
2
;
}
for
(
i
=
0
;
i
<
len
;
i
++
)
AM53C974_write_8
(
FFREG
,
hostdata
->
msgout
[
i
]);
AM53C974_write_8
(
CMDREG
,
CMDREG_IT
);
cmd
->
SCp
.
phase
=
PHASE_MSGOUT
;
hostdata
->
msgout
[
0
]
=
NOP
;
AM53C974_set_sync
(
instance
,
cmd
->
device
->
id
);
break
;
case
PHASE_CMDOUT
:
DEB_INFO
(
printk
(
"Command-Out phase
\n
"
));
AM53C974_set_async
(
instance
,
cmd
->
device
->
id
);
for
(
i
=
0
;
i
<
cmd
->
cmd_len
;
i
++
)
AM53C974_write_8
(
FFREG
,
cmd
->
cmnd
[
i
]);
AM53C974_write_8
(
CMDREG
,
CMDREG_IT
);
cmd
->
SCp
.
phase
=
PHASE_CMDOUT
;
AM53C974_set_sync
(
instance
,
cmd
->
device
->
id
);
break
;
case
PHASE_STATIN
:
DEB_INFO
(
printk
(
"Status phase
\n
"
));
if
(
cmd
->
SCp
.
phase
==
PHASE_DATAIN
)
AM53C974_dma_blast
(
instance
,
dmastatus
,
statreg
);
AM53C974_set_async
(
instance
,
cmd
->
device
->
id
);
if
(
cmd
->
SCp
.
phase
==
PHASE_DATAOUT
)
{
unsigned
long
residual
;
if
(
AM53C974_read_8
(
DMACMD
)
&
DMACMD_START
)
{
AM53C974_write_8
(
DMACMD
,
DMACMD_IDLE
);
residual
=
cfifo
+
(
AM53C974_read_8
(
CTCLREG
)
|
(
AM53C974_read_8
(
CTCMREG
)
<<
8
)
|
(
AM53C974_read_8
(
CTCHREG
)
<<
16
));
cmd
->
SCp
.
ptr
+=
cmd
->
SCp
.
this_residual
-
residual
;
cmd
->
SCp
.
this_residual
=
residual
;
}
if
(
cfifo
)
{
AM53C974_write_8
(
CMDREG
,
CMDREG_CFIFO
);
cfifo
=
0
;
}
}
cmd
->
SCp
.
phase
=
PHASE_STATIN
;
AM53C974_write_8
(
CMDREG
,
CMDREG_ICCS
);
/* command complete */
break
;
case
PHASE_RES_0
:
case
PHASE_RES_1
:
#ifdef AM53C974_DEBUG
deb_stop
=
1
;
#endif
DEB_INFO
(
printk
(
"Reserved phase
\n
"
));
break
;
}
KEYWAIT
();
}
/******************************************************************************
* Function : int AM53C974_message(struct Scsi_Host *instance, Scsi_Cmnd *cmd,
* unsigned char msg)
*
* Purpose : handle SCSI messages
*
* Inputs : instance -- which AM53C974
* cmd -- SCSI command the message belongs to
* msg -- message id byte
*
* Returns : 1 on success, 0 on failure.
**************************************************************************/
static
int
AM53C974_message
(
struct
Scsi_Host
*
instance
,
Scsi_Cmnd
*
cmd
,
unsigned
char
msg
)
{
AM53C974_local_declare
();
static
unsigned
char
extended_msg
[
10
];
unsigned
char
statreg
;
int
len
,
ret
=
0
;
unsigned
char
*
p
;
#ifdef AM53C974_DEBUG_MSG
int
j
;
#endif
struct
AM53C974_hostdata
*
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
AM53C974_setio
(
instance
);
DEB_MSG
(
printk
(
SEPARATOR_LINE
));
/* Linking lets us reduce the time required to get the
* next command out to the device, hopefully this will
* mean we don't waste another revolution due to the delays
* required by ARBITRATION and another SELECTION.
* In the current implementation proposal, low level drivers
* merely have to start the next command, pointed to by
* next_link, done() is called as with unlinked commands. */
switch
(
msg
)
{
#ifdef LINKED
case
LINKED_CMD_COMPLETE
:
case
LINKED_FLG_CMD_COMPLETE
:
/* Accept message by releasing ACK */
DEB_LINKED
(
printk
(
"scsi%d : target %d lun %d linked command complete.
\n
"
,
instance
->
host_no
,
cmd
->
device
->
id
,
cmd
->
device
->
lun
));
/* Sanity check : A linked command should only terminate with
* one of these messages if there are more linked commands available. */
if
(
!
cmd
->
next_link
)
{
printk
(
"scsi%d : target %d lun %d linked command complete, no next_link
\n
"
instance
->
host_no
,
cmd
->
device
->
id
,
cmd
->
device
->
lun
);
hostdata
->
aborted
=
1
;
AM53C974_write_8
(
CMDREG
,
CMDREG_SATN
);
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
break
;
}
if
(
hostdata
->
aborted
)
{
DEB_ABORT
(
printk
(
"ATN set for cmnd %d upon reception of LINKED_CMD_COMPLETE or"
"LINKED_FLG_CMD_COMPLETE message
\n
"
,
cmd
->
cmnd
[
0
]));
AM53C974_write_8
(
CMDREG
,
CMDREG_SATN
);
}
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
initialize_SCp
(
cmd
->
next_link
);
/* The next command is still part of this process */
cmd
->
next_link
->
tag
=
cmd
->
tag
;
cmd
->
result
=
cmd
->
SCp
.
Status
|
(
cmd
->
SCp
.
Message
<<
8
);
DEB_LINKED
(
printk
(
"scsi%d : target %d lun %d linked request done, calling scsi_done().
\n
"
,
instance
->
host_no
,
cmd
->
device
->
id
,
cmd
->
device
->
lun
));
cmd
->
scsi_done
(
cmd
);
cmd
=
hostdata
->
connected
;
break
;
#endif
/* def LINKED */
case
ABORT
:
case
COMMAND_COMPLETE
:
DEB_MSG
(
printk
(
"scsi%d: command complete message received; cmd %d for target %d, lun %d
\n
"
,
instance
->
host_no
,
cmd
->
cmnd
[
0
],
cmd
->
device
->
id
,
cmd
->
device
->
lun
));
hostdata
->
disconnecting
=
1
;
cmd
->
device
->
disconnect
=
0
;
/* I'm not sure what the correct thing to do here is :
* If the command that just executed is NOT a request
* sense, the obvious thing to do is to set the result
* code to the values of the stored parameters.
* If it was a REQUEST SENSE command, we need some way
* to differentiate between the failure code of the original
* and the failure code of the REQUEST sense - the obvious
* case is success, where we fall through and leave the result
* code unchanged.
*
* The non-obvious place is where the REQUEST SENSE failed */
if
(
cmd
->
cmnd
[
0
]
!=
REQUEST_SENSE
)
cmd
->
result
=
cmd
->
SCp
.
Status
|
(
cmd
->
SCp
.
Message
<<
8
);
else
if
(
cmd
->
SCp
.
Status
!=
GOOD
)
cmd
->
result
=
(
cmd
->
result
&
0x00ffff
)
|
(
DID_ERROR
<<
16
);
if
(
hostdata
->
aborted
)
{
AM53C974_write_8
(
CMDREG
,
CMDREG_SATN
);
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
DEB_ABORT
(
printk
(
"ATN set for cmnd %d upon reception of ABORT or"
"COMMAND_COMPLETE message
\n
"
,
cmd
->
cmnd
[
0
]));
break
;
}
if
((
cmd
->
cmnd
[
0
]
!=
REQUEST_SENSE
)
&&
(
cmd
->
SCp
.
Status
==
CHECK_CONDITION
))
{
DEB_MSG
(
printk
(
"scsi%d : performing request sense
\n
"
,
instance
->
host_no
));
cmd
->
cmnd
[
0
]
=
REQUEST_SENSE
;
cmd
->
cmnd
[
1
]
&=
0xe0
;
cmd
->
cmnd
[
2
]
=
0
;
cmd
->
cmnd
[
3
]
=
0
;
cmd
->
cmnd
[
4
]
=
sizeof
(
cmd
->
sense_buffer
);
cmd
->
cmnd
[
5
]
=
0
;
cmd
->
SCp
.
buffer
=
NULL
;
cmd
->
SCp
.
buffers_residual
=
0
;
cmd
->
SCp
.
ptr
=
(
char
*
)
cmd
->
sense_buffer
;
cmd
->
SCp
.
this_residual
=
sizeof
(
cmd
->
sense_buffer
);
LIST
(
cmd
,
hostdata
->
issue_queue
);
cmd
->
host_scribble
=
(
unsigned
char
*
)
hostdata
->
issue_queue
;
hostdata
->
issue_queue
=
(
Scsi_Cmnd
*
)
cmd
;
DEB_MSG
(
printk
(
"scsi%d : REQUEST SENSE added to head of issue queue
\n
"
,
instance
->
host_no
));
}
/* Accept message by clearing ACK */
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
break
;
case
MESSAGE_REJECT
:
DEB_MSG
(
printk
(
"scsi%d: reject message received; cmd %d for target %d, lun %d
\n
"
,
instance
->
host_no
,
cmd
->
cmnd
[
0
],
cmd
->
device
->
id
,
cmd
->
device
->
lun
));
switch
(
hostdata
->
last_message
[
0
])
{
case
EXTENDED_MESSAGE
:
if
(
hostdata
->
last_message
[
2
]
==
EXTENDED_SDTR
)
{
/* sync. negotiation was rejected, setup asynchronous transfer with target */
printk
(
"
\n
target %d: rate=%d Mhz, asynchronous (sync. negotiation rejected)
\n
"
,
cmd
->
device
->
id
,
DEF_CLK
/
DEF_STP
);
hostdata
->
sync_off
[
cmd
->
device
->
id
]
=
0
;
hostdata
->
sync_per
[
cmd
->
device
->
id
]
=
DEF_STP
;
}
break
;
case
HEAD_OF_QUEUE_TAG
:
case
ORDERED_QUEUE_TAG
:
case
SIMPLE_QUEUE_TAG
:
cmd
->
device
->
simple_tags
=
0
;
hostdata
->
busy
[
cmd
->
device
->
id
]
|=
(
1
<<
cmd
->
device
->
lun
);
break
;
default:
break
;
}
if
(
hostdata
->
aborted
)
AM53C974_write_8
(
CMDREG
,
CMDREG_SATN
);
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
break
;
case
DISCONNECT
:
DEB_MSG
(
printk
(
"scsi%d: disconnect message received; cmd %d for target %d, lun %d
\n
"
,
instance
->
host_no
,
cmd
->
cmnd
[
0
],
cmd
->
device
->
id
,
cmd
->
device
->
lun
));
cmd
->
device
->
disconnect
=
1
;
hostdata
->
disconnecting
=
1
;
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
/* Accept message by clearing ACK */
break
;
case
SAVE_POINTERS
:
case
RESTORE_POINTERS
:
DEB_MSG
(
printk
(
"scsi%d: save/restore pointers message received; cmd %d for target %d, lun %d
\n
"
,
instance
->
host_no
,
cmd
->
cmnd
[
0
],
cmd
->
device
->
id
,
cmd
->
device
->
lun
));
/* The SCSI data pointer is *IMPLICITLY* saved on a disconnect
* operation, in violation of the SCSI spec so we can safely
* ignore SAVE/RESTORE pointers calls.
*
* Unfortunately, some disks violate the SCSI spec and
* don't issue the required SAVE_POINTERS message before
* disconnecting, and we have to break spec to remain
* compatible. */
if
(
hostdata
->
aborted
)
{
DEB_ABORT
(
printk
(
"ATN set for cmnd %d upon reception of SAVE/REST. POINTERS message
\n
"
,
cmd
->
cmnd
[
0
]));
AM53C974_write_8
(
CMDREG
,
CMDREG_SATN
);
}
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
break
;
case
EXTENDED_MESSAGE
:
DEB_MSG
(
printk
(
"scsi%d: extended message received; cmd %d for target %d, lun %d
\n
"
,
instance
->
host_no
,
cmd
->
cmnd
[
0
],
cmd
->
device
->
id
,
cmd
->
device
->
lun
));
/* Extended messages are sent in the following format :
* Byte
* 0 EXTENDED_MESSAGE == 1
* 1 length (includes one byte for code, doesn't include first two bytes)
* 2 code
* 3..length+1 arguments
*/
/* BEWARE!! THIS CODE IS EXTREMELY UGLY */
extended_msg
[
0
]
=
EXTENDED_MESSAGE
;
AM53C974_read_8
(
INSTREG
);
/* clear int */
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
/* ack. msg byte, then wait for SO */
AM53C974_poll_int
();
/* get length */
AM53C974_write_8
(
CMDREG
,
CMDREG_IT
);
AM53C974_poll_int
();
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
/* ack. msg byte, then wait for SO */
AM53C974_poll_int
();
extended_msg
[
1
]
=
len
=
AM53C974_read_8
(
FFREG
);
/* get length */
p
=
extended_msg
+
2
;
/* read the remaining (len) bytes */
while
(
len
)
{
AM53C974_write_8
(
CMDREG
,
CMDREG_IT
);
AM53C974_poll_int
();
if
(
len
>
1
)
{
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
/* ack. msg byte, then wait for SO */
AM53C974_poll_int
();
}
*
p
=
AM53C974_read_8
(
FFREG
);
p
++
;
len
--
;
}
#ifdef AM53C974_DEBUG_MSG
printk
(
"scsi%d: received extended message: "
,
instance
->
host_no
);
for
(
j
=
0
;
j
<
extended_msg
[
1
]
+
2
;
j
++
)
{
printk
(
"0x%02x "
,
extended_msg
[
j
]);
if
(
j
&&
!
(
j
%
16
))
printk
(
"
\n
"
);
}
printk
(
"
\n
"
);
#endif
/* check message */
if
(
extended_msg
[
2
]
==
EXTENDED_SDTR
)
ret
=
AM53C974_sync_neg
(
instance
,
cmd
->
device
->
id
,
extended_msg
);
if
(
ret
||
hostdata
->
aborted
)
AM53C974_write_8
(
CMDREG
,
CMDREG_SATN
);
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
break
;
default:
printk
(
"scsi%d: unknown message 0x%02x received
\n
"
,
instance
->
host_no
,
msg
);
#ifdef AM53C974_DEBUG
deb_stop
=
1
;
#endif
/* reject message */
hostdata
->
msgout
[
0
]
=
MESSAGE_REJECT
;
AM53C974_write_8
(
CMDREG
,
CMDREG_SATN
);
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
return
(
0
);
break
;
}
/* switch (msg) */
KEYWAIT
();
return
(
1
);
}
/**************************************************************************
* Function : AM53C974_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
*
* Purpose : try to establish nexus for the command;
* start sync negotiation via start stop and transfer the command in
* cmdout phase in case of an inquiry or req. sense command with no
* sync. neg. performed yet
*
* Inputs : instance -- which AM53C974
* cmd -- command which requires the selection
* tag -- tagged queueing
*
* Returns : nothing
*
* Note: this function initializes the selection process, which is continued
* in the interrupt handler
**************************************************************************/
static
void
AM53C974_select
(
struct
Scsi_Host
*
instance
,
Scsi_Cmnd
*
cmd
,
int
tag
)
{
AM53C974_local_declare
();
struct
AM53C974_hostdata
*
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
unsigned
char
cfifo
,
tmp
[
3
];
unsigned
int
i
,
len
,
cmd_size
=
COMMAND_SIZE
(
cmd
->
cmnd
[
0
]);
AM53C974_setio
(
instance
);
cfifo
=
AM53C974_cfifo
();
if
(
cfifo
)
{
printk
(
"scsi%d: select error; %d residual bytes in FIFO
\n
"
,
instance
->
host_no
,
cfifo
);
AM53C974_write_8
(
CMDREG
,
CMDREG_CFIFO
);
/* clear FIFO */
}
#ifdef AM53C974_PROHIBIT_DISCONNECT
tmp
[
0
]
=
IDENTIFY
(
0
,
cmd
->
device
->
lun
);
#else
tmp
[
0
]
=
IDENTIFY
(
1
,
cmd
->
device
->
lun
);
#endif
#ifdef SCSI2
if
(
cmd
->
device
->
simple_tags
&&
(
tag
!=
TAG_NONE
))
{
tmp
[
1
]
=
SIMPLE_QUEUE_TAG
;
if
(
tag
==
TAG_NEXT
)
{
/* 0 is TAG_NONE, used to imply no tag for this command */
if
(
cmd
->
device
->
current_tag
==
0
)
cmd
->
device
->
current_tag
=
1
;
cmd
->
tag
=
cmd
->
device
->
current_tag
;
cmd
->
device
->
current_tag
++
;
}
else
cmd
->
tag
=
(
unsigned
char
)
tag
;
tmp
[
2
]
=
cmd
->
tag
;
hostdata
->
last_message
[
0
]
=
SIMPLE_QUEUE_TAG
;
len
=
3
;
AM53C974_write_8
(
FFREG
,
tmp
[
0
]);
AM53C974_write_8
(
FFREG
,
tmp
[
1
]);
AM53C974_write_8
(
FFREG
,
tmp
[
2
]);
}
else
#endif
/* def SCSI2 */
{
len
=
1
;
AM53C974_write_8
(
FFREG
,
tmp
[
0
]);
cmd
->
tag
=
0
;
}
/* in case of an inquiry or req. sense command with no sync. neg performed yet, we start
sync negotiation via start stops and transfer the command in cmdout phase */
if
(((
cmd
->
cmnd
[
0
]
==
INQUIRY
)
||
(
cmd
->
cmnd
[
0
]
==
REQUEST_SENSE
))
&&
!
(
hostdata
->
sync_neg
[
cmd
->
device
->
id
])
&&
hostdata
->
sync_en
[
cmd
->
device
->
id
])
{
hostdata
->
sync_neg
[
cmd
->
device
->
id
]
=
1
;
hostdata
->
msgout
[
0
]
=
EXTENDED_MESSAGE
;
hostdata
->
msgout
[
1
]
=
3
;
hostdata
->
msgout
[
2
]
=
EXTENDED_SDTR
;
hostdata
->
msgout
[
3
]
=
250
/
(
int
)
hostdata
->
max_rate
[
cmd
->
device
->
id
];
hostdata
->
msgout
[
4
]
=
hostdata
->
max_offset
[
cmd
->
device
->
id
];
len
+=
5
;
}
AM53C974_write_8
(
SDIDREG
,
SDIREG_MASK
&
cmd
->
device
->
id
);
/* setup dest. id */
AM53C974_write_8
(
STIMREG
,
DEF_SCSI_TIMEOUT
);
/* setup timeout reg */
switch
(
len
)
{
case
1
:
for
(
i
=
0
;
i
<
cmd_size
;
i
++
)
AM53C974_write_8
(
FFREG
,
cmd
->
cmnd
[
i
]);
AM53C974_write_8
(
CMDREG
,
CMDREG_SAS
);
/* select with ATN, 1 msg byte */
hostdata
->
msgout
[
0
]
=
NOP
;
break
;
case
3
:
for
(
i
=
0
;
i
<
cmd_size
;
i
++
)
AM53C974_write_8
(
FFREG
,
cmd
->
cmnd
[
i
]);
AM53C974_write_8
(
CMDREG
,
CMDREG_SA3S
);
/* select with ATN, 3 msg bytes */
hostdata
->
msgout
[
0
]
=
NOP
;
break
;
default:
AM53C974_write_8
(
CMDREG
,
CMDREG_SASS
);
/* select with ATN, stop steps; continue in message out phase */
break
;
}
}
/**************************************************************************
* Function : AM53C974_intr_select(struct Scsi_Host *instance, unsigned char statreg)
*
* Purpose : handle reselection
*
* Inputs : instance -- which AM53C974
* statreg -- status register
*
* Returns : nothing
*
* side effects: manipulates hostdata
**************************************************************************/
static
void
AM53C974_intr_reselect
(
struct
Scsi_Host
*
instance
,
unsigned
char
statreg
)
{
AM53C974_local_declare
();
struct
AM53C974_hostdata
*
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
unsigned
char
cfifo
,
msg
[
3
],
lun
,
t
,
target
=
0
;
#ifdef SCSI2
unsigned
char
tag
;
#endif
Scsi_Cmnd
*
tmp
=
NULL
,
*
prev
;
AM53C974_setio
(
instance
);
cfifo
=
AM53C974_cfifo
();
if
(
hostdata
->
selecting
)
{
/* caught reselect interrupt in selection process;
put selecting command back into the issue queue and continue with the
reselecting command */
DEB_RESEL
(
printk
(
"AM53C974_intr_reselect: in selection process
\n
"
));
LIST
(
hostdata
->
sel_cmd
,
hostdata
->
issue_queue
);
hostdata
->
sel_cmd
->
host_scribble
=
(
unsigned
char
*
)
hostdata
->
issue_queue
;
hostdata
->
issue_queue
=
hostdata
->
sel_cmd
;
hostdata
->
sel_cmd
=
NULL
;
hostdata
->
selecting
=
0
;
}
/* 2 bytes must be in the FIFO now */
if
(
cfifo
!=
2
)
{
printk
(
"scsi %d: error: %d bytes in fifo, 2 expected
\n
"
,
instance
->
host_no
,
cfifo
);
hostdata
->
aborted
=
1
;
goto
EXIT_ABORT
;
}
/* determine target which reselected */
t
=
AM53C974_read_8
(
FFREG
);
if
(
!
(
t
&
(
1
<<
instance
->
this_id
)))
{
printk
(
"scsi %d: error: invalid host id
\n
"
,
instance
->
host_no
);
hostdata
->
aborted
=
1
;
goto
EXIT_ABORT
;
}
t
^=
(
1
<<
instance
->
this_id
);
target
=
0
;
while
(
t
!=
1
)
{
t
>>=
1
;
target
++
;
}
DEB_RESEL
(
printk
(
"scsi %d: reselect; target: %d
\n
"
,
instance
->
host_no
,
target
));
if
(
hostdata
->
aborted
)
goto
EXIT_ABORT
;
if
((
statreg
&
STATREG_PHASE
)
!=
PHASE_MSGIN
)
{
printk
(
"scsi %d: error: upon reselection interrupt not in MSGIN
\n
"
,
instance
->
host_no
);
hostdata
->
aborted
=
1
;
goto
EXIT_ABORT
;
}
msg
[
0
]
=
AM53C974_read_8
(
FFREG
);
if
(
!
(
msg
[
0
]
&
0x80
))
{
printk
(
"scsi%d: error: expecting IDENTIFY message, got "
,
instance
->
host_no
);
print_msg
(
msg
);
hostdata
->
aborted
=
1
;
goto
EXIT_ABORT
;
}
lun
=
(
msg
[
0
]
&
0x07
);
/* We need to add code for SCSI-II to track which devices have
* I_T_L_Q nexuses established, and which have simple I_T_L
* nexuses so we can chose to do additional data transfer. */
#ifdef SCSI2
#error "SCSI-II tagged queueing is not supported yet"
#endif
/* Find the command corresponding to the I_T_L or I_T_L_Q nexus we
* just reestablished, and remove it from the disconnected queue. */
for
(
tmp
=
(
Scsi_Cmnd
*
)
hostdata
->
disconnected_queue
,
prev
=
NULL
;
tmp
;
prev
=
tmp
,
tmp
=
(
Scsi_Cmnd
*
)
tmp
->
host_scribble
)
if
((
target
==
tmp
->
device
->
id
)
&&
(
lun
==
tmp
->
device
->
lun
)
#ifdef SCSI2
&&
(
tag
==
tmp
->
tag
)
#endif
)
{
if
(
prev
)
{
REMOVE
(
prev
,
(
Scsi_Cmnd
*
)
(
prev
->
host_scribble
),
tmp
,
(
Scsi_Cmnd
*
)
(
tmp
->
host_scribble
));
prev
->
host_scribble
=
tmp
->
host_scribble
;
}
else
{
REMOVE
(
-
1
,
hostdata
->
disconnected_queue
,
tmp
,
tmp
->
host_scribble
);
hostdata
->
disconnected_queue
=
(
Scsi_Cmnd
*
)
tmp
->
host_scribble
;
}
tmp
->
host_scribble
=
NULL
;
hostdata
->
connected
=
tmp
;
break
;
}
if
(
!
tmp
)
{
#ifdef SCSI2
printk
(
"scsi%d: warning : target %d lun %d tag %d not in disconnect_queue.
\n
"
,
instance
->
host_no
,
target
,
lun
,
tag
);
#else
printk
(
"scsi%d: warning : target %d lun %d not in disconnect_queue.
\n
"
,
instance
->
host_no
,
target
,
lun
);
#endif
/* Since we have an established nexus that we can't do anything with, we must abort it. */
hostdata
->
aborted
=
1
;
DEB
(
AM53C974_keywait
());
goto
EXIT_ABORT
;
}
else
goto
EXIT_OK
;
EXIT_ABORT:
AM53C974_write_8
(
CMDREG
,
CMDREG_SATN
);
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
return
;
EXIT_OK:
DEB_RESEL
(
printk
(
"scsi%d: nexus established, target = %d, lun = %d, tag = %d
\n
"
,
instance
->
host_no
,
target
,
tmp
->
lun
,
tmp
->
tag
));
AM53C974_set_sync
(
instance
,
target
);
AM53C974_write_8
(
SDIDREG
,
SDIREG_MASK
&
target
);
/* setup dest. id */
AM53C974_write_8
(
CMDREG
,
CMDREG_MA
);
hostdata
->
dma_busy
=
0
;
hostdata
->
connected
->
SCp
.
phase
=
PHASE_CMDOUT
;
}
/**************************************************************************
* Function : AM53C974_transfer_dma(struct Scsi_Host *instance, short dir,
* unsigned long length, char *data)
*
* Purpose : setup DMA transfer
*
* Inputs : instance -- which AM53C974
* dir -- direction flag, 0: write to device, read from memory;
* 1: read from device, write to memory
* length -- number of bytes to transfer to from buffer
* data -- pointer to data buffer
*
* Returns : nothing
**************************************************************************/
static
__inline__
void
AM53C974_transfer_dma
(
struct
Scsi_Host
*
instance
,
short
dir
,
unsigned
long
length
,
char
*
data
)
{
AM53C974_local_declare
();
AM53C974_setio
(
instance
);
AM53C974_write_8
(
CMDREG
,
CMDREG_NOP
);
AM53C974_write_8
(
DMACMD
,
(
dir
<<
7
)
|
DMACMD_INTE_D
);
/* idle command */
AM53C974_write_8
(
STCLREG
,
(
unsigned
char
)
(
length
&
0xff
));
AM53C974_write_8
(
STCMREG
,
(
unsigned
char
)
((
length
&
0xff00
)
>>
8
));
AM53C974_write_8
(
STCHREG
,
(
unsigned
char
)
((
length
&
0xff0000
)
>>
16
));
AM53C974_write_32
(
DMASTC
,
length
&
0xffffff
);
AM53C974_write_32
(
DMASPA
,
virt_to_bus
(
data
));
AM53C974_write_8
(
CMDREG
,
CMDREG_IT
|
CMDREG_DMA
);
AM53C974_write_8
(
DMACMD
,
(
dir
<<
7
)
|
DMACMD_INTE_D
|
DMACMD_START
);
}
/**************************************************************************
* Function : AM53C974_dma_blast(struct Scsi_Host *instance, unsigned char dmastatus,
* unsigned char statreg)
*
* Purpose : cleanup DMA transfer
*
* Inputs : instance -- which AM53C974
* dmastatus -- dma status register
* statreg -- status register
*
* Returns : nothing
**************************************************************************/
static
void
AM53C974_dma_blast
(
struct
Scsi_Host
*
instance
,
unsigned
char
dmastatus
,
unsigned
char
statreg
)
{
AM53C974_local_declare
();
struct
AM53C974_hostdata
*
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
unsigned
long
ctcreg
;
int
dir
=
statreg
&
STATREG_IO
;
int
cfifo
,
pio
,
i
=
0
;
AM53C974_setio
(
instance
);
do
{
cfifo
=
AM53C974_cfifo
();
i
++
;
}
while
(
cfifo
&&
(
i
<
50000
));
pio
=
(
i
==
50000
)
?
1
:
0
;
if
(
statreg
&
STATREG_CTZ
)
{
AM53C974_write_8
(
DMACMD
,
DMACMD_IDLE
);
return
;
}
if
(
dmastatus
&
DMASTATUS_DONE
)
{
AM53C974_write_8
(
DMACMD
,
DMACMD_IDLE
);
return
;
}
AM53C974_write_8
(
DMACMD
,
((
dir
<<
7
)
&
DMACMD_DIR
)
|
DMACMD_BLAST
);
while
(
!
(
AM53C974_read_8
(
DMASTATUS
)
&
DMASTATUS_BCMPLT
));
AM53C974_write_8
(
DMACMD
,
DMACMD_IDLE
);
if
(
pio
)
{
/* transfer residual bytes via PIO */
unsigned
char
*
wac
=
(
unsigned
char
*
)
AM53C974_read_32
(
DMAWAC
);
printk
(
"pio mode, residual=%d
\n
"
,
AM53C974_read_8
(
CFIREG
)
&
CFIREG_CF
);
while
(
AM53C974_read_8
(
CFIREG
)
&
CFIREG_CF
)
*
(
wac
++
)
=
AM53C974_read_8
(
FFREG
);
}
ctcreg
=
AM53C974_read_8
(
CTCLREG
)
|
(
AM53C974_read_8
(
CTCMREG
)
<<
8
)
|
(
AM53C974_read_8
(
CTCHREG
)
<<
16
);
hostdata
->
connected
->
SCp
.
ptr
+=
hostdata
->
connected
->
SCp
.
this_residual
-
ctcreg
;
hostdata
->
connected
->
SCp
.
this_residual
=
ctcreg
;
}
/**************************************************************************
* Function : AM53C974_intr_bus_reset(struct Scsi_Host *instance)
*
* Purpose : handle bus reset interrupt
*
* Inputs : instance -- which AM53C974
*
* Returns : nothing
**************************************************************************/
static
void
AM53C974_intr_bus_reset
(
struct
Scsi_Host
*
instance
)
{
AM53C974_local_declare
();
unsigned
char
cntlreg1
;
AM53C974_setio
(
instance
);
AM53C974_write_8
(
CMDREG
,
CMDREG_CFIFO
);
AM53C974_write_8
(
CMDREG
,
CMDREG_NOP
);
cntlreg1
=
AM53C974_read_8
(
CNTLREG1
);
AM53C974_write_8
(
CNTLREG1
,
cntlreg1
|
CNTLREG1_DISR
);
}
/**************************************************************************
* Function : int AM53C974_abort(Scsi_Cmnd *cmd)
*
* Purpose : abort a command
*
* Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
* host byte of the result field to, if zero DID_ABORTED is
* used.
*
* Returns : 0 - success, -1 on failure.
**************************************************************************/
static
int
AM53C974_abort
(
Scsi_Cmnd
*
cmd
)
{
AM53C974_local_declare
();
unsigned
long
flags
;
struct
Scsi_Host
*
instance
=
cmd
->
device
->
host
;
struct
AM53C974_hostdata
*
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
Scsi_Cmnd
*
tmp
,
**
prev
;
#ifdef AM53C974_DEBUG
deb_stop
=
1
;
#endif
save_flags
(
flags
);
cli
();
AM53C974_setio
(
instance
);
DEB_ABORT
(
printk
(
SEPARATOR_LINE
));
DEB_ABORT
(
printk
(
"scsi%d : AM53C974_abort called -- trouble starts!!
\n
"
,
instance
->
host_no
));
DEB_ABORT
(
AM53C974_print
(
instance
));
DEB_ABORT
(
AM53C974_keywait
());
/* Case 1 : If the command is the currently executing command,
we'll set the aborted flag and return control so that the
information transfer routine can exit cleanly. */
if
((
hostdata
->
connected
==
cmd
)
||
(
hostdata
->
sel_cmd
==
cmd
))
{
DEB_ABORT
(
printk
(
"scsi%d: aborting connected command
\n
"
,
instance
->
host_no
));
hostdata
->
aborted
=
1
;
hostdata
->
msgout
[
0
]
=
ABORT
;
restore_flags
(
flags
);
return
(
SCSI_ABORT_PENDING
);
}
/* Case 2 : If the command hasn't been issued yet,
we simply remove it from the issue queue. */
for
(
prev
=
(
Scsi_Cmnd
**
)
&
(
hostdata
->
issue_queue
),
tmp
=
(
Scsi_Cmnd
*
)
hostdata
->
issue_queue
;
tmp
;
prev
=
(
Scsi_Cmnd
**
)
&
(
tmp
->
host_scribble
),
tmp
=
(
Scsi_Cmnd
*
)
tmp
->
host_scribble
)
{
if
(
cmd
==
tmp
)
{
DEB_ABORT
(
printk
(
"scsi%d : abort removed command from issue queue.
\n
"
,
instance
->
host_no
));
REMOVE
(
5
,
*
prev
,
tmp
,
tmp
->
host_scribble
);
(
*
prev
)
=
(
Scsi_Cmnd
*
)
tmp
->
host_scribble
;
tmp
->
host_scribble
=
NULL
;
tmp
->
result
=
DID_ABORT
<<
16
;
restore_flags
(
flags
);
tmp
->
done
(
tmp
);
return
(
SCSI_ABORT_SUCCESS
);
}
#ifdef AM53C974_DEBUG_ABORT
else
{
if
(
prev
==
(
Scsi_Cmnd
**
)
tmp
)
printk
(
"scsi%d : LOOP
\n
"
,
instance
->
host_no
);
}
#endif
}
/* Case 3 : If any commands are connected, we're going to fail the abort
* and let the high level SCSI driver retry at a later time or
* issue a reset.
*
* Timeouts, and therefore aborted commands, will be highly unlikely
* and handling them cleanly in this situation would make the common
* case of noresets less efficient, and would pollute our code. So,
* we fail. */
if
(
hostdata
->
connected
||
hostdata
->
sel_cmd
)
{
DEB_ABORT
(
printk
(
"scsi%d : abort failed, other command connected.
\n
"
,
instance
->
host_no
));
restore_flags
(
flags
);
return
(
SCSI_ABORT_NOT_RUNNING
);
}
/* Case 4: If the command is currently disconnected from the bus, and
* there are no connected commands, we reconnect the I_T_L or
* I_T_L_Q nexus associated with it, go into message out, and send
* an abort message. */
for
(
tmp
=
(
Scsi_Cmnd
*
)
hostdata
->
disconnected_queue
;
tmp
;
tmp
=
(
Scsi_Cmnd
*
)
tmp
->
host_scribble
)
{
if
(
cmd
==
tmp
)
{
DEB_ABORT
(
printk
(
"scsi%d: aborting disconnected command
\n
"
,
instance
->
host_no
));
hostdata
->
aborted
=
1
;
hostdata
->
msgout
[
0
]
=
ABORT
;
hostdata
->
selecting
=
1
;
hostdata
->
sel_cmd
=
tmp
;
AM53C974_write_8
(
CMDREG
,
CMDREG_DSR
);
restore_flags
(
flags
);
return
(
SCSI_ABORT_PENDING
);
}
}
/* Case 5 : If we reached this point, the command was not found in any of
* the queues.
*
* We probably reached this point because of an unlikely race condition
* between the command completing successfully and the abortion code,
* so we won't panic, but we will notify the user in case something really
* broke. */
DEB_ABORT
(
printk
(
"scsi%d : abort failed, command not found.
\n
"
,
instance
->
host_no
));
restore_flags
(
flags
);
return
(
SCSI_ABORT_NOT_RUNNING
);
}
/**************************************************************************
* Function : int AM53C974_reset(Scsi_Cmnd *cmd)
*
* Purpose : reset the SCSI controller and bus
*
* Inputs : cmd -- which command within the command block was responsible for the reset
*
* Returns : status (SCSI_ABORT_SUCCESS)
*
* FIXME(eric) the reset_flags are ignored.
**************************************************************************/
static
int
AM53C974_reset
(
Scsi_Cmnd
*
cmd
,
unsigned
int
reset_flags
)
{
AM53C974_local_declare
();
unsigned
long
flags
;
int
i
;
struct
Scsi_Host
*
instance
=
cmd
->
device
->
host
;
struct
AM53C974_hostdata
*
hostdata
=
(
struct
AM53C974_hostdata
*
)
instance
->
hostdata
;
AM53C974_setio
(
instance
);
save_flags
(
flags
);
cli
();
DEB
(
printk
(
"AM53C974_reset called; "
));
printk
(
"AM53C974_reset called
\n
"
);
AM53C974_print
(
instance
);
AM53C974_keywait
();
/* do hard reset */
AM53C974_write_8
(
CMDREG
,
CMDREG_RDEV
);
AM53C974_write_8
(
CMDREG
,
CMDREG_NOP
);
hostdata
->
msgout
[
0
]
=
NOP
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
hostdata
->
busy
[
i
]
=
0
;
hostdata
->
sync_per
[
i
]
=
DEF_STP
;
hostdata
->
sync_off
[
i
]
=
0
;
hostdata
->
sync_neg
[
i
]
=
0
;
}
hostdata
->
last_message
[
0
]
=
NOP
;
hostdata
->
sel_cmd
=
NULL
;
hostdata
->
connected
=
NULL
;
hostdata
->
issue_queue
=
NULL
;
hostdata
->
disconnected_queue
=
NULL
;
hostdata
->
in_reset
=
0
;
hostdata
->
aborted
=
0
;
hostdata
->
selecting
=
0
;
hostdata
->
disconnecting
=
0
;
hostdata
->
dma_busy
=
0
;
/* reset bus */
AM53C974_write_8
(
CNTLREG1
,
CNTLREG1_DISR
|
instance
->
this_id
);
/* disable interrupt upon SCSI RESET */
AM53C974_write_8
(
CMDREG
,
CMDREG_RBUS
);
/* reset SCSI bus */
udelay
(
40
);
AM53C974_config_after_reset
(
instance
);
restore_flags
(
flags
);
cmd
->
result
=
DID_RESET
<<
16
;
cmd
->
scsi_done
(
cmd
);
return
SCSI_ABORT_SUCCESS
;
}
/*
* AM53C974_release()
*
* Release resources allocated for a single AM53C974 adapter.
*/
static
int
AM53C974_release
(
struct
Scsi_Host
*
shp
)
{
free_irq
(
shp
->
irq
,
shp
);
release_region
(
shp
->
io_port
,
128
);
scsi_unregister
(
shp
);
return
0
;
}
/* You can specify overrides=a,b,c,d in the same format at AM53C974=a,b,c,d
on boot up */
MODULE_PARM
(
overrides
,
"1-32i"
);
MODULE_LICENSE
(
"GPL"
);
static
Scsi_Host_Template
driver_template
=
{
.
proc_name
=
"am53c974"
,
.
name
=
"AM53C974"
,
.
detect
=
AM53C974_pci_detect
,
.
release
=
AM53C974_release
,
.
info
=
AM53C974_info
,
.
queuecommand
=
AM53C974_queue_command
,
.
abort
=
AM53C974_abort
,
.
reset
=
AM53C974_reset
,
.
can_queue
=
12
,
.
this_id
=
-
1
,
.
sg_tablesize
=
SG_ALL
,
.
cmd_per_lun
=
1
,
.
use_clustering
=
DISABLE_CLUSTERING
,
};
#include "scsi_module.c"
drivers/scsi/AM53C974.h
deleted
100644 → 0
View file @
5cd7327e
/* AM53/79C974 (PCscsi) driver release 0.5
* The architecture and much of the code of this device
* driver was originally developed by Drew Eckhardt for
* the NCR5380. The following copyrights apply:
* For the architecture and all parts similar to the NCR5380:
* Copyright 1993, Drew Eckhardt
* Visionary Computing
* (Unix and Linux consulting and custom programming)
* drew@colorado.edu
* +1 (303) 666-5836
*
* The AM53C974_nobios_detect code was originally developed by
* Robin Cutshaw (robin@xfree86.org) and is used here in a
* modified form.
*
* For the other parts:
* Copyright 1994, D. Frieauff
* EMail: fri@rsx42sun0.dofn.de
* Phone: x49-7545-8-2256 , x49-7541-42305
*/
/*
* $Log: AM53C974.h,v $
*/
#ifndef AM53C974_H
#define AM53C974_H
#include <scsi/scsicam.h>
struct
AM53C974_hostdata
{
volatile
unsigned
in_reset
:
1
;
/* flag, says bus reset pending */
volatile
unsigned
aborted
:
1
;
/* flag, says aborted */
volatile
unsigned
selecting
:
1
;
/* selection started, but not yet finished */
volatile
unsigned
disconnecting
:
1
;
/* disconnection started, but not yet finished */
volatile
unsigned
dma_busy
:
1
;
/* dma busy when service request for info transfer received */
volatile
unsigned
char
msgout
[
10
];
/* message to output in MSGOUT_PHASE */
volatile
unsigned
char
last_message
[
10
];
/* last message OUT */
volatile
Scsi_Cmnd
*
issue_queue
;
/* waiting to be issued */
volatile
Scsi_Cmnd
*
disconnected_queue
;
/* waiting for reconnect */
volatile
Scsi_Cmnd
*
sel_cmd
;
/* command for selection */
volatile
Scsi_Cmnd
*
connected
;
/* currently connected command */
volatile
unsigned
char
busy
[
8
];
/* index = target, bit = lun */
unsigned
char
sync_per
[
8
];
/* synchronous transfer period (in effect) */
unsigned
char
sync_off
[
8
];
/* synchronous offset (in effect) */
unsigned
char
sync_neg
[
8
];
/* sync. negotiation performed (in effect) */
unsigned
char
sync_en
[
8
];
/* sync. negotiation performed (in effect) */
unsigned
char
max_rate
[
8
];
/* max. transfer rate (setup) */
unsigned
char
max_offset
[
8
];
/* max. sync. offset (setup), only valid if corresponding sync_en is nonzero */
};
static
int
AM53C974_pci_detect
(
Scsi_Host_Template
*
tpnt
);
static
int
AM53C974_release
(
struct
Scsi_Host
*
shp
);
static
const
char
*
AM53C974_info
(
struct
Scsi_Host
*
);
static
int
AM53C974_command
(
Scsi_Cmnd
*
SCpnt
);
static
int
AM53C974_queue_command
(
Scsi_Cmnd
*
cmd
,
void
(
*
done
)
(
Scsi_Cmnd
*
));
static
int
AM53C974_abort
(
Scsi_Cmnd
*
cmd
);
static
int
AM53C974_reset
(
Scsi_Cmnd
*
cmd
,
unsigned
int
);
#endif
/* AM53C974_H */
drivers/scsi/Kconfig
View file @
32d9ad84
...
...
@@ -376,23 +376,6 @@ config SCSI_IN2000
To compile this driver as a module, choose M here: the
module will be called in2000.
# does not use pci dma and seems to be onboard only for old machines
config SCSI_AM53C974
tristate "AM53/79C974 PCI SCSI support"
depends on X86 && PCI && SCSI && BROKEN
---help---
This is support for the AM53/79C974 SCSI host adapters. Please read
<file:Documentation/scsi/AM53C974.txt> for details. Also, the
SCSI-HOWTO, available from
<http://www.tldp.org/docs.html#howto>, is for you.
Note that there is another driver for AM53C974 based adapters:
"Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support", above. You
can pick either one.
To compile this driver as a module, choose M here: the
module will be called AM53C974.
config SCSI_MEGARAID
tristate "AMI MegaRAID support"
depends on PCI && SCSI
...
...
drivers/scsi/Makefile
View file @
32d9ad84
...
...
@@ -86,7 +86,6 @@ obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o
obj-$(CONFIG_SCSI_EATA)
+=
eata.o
obj-$(CONFIG_SCSI_DC395x)
+=
dc395x.o
obj-$(CONFIG_SCSI_DC390T)
+=
tmscsim.o
obj-$(CONFIG_SCSI_AM53C974)
+=
AM53C974.o
obj-$(CONFIG_SCSI_MEGARAID)
+=
megaraid.o
obj-$(CONFIG_SCSI_ACARD)
+=
atp870u.o
obj-$(CONFIG_SCSI_SUNESP)
+=
esp.o
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment