2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 1997 Wu Ching Chen
|
|
|
|
* 2.1.x update (C) 1998 Krzysztof G. Baranowski
|
2008-10-27 15:16:36 +00:00
|
|
|
* 2.5.x update (C) 2002 Red Hat
|
|
|
|
* 2.6.x update (C) 2004 Red Hat
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
|
|
|
* Marcelo Tosatti <marcelo@conectiva.com.br> : SMP fixes
|
|
|
|
*
|
|
|
|
* Wu Ching Chen : NULL pointer fixes 2000/06/02
|
|
|
|
* support atp876 chip
|
|
|
|
* enable 32 bit fifo transfer
|
|
|
|
* support cdrom & remove device run ultra speed
|
|
|
|
* fix disconnect bug 2000/12/21
|
|
|
|
* support atp880 chip lvd u160 2001/05/15
|
|
|
|
* fix prd table bug 2001/09/12 (7.1)
|
|
|
|
*
|
|
|
|
* atp885 support add by ACARD Hao Ping Lian 2005/01/05
|
|
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/ioport.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/proc_fs.h>
|
|
|
|
#include <linux/spinlock.h>
|
|
|
|
#include <linux/pci.h>
|
|
|
|
#include <linux/blkdev.h>
|
2006-03-28 09:56:48 +00:00
|
|
|
#include <linux/dma-mapping.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <asm/io.h>
|
|
|
|
|
|
|
|
#include <scsi/scsi.h>
|
|
|
|
#include <scsi/scsi_cmnd.h>
|
|
|
|
#include <scsi/scsi_device.h>
|
|
|
|
#include <scsi/scsi_host.h>
|
|
|
|
|
|
|
|
#include "atp870u.h"
|
|
|
|
|
|
|
|
static struct scsi_host_template atp870u_template;
|
|
|
|
static void send_s870(struct atp_unit *dev,unsigned char c);
|
|
|
|
static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c);
|
|
|
|
static void tscam_885(void);
|
|
|
|
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 13:55:46 +00:00
|
|
|
static irqreturn_t atp870u_intr_handle(int irq, void *dev_id)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
unsigned long flags;
|
2015-11-17 18:23:47 +00:00
|
|
|
unsigned short int id;
|
2005-04-16 22:20:36 +00:00
|
|
|
unsigned char i, j, c, target_id, lun,cmdp;
|
|
|
|
unsigned char *prd;
|
|
|
|
struct scsi_cmnd *workreq;
|
|
|
|
unsigned long adrcnt, k;
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
unsigned long l;
|
|
|
|
#endif
|
|
|
|
struct Scsi_Host *host = dev_id;
|
|
|
|
struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
|
|
|
|
|
|
|
|
for (c = 0; c < 2; c++) {
|
2015-11-17 18:23:39 +00:00
|
|
|
j = inb(dev->ioport[c] + 0x1f);
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((j & 0x80) != 0)
|
2015-11-17 18:23:49 +00:00
|
|
|
break;
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->in_int[c] = 0;
|
|
|
|
}
|
2015-11-17 18:23:49 +00:00
|
|
|
if ((j & 0x80) == 0)
|
|
|
|
return IRQ_NONE;
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("atp870u_intr_handle enter\n");
|
|
|
|
#endif
|
|
|
|
dev->in_int[c] = 1;
|
|
|
|
cmdp = inb(dev->ioport[c] + 0x10);
|
|
|
|
if (dev->working[c] != 0) {
|
|
|
|
if (dev->dev_id == ATP885_DEVID) {
|
2015-11-17 18:23:38 +00:00
|
|
|
if ((inb(dev->ioport[c] + 0x16) & 0x80) == 0)
|
|
|
|
outb((inb(dev->ioport[c] + 0x16) | 0x80), dev->ioport[c] + 0x16);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-11-17 18:23:47 +00:00
|
|
|
if ((inb(dev->pciport[c]) & 0x08) != 0)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
for (k=0; k < 1000; k++) {
|
2015-11-17 18:23:49 +00:00
|
|
|
if ((inb(dev->pciport[c] + 2) & 0x08) == 0)
|
|
|
|
break;
|
|
|
|
if ((inb(dev->pciport[c] + 2) & 0x01) == 0)
|
|
|
|
break;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
2015-11-17 18:23:47 +00:00
|
|
|
outb(0x00, dev->pciport[c]);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:39 +00:00
|
|
|
i = inb(dev->ioport[c] + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:47 +00:00
|
|
|
if (dev->dev_id == ATP885_DEVID)
|
|
|
|
outb(0x06, dev->pciport[c] + 2);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:39 +00:00
|
|
|
target_id = inb(dev->ioport[c] + 0x15);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Remap wide devices onto id numbers
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((target_id & 0x40) != 0) {
|
|
|
|
target_id = (target_id & 0x07) | 0x08;
|
|
|
|
} else {
|
|
|
|
target_id &= 0x07;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((j & 0x40) != 0) {
|
|
|
|
if (dev->last_cmd[c] == 0xff) {
|
|
|
|
dev->last_cmd[c] = target_id;
|
|
|
|
}
|
|
|
|
dev->last_cmd[c] |= 0x40;
|
|
|
|
}
|
|
|
|
if (dev->dev_id == ATP885_DEVID)
|
|
|
|
dev->r1f[c][target_id] |= j;
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("atp870u_intr_handle status = %x\n",i);
|
|
|
|
#endif
|
|
|
|
if (i == 0x85) {
|
|
|
|
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
|
|
|
|
dev->last_cmd[c] = 0xff;
|
|
|
|
}
|
|
|
|
if (dev->dev_id == ATP885_DEVID) {
|
|
|
|
adrcnt = 0;
|
2015-11-17 18:23:39 +00:00
|
|
|
((unsigned char *) &adrcnt)[2] = inb(dev->ioport[c] + 0x12);
|
|
|
|
((unsigned char *) &adrcnt)[1] = inb(dev->ioport[c] + 0x13);
|
|
|
|
((unsigned char *) &adrcnt)[0] = inb(dev->ioport[c] + 0x14);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (dev->id[c][target_id].last_len != adrcnt)
|
|
|
|
{
|
|
|
|
k = dev->id[c][target_id].last_len;
|
|
|
|
k -= adrcnt;
|
|
|
|
dev->id[c][target_id].tran_len = k;
|
|
|
|
dev->id[c][target_id].last_len = adrcnt;
|
|
|
|
}
|
|
|
|
#ifdef ED_DBGP
|
2015-11-17 18:23:39 +00:00
|
|
|
printk("dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len);
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Flip wide
|
|
|
|
*/
|
|
|
|
if (dev->wide_id[c] != 0) {
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x01, dev->ioport[c] + 0x1b);
|
|
|
|
while ((inb(dev->ioport[c] + 0x1b) & 0x01) != 0x01) {
|
|
|
|
outb(0x01, dev->ioport[c] + 0x1b);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Issue more commands
|
|
|
|
*/
|
|
|
|
spin_lock_irqsave(dev->host->host_lock, flags);
|
|
|
|
if (((dev->quhd[c] != dev->quend[c]) || (dev->last_cmd[c] != 0xff)) &&
|
|
|
|
(dev->in_snd[c] == 0)) {
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("Call sent_s870\n");
|
|
|
|
#endif
|
|
|
|
send_s870(dev,c);
|
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(dev->host->host_lock, flags);
|
|
|
|
/*
|
|
|
|
* Done
|
|
|
|
*/
|
|
|
|
dev->in_int[c] = 0;
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("Status 0x85 return\n");
|
|
|
|
#endif
|
2015-11-17 18:23:49 +00:00
|
|
|
return IRQ_HANDLED;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (i == 0x40) {
|
|
|
|
dev->last_cmd[c] |= 0x40;
|
|
|
|
dev->in_int[c] = 0;
|
2015-11-17 18:23:49 +00:00
|
|
|
return IRQ_HANDLED;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (i == 0x21) {
|
|
|
|
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
|
|
|
|
dev->last_cmd[c] = 0xff;
|
|
|
|
}
|
|
|
|
adrcnt = 0;
|
2015-11-17 18:23:39 +00:00
|
|
|
((unsigned char *) &adrcnt)[2] = inb(dev->ioport[c] + 0x12);
|
|
|
|
((unsigned char *) &adrcnt)[1] = inb(dev->ioport[c] + 0x13);
|
|
|
|
((unsigned char *) &adrcnt)[0] = inb(dev->ioport[c] + 0x14);
|
2005-04-16 22:20:36 +00:00
|
|
|
k = dev->id[c][target_id].last_len;
|
|
|
|
k -= adrcnt;
|
|
|
|
dev->id[c][target_id].tran_len = k;
|
|
|
|
dev->id[c][target_id].last_len = adrcnt;
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x41, dev->ioport[c] + 0x10);
|
|
|
|
outb(0x08, dev->ioport[c] + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->in_int[c] = 0;
|
2015-11-17 18:23:49 +00:00
|
|
|
return IRQ_HANDLED;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->dev_id == ATP885_DEVID) {
|
|
|
|
if ((i == 0x4c) || (i == 0x4d) || (i == 0x8c) || (i == 0x8d)) {
|
|
|
|
if ((i == 0x4c) || (i == 0x8c))
|
|
|
|
i=0x48;
|
|
|
|
else
|
|
|
|
i=0x49;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if ((i == 0x80) || (i == 0x8f)) {
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk(KERN_DEBUG "Device reselect\n");
|
|
|
|
#endif
|
|
|
|
lun = 0;
|
|
|
|
if (cmdp == 0x44 || i==0x80) {
|
2015-11-17 18:23:39 +00:00
|
|
|
lun = inb(dev->ioport[c] + 0x1d) & 0x07;
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
|
|
|
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
|
|
|
|
dev->last_cmd[c] = 0xff;
|
|
|
|
}
|
|
|
|
if (cmdp == 0x41) {
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("cmdp = 0x41\n");
|
|
|
|
#endif
|
|
|
|
adrcnt = 0;
|
2015-11-17 18:23:39 +00:00
|
|
|
((unsigned char *) &adrcnt)[2] = inb(dev->ioport[c] + 0x12);
|
|
|
|
((unsigned char *) &adrcnt)[1] = inb(dev->ioport[c] + 0x13);
|
|
|
|
((unsigned char *) &adrcnt)[0] = inb(dev->ioport[c] + 0x14);
|
2005-04-16 22:20:36 +00:00
|
|
|
k = dev->id[c][target_id].last_len;
|
|
|
|
k -= adrcnt;
|
|
|
|
dev->id[c][target_id].tran_len = k;
|
|
|
|
dev->id[c][target_id].last_len = adrcnt;
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x08, dev->ioport[c] + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->in_int[c] = 0;
|
2015-11-17 18:23:49 +00:00
|
|
|
return IRQ_HANDLED;
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("cmdp != 0x41\n");
|
|
|
|
#endif
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x46, dev->ioport[c] + 0x10);
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->id[c][target_id].dirct = 0x00;
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x00, dev->ioport[c] + 0x12);
|
|
|
|
outb(0x00, dev->ioport[c] + 0x13);
|
|
|
|
outb(0x00, dev->ioport[c] + 0x14);
|
|
|
|
outb(0x08, dev->ioport[c] + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->in_int[c] = 0;
|
2015-11-17 18:23:49 +00:00
|
|
|
return IRQ_HANDLED;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dev->last_cmd[c] != 0xff) {
|
|
|
|
dev->last_cmd[c] |= 0x40;
|
|
|
|
}
|
|
|
|
if (dev->dev_id == ATP885_DEVID) {
|
|
|
|
j = inb(dev->baseport + 0x29) & 0xfe;
|
|
|
|
outb(j, dev->baseport + 0x29);
|
2015-11-17 18:23:39 +00:00
|
|
|
} else
|
|
|
|
outb(0x45, dev->ioport[c] + 0x10);
|
|
|
|
|
|
|
|
target_id = inb(dev->ioport[c] + 0x16);
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Remap wide identifiers
|
|
|
|
*/
|
|
|
|
if ((target_id & 0x10) != 0) {
|
|
|
|
target_id = (target_id & 0x07) | 0x08;
|
|
|
|
} else {
|
|
|
|
target_id &= 0x07;
|
|
|
|
}
|
2015-11-17 18:23:39 +00:00
|
|
|
if (dev->dev_id == ATP885_DEVID)
|
|
|
|
outb(0x45, dev->ioport[c] + 0x10);
|
2005-04-16 22:20:36 +00:00
|
|
|
workreq = dev->id[c][target_id].curr_req;
|
|
|
|
#ifdef ED_DBGP
|
2005-10-24 22:04:36 +00:00
|
|
|
scmd_printk(KERN_DEBUG, workreq, "CDB");
|
|
|
|
for (l = 0; l < workreq->cmd_len; l++)
|
2005-04-16 22:20:36 +00:00
|
|
|
printk(KERN_DEBUG " %x",workreq->cmnd[l]);
|
2005-10-24 22:04:36 +00:00
|
|
|
printk("\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
|
|
|
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(lun, dev->ioport[c] + 0x0f);
|
|
|
|
outb(dev->id[c][target_id].devsp, dev->ioport[c] + 0x11);
|
2005-04-16 22:20:36 +00:00
|
|
|
adrcnt = dev->id[c][target_id].tran_len;
|
|
|
|
k = dev->id[c][target_id].last_len;
|
|
|
|
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(((unsigned char *) &k)[2], dev->ioport[c] + 0x12);
|
|
|
|
outb(((unsigned char *) &k)[1], dev->ioport[c] + 0x13);
|
|
|
|
outb(((unsigned char *) &k)[0], dev->ioport[c] + 0x14);
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef ED_DBGP
|
2015-11-17 18:23:39 +00:00
|
|
|
printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, inb(dev->ioport[c] + 0x14), inb(dev->ioport[c] + 0x13), inb(dev->ioport[c] + 0x12));
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
|
|
|
/* Remap wide */
|
|
|
|
j = target_id;
|
|
|
|
if (target_id > 7) {
|
|
|
|
j = (j & 0x07) | 0x40;
|
|
|
|
}
|
|
|
|
/* Add direction */
|
|
|
|
j |= dev->id[c][target_id].dirct;
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(j, dev->ioport[c] + 0x15);
|
|
|
|
outb(0x80, dev->ioport[c] + 0x16);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/* enable 32 bit fifo transfer */
|
|
|
|
if (dev->dev_id == ATP885_DEVID) {
|
2015-11-17 18:23:47 +00:00
|
|
|
i=inb(dev->pciport[c] + 1) & 0xf3;
|
2005-04-16 22:20:36 +00:00
|
|
|
//j=workreq->cmnd[0];
|
|
|
|
if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
|
|
|
|
i |= 0x0c;
|
|
|
|
}
|
2015-11-17 18:23:47 +00:00
|
|
|
outb(i, dev->pciport[c] + 1);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else if ((dev->dev_id == ATP880_DEVID1) ||
|
|
|
|
(dev->dev_id == ATP880_DEVID2) ) {
|
|
|
|
if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
|
2015-11-17 18:23:39 +00:00
|
|
|
outb((unsigned char) ((inb(dev->ioport[c] - 0x05) & 0x3f) | 0xc0), dev->ioport[c] - 0x05);///minus 0x05???
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:39 +00:00
|
|
|
outb((unsigned char) (inb(dev->ioport[c] - 0x05) & 0x3f), dev->ioport[c] - 0x05);///minus 0x05???
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
|
2015-11-17 18:23:39 +00:00
|
|
|
outb((unsigned char) ((inb(dev->ioport[c] + 0x3a) & 0xf3) | 0x08), dev->ioport[c] + 0x3a);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:39 +00:00
|
|
|
outb((unsigned char) (inb(dev->ioport[c] + 0x3a) & 0xf3), dev->ioport[c] + 0x3a);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
j = 0;
|
|
|
|
id = 1;
|
|
|
|
id = id << target_id;
|
|
|
|
/*
|
|
|
|
* Is this a wide device
|
|
|
|
*/
|
|
|
|
if ((id & dev->wide_id[c]) != 0) {
|
|
|
|
j |= 0x01;
|
|
|
|
}
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(j, dev->ioport[c] + 0x1b);
|
|
|
|
while ((inb(dev->ioport[c] + 0x1b) & 0x01) != j) {
|
|
|
|
outb(j,dev->ioport[c] + 0x1b);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
if (dev->id[c][target_id].last_len == 0) {
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x08, dev->ioport[c] + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->in_int[c] = 0;
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("dev->id[c][target_id].last_len = 0\n");
|
|
|
|
#endif
|
2015-11-17 18:23:49 +00:00
|
|
|
return IRQ_HANDLED;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("target_id = %d adrcnt = %d\n",target_id,adrcnt);
|
|
|
|
#endif
|
|
|
|
prd = dev->id[c][target_id].prd_pos;
|
|
|
|
while (adrcnt != 0) {
|
|
|
|
id = ((unsigned short int *)prd)[2];
|
|
|
|
if (id == 0) {
|
|
|
|
k = 0x10000;
|
|
|
|
} else {
|
|
|
|
k = id;
|
|
|
|
}
|
|
|
|
if (k > adrcnt) {
|
|
|
|
((unsigned short int *)prd)[2] = (unsigned short int)
|
|
|
|
(k - adrcnt);
|
|
|
|
((unsigned long *)prd)[0] += adrcnt;
|
|
|
|
adrcnt = 0;
|
|
|
|
dev->id[c][target_id].prd_pos = prd;
|
|
|
|
} else {
|
|
|
|
adrcnt -= k;
|
|
|
|
dev->id[c][target_id].prdaddr += 0x08;
|
|
|
|
prd += 0x08;
|
|
|
|
if (adrcnt == 0) {
|
|
|
|
dev->id[c][target_id].prd_pos = prd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-11-17 18:23:47 +00:00
|
|
|
outl(dev->id[c][target_id].prdaddr, dev->pciport[c] + 0x04);
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("dev->id[%d][%d].prdaddr 0x%8x\n", c, target_id, dev->id[c][target_id].prdaddr);
|
|
|
|
#endif
|
2015-11-17 18:23:47 +00:00
|
|
|
if (dev->dev_id != ATP885_DEVID) {
|
|
|
|
outb(0x06, dev->pciport[c] + 2);
|
|
|
|
outb(0x00, dev->pciport[c] + 2);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Check transfer direction
|
|
|
|
*/
|
|
|
|
if (dev->id[c][target_id].dirct != 0) {
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x08, dev->ioport[c] + 0x18);
|
2015-11-17 18:23:47 +00:00
|
|
|
outb(0x01, dev->pciport[c]);
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->in_int[c] = 0;
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("status 0x80 return dirct != 0\n");
|
|
|
|
#endif
|
2015-11-17 18:23:49 +00:00
|
|
|
return IRQ_HANDLED;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x08, dev->ioport[c] + 0x18);
|
2015-11-17 18:23:47 +00:00
|
|
|
outb(0x09, dev->pciport[c]);
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->in_int[c] = 0;
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("status 0x80 return dirct = 0\n");
|
|
|
|
#endif
|
2015-11-17 18:23:49 +00:00
|
|
|
return IRQ_HANDLED;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Current scsi request on this target
|
|
|
|
*/
|
|
|
|
|
|
|
|
workreq = dev->id[c][target_id].curr_req;
|
|
|
|
|
2015-11-17 18:23:49 +00:00
|
|
|
if (i == 0x42 || i == 0x16) {
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
|
|
|
|
dev->last_cmd[c] = 0xff;
|
|
|
|
}
|
2015-11-17 18:23:49 +00:00
|
|
|
if (i == 0x16) {
|
|
|
|
workreq->result = inb(dev->ioport[c] + 0x0f);
|
|
|
|
if (((dev->r1f[c][target_id] & 0x10) != 0)&&(dev->dev_id==ATP885_DEVID)) {
|
|
|
|
printk(KERN_WARNING "AEC67162 CRC ERROR !\n");
|
|
|
|
workreq->result = 0x02;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
workreq->result = 0x02;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (dev->dev_id == ATP885_DEVID) {
|
|
|
|
j = inb(dev->baseport + 0x29) | 0x01;
|
|
|
|
outb(j, dev->baseport + 0x29);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Complete the command
|
|
|
|
*/
|
2007-09-09 18:06:23 +00:00
|
|
|
scsi_dma_unmap(workreq);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
spin_lock_irqsave(dev->host->host_lock, flags);
|
|
|
|
(*workreq->scsi_done) (workreq);
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("workreq->scsi_done\n");
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* Clear it off the queue
|
|
|
|
*/
|
|
|
|
dev->id[c][target_id].curr_req = NULL;
|
|
|
|
dev->working[c]--;
|
|
|
|
spin_unlock_irqrestore(dev->host->host_lock, flags);
|
|
|
|
/*
|
|
|
|
* Take it back wide
|
|
|
|
*/
|
|
|
|
if (dev->wide_id[c] != 0) {
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x01, dev->ioport[c] + 0x1b);
|
|
|
|
while ((inb(dev->ioport[c] + 0x1b) & 0x01) != 0x01) {
|
|
|
|
outb(0x01, dev->ioport[c] + 0x1b);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If there is stuff to send and nothing going then send it
|
|
|
|
*/
|
|
|
|
spin_lock_irqsave(dev->host->host_lock, flags);
|
|
|
|
if (((dev->last_cmd[c] != 0xff) || (dev->quhd[c] != dev->quend[c])) &&
|
|
|
|
(dev->in_snd[c] == 0)) {
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("Call sent_s870(scsi_done)\n");
|
|
|
|
#endif
|
|
|
|
send_s870(dev,c);
|
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(dev->host->host_lock, flags);
|
|
|
|
dev->in_int[c] = 0;
|
2015-11-17 18:23:49 +00:00
|
|
|
return IRQ_HANDLED;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
|
|
|
|
dev->last_cmd[c] = 0xff;
|
|
|
|
}
|
|
|
|
if (i == 0x4f) {
|
|
|
|
i = 0x89;
|
|
|
|
}
|
|
|
|
i &= 0x0f;
|
|
|
|
if (i == 0x09) {
|
2015-11-17 18:23:47 +00:00
|
|
|
outl(dev->id[c][target_id].prdaddr, dev->pciport[c] + 4);
|
|
|
|
outb(0x06, dev->pciport[c] + 2);
|
|
|
|
outb(0x00, dev->pciport[c] + 2);
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x41, dev->ioport[c] + 0x10);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (dev->dev_id == ATP885_DEVID) {
|
|
|
|
k = dev->id[c][target_id].last_len;
|
2015-11-17 18:23:39 +00:00
|
|
|
outb((unsigned char) (((unsigned char *) (&k))[2]), dev->ioport[c] + 0x12);
|
|
|
|
outb((unsigned char) (((unsigned char *) (&k))[1]), dev->ioport[c] + 0x13);
|
|
|
|
outb((unsigned char) (((unsigned char *) (&k))[0]), dev->ioport[c] + 0x14);
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->id[c][target_id].dirct = 0x00;
|
|
|
|
} else {
|
|
|
|
dev->id[c][target_id].dirct = 0x00;
|
|
|
|
}
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x08, dev->ioport[c] + 0x18);
|
2015-11-17 18:23:47 +00:00
|
|
|
outb(0x09, dev->pciport[c]);
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->in_int[c] = 0;
|
2015-11-17 18:23:49 +00:00
|
|
|
return IRQ_HANDLED;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
if (i == 0x08) {
|
2015-11-17 18:23:47 +00:00
|
|
|
outl(dev->id[c][target_id].prdaddr, dev->pciport[c] + 4);
|
|
|
|
outb(0x06, dev->pciport[c] + 2);
|
|
|
|
outb(0x00, dev->pciport[c] + 2);
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x41, dev->ioport[c] + 0x10);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (dev->dev_id == ATP885_DEVID) {
|
|
|
|
k = dev->id[c][target_id].last_len;
|
2015-11-17 18:23:39 +00:00
|
|
|
outb((unsigned char) (((unsigned char *) (&k))[2]), dev->ioport[c] + 0x12);
|
|
|
|
outb((unsigned char) (((unsigned char *) (&k))[1]), dev->ioport[c] + 0x13);
|
|
|
|
outb((unsigned char) (((unsigned char *) (&k))[0]), dev->ioport[c] + 0x14);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-11-17 18:23:39 +00:00
|
|
|
outb((unsigned char) (inb(dev->ioport[c] + 0x15) | 0x20), dev->ioport[c] + 0x15);
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->id[c][target_id].dirct = 0x20;
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x08, dev->ioport[c] + 0x18);
|
2015-11-17 18:23:47 +00:00
|
|
|
outb(0x01, dev->pciport[c]);
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->in_int[c] = 0;
|
2015-11-17 18:23:49 +00:00
|
|
|
return IRQ_HANDLED;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
if (i == 0x0a) {
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x30, dev->ioport[c] + 0x10);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x46, dev->ioport[c] + 0x10);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
dev->id[c][target_id].dirct = 0x00;
|
2015-11-17 18:23:39 +00:00
|
|
|
outb(0x00, dev->ioport[c] + 0x12);
|
|
|
|
outb(0x00, dev->ioport[c] + 0x13);
|
|
|
|
outb(0x00, dev->ioport[c] + 0x14);
|
|
|
|
outb(0x08, dev->ioport[c] + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-11-17 18:23:49 +00:00
|
|
|
dev->in_int[c] = 0;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* atp870u_queuecommand - Queue SCSI command
|
|
|
|
* @req_p: request block
|
|
|
|
* @done: completion function
|
|
|
|
*
|
|
|
|
* Queue a command to the ATP queue. Called with the host lock held.
|
|
|
|
*/
|
2010-11-16 07:10:29 +00:00
|
|
|
static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p,
|
2005-04-16 22:20:36 +00:00
|
|
|
void (*done) (struct scsi_cmnd *))
|
|
|
|
{
|
|
|
|
unsigned char c;
|
2015-11-17 18:23:40 +00:00
|
|
|
unsigned int m;
|
2005-04-16 22:20:36 +00:00
|
|
|
struct atp_unit *dev;
|
|
|
|
struct Scsi_Host *host;
|
|
|
|
|
2005-10-24 22:05:09 +00:00
|
|
|
c = scmd_channel(req_p);
|
2005-04-16 22:20:36 +00:00
|
|
|
req_p->sense_buffer[0]=0;
|
2007-09-09 18:06:23 +00:00
|
|
|
scsi_set_resid(req_p, 0);
|
2005-10-24 22:05:09 +00:00
|
|
|
if (scmd_channel(req_p) > 1) {
|
2005-04-16 22:20:36 +00:00
|
|
|
req_p->result = 0x00040000;
|
|
|
|
done(req_p);
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("atp870u_queuecommand : req_p->device->channel > 1\n");
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
host = req_p->device->host;
|
|
|
|
dev = (struct atp_unit *)&host->hostdata;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m = 1;
|
2005-10-24 22:05:09 +00:00
|
|
|
m = m << scmd_id(req_p);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Fake a timeout for missing targets
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((m & dev->active_id[c]) == 0) {
|
|
|
|
req_p->result = 0x00040000;
|
|
|
|
done(req_p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (done) {
|
|
|
|
req_p->scsi_done = done;
|
|
|
|
} else {
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk( "atp870u_queuecommand: done can't be NULL\n");
|
|
|
|
#endif
|
|
|
|
req_p->result = 0;
|
|
|
|
done(req_p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Count new command
|
|
|
|
*/
|
|
|
|
dev->quend[c]++;
|
|
|
|
if (dev->quend[c] >= qcnt) {
|
|
|
|
dev->quend[c] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check queue state
|
|
|
|
*/
|
|
|
|
if (dev->quhd[c] == dev->quend[c]) {
|
|
|
|
if (dev->quend[c] == 0) {
|
|
|
|
dev->quend[c] = qcnt;
|
|
|
|
}
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("atp870u_queuecommand : dev->quhd[c] == dev->quend[c]\n");
|
|
|
|
#endif
|
|
|
|
dev->quend[c]--;
|
|
|
|
req_p->result = 0x00020000;
|
|
|
|
done(req_p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
dev->quereq[c][dev->quend[c]] = req_p;
|
|
|
|
#ifdef ED_DBGP
|
2015-11-17 18:23:40 +00:00
|
|
|
printk("dev->ioport[c] = %x inb(dev->ioport[c] + 0x1c) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],inb(dev->ioport[c] + 0x1c),c,dev->in_int[c],c,dev->in_snd[c]);
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
2015-11-17 18:23:40 +00:00
|
|
|
if ((inb(dev->ioport[c] + 0x1c) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("Call sent_s870(atp870u_queuecommand)\n");
|
|
|
|
#endif
|
|
|
|
send_s870(dev,c);
|
|
|
|
}
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("atp870u_queuecommand : exit\n");
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-11-16 07:10:29 +00:00
|
|
|
static DEF_SCSI_QCMD(atp870u_queuecommand)
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/**
|
|
|
|
* send_s870 - send a command to the controller
|
|
|
|
* @host: host
|
|
|
|
*
|
|
|
|
* On entry there is work queued to be done. We move some of that work to the
|
|
|
|
* controller itself.
|
|
|
|
*
|
|
|
|
* Caller holds the host lock.
|
|
|
|
*/
|
|
|
|
static void send_s870(struct atp_unit *dev,unsigned char c)
|
|
|
|
{
|
|
|
|
struct scsi_cmnd *workreq;
|
|
|
|
unsigned int i;//,k;
|
|
|
|
unsigned char j, target_id;
|
|
|
|
unsigned char *prd;
|
2015-11-17 18:23:48 +00:00
|
|
|
unsigned short int w;
|
2005-04-16 22:20:36 +00:00
|
|
|
unsigned long l, bttl = 0;
|
|
|
|
unsigned long sg_count;
|
|
|
|
|
|
|
|
if (dev->in_snd[c] != 0) {
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("cmnd in_snd\n");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("Sent_s870 enter\n");
|
|
|
|
#endif
|
|
|
|
dev->in_snd[c] = 1;
|
|
|
|
if ((dev->last_cmd[c] != 0xff) && ((dev->last_cmd[c] & 0x40) != 0)) {
|
|
|
|
dev->last_cmd[c] &= 0x0f;
|
|
|
|
workreq = dev->id[c][dev->last_cmd[c]].curr_req;
|
|
|
|
if (workreq != NULL) { /* check NULL pointer */
|
|
|
|
goto cmd_subp;
|
|
|
|
}
|
|
|
|
dev->last_cmd[c] = 0xff;
|
|
|
|
if (dev->quhd[c] == dev->quend[c]) {
|
|
|
|
dev->in_snd[c] = 0;
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) {
|
|
|
|
dev->in_snd[c] = 0;
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
dev->working[c]++;
|
|
|
|
j = dev->quhd[c];
|
|
|
|
dev->quhd[c]++;
|
|
|
|
if (dev->quhd[c] >= qcnt) {
|
|
|
|
dev->quhd[c] = 0;
|
|
|
|
}
|
|
|
|
workreq = dev->quereq[c][dev->quhd[c]];
|
2008-05-22 22:45:07 +00:00
|
|
|
if (dev->id[c][scmd_id(workreq)].curr_req == NULL) {
|
2005-10-24 22:05:09 +00:00
|
|
|
dev->id[c][scmd_id(workreq)].curr_req = workreq;
|
|
|
|
dev->last_cmd[c] = scmd_id(workreq);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto cmd_subp;
|
|
|
|
}
|
|
|
|
dev->quhd[c] = j;
|
|
|
|
dev->working[c]--;
|
|
|
|
dev->in_snd[c] = 0;
|
|
|
|
return;
|
|
|
|
cmd_subp:
|
2015-11-17 18:23:40 +00:00
|
|
|
if ((inb(dev->ioport[c] + 0x1f) & 0xb0) != 0) {
|
2005-04-16 22:20:36 +00:00
|
|
|
goto abortsnd;
|
|
|
|
}
|
2015-11-17 18:23:40 +00:00
|
|
|
if (inb(dev->ioport[c] + 0x1c) == 0) {
|
2005-04-16 22:20:36 +00:00
|
|
|
goto oktosend;
|
|
|
|
}
|
|
|
|
abortsnd:
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("Abort to Send\n");
|
|
|
|
#endif
|
|
|
|
dev->last_cmd[c] |= 0x40;
|
|
|
|
dev->in_snd[c] = 0;
|
|
|
|
return;
|
|
|
|
oktosend:
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("OK to Send\n");
|
2005-10-24 22:05:09 +00:00
|
|
|
scmd_printk(KERN_DEBUG, workreq, "CDB");
|
2005-04-16 22:20:36 +00:00
|
|
|
for(i=0;i<workreq->cmd_len;i++) {
|
|
|
|
printk(" %x",workreq->cmnd[i]);
|
|
|
|
}
|
2005-10-24 22:05:09 +00:00
|
|
|
printk("\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
2007-09-09 18:06:23 +00:00
|
|
|
l = scsi_bufflen(workreq);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (dev->dev_id == ATP885_DEVID) {
|
|
|
|
j = inb(dev->baseport + 0x29) & 0xfe;
|
|
|
|
outb(j, dev->baseport + 0x29);
|
2005-10-24 22:05:09 +00:00
|
|
|
dev->r1f[c][scmd_id(workreq)] = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (workreq->cmnd[0] == READ_CAPACITY) {
|
2007-09-09 18:06:23 +00:00
|
|
|
if (l > 8)
|
|
|
|
l = 8;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
if (workreq->cmnd[0] == 0x00) {
|
2007-09-09 18:06:23 +00:00
|
|
|
l = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
j = 0;
|
2005-10-24 22:05:09 +00:00
|
|
|
target_id = scmd_id(workreq);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Wide ?
|
|
|
|
*/
|
|
|
|
w = 1;
|
|
|
|
w = w << target_id;
|
|
|
|
if ((w & dev->wide_id[c]) != 0) {
|
|
|
|
j |= 0x01;
|
|
|
|
}
|
2015-11-17 18:23:40 +00:00
|
|
|
outb(j, dev->ioport[c] + 0x1b);
|
|
|
|
while ((inb(dev->ioport[c] + 0x1b) & 0x01) != j) {
|
|
|
|
outb(j,dev->ioport[c] + 0x1b);
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("send_s870 while loop 1\n");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Write the command
|
|
|
|
*/
|
|
|
|
|
2015-11-17 18:23:40 +00:00
|
|
|
outb(workreq->cmd_len, dev->ioport[c] + 0x00);
|
|
|
|
outb(0x2c, dev->ioport[c] + 0x01);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (dev->dev_id == ATP885_DEVID) {
|
2015-11-17 18:23:40 +00:00
|
|
|
outb(0x7f, dev->ioport[c] + 0x02);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:40 +00:00
|
|
|
outb(0xcf, dev->ioport[c] + 0x02);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < workreq->cmd_len; i++) {
|
2015-11-17 18:23:40 +00:00
|
|
|
outb(workreq->cmnd[i], dev->ioport[c] + 0x03 + i);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-11-17 18:23:40 +00:00
|
|
|
outb(workreq->device->lun, dev->ioport[c] + 0x0f);
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Write the target
|
|
|
|
*/
|
2015-11-17 18:23:40 +00:00
|
|
|
outb(dev->id[c][target_id].devsp, dev->ioport[c] + 0x11);
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp);
|
|
|
|
#endif
|
2007-09-09 18:06:23 +00:00
|
|
|
|
|
|
|
sg_count = scsi_dma_map(workreq);
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Write transfer size
|
|
|
|
*/
|
2015-11-17 18:23:40 +00:00
|
|
|
outb((unsigned char) (((unsigned char *) (&l))[2]), dev->ioport[c] + 0x12);
|
|
|
|
outb((unsigned char) (((unsigned char *) (&l))[1]), dev->ioport[c] + 0x13);
|
|
|
|
outb((unsigned char) (((unsigned char *) (&l))[0]), dev->ioport[c] + 0x14);
|
2005-04-16 22:20:36 +00:00
|
|
|
j = target_id;
|
|
|
|
dev->id[c][j].last_len = l;
|
|
|
|
dev->id[c][j].tran_len = 0;
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("dev->id[%2d][%2d].last_len = %d\n",c,j,dev->id[c][j].last_len);
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* Flip the wide bits
|
|
|
|
*/
|
|
|
|
if ((j & 0x08) != 0) {
|
|
|
|
j = (j & 0x07) | 0x40;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Check transfer direction
|
|
|
|
*/
|
|
|
|
if (workreq->sc_data_direction == DMA_TO_DEVICE) {
|
2015-11-17 18:23:40 +00:00
|
|
|
outb((unsigned char) (j | 0x20), dev->ioport[c] + 0x15);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:40 +00:00
|
|
|
outb(j, dev->ioport[c] + 0x15);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-11-17 18:23:40 +00:00
|
|
|
outb((unsigned char) (inb(dev->ioport[c] + 0x16) | 0x80), dev->ioport[c] + 0x16);
|
|
|
|
outb(0x80, dev->ioport[c] + 0x16);
|
2005-04-16 22:20:36 +00:00
|
|
|
dev->id[c][target_id].dirct = 0;
|
|
|
|
if (l == 0) {
|
2015-11-17 18:23:40 +00:00
|
|
|
if (inb(dev->ioport[c] + 0x1c) == 0) {
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("change SCSI_CMD_REG 0x08\n");
|
|
|
|
#endif
|
2015-11-17 18:23:40 +00:00
|
|
|
outb(0x08, dev->ioport[c] + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
|
|
|
dev->last_cmd[c] |= 0x40;
|
|
|
|
}
|
|
|
|
dev->in_snd[c] = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
prd = dev->id[c][target_id].prd_table;
|
|
|
|
dev->id[c][target_id].prd_pos = prd;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now write the request list. Either as scatter/gather or as
|
|
|
|
* a linear chain.
|
|
|
|
*/
|
|
|
|
|
2007-09-09 18:06:23 +00:00
|
|
|
if (l) {
|
|
|
|
struct scatterlist *sgpnt;
|
2005-04-16 22:20:36 +00:00
|
|
|
i = 0;
|
2007-09-09 18:06:23 +00:00
|
|
|
scsi_for_each_sg(workreq, sgpnt, sg_count, j) {
|
|
|
|
bttl = sg_dma_address(sgpnt);
|
|
|
|
l=sg_dma_len(sgpnt);
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef ED_DBGP
|
2007-09-09 18:06:23 +00:00
|
|
|
printk("1. bttl %x, l %x\n",bttl, l);
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
2007-09-09 18:06:23 +00:00
|
|
|
while (l > 0x10000) {
|
2005-04-16 22:20:36 +00:00
|
|
|
(((u16 *) (prd))[i + 3]) = 0x0000;
|
|
|
|
(((u16 *) (prd))[i + 2]) = 0x0000;
|
|
|
|
(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
|
|
|
|
l -= 0x10000;
|
|
|
|
bttl += 0x10000;
|
|
|
|
i += 0x04;
|
|
|
|
}
|
|
|
|
(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
|
|
|
|
(((u16 *) (prd))[i + 2]) = cpu_to_le16(l);
|
|
|
|
(((u16 *) (prd))[i + 3]) = 0;
|
|
|
|
i += 0x04;
|
|
|
|
}
|
|
|
|
(((u16 *) (prd))[i - 1]) = cpu_to_le16(0x8000);
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3]));
|
|
|
|
printk("2. bttl %x, l %x\n",bttl, l);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef ED_DBGP
|
2015-11-17 18:23:48 +00:00
|
|
|
printk("send_s870: prdaddr_2 0x%8x target_id %d\n", dev->id[c][target_id].prdaddr,target_id);
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
2005-09-15 13:59:36 +00:00
|
|
|
dev->id[c][target_id].prdaddr = dev->id[c][target_id].prd_bus;
|
2015-11-17 18:23:48 +00:00
|
|
|
outl(dev->id[c][target_id].prdaddr, dev->pciport[c] + 4);
|
|
|
|
outb(0x06, dev->pciport[c] + 2);
|
|
|
|
outb(0x00, dev->pciport[c] + 2);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (dev->dev_id == ATP885_DEVID) {
|
2015-11-17 18:23:48 +00:00
|
|
|
j = inb(dev->pciport[c] + 1) & 0xf3;
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) ||
|
|
|
|
(workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
|
|
|
|
j |= 0x0c;
|
|
|
|
}
|
2015-11-17 18:23:48 +00:00
|
|
|
outb(j, dev->pciport[c] + 1);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else if ((dev->dev_id == ATP880_DEVID1) ||
|
|
|
|
(dev->dev_id == ATP880_DEVID2)) {
|
|
|
|
if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
|
2015-11-17 18:23:40 +00:00
|
|
|
outb((unsigned char) ((inb(dev->ioport[c] - 0x05) & 0x3f) | 0xc0), dev->ioport[c] - 0x05);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:40 +00:00
|
|
|
outb((unsigned char) (inb(dev->ioport[c] - 0x05) & 0x3f), dev->ioport[c] - 0x05);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
|
2015-11-17 18:23:40 +00:00
|
|
|
outb((inb(dev->ioport[c] + 0x3a) & 0xf3) | 0x08, dev->ioport[c] + 0x3a);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:40 +00:00
|
|
|
outb(inb(dev->ioport[c] + 0x3a) & 0xf3, dev->ioport[c] + 0x3a);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(workreq->sc_data_direction == DMA_TO_DEVICE) {
|
|
|
|
dev->id[c][target_id].dirct = 0x20;
|
2015-11-17 18:23:40 +00:00
|
|
|
if (inb(dev->ioport[c] + 0x1c) == 0) {
|
|
|
|
outb(0x08, dev->ioport[c] + 0x18);
|
2015-11-17 18:23:48 +00:00
|
|
|
outb(0x01, dev->pciport[c]);
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk( "start DMA(to target)\n");
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
dev->last_cmd[c] |= 0x40;
|
|
|
|
}
|
|
|
|
dev->in_snd[c] = 0;
|
|
|
|
return;
|
|
|
|
}
|
2015-11-17 18:23:40 +00:00
|
|
|
if (inb(dev->ioport[c] + 0x1c) == 0) {
|
|
|
|
outb(0x08, dev->ioport[c] + 0x18);
|
2015-11-17 18:23:48 +00:00
|
|
|
outb(0x09, dev->pciport[c]);
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk( "start DMA(to host)\n");
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
dev->last_cmd[c] |= 0x40;
|
|
|
|
}
|
|
|
|
dev->in_snd[c] = 0;
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val)
|
|
|
|
{
|
|
|
|
unsigned short int i, k;
|
|
|
|
unsigned char j;
|
|
|
|
|
2015-11-17 18:23:41 +00:00
|
|
|
outw(*val, dev->ioport[0] + 0x1c);
|
2005-04-16 22:20:36 +00:00
|
|
|
FUN_D7:
|
|
|
|
for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
|
2015-11-17 18:23:41 +00:00
|
|
|
k = inw(dev->ioport[0] + 0x1c);
|
2005-04-16 22:20:36 +00:00
|
|
|
j = (unsigned char) (k >> 8);
|
|
|
|
if ((k & 0x8000) != 0) { /* DB7 all release? */
|
|
|
|
goto FUN_D7;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*val |= 0x4000; /* assert DB6 */
|
2015-11-17 18:23:41 +00:00
|
|
|
outw(*val, dev->ioport[0] + 0x1c);
|
2005-04-16 22:20:36 +00:00
|
|
|
*val &= 0xdfff; /* assert DB5 */
|
2015-11-17 18:23:41 +00:00
|
|
|
outw(*val, dev->ioport[0] + 0x1c);
|
2005-04-16 22:20:36 +00:00
|
|
|
FUN_D5:
|
|
|
|
for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
|
2015-11-17 18:23:41 +00:00
|
|
|
if ((inw(dev->ioport[0] + 0x1c) & 0x2000) != 0) { /* DB5 all release? */
|
2005-04-16 22:20:36 +00:00
|
|
|
goto FUN_D5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*val |= 0x8000; /* no DB4-0, assert DB7 */
|
|
|
|
*val &= 0xe0ff;
|
2015-11-17 18:23:41 +00:00
|
|
|
outw(*val, dev->ioport[0] + 0x1c);
|
2005-04-16 22:20:36 +00:00
|
|
|
*val &= 0xbfff; /* release DB6 */
|
2015-11-17 18:23:41 +00:00
|
|
|
outw(*val, dev->ioport[0] + 0x1c);
|
2005-04-16 22:20:36 +00:00
|
|
|
FUN_D6:
|
|
|
|
for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
|
2015-11-17 18:23:41 +00:00
|
|
|
if ((inw(dev->ioport[0] + 0x1c) & 0x4000) != 0) { /* DB6 all release? */
|
2005-04-16 22:20:36 +00:00
|
|
|
goto FUN_D6;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return j;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tscam(struct Scsi_Host *host)
|
|
|
|
{
|
|
|
|
|
|
|
|
unsigned char i, j, k;
|
|
|
|
unsigned long n;
|
|
|
|
unsigned short int m, assignid_map, val;
|
|
|
|
unsigned char mbuf[33], quintet[2];
|
|
|
|
struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
|
|
|
|
static unsigned char g2q_tab[8] = {
|
|
|
|
0x38, 0x31, 0x32, 0x2b, 0x34, 0x2d, 0x2e, 0x27
|
|
|
|
};
|
|
|
|
|
|
|
|
/* I can't believe we need this before we've even done anything. Remove it
|
|
|
|
* and see if anyone bitches.
|
|
|
|
for (i = 0; i < 0x10; i++) {
|
|
|
|
udelay(0xffff);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2015-11-17 18:23:41 +00:00
|
|
|
outb(0x08, dev->ioport[0] + 1);
|
|
|
|
outb(0x7f, dev->ioport[0] + 2);
|
|
|
|
outb(0x20, dev->ioport[0] + 0x11);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if ((dev->scam_on & 0x40) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m = 1;
|
|
|
|
m <<= dev->host_id[0];
|
|
|
|
j = 16;
|
|
|
|
if (dev->chip_ver < 4) {
|
|
|
|
m |= 0xff00;
|
|
|
|
j = 8;
|
|
|
|
}
|
|
|
|
assignid_map = m;
|
2015-11-17 18:23:41 +00:00
|
|
|
outb(0x02, dev->ioport[0] + 0x02); /* 2*2=4ms,3EH 2/32*3E=3.9ms */
|
|
|
|
outb(0, dev->ioport[0] + 0x03);
|
|
|
|
outb(0, dev->ioport[0] + 0x04);
|
|
|
|
outb(0, dev->ioport[0] + 0x05);
|
|
|
|
outb(0, dev->ioport[0] + 0x06);
|
|
|
|
outb(0, dev->ioport[0] + 0x07);
|
|
|
|
outb(0, dev->ioport[0] + 0x08);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
for (i = 0; i < j; i++) {
|
|
|
|
m = 1;
|
|
|
|
m = m << i;
|
|
|
|
if ((m & assignid_map) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-11-17 18:23:41 +00:00
|
|
|
outb(0, dev->ioport[0] + 0x0f);
|
|
|
|
outb(0, dev->ioport[0] + 0x12);
|
|
|
|
outb(0, dev->ioport[0] + 0x13);
|
|
|
|
outb(0, dev->ioport[0] + 0x14);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (i > 7) {
|
|
|
|
k = (i & 0x07) | 0x40;
|
|
|
|
} else {
|
|
|
|
k = i;
|
|
|
|
}
|
2015-11-17 18:23:41 +00:00
|
|
|
outb(k, dev->ioport[0] + 0x15);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (dev->chip_ver == 4) {
|
2015-11-17 18:23:41 +00:00
|
|
|
outb(0x01, dev->ioport[0] + 0x1b);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:41 +00:00
|
|
|
outb(0x00, dev->ioport[0] + 0x1b);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
wait_rdyok:
|
2015-11-17 18:23:41 +00:00
|
|
|
outb(0x09, dev->ioport[0] + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:41 +00:00
|
|
|
while ((inb(dev->ioport[0] + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:41 +00:00
|
|
|
k = inb(dev->ioport[0] + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (k != 0x16) {
|
|
|
|
if ((k == 0x85) || (k == 0x42)) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-11-17 18:23:41 +00:00
|
|
|
outb(0x41, dev->ioport[0] + 0x10);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto wait_rdyok;
|
|
|
|
}
|
|
|
|
assignid_map |= m;
|
|
|
|
|
|
|
|
}
|
2015-11-17 18:23:41 +00:00
|
|
|
outb(0x7f, dev->ioport[0] + 0x02);
|
|
|
|
outb(0x02, dev->ioport[0] + 0x1b);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
outb(0, 0x80);
|
|
|
|
|
|
|
|
val = 0x0080; /* bsy */
|
2015-11-17 18:23:41 +00:00
|
|
|
outw(val, dev->ioport[0] + 0x1c);
|
2005-04-16 22:20:36 +00:00
|
|
|
val |= 0x0040; /* sel */
|
2015-11-17 18:23:41 +00:00
|
|
|
outw(val, dev->ioport[0] + 0x1c);
|
2005-04-16 22:20:36 +00:00
|
|
|
val |= 0x0004; /* msg */
|
2015-11-17 18:23:41 +00:00
|
|
|
outw(val, dev->ioport[0] + 0x1c);
|
2005-04-16 22:20:36 +00:00
|
|
|
inb(0x80); /* 2 deskew delay(45ns*2=90ns) */
|
|
|
|
val &= 0x007f; /* no bsy */
|
2015-11-17 18:23:41 +00:00
|
|
|
outw(val, dev->ioport[0] + 0x1c);
|
2005-04-16 22:20:36 +00:00
|
|
|
mdelay(128);
|
|
|
|
val &= 0x00fb; /* after 1ms no msg */
|
2015-11-17 18:23:41 +00:00
|
|
|
outw(val, dev->ioport[0] + 0x1c);
|
2005-04-16 22:20:36 +00:00
|
|
|
wait_nomsg:
|
2015-11-17 18:23:41 +00:00
|
|
|
if ((inb(dev->ioport[0] + 0x1c) & 0x04) != 0) {
|
2005-04-16 22:20:36 +00:00
|
|
|
goto wait_nomsg;
|
|
|
|
}
|
|
|
|
outb(1, 0x80);
|
|
|
|
udelay(100);
|
|
|
|
for (n = 0; n < 0x30000; n++) {
|
2015-11-17 18:23:41 +00:00
|
|
|
if ((inb(dev->ioport[0] + 0x1c) & 0x80) != 0) { /* bsy ? */
|
2005-04-16 22:20:36 +00:00
|
|
|
goto wait_io;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
goto TCM_SYNC;
|
|
|
|
wait_io:
|
|
|
|
for (n = 0; n < 0x30000; n++) {
|
2015-11-17 18:23:41 +00:00
|
|
|
if ((inb(dev->ioport[0] + 0x1c) & 0x81) == 0x0081) {
|
2005-04-16 22:20:36 +00:00
|
|
|
goto wait_io1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
goto TCM_SYNC;
|
|
|
|
wait_io1:
|
|
|
|
inb(0x80);
|
|
|
|
val |= 0x8003; /* io,cd,db7 */
|
2015-11-17 18:23:41 +00:00
|
|
|
outw(val, dev->ioport[0] + 0x1c);
|
2005-04-16 22:20:36 +00:00
|
|
|
inb(0x80);
|
|
|
|
val &= 0x00bf; /* no sel */
|
2015-11-17 18:23:41 +00:00
|
|
|
outw(val, dev->ioport[0] + 0x1c);
|
2005-04-16 22:20:36 +00:00
|
|
|
outb(2, 0x80);
|
|
|
|
TCM_SYNC:
|
2012-10-05 00:11:25 +00:00
|
|
|
/*
|
|
|
|
* The funny division into multiple delays is to accomodate
|
|
|
|
* arches like ARM where udelay() multiplies its argument by
|
|
|
|
* a large number to initialize a loop counter. To avoid
|
|
|
|
* overflow, the maximum supported udelay is 2000 microseconds.
|
|
|
|
*
|
|
|
|
* XXX it would be more polite to find a way to use msleep()
|
|
|
|
*/
|
|
|
|
mdelay(2);
|
|
|
|
udelay(48);
|
2015-11-17 18:23:41 +00:00
|
|
|
if ((inb(dev->ioport[0] + 0x1c) & 0x80) == 0x00) { /* bsy ? */
|
|
|
|
outw(0, dev->ioport[0] + 0x1c);
|
|
|
|
outb(0, dev->ioport[0] + 0x1b);
|
|
|
|
outb(0, dev->ioport[0] + 0x15);
|
|
|
|
outb(0x09, dev->ioport[0] + 0x18);
|
|
|
|
while ((inb(dev->ioport[0] + 0x1f) & 0x80) == 0)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:41 +00:00
|
|
|
inb(dev->ioport[0] + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
val &= 0x00ff; /* synchronization */
|
|
|
|
val |= 0x3f00;
|
|
|
|
fun_scam(dev, &val);
|
|
|
|
outb(3, 0x80);
|
|
|
|
val &= 0x00ff; /* isolation */
|
|
|
|
val |= 0x2000;
|
|
|
|
fun_scam(dev, &val);
|
|
|
|
outb(4, 0x80);
|
|
|
|
i = 8;
|
|
|
|
j = 0;
|
|
|
|
TCM_ID:
|
2015-11-17 18:23:41 +00:00
|
|
|
if ((inw(dev->ioport[0] + 0x1c) & 0x2000) == 0) {
|
2005-04-16 22:20:36 +00:00
|
|
|
goto TCM_ID;
|
|
|
|
}
|
|
|
|
outb(5, 0x80);
|
|
|
|
val &= 0x00ff; /* get ID_STRING */
|
|
|
|
val |= 0x2000;
|
|
|
|
k = fun_scam(dev, &val);
|
|
|
|
if ((k & 0x03) == 0) {
|
|
|
|
goto TCM_5;
|
|
|
|
}
|
|
|
|
mbuf[j] <<= 0x01;
|
|
|
|
mbuf[j] &= 0xfe;
|
|
|
|
if ((k & 0x02) != 0) {
|
|
|
|
mbuf[j] |= 0x01;
|
|
|
|
}
|
|
|
|
i--;
|
|
|
|
if (i > 0) {
|
|
|
|
goto TCM_ID;
|
|
|
|
}
|
|
|
|
j++;
|
|
|
|
i = 8;
|
|
|
|
goto TCM_ID;
|
|
|
|
|
|
|
|
TCM_5: /* isolation complete.. */
|
|
|
|
/* mbuf[32]=0;
|
|
|
|
printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */
|
|
|
|
i = 15;
|
|
|
|
j = mbuf[0];
|
2011-03-31 01:57:33 +00:00
|
|
|
if ((j & 0x20) != 0) { /* bit5=1:ID up to 7 */
|
2005-04-16 22:20:36 +00:00
|
|
|
i = 7;
|
|
|
|
}
|
|
|
|
if ((j & 0x06) == 0) { /* IDvalid? */
|
|
|
|
goto G2Q5;
|
|
|
|
}
|
|
|
|
k = mbuf[1];
|
|
|
|
small_id:
|
|
|
|
m = 1;
|
|
|
|
m <<= k;
|
|
|
|
if ((m & assignid_map) == 0) {
|
|
|
|
goto G2Q_QUIN;
|
|
|
|
}
|
|
|
|
if (k > 0) {
|
|
|
|
k--;
|
|
|
|
goto small_id;
|
|
|
|
}
|
|
|
|
G2Q5: /* srch from max acceptable ID# */
|
|
|
|
k = i; /* max acceptable ID# */
|
|
|
|
G2Q_LP:
|
|
|
|
m = 1;
|
|
|
|
m <<= k;
|
|
|
|
if ((m & assignid_map) == 0) {
|
|
|
|
goto G2Q_QUIN;
|
|
|
|
}
|
|
|
|
if (k > 0) {
|
|
|
|
k--;
|
|
|
|
goto G2Q_LP;
|
|
|
|
}
|
|
|
|
G2Q_QUIN: /* k=binID#, */
|
|
|
|
assignid_map |= m;
|
|
|
|
if (k < 8) {
|
|
|
|
quintet[0] = 0x38; /* 1st dft ID<8 */
|
|
|
|
} else {
|
|
|
|
quintet[0] = 0x31; /* 1st ID>=8 */
|
|
|
|
}
|
|
|
|
k &= 0x07;
|
|
|
|
quintet[1] = g2q_tab[k];
|
|
|
|
|
|
|
|
val &= 0x00ff; /* AssignID 1stQuintet,AH=001xxxxx */
|
|
|
|
m = quintet[0] << 8;
|
|
|
|
val |= m;
|
|
|
|
fun_scam(dev, &val);
|
|
|
|
val &= 0x00ff; /* AssignID 2ndQuintet,AH=001xxxxx */
|
|
|
|
m = quintet[1] << 8;
|
|
|
|
val |= m;
|
|
|
|
fun_scam(dev, &val);
|
|
|
|
|
|
|
|
goto TCM_SYNC;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void is870(struct atp_unit *dev, unsigned int wkport)
|
|
|
|
{
|
|
|
|
unsigned char i, j, k, rmb, n;
|
|
|
|
unsigned short int m;
|
|
|
|
static unsigned char mbuf[512];
|
|
|
|
static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
|
|
|
|
static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
|
|
|
|
static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
|
|
|
|
static unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0c, 0x0e };
|
|
|
|
static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 };
|
|
|
|
static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
outb((unsigned char) (inb(wkport + 0x3a) | 0x10), wkport + 0x3a);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
if ((dev->chip_ver != 4) && (i > 7)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
m = 1;
|
|
|
|
m = m << i;
|
|
|
|
if ((m & dev->active_id[0]) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (i == dev->host_id[0]) {
|
|
|
|
printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[0]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (dev->chip_ver == 4) {
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x01, wkport + 0x1b);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x00, wkport + 0x1b);
|
|
|
|
}
|
|
|
|
outb(0x08, wkport + 1);
|
|
|
|
outb(0x7f, wkport + 2);
|
|
|
|
outb(satn[0], wkport + 3);
|
|
|
|
outb(satn[1], wkport + 4);
|
|
|
|
outb(satn[2], wkport + 5);
|
|
|
|
outb(satn[3], wkport + 6);
|
|
|
|
outb(satn[4], wkport + 7);
|
|
|
|
outb(satn[5], wkport + 8);
|
|
|
|
outb(0, wkport + 0x0f);
|
|
|
|
outb(dev->id[0][i].devsp, wkport + 0x11);
|
|
|
|
outb(0, wkport + 0x12);
|
|
|
|
outb(satn[6], wkport + 0x13);
|
|
|
|
outb(satn[7], wkport + 0x14);
|
2005-04-16 22:20:36 +00:00
|
|
|
j = i;
|
|
|
|
if ((j & 0x08) != 0) {
|
|
|
|
j = (j & 0x07) | 0x40;
|
|
|
|
}
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(j, wkport + 0x15);
|
|
|
|
outb(satn[8], wkport + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
if (inb(wkport + 0x17) != 0x11 && inb(wkport + 0x17) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
while (inb(wkport + 0x17) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
|
|
|
dev->active_id[0] |= m;
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x30, wkport + 0x10);
|
|
|
|
outb(0x00, wkport + 0x04);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
phase_cmd:
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x08, wkport + 0x18);
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:42 +00:00
|
|
|
j = inb(wkport + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j != 0x16) {
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x41, wkport + 0x10);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto phase_cmd;
|
|
|
|
}
|
|
|
|
sel_ok:
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(inqd[0], wkport + 3);
|
|
|
|
outb(inqd[1], wkport + 4);
|
|
|
|
outb(inqd[2], wkport + 5);
|
|
|
|
outb(inqd[3], wkport + 6);
|
|
|
|
outb(inqd[4], wkport + 7);
|
|
|
|
outb(inqd[5], wkport + 8);
|
|
|
|
outb(0, wkport + 0x0f);
|
|
|
|
outb(dev->id[0][i].devsp, wkport + 0x11);
|
|
|
|
outb(0, wkport + 0x12);
|
|
|
|
outb(inqd[6], wkport + 0x13);
|
|
|
|
outb(inqd[7], wkport + 0x14);
|
|
|
|
outb(inqd[8], wkport + 0x18);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
if (inb(wkport + 0x17) != 0x11 && inb(wkport + 0x17) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
while (inb(wkport + 0x17) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
|
|
|
if (dev->chip_ver == 4)
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x00, wkport + 0x1b);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x08, wkport + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
j = 0;
|
|
|
|
rd_inq_data:
|
2015-11-17 18:23:42 +00:00
|
|
|
k = inb(wkport + 0x1f);
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((k & 0x01) != 0) {
|
2015-11-17 18:23:42 +00:00
|
|
|
mbuf[j++] = inb(wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto rd_inq_data;
|
|
|
|
}
|
|
|
|
if ((k & 0x80) == 0) {
|
|
|
|
goto rd_inq_data;
|
|
|
|
}
|
2015-11-17 18:23:42 +00:00
|
|
|
j = inb(wkport + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x16) {
|
|
|
|
goto inq_ok;
|
|
|
|
}
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x46, wkport + 0x10);
|
|
|
|
outb(0, wkport + 0x12);
|
|
|
|
outb(0, wkport + 0x13);
|
|
|
|
outb(0, wkport + 0x14);
|
|
|
|
outb(0x08, wkport + 0x18);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
if (inb(wkport + 0x17) != 0x16) {
|
2005-04-16 22:20:36 +00:00
|
|
|
goto sel_ok;
|
|
|
|
}
|
|
|
|
inq_ok:
|
|
|
|
mbuf[36] = 0;
|
|
|
|
printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]);
|
|
|
|
dev->id[0][i].devtype = mbuf[0];
|
|
|
|
rmb = mbuf[1];
|
|
|
|
n = mbuf[7];
|
|
|
|
if (dev->chip_ver != 4) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if ((mbuf[7] & 0x60) == 0) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if ((dev->global_map[0] & 0x20) == 0) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x01, wkport + 0x1b);
|
|
|
|
outb(satn[0], wkport + 3);
|
|
|
|
outb(satn[1], wkport + 4);
|
|
|
|
outb(satn[2], wkport + 5);
|
|
|
|
outb(satn[3], wkport + 6);
|
|
|
|
outb(satn[4], wkport + 7);
|
|
|
|
outb(satn[5], wkport + 8);
|
|
|
|
outb(0, wkport + 0x0f);
|
|
|
|
outb(dev->id[0][i].devsp, wkport + 0x11);
|
|
|
|
outb(0, wkport + 0x12);
|
|
|
|
outb(satn[6], wkport + 0x13);
|
|
|
|
outb(satn[7], wkport + 0x14);
|
|
|
|
outb(satn[8], wkport + 0x18);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
if (inb(wkport + 0x17) != 0x11 && inb(wkport + 0x17) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
while (inb(wkport + 0x17) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
|
|
|
try_wide:
|
|
|
|
j = 0;
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x05, wkport + 0x14);
|
|
|
|
outb(0x20, wkport + 0x18);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0) {
|
|
|
|
if ((inb(wkport + 0x1f) & 0x01) != 0)
|
|
|
|
outb(wide[j++], wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
while ((inb(wkport + 0x17) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
j = inb(wkport + 0x17) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto widep_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto widep_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto try_wide;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
widep_out:
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x20, wkport + 0x18);
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0) {
|
|
|
|
if ((inb(wkport + 0x1f) & 0x01) != 0)
|
|
|
|
outb(0, wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-11-17 18:23:42 +00:00
|
|
|
j = inb(wkport + 0x17) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto widep_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto widep_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto widep_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
widep_in:
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0xff, wkport + 0x14);
|
|
|
|
outb(0x20, wkport + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
k = 0;
|
|
|
|
widep_in1:
|
2015-11-17 18:23:42 +00:00
|
|
|
j = inb(wkport + 0x1f);
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((j & 0x01) != 0) {
|
2015-11-17 18:23:42 +00:00
|
|
|
mbuf[k++] = inb(wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto widep_in1;
|
|
|
|
}
|
|
|
|
if ((j & 0x80) == 0x00) {
|
|
|
|
goto widep_in1;
|
|
|
|
}
|
2015-11-17 18:23:42 +00:00
|
|
|
j = inb(wkport + 0x17) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto widep_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto widep_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto widep_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
widep_cmd:
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x30, wkport + 0x10);
|
|
|
|
outb(0x00, wkport + 0x14);
|
|
|
|
outb(0x08, wkport + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
j = inb(wkport + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j != 0x16) {
|
|
|
|
if (j == 0x4e) {
|
|
|
|
goto widep_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[0] != 0x01) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[1] != 0x02) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[2] != 0x03) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[3] != 0x01) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
m = 1;
|
|
|
|
m = m << i;
|
|
|
|
dev->wide_id[0] |= m;
|
|
|
|
not_wide:
|
|
|
|
if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
|
|
|
|
goto set_sync;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
set_sync:
|
|
|
|
j = 0;
|
|
|
|
if ((m & dev->wide_id[0]) != 0) {
|
|
|
|
j |= 0x01;
|
|
|
|
}
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(j, wkport + 0x1b);
|
|
|
|
outb(satn[0], wkport + 3);
|
|
|
|
outb(satn[1], wkport + 4);
|
|
|
|
outb(satn[2], wkport + 5);
|
|
|
|
outb(satn[3], wkport + 6);
|
|
|
|
outb(satn[4], wkport + 7);
|
|
|
|
outb(satn[5], wkport + 8);
|
|
|
|
outb(0, wkport + 0x0f);
|
|
|
|
outb(dev->id[0][i].devsp, wkport + 0x11);
|
|
|
|
outb(0, wkport + 0x12);
|
|
|
|
outb(satn[6], wkport + 0x13);
|
|
|
|
outb(satn[7], wkport + 0x14);
|
|
|
|
outb(satn[8], wkport + 0x18);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
if (inb(wkport + 0x17) != 0x11 && inb(wkport + 0x17) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
while (inb(wkport + 0x17) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
|
|
|
try_sync:
|
|
|
|
j = 0;
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x06, wkport + 0x14);
|
|
|
|
outb(0x20, wkport + 0x18);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0) {
|
|
|
|
if ((inb(wkport + 0x1f) & 0x01) != 0) {
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((m & dev->wide_id[0]) != 0) {
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(synw[j++], wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
|
|
|
if ((m & dev->ultra_map[0]) != 0) {
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(synu[j++], wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(synn[j++], wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
while ((inb(wkport + 0x17) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
j = inb(wkport + 0x17) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto phase_ins;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto phase_cmds;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto try_sync;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
phase_outs:
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x20, wkport + 0x18);
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00) {
|
|
|
|
if ((inb(wkport + 0x1f) & 0x01) != 0x00)
|
|
|
|
outb(0x00, wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-11-17 18:23:42 +00:00
|
|
|
j = inb(wkport + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x85) {
|
|
|
|
goto tar_dcons;
|
|
|
|
}
|
|
|
|
j &= 0x0f;
|
|
|
|
if (j == 0x0f) {
|
|
|
|
goto phase_ins;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto phase_cmds;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto phase_outs;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
phase_ins:
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0xff, wkport + 0x14);
|
|
|
|
outb(0x20, wkport + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
k = 0;
|
|
|
|
phase_ins1:
|
2015-11-17 18:23:42 +00:00
|
|
|
j = inb(wkport + 0x1f);
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((j & 0x01) != 0x00) {
|
2015-11-17 18:23:42 +00:00
|
|
|
mbuf[k++] = inb(wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto phase_ins1;
|
|
|
|
}
|
|
|
|
if ((j & 0x80) == 0x00) {
|
|
|
|
goto phase_ins1;
|
|
|
|
}
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
while ((inb(wkport + 0x17) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
j = inb(wkport + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x85) {
|
|
|
|
goto tar_dcons;
|
|
|
|
}
|
|
|
|
j &= 0x0f;
|
|
|
|
if (j == 0x0f) {
|
|
|
|
goto phase_ins;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto phase_cmds;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto phase_outs;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
phase_cmds:
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x30, wkport + 0x10);
|
2005-04-16 22:20:36 +00:00
|
|
|
tar_dcons:
|
2015-11-17 18:23:42 +00:00
|
|
|
outb(0x00, wkport + 0x14);
|
|
|
|
outb(0x08, wkport + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:42 +00:00
|
|
|
j = inb(wkport + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j != 0x16) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[0] != 0x01) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[1] != 0x03) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[4] == 0x00) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[3] > 0x64) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[4] > 0x0c) {
|
|
|
|
mbuf[4] = 0x0c;
|
|
|
|
}
|
|
|
|
dev->id[0][i].devsp = mbuf[4];
|
|
|
|
if ((mbuf[3] < 0x0d) && (rmb == 0)) {
|
|
|
|
j = 0xa0;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
if (mbuf[3] < 0x1a) {
|
|
|
|
j = 0x20;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
if (mbuf[3] < 0x33) {
|
|
|
|
j = 0x40;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
if (mbuf[3] < 0x4c) {
|
|
|
|
j = 0x50;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
j = 0x60;
|
|
|
|
set_syn_ok:
|
|
|
|
dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
|
|
|
|
}
|
2015-11-17 18:23:42 +00:00
|
|
|
outb((unsigned char) (inb(wkport + 0x3a) & 0xef), wkport + 0x3a);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void is880(struct atp_unit *dev, unsigned int wkport)
|
|
|
|
{
|
|
|
|
unsigned char i, j, k, rmb, n, lvdmode;
|
|
|
|
unsigned short int m;
|
|
|
|
static unsigned char mbuf[512];
|
|
|
|
static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
|
|
|
|
static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
|
|
|
|
static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
|
|
|
|
unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
|
|
|
|
static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
|
|
|
|
unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
|
|
|
|
static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
|
|
|
|
static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 };
|
|
|
|
|
|
|
|
lvdmode = inb(wkport + 0x3f) & 0x40;
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
m = 1;
|
|
|
|
m = m << i;
|
|
|
|
if ((m & dev->active_id[0]) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (i == dev->host_id[0]) {
|
|
|
|
printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[0]);
|
|
|
|
continue;
|
|
|
|
}
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x01, wkport + 0x5b);
|
|
|
|
outb(0x08, wkport + 0x41);
|
|
|
|
outb(0x7f, wkport + 0x42);
|
|
|
|
outb(satn[0], wkport + 0x43);
|
|
|
|
outb(satn[1], wkport + 0x44);
|
|
|
|
outb(satn[2], wkport + 0x45);
|
|
|
|
outb(satn[3], wkport + 0x46);
|
|
|
|
outb(satn[4], wkport + 0x47);
|
|
|
|
outb(satn[5], wkport + 0x48);
|
|
|
|
outb(0, wkport + 0x4f);
|
|
|
|
outb(dev->id[0][i].devsp, wkport + 0x51);
|
|
|
|
outb(0, wkport + 0x52);
|
|
|
|
outb(satn[6], wkport + 0x53);
|
|
|
|
outb(satn[7], wkport + 0x54);
|
2005-04-16 22:20:36 +00:00
|
|
|
j = i;
|
|
|
|
if ((j & 0x08) != 0) {
|
|
|
|
j = (j & 0x07) | 0x40;
|
|
|
|
}
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(j, wkport + 0x55);
|
|
|
|
outb(satn[8], wkport + 0x58);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
if (inb(wkport + 0x57) != 0x11 && inb(wkport + 0x57) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
while (inb(wkport + 0x57) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
|
|
|
dev->active_id[0] |= m;
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x30, wkport + 0x50);
|
|
|
|
outb(0x00, wkport + 0x54);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
phase_cmd:
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x08, wkport + 0x58);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j != 0x16) {
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x41, wkport + 0x50);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto phase_cmd;
|
|
|
|
}
|
|
|
|
sel_ok:
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(inqd[0], wkport + 0x43);
|
|
|
|
outb(inqd[1], wkport + 0x44);
|
|
|
|
outb(inqd[2], wkport + 0x45);
|
|
|
|
outb(inqd[3], wkport + 0x46);
|
|
|
|
outb(inqd[4], wkport + 0x47);
|
|
|
|
outb(inqd[5], wkport + 0x48);
|
|
|
|
outb(0, wkport + 0x4f);
|
|
|
|
outb(dev->id[0][i].devsp, wkport + 0x51);
|
|
|
|
outb(0, wkport + 0x52);
|
|
|
|
outb(inqd[6], wkport + 0x53);
|
|
|
|
outb(inqd[7], wkport + 0x54);
|
|
|
|
outb(inqd[8], wkport + 0x58);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
if (inb(wkport + 0x57) != 0x11 && inb(wkport + 0x57) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
while (inb(wkport + 0x57) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x00, wkport + 0x5b);
|
|
|
|
outb(0x08, wkport + 0x58);
|
2005-04-16 22:20:36 +00:00
|
|
|
j = 0;
|
|
|
|
rd_inq_data:
|
2015-11-17 18:23:43 +00:00
|
|
|
k = inb(wkport + 0x5f);
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((k & 0x01) != 0) {
|
2015-11-17 18:23:43 +00:00
|
|
|
mbuf[j++] = inb(wkport + 0x59);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto rd_inq_data;
|
|
|
|
}
|
|
|
|
if ((k & 0x80) == 0) {
|
|
|
|
goto rd_inq_data;
|
|
|
|
}
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x16) {
|
|
|
|
goto inq_ok;
|
|
|
|
}
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x46, wkport + 0x50);
|
|
|
|
outb(0, wkport + 0x52);
|
|
|
|
outb(0, wkport + 0x53);
|
|
|
|
outb(0, wkport + 0x54);
|
|
|
|
outb(0x08, wkport + 0x58);
|
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
if (inb(wkport + 0x57) != 0x16)
|
2005-04-16 22:20:36 +00:00
|
|
|
goto sel_ok;
|
|
|
|
|
|
|
|
inq_ok:
|
|
|
|
mbuf[36] = 0;
|
|
|
|
printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]);
|
|
|
|
dev->id[0][i].devtype = mbuf[0];
|
|
|
|
rmb = mbuf[1];
|
|
|
|
n = mbuf[7];
|
|
|
|
if ((mbuf[7] & 0x60) == 0) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if ((i < 8) && ((dev->global_map[0] & 0x20) == 0)) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if (lvdmode == 0) {
|
|
|
|
goto chg_wide;
|
|
|
|
}
|
|
|
|
if (dev->sp[0][i] != 0x04) // force u2
|
|
|
|
{
|
|
|
|
goto chg_wide;
|
|
|
|
}
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x01, wkport + 0x5b);
|
|
|
|
outb(satn[0], wkport + 0x43);
|
|
|
|
outb(satn[1], wkport + 0x44);
|
|
|
|
outb(satn[2], wkport + 0x45);
|
|
|
|
outb(satn[3], wkport + 0x46);
|
|
|
|
outb(satn[4], wkport + 0x47);
|
|
|
|
outb(satn[5], wkport + 0x48);
|
|
|
|
outb(0, wkport + 0x4f);
|
|
|
|
outb(dev->id[0][i].devsp, wkport + 0x51);
|
|
|
|
outb(0, wkport + 0x52);
|
|
|
|
outb(satn[6], wkport + 0x53);
|
|
|
|
outb(satn[7], wkport + 0x54);
|
|
|
|
outb(satn[8], wkport + 0x58);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
if (inb(wkport + 0x57) != 0x11 && inb(wkport + 0x57) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
while (inb(wkport + 0x57) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
|
|
|
try_u3:
|
|
|
|
j = 0;
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x09, wkport + 0x54);
|
|
|
|
outb(0x20, wkport + 0x58);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0) {
|
|
|
|
if ((inb(wkport + 0x5f) & 0x01) != 0)
|
|
|
|
outb(u3[j++], wkport + 0x59);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
while ((inb(wkport + 0x57) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto u3p_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto u3p_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto try_u3;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
u3p_out:
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x20, wkport + 0x58);
|
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0) {
|
|
|
|
if ((inb(wkport + 0x5f) & 0x01) != 0)
|
|
|
|
outb(0, wkport + 0x59);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto u3p_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto u3p_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto u3p_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
u3p_in:
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x09, wkport + 0x54);
|
|
|
|
outb(0x20, wkport + 0x58);
|
2005-04-16 22:20:36 +00:00
|
|
|
k = 0;
|
|
|
|
u3p_in1:
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x5f);
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((j & 0x01) != 0) {
|
2015-11-17 18:23:43 +00:00
|
|
|
mbuf[k++] = inb(wkport + 0x59);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto u3p_in1;
|
|
|
|
}
|
|
|
|
if ((j & 0x80) == 0x00) {
|
|
|
|
goto u3p_in1;
|
|
|
|
}
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto u3p_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto u3p_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto u3p_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
u3p_cmd:
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x30, wkport + 0x50);
|
|
|
|
outb(0x00, wkport + 0x54);
|
|
|
|
outb(0x08, wkport + 0x58);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j != 0x16) {
|
|
|
|
if (j == 0x4e) {
|
|
|
|
goto u3p_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[0] != 0x01) {
|
|
|
|
goto chg_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[1] != 0x06) {
|
|
|
|
goto chg_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[2] != 0x04) {
|
|
|
|
goto chg_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[3] == 0x09) {
|
|
|
|
m = 1;
|
|
|
|
m = m << i;
|
|
|
|
dev->wide_id[0] |= m;
|
|
|
|
dev->id[0][i].devsp = 0xce;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
chg_wide:
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x01, wkport + 0x5b);
|
|
|
|
outb(satn[0], wkport + 0x43);
|
|
|
|
outb(satn[1], wkport + 0x44);
|
|
|
|
outb(satn[2], wkport + 0x45);
|
|
|
|
outb(satn[3], wkport + 0x46);
|
|
|
|
outb(satn[4], wkport + 0x47);
|
|
|
|
outb(satn[5], wkport + 0x48);
|
|
|
|
outb(0, wkport + 0x4f);
|
|
|
|
outb(dev->id[0][i].devsp, wkport + 0x51);
|
|
|
|
outb(0, wkport + 0x52);
|
|
|
|
outb(satn[6], wkport + 0x53);
|
|
|
|
outb(satn[7], wkport + 0x54);
|
|
|
|
outb(satn[8], wkport + 0x58);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
if (inb(wkport + 0x57) != 0x11 && inb(wkport + 0x57) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
while (inb(wkport + 0x57) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
|
|
|
try_wide:
|
|
|
|
j = 0;
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x05, wkport + 0x54);
|
|
|
|
outb(0x20, wkport + 0x58);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0) {
|
|
|
|
if ((inb(wkport + 0x5f) & 0x01) != 0)
|
|
|
|
outb(wide[j++], wkport + 0x59);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-11-17 18:23:43 +00:00
|
|
|
while ((inb(wkport + 0x57) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto widep_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto widep_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto try_wide;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
widep_out:
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x20, wkport + 0x58);
|
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0) {
|
|
|
|
if ((inb(wkport + 0x5f) & 0x01) != 0)
|
|
|
|
outb(0, wkport + 0x59);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto widep_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto widep_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto widep_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
widep_in:
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0xff, wkport + 0x54);
|
|
|
|
outb(0x20, wkport + 0x58);
|
2005-04-16 22:20:36 +00:00
|
|
|
k = 0;
|
|
|
|
widep_in1:
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x5f);
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((j & 0x01) != 0) {
|
2015-11-17 18:23:43 +00:00
|
|
|
mbuf[k++] = inb(wkport + 0x59);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto widep_in1;
|
|
|
|
}
|
|
|
|
if ((j & 0x80) == 0x00) {
|
|
|
|
goto widep_in1;
|
|
|
|
}
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto widep_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto widep_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto widep_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
widep_cmd:
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x30, wkport + 0x50);
|
|
|
|
outb(0x00, wkport + 0x54);
|
|
|
|
outb(0x08, wkport + 0x58);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j != 0x16) {
|
|
|
|
if (j == 0x4e) {
|
|
|
|
goto widep_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[0] != 0x01) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[1] != 0x02) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[2] != 0x03) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[3] != 0x01) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
m = 1;
|
|
|
|
m = m << i;
|
|
|
|
dev->wide_id[0] |= m;
|
|
|
|
not_wide:
|
|
|
|
if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
|
|
|
|
m = 1;
|
|
|
|
m = m << i;
|
|
|
|
if ((dev->async[0] & m) != 0) {
|
|
|
|
goto set_sync;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
set_sync:
|
|
|
|
if (dev->sp[0][i] == 0x02) {
|
|
|
|
synu[4] = 0x0c;
|
|
|
|
synuw[4] = 0x0c;
|
|
|
|
} else {
|
|
|
|
if (dev->sp[0][i] >= 0x03) {
|
|
|
|
synu[4] = 0x0a;
|
|
|
|
synuw[4] = 0x0a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
j = 0;
|
|
|
|
if ((m & dev->wide_id[0]) != 0) {
|
|
|
|
j |= 0x01;
|
|
|
|
}
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(j, wkport + 0x5b);
|
|
|
|
outb(satn[0], wkport + 0x43);
|
|
|
|
outb(satn[1], wkport + 0x44);
|
|
|
|
outb(satn[2], wkport + 0x45);
|
|
|
|
outb(satn[3], wkport + 0x46);
|
|
|
|
outb(satn[4], wkport + 0x47);
|
|
|
|
outb(satn[5], wkport + 0x48);
|
|
|
|
outb(0, wkport + 0x4f);
|
|
|
|
outb(dev->id[0][i].devsp, wkport + 0x51);
|
|
|
|
outb(0, wkport + 0x52);
|
|
|
|
outb(satn[6], wkport + 0x53);
|
|
|
|
outb(satn[7], wkport + 0x54);
|
|
|
|
outb(satn[8], wkport + 0x58);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
if ((inb(wkport + 0x57) != 0x11) && (inb(wkport + 0x57) != 0x8e)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
}
|
2015-11-17 18:23:43 +00:00
|
|
|
while (inb(wkport + 0x57) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
|
|
|
try_sync:
|
|
|
|
j = 0;
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x06, wkport + 0x54);
|
|
|
|
outb(0x20, wkport + 0x58);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0) {
|
|
|
|
if ((inb(wkport + 0x5f) & 0x01) != 0) {
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((m & dev->wide_id[0]) != 0) {
|
|
|
|
if ((m & dev->ultra_map[0]) != 0) {
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(synuw[j++], wkport + 0x59);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(synw[j++], wkport + 0x59);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((m & dev->ultra_map[0]) != 0) {
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(synu[j++], wkport + 0x59);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(synn[j++], wkport + 0x59);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
while ((inb(wkport + 0x57) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto phase_ins;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto phase_cmds;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto try_sync;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
phase_outs:
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x20, wkport + 0x58);
|
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0x00) {
|
|
|
|
if ((inb(wkport + 0x5f) & 0x01) != 0x00)
|
|
|
|
outb(0x00, wkport + 0x59);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x85) {
|
|
|
|
goto tar_dcons;
|
|
|
|
}
|
|
|
|
j &= 0x0f;
|
|
|
|
if (j == 0x0f) {
|
|
|
|
goto phase_ins;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto phase_cmds;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto phase_outs;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
phase_ins:
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x06, wkport + 0x54);
|
|
|
|
outb(0x20, wkport + 0x58);
|
2005-04-16 22:20:36 +00:00
|
|
|
k = 0;
|
|
|
|
phase_ins1:
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x5f);
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((j & 0x01) != 0x00) {
|
2015-11-17 18:23:43 +00:00
|
|
|
mbuf[k++] = inb(wkport + 0x59);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto phase_ins1;
|
|
|
|
}
|
|
|
|
if ((j & 0x80) == 0x00) {
|
|
|
|
goto phase_ins1;
|
|
|
|
}
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
while ((inb(wkport + 0x57) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x85) {
|
|
|
|
goto tar_dcons;
|
|
|
|
}
|
|
|
|
j &= 0x0f;
|
|
|
|
if (j == 0x0f) {
|
|
|
|
goto phase_ins;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto phase_cmds;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto phase_outs;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
phase_cmds:
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x30, wkport + 0x50);
|
2005-04-16 22:20:36 +00:00
|
|
|
tar_dcons:
|
2015-11-17 18:23:43 +00:00
|
|
|
outb(0x00, wkport + 0x54);
|
|
|
|
outb(0x08, wkport + 0x58);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
while ((inb(wkport + 0x5f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:43 +00:00
|
|
|
j = inb(wkport + 0x57);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j != 0x16) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[0] != 0x01) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[1] != 0x03) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[4] == 0x00) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[3] > 0x64) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[4] > 0x0e) {
|
|
|
|
mbuf[4] = 0x0e;
|
|
|
|
}
|
|
|
|
dev->id[0][i].devsp = mbuf[4];
|
|
|
|
if (mbuf[3] < 0x0c) {
|
|
|
|
j = 0xb0;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
if ((mbuf[3] < 0x0d) && (rmb == 0)) {
|
|
|
|
j = 0xa0;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
if (mbuf[3] < 0x1a) {
|
|
|
|
j = 0x20;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
if (mbuf[3] < 0x33) {
|
|
|
|
j = 0x40;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
if (mbuf[3] < 0x4c) {
|
|
|
|
j = 0x50;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
j = 0x60;
|
|
|
|
set_syn_ok:
|
|
|
|
dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void atp870u_free_tables(struct Scsi_Host *host)
|
|
|
|
{
|
|
|
|
struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata;
|
|
|
|
int j, k;
|
|
|
|
for (j=0; j < 2; j++) {
|
|
|
|
for (k = 0; k < 16; k++) {
|
|
|
|
if (!atp_dev->id[j][k].prd_table)
|
|
|
|
continue;
|
2005-09-15 13:59:36 +00:00
|
|
|
pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prd_bus);
|
2005-04-16 22:20:36 +00:00
|
|
|
atp_dev->id[j][k].prd_table = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int atp870u_init_tables(struct Scsi_Host *host)
|
|
|
|
{
|
|
|
|
struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata;
|
|
|
|
int c,k;
|
|
|
|
for(c=0;c < 2;c++) {
|
|
|
|
for(k=0;k<16;k++) {
|
2005-09-15 13:59:36 +00:00
|
|
|
atp_dev->id[c][k].prd_table = pci_alloc_consistent(atp_dev->pdev, 1024, &(atp_dev->id[c][k].prd_bus));
|
2005-04-16 22:20:36 +00:00
|
|
|
if (!atp_dev->id[c][k].prd_table) {
|
|
|
|
printk("atp870u_init_tables fail\n");
|
|
|
|
atp870u_free_tables(host);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2005-09-15 13:59:36 +00:00
|
|
|
atp_dev->id[c][k].prdaddr = atp_dev->id[c][k].prd_bus;
|
2005-04-16 22:20:36 +00:00
|
|
|
atp_dev->id[c][k].devsp=0x20;
|
|
|
|
atp_dev->id[c][k].devtype = 0x7f;
|
|
|
|
atp_dev->id[c][k].curr_req = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
atp_dev->active_id[c] = 0;
|
|
|
|
atp_dev->wide_id[c] = 0;
|
|
|
|
atp_dev->host_id[c] = 0x07;
|
|
|
|
atp_dev->quhd[c] = 0;
|
|
|
|
atp_dev->quend[c] = 0;
|
|
|
|
atp_dev->last_cmd[c] = 0xff;
|
|
|
|
atp_dev->in_snd[c] = 0;
|
|
|
|
atp_dev->in_int[c] = 0;
|
|
|
|
|
|
|
|
for (k = 0; k < qcnt; k++) {
|
|
|
|
atp_dev->quereq[c][k] = NULL;
|
|
|
|
}
|
|
|
|
for (k = 0; k < 16; k++) {
|
|
|
|
atp_dev->id[c][k].curr_req = NULL;
|
|
|
|
atp_dev->sp[c][k] = 0x04;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return non-zero on detection */
|
|
|
|
static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
|
{
|
|
|
|
unsigned char k, m, c;
|
|
|
|
unsigned long flags;
|
2015-11-17 18:23:44 +00:00
|
|
|
unsigned int base_io, error,n;
|
2005-04-16 22:20:36 +00:00
|
|
|
unsigned char host_id;
|
|
|
|
struct Scsi_Host *shpnt = NULL;
|
2006-06-28 05:01:28 +00:00
|
|
|
struct atp_unit *atpdev, *p;
|
2005-04-16 22:20:36 +00:00
|
|
|
unsigned char setupdata[2][16];
|
|
|
|
int count = 0;
|
2006-06-28 05:01:28 +00:00
|
|
|
|
|
|
|
atpdev = kzalloc(sizeof(*atpdev), GFP_KERNEL);
|
|
|
|
if (!atpdev)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (pci_enable_device(pdev))
|
2006-06-28 05:01:28 +00:00
|
|
|
goto err_eio;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2009-04-07 02:01:15 +00:00
|
|
|
if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
|
2005-04-16 22:20:36 +00:00
|
|
|
printk(KERN_INFO "atp870u: use 32bit DMA mask.\n");
|
|
|
|
} else {
|
|
|
|
printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
|
2006-06-28 05:01:28 +00:00
|
|
|
goto err_eio;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It's probably easier to weed out some revisions like
|
|
|
|
* this than via the PCI device table
|
|
|
|
*/
|
|
|
|
if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) {
|
2012-03-14 19:04:30 +00:00
|
|
|
atpdev->chip_ver = pdev->revision;
|
2006-06-28 05:01:28 +00:00
|
|
|
if (atpdev->chip_ver < 2)
|
|
|
|
goto err_eio;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (ent->device) {
|
|
|
|
case PCI_DEVICE_ID_ARTOP_AEC7612UW:
|
|
|
|
case PCI_DEVICE_ID_ARTOP_AEC7612SUW:
|
|
|
|
case ATP880_DEVID1:
|
|
|
|
case ATP880_DEVID2:
|
|
|
|
case ATP885_DEVID:
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->chip_ver = 0x04;
|
2005-04-16 22:20:36 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
base_io = pci_resource_start(pdev, 0);
|
|
|
|
base_io &= 0xfffffff8;
|
2006-06-28 05:01:28 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) {
|
2012-03-14 19:04:30 +00:00
|
|
|
atpdev->chip_ver = pdev->revision;
|
2005-04-16 22:20:36 +00:00
|
|
|
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803
|
|
|
|
|
|
|
|
host_id = inb(base_io + 0x39);
|
|
|
|
host_id >>= 0x04;
|
|
|
|
|
|
|
|
printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d"
|
|
|
|
" IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->ioport[0] = base_io + 0x40;
|
|
|
|
atpdev->pciport[0] = base_io + 0x28;
|
|
|
|
atpdev->dev_id = ent->device;
|
|
|
|
atpdev->host_id[0] = host_id;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:44 +00:00
|
|
|
atpdev->scam_on = inb(base_io + 0x22);
|
|
|
|
atpdev->global_map[0] = inb(base_io + 0x35);
|
|
|
|
atpdev->ultra_map[0] = inw(base_io + 0x3c);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
n = 0x3f09;
|
|
|
|
next_fblk_880:
|
|
|
|
if (n >= 0x4000)
|
|
|
|
goto flash_ok_880;
|
|
|
|
|
|
|
|
m = 0;
|
|
|
|
outw(n, base_io + 0x34);
|
|
|
|
n += 0x0002;
|
|
|
|
if (inb(base_io + 0x30) == 0xff)
|
|
|
|
goto flash_ok_880;
|
|
|
|
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x30);
|
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x31);
|
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x32);
|
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x33);
|
2005-04-16 22:20:36 +00:00
|
|
|
outw(n, base_io + 0x34);
|
|
|
|
n += 0x0002;
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x30);
|
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x31);
|
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x32);
|
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x33);
|
2005-04-16 22:20:36 +00:00
|
|
|
outw(n, base_io + 0x34);
|
|
|
|
n += 0x0002;
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x30);
|
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x31);
|
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x32);
|
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x33);
|
2005-04-16 22:20:36 +00:00
|
|
|
outw(n, base_io + 0x34);
|
|
|
|
n += 0x0002;
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x30);
|
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x31);
|
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x32);
|
|
|
|
atpdev->sp[0][m++] = inb(base_io + 0x33);
|
2005-04-16 22:20:36 +00:00
|
|
|
n += 0x0018;
|
|
|
|
goto next_fblk_880;
|
|
|
|
flash_ok_880:
|
|
|
|
outw(0, base_io + 0x34);
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->ultra_map[0] = 0;
|
|
|
|
atpdev->async[0] = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
for (k = 0; k < 16; k++) {
|
|
|
|
n = 1;
|
|
|
|
n = n << k;
|
2006-06-28 05:01:28 +00:00
|
|
|
if (atpdev->sp[0][k] > 1) {
|
|
|
|
atpdev->ultra_map[0] |= n;
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2006-06-28 05:01:28 +00:00
|
|
|
if (atpdev->sp[0][k] == 0)
|
|
|
|
atpdev->async[0] |= n;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->async[0] = ~(atpdev->async[0]);
|
|
|
|
outb(atpdev->global_map[0], base_io + 0x35);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
|
|
|
|
if (!shpnt)
|
2006-06-28 05:01:28 +00:00
|
|
|
goto err_nomem;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
p = (struct atp_unit *)&shpnt->hostdata;
|
|
|
|
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->host = shpnt;
|
|
|
|
atpdev->pdev = pdev;
|
2005-04-16 22:20:36 +00:00
|
|
|
pci_set_drvdata(pdev, p);
|
2006-06-28 05:01:28 +00:00
|
|
|
memcpy(p, atpdev, sizeof(*atpdev));
|
2005-04-16 22:20:36 +00:00
|
|
|
if (atp870u_init_tables(shpnt) < 0) {
|
|
|
|
printk(KERN_ERR "Unable to allocate tables for Acard controller\n");
|
|
|
|
goto unregister;
|
|
|
|
}
|
|
|
|
|
2006-07-02 02:29:42 +00:00
|
|
|
if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp880i", shpnt)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
|
|
|
|
goto free_tables;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock_irqsave(shpnt->host_lock, flags);
|
2015-11-17 18:23:44 +00:00
|
|
|
k = inb(base_io + 0x38) & 0x80;
|
|
|
|
outb(k, base_io + 0x38);
|
|
|
|
outb(0x20, base_io + 0x3b);
|
2005-04-16 22:20:36 +00:00
|
|
|
mdelay(32);
|
2015-11-17 18:23:44 +00:00
|
|
|
outb(0, base_io + 0x3b);
|
2005-04-16 22:20:36 +00:00
|
|
|
mdelay(32);
|
2015-11-17 18:23:44 +00:00
|
|
|
inb(base_io + 0x5b);
|
|
|
|
inb(base_io + 0x57);
|
|
|
|
outb((host_id | 0x08), base_io + 0x40);
|
|
|
|
outb(0, base_io + 0x58);
|
|
|
|
while ((inb(base_io + 0x5f) & 0x80) == 0)
|
2005-04-16 22:20:36 +00:00
|
|
|
mdelay(1);
|
2015-11-17 18:23:44 +00:00
|
|
|
inb(base_io + 0x57);
|
|
|
|
outb(8, base_io + 0x41);
|
|
|
|
outb(0x7f, base_io + 0x42);
|
|
|
|
outb(0x20, base_io + 0x51);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
tscam(shpnt);
|
|
|
|
is880(p, base_io);
|
2015-11-17 18:23:44 +00:00
|
|
|
outb(0xb0, base_io + 0x38);
|
2005-04-16 22:20:36 +00:00
|
|
|
shpnt->max_id = 16;
|
|
|
|
shpnt->this_id = host_id;
|
|
|
|
shpnt->unique_id = base_io;
|
|
|
|
shpnt->io_port = base_io;
|
|
|
|
shpnt->n_io_port = 0x60; /* Number of bytes of I/O space used */
|
|
|
|
shpnt->irq = pdev->irq;
|
|
|
|
} else if (ent->device == ATP885_DEVID) {
|
|
|
|
printk(KERN_INFO " ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%x, IRQ:%d.\n"
|
|
|
|
, base_io, pdev->irq);
|
|
|
|
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->pdev = pdev;
|
|
|
|
atpdev->dev_id = ent->device;
|
|
|
|
atpdev->baseport = base_io;
|
|
|
|
atpdev->ioport[0] = base_io + 0x80;
|
|
|
|
atpdev->ioport[1] = base_io + 0xc0;
|
|
|
|
atpdev->pciport[0] = base_io + 0x40;
|
|
|
|
atpdev->pciport[1] = base_io + 0x50;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
|
|
|
|
if (!shpnt)
|
2006-06-28 05:01:28 +00:00
|
|
|
goto err_nomem;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
p = (struct atp_unit *)&shpnt->hostdata;
|
|
|
|
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->host = shpnt;
|
|
|
|
atpdev->pdev = pdev;
|
2005-04-16 22:20:36 +00:00
|
|
|
pci_set_drvdata(pdev, p);
|
2006-06-28 05:01:28 +00:00
|
|
|
memcpy(p, atpdev, sizeof(struct atp_unit));
|
2005-04-16 22:20:36 +00:00
|
|
|
if (atp870u_init_tables(shpnt) < 0)
|
|
|
|
goto unregister;
|
|
|
|
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("request_irq() shpnt %p hostdata %p\n", shpnt, p);
|
|
|
|
#endif
|
2006-07-02 02:29:42 +00:00
|
|
|
if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870u", shpnt)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n");
|
|
|
|
goto free_tables;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock_irqsave(shpnt->host_lock, flags);
|
|
|
|
|
|
|
|
c=inb(base_io + 0x29);
|
|
|
|
outb((c | 0x04),base_io + 0x29);
|
|
|
|
|
|
|
|
n=0x1f80;
|
|
|
|
next_fblk_885:
|
|
|
|
if (n >= 0x2000) {
|
|
|
|
goto flash_ok_885;
|
|
|
|
}
|
|
|
|
outw(n,base_io + 0x3c);
|
|
|
|
if (inl(base_io + 0x38) == 0xffffffff) {
|
|
|
|
goto flash_ok_885;
|
|
|
|
}
|
|
|
|
for (m=0; m < 2; m++) {
|
|
|
|
p->global_map[m]= 0;
|
|
|
|
for (k=0; k < 4; k++) {
|
|
|
|
outw(n++,base_io + 0x3c);
|
|
|
|
((unsigned long *)&setupdata[m][0])[k]=inl(base_io + 0x38);
|
|
|
|
}
|
|
|
|
for (k=0; k < 4; k++) {
|
|
|
|
outw(n++,base_io + 0x3c);
|
|
|
|
((unsigned long *)&p->sp[m][0])[k]=inl(base_io + 0x38);
|
|
|
|
}
|
|
|
|
n += 8;
|
|
|
|
}
|
|
|
|
goto next_fblk_885;
|
|
|
|
flash_ok_885:
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk( "Flash Read OK\n");
|
|
|
|
#endif
|
|
|
|
c=inb(base_io + 0x29);
|
|
|
|
outb((c & 0xfb),base_io + 0x29);
|
|
|
|
for (c=0;c < 2;c++) {
|
|
|
|
p->ultra_map[c]=0;
|
|
|
|
p->async[c] = 0;
|
|
|
|
for (k=0; k < 16; k++) {
|
|
|
|
n=1;
|
|
|
|
n = n << k;
|
|
|
|
if (p->sp[c][k] > 1) {
|
|
|
|
p->ultra_map[c] |= n;
|
|
|
|
} else {
|
|
|
|
if (p->sp[c][k] == 0) {
|
|
|
|
p->async[c] |= n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p->async[c] = ~(p->async[c]);
|
|
|
|
|
|
|
|
if (p->global_map[c] == 0) {
|
|
|
|
k=setupdata[c][1];
|
|
|
|
if ((k & 0x40) != 0)
|
|
|
|
p->global_map[c] |= 0x20;
|
|
|
|
k &= 0x07;
|
|
|
|
p->global_map[c] |= k;
|
|
|
|
if ((setupdata[c][2] & 0x04) != 0)
|
|
|
|
p->global_map[c] |= 0x08;
|
|
|
|
p->host_id[c] = setupdata[c][0] & 0x07;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
k = inb(base_io + 0x28) & 0x8f;
|
|
|
|
k |= 0x10;
|
|
|
|
outb(k, base_io + 0x28);
|
|
|
|
outb(0x80, base_io + 0x41);
|
|
|
|
outb(0x80, base_io + 0x51);
|
|
|
|
mdelay(100);
|
|
|
|
outb(0, base_io + 0x41);
|
|
|
|
outb(0, base_io + 0x51);
|
|
|
|
mdelay(1000);
|
|
|
|
inb(base_io + 0x9b);
|
|
|
|
inb(base_io + 0x97);
|
|
|
|
inb(base_io + 0xdb);
|
|
|
|
inb(base_io + 0xd7);
|
|
|
|
k=p->host_id[0];
|
|
|
|
if (k > 7)
|
|
|
|
k = (k & 0x07) | 0x40;
|
|
|
|
k |= 0x08;
|
2015-11-17 18:23:44 +00:00
|
|
|
outb(k, base_io + 0x80);
|
|
|
|
outb(0, base_io + 0x98);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:44 +00:00
|
|
|
while ((inb(base_io + 0x9f) & 0x80) == 0)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:44 +00:00
|
|
|
inb(base_io + 0x97);
|
|
|
|
outb(8, base_io + 0x81);
|
|
|
|
outb(0x7f, base_io + 0x82);
|
|
|
|
outb(0x20, base_io + 0x91);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
k=p->host_id[1];
|
|
|
|
if (k > 7)
|
|
|
|
k = (k & 0x07) | 0x40;
|
|
|
|
k |= 0x08;
|
2015-11-17 18:23:44 +00:00
|
|
|
outb(k, base_io + 0xc0);
|
|
|
|
outb(0, base_io + 0xd8);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:44 +00:00
|
|
|
while ((inb(base_io + 0xdf) & 0x80) == 0)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
|
2015-11-17 18:23:44 +00:00
|
|
|
inb(base_io + 0xd7);
|
|
|
|
outb(8, base_io + 0xc1);
|
|
|
|
outb(0x7f, base_io + 0xc2);
|
|
|
|
outb(0x20, base_io + 0xd1);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
tscam_885();
|
|
|
|
printk(KERN_INFO " Scanning Channel A SCSI Device ...\n");
|
|
|
|
is885(p, base_io + 0x80, 0);
|
|
|
|
printk(KERN_INFO " Scanning Channel B SCSI Device ...\n");
|
|
|
|
is885(p, base_io + 0xc0, 1);
|
|
|
|
|
|
|
|
k = inb(base_io + 0x28) & 0xcf;
|
|
|
|
k |= 0xc0;
|
|
|
|
outb(k, base_io + 0x28);
|
|
|
|
k = inb(base_io + 0x1f) | 0x80;
|
|
|
|
outb(k, base_io + 0x1f);
|
|
|
|
k = inb(base_io + 0x29) | 0x01;
|
|
|
|
outb(k, base_io + 0x29);
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
//printk("atp885: atp_host[0] 0x%p\n", atp_host[0]);
|
|
|
|
#endif
|
|
|
|
shpnt->max_id = 16;
|
|
|
|
shpnt->max_lun = (p->global_map[0] & 0x07) + 1;
|
|
|
|
shpnt->max_channel = 1;
|
|
|
|
shpnt->this_id = p->host_id[0];
|
|
|
|
shpnt->unique_id = base_io;
|
|
|
|
shpnt->io_port = base_io;
|
|
|
|
shpnt->n_io_port = 0xff; /* Number of bytes of I/O space used */
|
|
|
|
shpnt->irq = pdev->irq;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
error = pci_read_config_byte(pdev, 0x49, &host_id);
|
|
|
|
|
|
|
|
printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d "
|
|
|
|
"IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
|
|
|
|
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->ioport[0] = base_io;
|
|
|
|
atpdev->pciport[0] = base_io + 0x20;
|
|
|
|
atpdev->dev_id = ent->device;
|
2005-04-16 22:20:36 +00:00
|
|
|
host_id &= 0x07;
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->host_id[0] = host_id;
|
2015-11-17 18:23:44 +00:00
|
|
|
atpdev->scam_on = inb(base_io + 0x22);
|
|
|
|
atpdev->global_map[0] = inb(base_io + 0x2d);
|
|
|
|
atpdev->ultra_map[0] = inw(base_io + 0x2e);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2006-06-28 05:01:28 +00:00
|
|
|
if (atpdev->ultra_map[0] == 0) {
|
|
|
|
atpdev->scam_on = 0x00;
|
|
|
|
atpdev->global_map[0] = 0x20;
|
|
|
|
atpdev->ultra_map[0] = 0xffff;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
|
|
|
|
if (!shpnt)
|
2006-06-28 05:01:28 +00:00
|
|
|
goto err_nomem;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
p = (struct atp_unit *)&shpnt->hostdata;
|
|
|
|
|
2006-06-28 05:01:28 +00:00
|
|
|
atpdev->host = shpnt;
|
|
|
|
atpdev->pdev = pdev;
|
2005-04-16 22:20:36 +00:00
|
|
|
pci_set_drvdata(pdev, p);
|
2006-06-28 05:01:28 +00:00
|
|
|
memcpy(p, atpdev, sizeof(*atpdev));
|
2005-04-16 22:20:36 +00:00
|
|
|
if (atp870u_init_tables(shpnt) < 0)
|
|
|
|
goto unregister;
|
|
|
|
|
2006-07-02 02:29:42 +00:00
|
|
|
if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870i", shpnt)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
|
|
|
|
goto free_tables;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock_irqsave(shpnt->host_lock, flags);
|
2006-06-28 05:01:28 +00:00
|
|
|
if (atpdev->chip_ver > 0x07) { /* check if atp876 chip then enable terminator */
|
2015-11-17 18:23:44 +00:00
|
|
|
outb(0x00, base_io + 0x3e);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2015-11-17 18:23:44 +00:00
|
|
|
k = (inb(base_io + 0x3a) & 0xf3) | 0x10;
|
|
|
|
outb(k, base_io + 0x3a);
|
|
|
|
outb((k & 0xdf), base_io + 0x3a);
|
2005-04-16 22:20:36 +00:00
|
|
|
mdelay(32);
|
2015-11-17 18:23:44 +00:00
|
|
|
outb(k, base_io + 0x3a);
|
2005-04-16 22:20:36 +00:00
|
|
|
mdelay(32);
|
2015-11-17 18:23:44 +00:00
|
|
|
outb((host_id | 0x08), base_io + 0);
|
|
|
|
outb(0, base_io + 0x18);
|
|
|
|
while ((inb(base_io + 0x1f) & 0x80) == 0)
|
2005-04-16 22:20:36 +00:00
|
|
|
mdelay(1);
|
|
|
|
|
2015-11-17 18:23:44 +00:00
|
|
|
inb(base_io + 0x17);
|
|
|
|
outb(8, base_io + 1);
|
|
|
|
outb(0x7f, base_io + 2);
|
|
|
|
outb(0x20, base_io + 0x11);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
tscam(shpnt);
|
|
|
|
is870(p, base_io);
|
2015-11-17 18:23:44 +00:00
|
|
|
outb((inb(base_io + 0x3a) & 0xef), base_io + 0x3a);
|
|
|
|
outb((inb(base_io + 0x3b) | 0x20), base_io + 0x3b);
|
2006-06-28 05:01:28 +00:00
|
|
|
if (atpdev->chip_ver == 4)
|
2005-04-16 22:20:36 +00:00
|
|
|
shpnt->max_id = 16;
|
|
|
|
else
|
2006-05-23 08:29:28 +00:00
|
|
|
shpnt->max_id = 8;
|
2005-04-16 22:20:36 +00:00
|
|
|
shpnt->this_id = host_id;
|
|
|
|
shpnt->unique_id = base_io;
|
|
|
|
shpnt->io_port = base_io;
|
|
|
|
shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */
|
|
|
|
shpnt->irq = pdev->irq;
|
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(shpnt->host_lock, flags);
|
|
|
|
if(ent->device==ATP885_DEVID) {
|
|
|
|
if(!request_region(base_io, 0xff, "atp870u")) /* Register the IO ports that we use */
|
|
|
|
goto request_io_fail;
|
|
|
|
} else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
|
|
|
|
if(!request_region(base_io, 0x60, "atp870u")) /* Register the IO ports that we use */
|
|
|
|
goto request_io_fail;
|
|
|
|
} else {
|
|
|
|
if(!request_region(base_io, 0x40, "atp870u")) /* Register the IO ports that we use */
|
|
|
|
goto request_io_fail;
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
if (scsi_add_host(shpnt, &pdev->dev))
|
|
|
|
goto scsi_add_fail;
|
|
|
|
scsi_scan_host(shpnt);
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("atp870u_prob : exit\n");
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
scsi_add_fail:
|
|
|
|
printk("atp870u_prob:scsi_add_fail\n");
|
|
|
|
if(ent->device==ATP885_DEVID) {
|
|
|
|
release_region(base_io, 0xff);
|
|
|
|
} else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
|
|
|
|
release_region(base_io, 0x60);
|
|
|
|
} else {
|
|
|
|
release_region(base_io, 0x40);
|
|
|
|
}
|
|
|
|
request_io_fail:
|
|
|
|
printk("atp870u_prob:request_io_fail\n");
|
|
|
|
free_irq(pdev->irq, shpnt);
|
|
|
|
free_tables:
|
|
|
|
printk("atp870u_prob:free_table\n");
|
|
|
|
atp870u_free_tables(shpnt);
|
|
|
|
unregister:
|
|
|
|
printk("atp870u_prob:unregister\n");
|
|
|
|
scsi_host_put(shpnt);
|
|
|
|
return -1;
|
2006-06-28 05:01:28 +00:00
|
|
|
err_eio:
|
|
|
|
kfree(atpdev);
|
|
|
|
return -EIO;
|
|
|
|
err_nomem:
|
|
|
|
kfree(atpdev);
|
|
|
|
return -ENOMEM;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The abort command does not leave the device in a clean state where
|
|
|
|
it is available to be used again. Until this gets worked out, we will
|
|
|
|
leave it commented out. */
|
|
|
|
|
|
|
|
static int atp870u_abort(struct scsi_cmnd * SCpnt)
|
|
|
|
{
|
|
|
|
unsigned char j, k, c;
|
|
|
|
struct scsi_cmnd *workrequ;
|
|
|
|
struct atp_unit *dev;
|
|
|
|
struct Scsi_Host *host;
|
|
|
|
host = SCpnt->device->host;
|
|
|
|
|
|
|
|
dev = (struct atp_unit *)&host->hostdata;
|
2005-10-24 22:05:09 +00:00
|
|
|
c = scmd_channel(SCpnt);
|
2005-04-16 22:20:36 +00:00
|
|
|
printk(" atp870u: abort Channel = %x \n", c);
|
|
|
|
printk("working=%x last_cmd=%x ", dev->working[c], dev->last_cmd[c]);
|
|
|
|
printk(" quhdu=%x quendu=%x ", dev->quhd[c], dev->quend[c]);
|
|
|
|
for (j = 0; j < 0x18; j++) {
|
2015-11-17 18:23:45 +00:00
|
|
|
printk(" r%2x=%2x", j, inb(dev->ioport[c] + j));
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2015-11-17 18:23:45 +00:00
|
|
|
printk(" r1c=%2x", inb(dev->ioport[c] + 0x1c));
|
|
|
|
printk(" r1f=%2x in_snd=%2x ", inb(dev->ioport[c] + 0x1f), dev->in_snd[c]);
|
|
|
|
printk(" d00=%2x", inb(dev->pciport[c]));
|
|
|
|
printk(" d02=%2x", inb(dev->pciport[c] + 0x02));
|
2005-04-16 22:20:36 +00:00
|
|
|
for(j=0;j<16;j++) {
|
|
|
|
if (dev->id[c][j].curr_req != NULL) {
|
|
|
|
workrequ = dev->id[c][j].curr_req;
|
|
|
|
printk("\n que cdb= ");
|
|
|
|
for (k=0; k < workrequ->cmd_len; k++) {
|
|
|
|
printk(" %2x ",workrequ->cmnd[k]);
|
|
|
|
}
|
|
|
|
printk(" last_lenu= %x ",(unsigned int)dev->id[c][j].last_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *atp870u_info(struct Scsi_Host *notused)
|
|
|
|
{
|
|
|
|
static char buffer[128];
|
|
|
|
|
|
|
|
strcpy(buffer, "ACARD AEC-6710/6712/67160 PCI Ultra/W/LVD SCSI-3 Adapter Driver V2.6+ac ");
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2013-03-31 07:26:26 +00:00
|
|
|
static int atp870u_show_info(struct seq_file *m, struct Scsi_Host *HBAptr)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2014-12-02 23:10:53 +00:00
|
|
|
seq_puts(m, "ACARD AEC-671X Driver Version: 2.6+ac\n\n"
|
|
|
|
"Adapter Configuration:\n");
|
2013-03-31 07:26:26 +00:00
|
|
|
seq_printf(m, " Base IO: %#.4lx\n", HBAptr->io_port);
|
|
|
|
seq_printf(m, " IRQ: %d\n", HBAptr->irq);
|
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int atp870u_biosparam(struct scsi_device *disk, struct block_device *dev,
|
|
|
|
sector_t capacity, int *ip)
|
|
|
|
{
|
|
|
|
int heads, sectors, cylinders;
|
|
|
|
|
|
|
|
heads = 64;
|
|
|
|
sectors = 32;
|
|
|
|
cylinders = (unsigned long)capacity / (heads * sectors);
|
|
|
|
if (cylinders > 1024) {
|
|
|
|
heads = 255;
|
|
|
|
sectors = 63;
|
|
|
|
cylinders = (unsigned long)capacity / (heads * sectors);
|
|
|
|
}
|
|
|
|
ip[0] = heads;
|
|
|
|
ip[1] = sectors;
|
|
|
|
ip[2] = cylinders;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void atp870u_remove (struct pci_dev *pdev)
|
|
|
|
{
|
|
|
|
struct atp_unit *devext = pci_get_drvdata(pdev);
|
|
|
|
struct Scsi_Host *pshost = devext->host;
|
|
|
|
|
|
|
|
|
|
|
|
scsi_remove_host(pshost);
|
|
|
|
printk(KERN_INFO "free_irq : %d\n",pshost->irq);
|
|
|
|
free_irq(pshost->irq, pshost);
|
|
|
|
release_region(pshost->io_port, pshost->n_io_port);
|
|
|
|
printk(KERN_INFO "atp870u_free_tables : %p\n",pshost);
|
|
|
|
atp870u_free_tables(pshost);
|
|
|
|
printk(KERN_INFO "scsi_host_put : %p\n",pshost);
|
|
|
|
scsi_host_put(pshost);
|
|
|
|
}
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
|
|
|
|
static struct scsi_host_template atp870u_template = {
|
|
|
|
.module = THIS_MODULE,
|
|
|
|
.name = "atp870u" /* name */,
|
|
|
|
.proc_name = "atp870u",
|
2013-03-31 07:26:26 +00:00
|
|
|
.show_info = atp870u_show_info,
|
2005-04-16 22:20:36 +00:00
|
|
|
.info = atp870u_info /* info */,
|
|
|
|
.queuecommand = atp870u_queuecommand /* queuecommand */,
|
|
|
|
.eh_abort_handler = atp870u_abort /* abort */,
|
|
|
|
.bios_param = atp870u_biosparam /* biosparm */,
|
|
|
|
.can_queue = qcnt /* can_queue */,
|
|
|
|
.this_id = 7 /* SCSI ID */,
|
|
|
|
.sg_tablesize = ATP870U_SCATTER /*SG_ALL*/ /*SG_NONE*/,
|
|
|
|
.use_clustering = ENABLE_CLUSTERING,
|
|
|
|
.max_sectors = ATP870U_MAX_SECTORS,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct pci_device_id atp870u_id_table[] = {
|
|
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP885_DEVID) },
|
|
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP880_DEVID1) },
|
|
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP880_DEVID2) },
|
|
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7610) },
|
|
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612UW) },
|
|
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612U) },
|
|
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612S) },
|
|
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612D) },
|
|
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612SUW) },
|
|
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_8060) },
|
|
|
|
{ 0, },
|
|
|
|
};
|
|
|
|
|
|
|
|
MODULE_DEVICE_TABLE(pci, atp870u_id_table);
|
|
|
|
|
|
|
|
static struct pci_driver atp870u_driver = {
|
|
|
|
.id_table = atp870u_id_table,
|
|
|
|
.name = "atp870u",
|
|
|
|
.probe = atp870u_probe,
|
2012-12-21 21:08:55 +00:00
|
|
|
.remove = atp870u_remove,
|
2005-04-16 22:20:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int __init atp870u_init(void)
|
|
|
|
{
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("atp870u_init: Entry\n");
|
|
|
|
#endif
|
|
|
|
return pci_register_driver(&atp870u_driver);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit atp870u_exit(void)
|
|
|
|
{
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("atp870u_exit: Entry\n");
|
|
|
|
#endif
|
|
|
|
pci_unregister_driver(&atp870u_driver);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tscam_885(void)
|
|
|
|
{
|
|
|
|
unsigned char i;
|
|
|
|
|
|
|
|
for (i = 0; i < 0x2; i++) {
|
|
|
|
mdelay(300);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c)
|
|
|
|
{
|
|
|
|
unsigned char i, j, k, rmb, n, lvdmode;
|
|
|
|
unsigned short int m;
|
|
|
|
static unsigned char mbuf[512];
|
|
|
|
static unsigned char satn[9] = {0, 0, 0, 0, 0, 0, 0, 6, 6};
|
|
|
|
static unsigned char inqd[9] = {0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6};
|
|
|
|
static unsigned char synn[6] = {0x80, 1, 3, 1, 0x19, 0x0e};
|
|
|
|
unsigned char synu[6] = {0x80, 1, 3, 1, 0x0a, 0x0e};
|
|
|
|
static unsigned char synw[6] = {0x80, 1, 3, 1, 0x19, 0x0e};
|
|
|
|
unsigned char synuw[6] = {0x80, 1, 3, 1, 0x0a, 0x0e};
|
|
|
|
static unsigned char wide[6] = {0x80, 1, 2, 3, 1, 0};
|
|
|
|
static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 };
|
|
|
|
|
|
|
|
lvdmode=inb(wkport + 0x1b) >> 7;
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
m = 1;
|
|
|
|
m = m << i;
|
|
|
|
if ((m & dev->active_id[c]) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (i == dev->host_id[c]) {
|
|
|
|
printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[c]);
|
|
|
|
continue;
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x01, wkport + 0x1b);
|
|
|
|
outb(0x08, wkport + 0x01);
|
|
|
|
outb(0x7f, wkport + 0x02);
|
|
|
|
outb(satn[0], wkport + 0x03);
|
|
|
|
outb(satn[1], wkport + 0x04);
|
|
|
|
outb(satn[2], wkport + 0x05);
|
|
|
|
outb(satn[3], wkport + 0x06);
|
|
|
|
outb(satn[4], wkport + 0x07);
|
|
|
|
outb(satn[5], wkport + 0x08);
|
|
|
|
outb(0, wkport + 0x0f);
|
|
|
|
outb(dev->id[c][i].devsp, wkport + 0x11);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0, wkport + 0x12);
|
|
|
|
outb(satn[6], wkport + 0x13);
|
|
|
|
outb(satn[7], wkport + 0x14);
|
2005-04-16 22:20:36 +00:00
|
|
|
j = i;
|
|
|
|
if ((j & 0x08) != 0) {
|
|
|
|
j = (j & 0x07) | 0x40;
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(j, wkport + 0x15);
|
|
|
|
outb(satn[8], wkport + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-11-17 18:23:46 +00:00
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:46 +00:00
|
|
|
if ((inb(wkport + 0x17) != 0x11) && (inb(wkport + 0x17) != 0x8e)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
while (inb(wkport + 0x17) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
dev->active_id[c] |= m;
|
|
|
|
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x30, wkport + 0x10);
|
|
|
|
outb(0x00, wkport + 0x14);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
phase_cmd:
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x08, wkport + 0x18);
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j != 0x16) {
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x41, wkport + 0x10);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto phase_cmd;
|
|
|
|
}
|
|
|
|
sel_ok:
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(inqd[0], wkport + 0x03);
|
|
|
|
outb(inqd[1], wkport + 0x04);
|
|
|
|
outb(inqd[2], wkport + 0x05);
|
|
|
|
outb(inqd[3], wkport + 0x06);
|
|
|
|
outb(inqd[4], wkport + 0x07);
|
|
|
|
outb(inqd[5], wkport + 0x08);
|
|
|
|
outb(0, wkport + 0x0f);
|
|
|
|
outb(dev->id[c][i].devsp, wkport + 0x11);
|
|
|
|
outb(0, wkport + 0x12);
|
|
|
|
outb(inqd[6], wkport + 0x13);
|
|
|
|
outb(inqd[7], wkport + 0x14);
|
|
|
|
outb(inqd[8], wkport + 0x18);
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:46 +00:00
|
|
|
if ((inb(wkport + 0x17) != 0x11) && (inb(wkport + 0x17) != 0x8e)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
while (inb(wkport + 0x17) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x00, wkport + 0x1b);
|
|
|
|
outb(0x08, wkport + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
j = 0;
|
|
|
|
rd_inq_data:
|
2015-11-17 18:23:46 +00:00
|
|
|
k = inb(wkport + 0x1f);
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((k & 0x01) != 0) {
|
2015-11-17 18:23:46 +00:00
|
|
|
mbuf[j++] = inb(wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto rd_inq_data;
|
|
|
|
}
|
|
|
|
if ((k & 0x80) == 0) {
|
|
|
|
goto rd_inq_data;
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x16) {
|
|
|
|
goto inq_ok;
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x46, wkport + 0x10);
|
|
|
|
outb(0, wkport + 0x12);
|
|
|
|
outb(0, wkport + 0x13);
|
|
|
|
outb(0, wkport + 0x14);
|
|
|
|
outb(0x08, wkport + 0x18);
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:46 +00:00
|
|
|
if (inb(wkport + 0x17) != 0x16) {
|
2005-04-16 22:20:36 +00:00
|
|
|
goto sel_ok;
|
|
|
|
}
|
|
|
|
inq_ok:
|
|
|
|
mbuf[36] = 0;
|
|
|
|
printk( KERN_INFO" ID: %2d %s\n", i, &mbuf[8]);
|
|
|
|
dev->id[c][i].devtype = mbuf[0];
|
|
|
|
rmb = mbuf[1];
|
|
|
|
n = mbuf[7];
|
|
|
|
if ((mbuf[7] & 0x60) == 0) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if ((i < 8) && ((dev->global_map[c] & 0x20) == 0)) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if (lvdmode == 0) {
|
|
|
|
goto chg_wide;
|
|
|
|
}
|
|
|
|
if (dev->sp[c][i] != 0x04) { // force u2
|
|
|
|
goto chg_wide;
|
|
|
|
}
|
|
|
|
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x01, wkport + 0x1b);
|
|
|
|
outb(satn[0], wkport + 0x03);
|
|
|
|
outb(satn[1], wkport + 0x04);
|
|
|
|
outb(satn[2], wkport + 0x05);
|
|
|
|
outb(satn[3], wkport + 0x06);
|
|
|
|
outb(satn[4], wkport + 0x07);
|
|
|
|
outb(satn[5], wkport + 0x08);
|
|
|
|
outb(0, wkport + 0x0f);
|
|
|
|
outb(dev->id[c][i].devsp, wkport + 0x11);
|
|
|
|
outb(0, wkport + 0x12);
|
|
|
|
outb(satn[6], wkport + 0x13);
|
|
|
|
outb(satn[7], wkport + 0x14);
|
|
|
|
outb(satn[8], wkport + 0x18);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:46 +00:00
|
|
|
if ((inb(wkport + 0x17) != 0x11) && (inb(wkport + 0x17) != 0x8e)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
while (inb(wkport + 0x17) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
try_u3:
|
|
|
|
j = 0;
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x09, wkport + 0x14);
|
|
|
|
outb(0x20, wkport + 0x18);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0) {
|
|
|
|
if ((inb(wkport + 0x1f) & 0x01) != 0)
|
|
|
|
outb(u3[j++], wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
while ((inb(wkport + 0x17) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x17) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto u3p_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto u3p_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto try_u3;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
u3p_out:
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x20, wkport + 0x18);
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0) {
|
|
|
|
if ((inb(wkport + 0x1f) & 0x01) != 0)
|
|
|
|
outb(0, wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x17) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto u3p_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto u3p_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto u3p_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
u3p_in:
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x09, wkport + 0x14);
|
|
|
|
outb(0x20, wkport + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
k = 0;
|
|
|
|
u3p_in1:
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x1f);
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((j & 0x01) != 0) {
|
2015-11-17 18:23:46 +00:00
|
|
|
mbuf[k++] = inb(wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto u3p_in1;
|
|
|
|
}
|
|
|
|
if ((j & 0x80) == 0x00) {
|
|
|
|
goto u3p_in1;
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x17) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto u3p_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto u3p_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto u3p_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
u3p_cmd:
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x30, wkport + 0x10);
|
|
|
|
outb(0x00, wkport + 0x14);
|
|
|
|
outb(0x08, wkport + 0x18);
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00);
|
|
|
|
j = inb(wkport + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j != 0x16) {
|
|
|
|
if (j == 0x4e) {
|
|
|
|
goto u3p_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[0] != 0x01) {
|
|
|
|
goto chg_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[1] != 0x06) {
|
|
|
|
goto chg_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[2] != 0x04) {
|
|
|
|
goto chg_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[3] == 0x09) {
|
|
|
|
m = 1;
|
|
|
|
m = m << i;
|
|
|
|
dev->wide_id[c] |= m;
|
|
|
|
dev->id[c][i].devsp = 0xce;
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp);
|
|
|
|
#endif
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
chg_wide:
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x01, wkport + 0x1b);
|
|
|
|
outb(satn[0], wkport + 0x03);
|
|
|
|
outb(satn[1], wkport + 0x04);
|
|
|
|
outb(satn[2], wkport + 0x05);
|
|
|
|
outb(satn[3], wkport + 0x06);
|
|
|
|
outb(satn[4], wkport + 0x07);
|
|
|
|
outb(satn[5], wkport + 0x08);
|
|
|
|
outb(0, wkport + 0x0f);
|
|
|
|
outb(dev->id[c][i].devsp, wkport + 0x11);
|
|
|
|
outb(0, wkport + 0x12);
|
|
|
|
outb(satn[6], wkport + 0x13);
|
|
|
|
outb(satn[7], wkport + 0x14);
|
|
|
|
outb(satn[8], wkport + 0x18);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:46 +00:00
|
|
|
if ((inb(wkport + 0x17) != 0x11) && (inb(wkport + 0x17) != 0x8e)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
while (inb(wkport + 0x17) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
try_wide:
|
|
|
|
j = 0;
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x05, wkport + 0x14);
|
|
|
|
outb(0x20, wkport + 0x18);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0) {
|
|
|
|
if ((inb(wkport + 0x1f) & 0x01) != 0)
|
|
|
|
outb(wide[j++], wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
while ((inb(wkport + 0x17) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x17) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto widep_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto widep_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto try_wide;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
widep_out:
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x20, wkport + 0x18);
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0) {
|
|
|
|
if ((inb(wkport + 0x1f) & 0x01) != 0)
|
|
|
|
outb(0, wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x17) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto widep_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto widep_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto widep_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
widep_in:
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0xff, wkport + 0x14);
|
|
|
|
outb(0x20, wkport + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
k = 0;
|
|
|
|
widep_in1:
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x1f);
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((j & 0x01) != 0) {
|
2015-11-17 18:23:46 +00:00
|
|
|
mbuf[k++] = inb(wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto widep_in1;
|
|
|
|
}
|
|
|
|
if ((j & 0x80) == 0x00) {
|
|
|
|
goto widep_in1;
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x17) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto widep_in;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto widep_cmd;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto widep_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
widep_cmd:
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x30, wkport + 0x10);
|
|
|
|
outb(0x00, wkport + 0x14);
|
|
|
|
outb(0x08, wkport + 0x18);
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j != 0x16) {
|
|
|
|
if (j == 0x4e) {
|
|
|
|
goto widep_out;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[0] != 0x01) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[1] != 0x02) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[2] != 0x03) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
if (mbuf[3] != 0x01) {
|
|
|
|
goto not_wide;
|
|
|
|
}
|
|
|
|
m = 1;
|
|
|
|
m = m << i;
|
|
|
|
dev->wide_id[c] |= m;
|
|
|
|
not_wide:
|
|
|
|
if ((dev->id[c][i].devtype == 0x00) || (dev->id[c][i].devtype == 0x07) ||
|
|
|
|
((dev->id[c][i].devtype == 0x05) && ((n & 0x10) != 0))) {
|
|
|
|
m = 1;
|
|
|
|
m = m << i;
|
|
|
|
if ((dev->async[c] & m) != 0) {
|
|
|
|
goto set_sync;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
set_sync:
|
|
|
|
if (dev->sp[c][i] == 0x02) {
|
|
|
|
synu[4]=0x0c;
|
|
|
|
synuw[4]=0x0c;
|
|
|
|
} else {
|
|
|
|
if (dev->sp[c][i] >= 0x03) {
|
|
|
|
synu[4]=0x0a;
|
|
|
|
synuw[4]=0x0a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
j = 0;
|
|
|
|
if ((m & dev->wide_id[c]) != 0) {
|
|
|
|
j |= 0x01;
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(j, wkport + 0x1b);
|
|
|
|
outb(satn[0], wkport + 0x03);
|
|
|
|
outb(satn[1], wkport + 0x04);
|
|
|
|
outb(satn[2], wkport + 0x05);
|
|
|
|
outb(satn[3], wkport + 0x06);
|
|
|
|
outb(satn[4], wkport + 0x07);
|
|
|
|
outb(satn[5], wkport + 0x08);
|
|
|
|
outb(0, wkport + 0x0f);
|
|
|
|
outb(dev->id[c][i].devsp, wkport + 0x11);
|
|
|
|
outb(0, wkport + 0x12);
|
|
|
|
outb(satn[6], wkport + 0x13);
|
|
|
|
outb(satn[7], wkport + 0x14);
|
|
|
|
outb(satn[8], wkport + 0x18);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:46 +00:00
|
|
|
if ((inb(wkport + 0x17) != 0x11) && (inb(wkport + 0x17) != 0x8e)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
while (inb(wkport + 0x17) != 0x8e)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
try_sync:
|
|
|
|
j = 0;
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x06, wkport + 0x14);
|
|
|
|
outb(0x20, wkport + 0x18);
|
|
|
|
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0) {
|
|
|
|
if ((inb(wkport + 0x1f) & 0x01) != 0) {
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((m & dev->wide_id[c]) != 0) {
|
|
|
|
if ((m & dev->ultra_map[c]) != 0) {
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(synuw[j++], wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(synw[j++], wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((m & dev->ultra_map[c]) != 0) {
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(synu[j++], wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(synn[j++], wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
while ((inb(wkport + 0x17) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x17) & 0x0f;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x0f) {
|
|
|
|
goto phase_ins;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto phase_cmds;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto try_sync;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
phase_outs:
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x20, wkport + 0x18);
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00) {
|
|
|
|
if ((inb(wkport + 0x1f) & 0x01) != 0x00)
|
|
|
|
outb(0x00, wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x85) {
|
|
|
|
goto tar_dcons;
|
|
|
|
}
|
|
|
|
j &= 0x0f;
|
|
|
|
if (j == 0x0f) {
|
|
|
|
goto phase_ins;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto phase_cmds;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto phase_outs;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
phase_ins:
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x06, wkport + 0x14);
|
|
|
|
outb(0x20, wkport + 0x18);
|
2005-04-16 22:20:36 +00:00
|
|
|
k = 0;
|
|
|
|
phase_ins1:
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x1f);
|
2005-04-16 22:20:36 +00:00
|
|
|
if ((j & 0x01) != 0x00) {
|
2015-11-17 18:23:46 +00:00
|
|
|
mbuf[k++] = inb(wkport + 0x19);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto phase_ins1;
|
|
|
|
}
|
|
|
|
if ((j & 0x80) == 0x00) {
|
|
|
|
goto phase_ins1;
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
while ((inb(wkport + 0x17) & 0x80) == 0x00);
|
|
|
|
j = inb(wkport + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j == 0x85) {
|
|
|
|
goto tar_dcons;
|
|
|
|
}
|
|
|
|
j &= 0x0f;
|
|
|
|
if (j == 0x0f) {
|
|
|
|
goto phase_ins;
|
|
|
|
}
|
|
|
|
if (j == 0x0a) {
|
|
|
|
goto phase_cmds;
|
|
|
|
}
|
|
|
|
if (j == 0x0e) {
|
|
|
|
goto phase_outs;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
phase_cmds:
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x30, wkport + 0x10);
|
2005-04-16 22:20:36 +00:00
|
|
|
tar_dcons:
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x00, wkport + 0x14);
|
|
|
|
outb(0x08, wkport + 0x18);
|
|
|
|
while ((inb(wkport + 0x1f) & 0x80) == 0x00)
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu_relax();
|
2015-11-17 18:23:46 +00:00
|
|
|
j = inb(wkport + 0x17);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (j != 0x16) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[0] != 0x01) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[1] != 0x03) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[4] == 0x00) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[3] > 0x64) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mbuf[4] > 0x0e) {
|
|
|
|
mbuf[4] = 0x0e;
|
|
|
|
}
|
|
|
|
dev->id[c][i].devsp = mbuf[4];
|
|
|
|
if (mbuf[3] < 0x0c){
|
|
|
|
j = 0xb0;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
if ((mbuf[3] < 0x0d) && (rmb == 0)) {
|
|
|
|
j = 0xa0;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
if (mbuf[3] < 0x1a) {
|
|
|
|
j = 0x20;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
if (mbuf[3] < 0x33) {
|
|
|
|
j = 0x40;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
if (mbuf[3] < 0x4c) {
|
|
|
|
j = 0x50;
|
|
|
|
goto set_syn_ok;
|
|
|
|
}
|
|
|
|
j = 0x60;
|
|
|
|
set_syn_ok:
|
|
|
|
dev->id[c][i].devsp = (dev->id[c][i].devsp & 0x0f) | j;
|
|
|
|
#ifdef ED_DBGP
|
|
|
|
printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp);
|
|
|
|
#endif
|
|
|
|
}
|
2015-11-17 18:23:46 +00:00
|
|
|
outb(0x80, wkport + 0x16);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
module_init(atp870u_init);
|
|
|
|
module_exit(atp870u_exit);
|
|
|
|
|