summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/atp870u.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/atp870u.c')
-rw-r--r--drivers/scsi/atp870u.c2037
1 files changed, 2037 insertions, 0 deletions
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
new file mode 100644
index 000000000..96280a8c3
--- /dev/null
+++ b/drivers/scsi/atp870u.c
@@ -0,0 +1,2037 @@
+/* $Id: atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $
+ * linux/kernel/atp870u.c
+ *
+ * Copyright (C) 1997 Wu Ching Chen
+ * 2.1.x update (C) 1998 Krzysztof G. Baranowski
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/pci.h>
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+
+
+#include "atp870u.h"
+
+#include<linux/stat.h>
+
+struct proc_dir_entry proc_scsi_atp870u = {
+ PROC_SCSI_ATP870U, 7, "atp870u",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+void mydlyu(unsigned int);
+/*
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $";
+*/
+
+static unsigned char admaxu=1,host_idu[2],chip_veru[2],scam_on[2],global_map[2];
+static unsigned short int active_idu[2],wide_idu[2],sync_idu,ultra_map[2];
+static int workingu[2]={0,0};
+static Scsi_Cmnd *querequ[2][qcnt],*curr_req[2][16];
+static unsigned char devspu[2][16] = {{0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20},
+ {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20}};
+static unsigned char dirctu[2][16],last_cmd[2],in_snd[2],in_int[2];
+static unsigned char ata_cdbu[2][16];
+static unsigned int ioportu[2]={0,0};
+static unsigned int irqnumu[2]={0,0};
+static unsigned short int pciportu[2];
+static unsigned long prdaddru[2][16],tran_lenu[2][16],last_lenu[2][16];
+static unsigned char prd_tableu[2][16][1024];
+static unsigned char *prd_posu[2][16];
+static unsigned char quhdu[2],quendu[2];
+static unsigned char devtypeu[2][16] = {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+static struct Scsi_Host * atp_host[2]={NULL,NULL};
+
+static void atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned short int tmpcip,id;
+ unsigned char i,j,h,tarid,lun;
+ unsigned char *prd;
+ Scsi_Cmnd *workrequ;
+ unsigned int workportu,tmport;
+ unsigned long adrcntu,k;
+ int errstus;
+
+ for ( h=0; h < 2; h++ )
+ {
+ if ( ( irq & 0x0f ) == irqnumu[h] )
+ {
+ goto irq_numok;
+ }
+ }
+ return;
+irq_numok:
+ in_int[h]=1;
+ workportu=ioportu[h];
+ tmport=workportu;
+
+ if ( workingu[h] != 0 )
+ {
+ tmport += 0x1f;
+ j=inb(tmport);
+ tmpcip=pciportu[h];
+ if ((inb(tmpcip) & 0x08) != 0)
+ {
+ tmpcip += 0x2;
+ while((inb(tmpcip) & 0x08) != 0);
+ }
+ tmpcip=pciportu[h];
+ outb(0x00,tmpcip);
+ tmport -=0x08;
+ i=inb(tmport);
+ if ((j & 0x40) == 0)
+ {
+ if ((last_cmd[h] & 0x40) == 0)
+ {
+ last_cmd[h]=0xff;
+ }
+ }
+ else
+ {
+ last_cmd[h] |= 0x40;
+ }
+ tmport -= 0x02;
+ tarid=inb(tmport);
+ tmport += 0x02;
+ if ((tarid & 0x40) != 0)
+ {
+ tarid=(tarid & 0x07) | 0x08;
+ }
+ else
+ {
+ tarid &= 0x07;
+ }
+ if ( i == 0x85 )
+ {
+ if (wide_idu[h] != 0)
+ {
+ tmport=workportu+0x1b;
+ j=inb(tmport) & 0x0e;
+ j |= 0x01;
+ outb(j,tmport);
+ }
+ if (((quhdu[h] != quendu[h]) || (last_cmd[h] != 0xff)) &&
+ (in_snd[h] == 0))
+ {
+ send_s870(h);
+ }
+ in_int[h]=0;
+ return;
+ }
+ if ( i == 0x21 )
+ {
+ tmport -= 0x05;
+ adrcntu=0;
+ ((unsigned char *)&adrcntu)[2]=inb(tmport++);
+ ((unsigned char *)&adrcntu)[1]=inb(tmport++);
+ ((unsigned char *)&adrcntu)[0]=inb(tmport);
+ k=last_lenu[h][tarid];
+ k -= adrcntu;
+ tran_lenu[h][tarid]= k;
+ last_lenu[h][tarid]=adrcntu;
+ tmport -= 0x04;
+ outb(0x41,tmport);
+ tmport += 0x08;
+ outb(0x08,tmport);
+ in_int[h]=0;
+ return ;
+ }
+
+ if ((i == 0x80) || (i == 0x8f))
+ {
+ lun=0;
+ tmport -= 0x07;
+ j=inb(tmport);
+ if ( j == 0x44 )
+ {
+ tmport += 0x0d;
+ lun=inb(tmport) & 0x07;
+ }
+ else
+ {
+ if ( j == 0x41 )
+ {
+ tmport += 0x02;
+ adrcntu=0;
+ ((unsigned char *)&adrcntu)[2]=inb(tmport++);
+ ((unsigned char *)&adrcntu)[1]=inb(tmport++);
+ ((unsigned char *)&adrcntu)[0]=inb(tmport);
+ k=last_lenu[h][tarid];
+ k -= adrcntu;
+ tran_lenu[h][tarid]= k;
+ last_lenu[h][tarid]=adrcntu;
+ tmport += 0x04;
+ outb(0x08,tmport);
+ in_int[h]=0;
+ return ;
+ }
+ else
+ {
+ outb(0x46,tmport);
+ dirctu[h][tarid]=0x00;
+ tmport += 0x02;
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ tmport+=0x03;
+ outb(0x08,tmport);
+ in_int[h]=0;
+ return;
+ }
+ }
+ tmport=workportu + 0x10;
+ outb(0x45,tmport);
+ tmport += 0x06;
+ tarid=inb(tmport);
+ if ((tarid & 0x10) != 0)
+ {
+ tarid=(tarid & 0x07) | 0x08;
+ }
+ else
+ {
+ tarid &= 0x07;
+ }
+ workrequ=curr_req[h][tarid];
+ tmport=workportu + 0x0f;
+ outb(lun,tmport);
+ tmport += 0x02;
+ outb(devspu[h][tarid],tmport++);
+ adrcntu=tran_lenu[h][tarid];
+ k=last_lenu[h][tarid];
+ outb(((unsigned char *)&k)[2],tmport++);
+ outb(((unsigned char *)&k)[1],tmport++);
+ outb(((unsigned char *)&k)[0],tmport++);
+ j=tarid;
+ if ( tarid > 7 )
+ {
+ j = (j & 0x07) | 0x40;
+ }
+ j |= dirctu[h][tarid];
+ outb(j,tmport++);
+ outb(0x80,tmport);
+ tmport=workportu + 0x1b;
+ j=inb(tmport) & 0x0e;
+ id=1;
+ id=id << tarid;
+ if ((id & wide_idu[h]) != 0)
+ {
+ j |= 0x01;
+ }
+ outb(j,tmport);
+ if ( last_lenu[h][tarid] == 0 )
+ {
+ tmport=workportu + 0x18;
+ outb(0x08,tmport);
+ in_int[h]=0;
+ return ;
+ }
+ prd=prd_posu[h][tarid];
+ while ( adrcntu != 0 )
+ {
+ id=((unsigned short int *)(prd))[2];
+ if ( id == 0 )
+ {
+ k=0x10000;
+ }
+ else
+ {
+ k=id;
+ }
+ if ( k > adrcntu )
+ {
+ ((unsigned short int *)(prd))[2] =(unsigned short int)
+ (k - adrcntu);
+ ((unsigned long *)(prd))[0] += adrcntu;
+ adrcntu=0;
+ prd_posu[h][tarid]=prd;
+ }
+ else
+ {
+ adrcntu -= k;
+ prdaddru[h][tarid] += 0x08;
+ prd += 0x08;
+ if ( adrcntu == 0 )
+ {
+ prd_posu[h][tarid]=prd;
+ }
+ }
+ }
+ tmpcip=pciportu[h] + 0x04;
+ outl(prdaddru[h][tarid],tmpcip);
+ tmpcip -= 0x02;
+ outb(0x06,tmpcip);
+ outb(0x00,tmpcip);
+ tmpcip -= 0x02;
+ tmport=workportu + 0x18;
+ if ( dirctu[h][tarid] != 0 )
+ {
+ outb(0x08,tmport);
+ outb(0x01,tmpcip);
+ in_int[h]=0;
+ return;
+ }
+ outb(0x08,tmport);
+ outb(0x09,tmpcip);
+ in_int[h]=0;
+ return;
+ }
+
+ workrequ=curr_req[h][tarid];
+ if ( i == 0x42 )
+ {
+ errstus=0x02;
+ workrequ->result=errstus;
+ goto go_42;
+ }
+ if ( i == 0x16 )
+ {
+ errstus=0;
+ tmport -= 0x08;
+ errstus=inb(tmport);
+ workrequ->result=errstus;
+/* if ( errstus == 0x02 )
+ {
+ tmport +=0x10;
+ if ((inb(tmport) & 0x80) != 0)
+ {
+ printk(" autosense ");
+ }
+ tmport -=0x09;
+ outb(0,tmport);
+ tmport=workportu+0x3a;
+ outb((unsigned char)(inb(tmport) | 0x10),tmport);
+ tmport -= 0x39;
+
+ outb(0x08,tmport++);
+ outb(0x7f,tmport++);
+ outb(0x03,tmport++);
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ outb(0x0e,tmport++);
+ outb(0x00,tmport);
+ tmport+=0x07;
+ outb(0x00,tmport++);
+ tmport++;
+ outb(devspu[h][workrequ->target],tmport++);
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ outb(0x0e,tmport++);
+ tmport+=0x03;
+ outb(0x09,tmport);
+ tmport+=0x07;
+ i=0;
+ adrcntu=(unsigned long)(&workrequ->sense_buffer[0]);
+get_sens:
+ j=inb(tmport);
+ if ((j & 0x01) != 0)
+ {
+ tmport-=0x06;
+ (unsigned char)(((caddr_t) adrcntu)[i++])=inb(tmport);
+ tmport+=0x06;
+ goto get_sens;
+ }
+ if ((j & 0x80) == 0)
+ {
+ goto get_sens;
+ }
+ if ((j & 0x40) == 0)
+ {
+ tmport-=0x08;
+ i=inb(tmport);
+ }
+ tmport=workportu+0x3a;
+ outb((unsigned char)(inb(tmport) & 0xef),tmport);
+ tmport=workportu+0x01;
+ outb(0x2c,tmport);
+ tmport += 0x15;
+ outb(0x80,tmport);
+ } */
+go_42:
+ (*workrequ->scsi_done)(workrequ);
+ curr_req[h][tarid]=0;
+ workingu[h]--;
+ if (wide_idu[h] != 0)
+ {
+ tmport=workportu+0x1b;
+ j=inb(tmport) & 0x0e;
+ j |= 0x01;
+ outb(j,tmport);
+ }
+ if (((last_cmd[h] != 0xff) || (quhdu[h] != quendu[h])) &&
+ (in_snd[h] == 0))
+ {
+ send_s870(h);
+ }
+ in_int[h]=0;
+ return;
+ }
+ if ( i == 0x4f )
+ {
+ i=0x89;
+ }
+ i &= 0x0f;
+ if ( i == 0x09 )
+ {
+ tmpcip=tmpcip+4;
+ outl(prdaddru[h][tarid],tmpcip);
+ tmpcip=tmpcip-2;
+ outb(0x06,tmpcip);
+ outb(0x00,tmpcip);
+ tmpcip=tmpcip-2;
+ tmport=workportu+0x10;
+ outb(0x41,tmport);
+ dirctu[h][tarid]=0x00;
+ tmport += 0x08;
+ outb(0x08,tmport);
+ outb(0x09,tmpcip);
+ in_int[h]=0;
+ return;
+ }
+ if ( i == 0x08 )
+ {
+ tmpcip=tmpcip+4;
+ outl(prdaddru[h][tarid],tmpcip);
+ tmpcip=tmpcip-2;
+ outb(0x06,tmpcip);
+ outb(0x00,tmpcip);
+ tmpcip=tmpcip-2;
+ tmport=workportu+0x10;
+ outb(0x41,tmport);
+ tmport += 0x05;
+ outb((unsigned char)(inb(tmport) | 0x20),tmport);
+ dirctu[h][tarid]=0x20;
+ tmport += 0x03;
+ outb(0x08,tmport);
+ outb(0x01,tmpcip);
+ in_int[h]=0;
+ return;
+ }
+ tmport -= 0x07;
+ if ( i == 0x0a )
+ {
+ outb(0x30,tmport);
+ }
+ else
+ {
+ outb(0x46,tmport);
+ }
+ dirctu[h][tarid]=0x00;
+ tmport += 0x02;
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ outb(0x00,tmport++);
+ tmport+=0x03;
+ outb(0x08,tmport);
+ in_int[h]=0;
+ return;
+ }
+ else
+ {
+ tmport=workportu+0x17;
+ inb(tmport);
+ workingu[h]=0;
+ in_int[h]=0;
+ return;
+ }
+}
+
+int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done)(Scsi_Cmnd *))
+{
+ unsigned char i,h;
+ unsigned long flags;
+ unsigned short int m;
+ unsigned int tmport;
+
+ for( h=0; h <= admaxu; h++ )
+ {
+ if ( req_p->host == atp_host[h] )
+ {
+ goto host_ok;
+ }
+ }
+ return 0;
+host_ok:
+ if ( req_p->channel != 0 )
+ {
+ req_p->result = 0x00040000;
+ done(req_p);
+ return 0;
+ }
+ m=1;
+ m= m << req_p->target;
+ if ( ( m & active_idu[h] ) == 0 )
+ {
+ req_p->result = 0x00040000;
+ done(req_p);
+ return 0;
+ }
+ if (done)
+ {
+ req_p->scsi_done = done;
+ }
+ else
+ {
+ printk("atp870u_queuecommand: done can't be NULL\n");
+ req_p->result = 0;
+ done(req_p);
+ return 0;
+ }
+ quendu[h]++;
+ if ( quendu[h] >= qcnt )
+ {
+ quendu[h]=0;
+ }
+ wait_que_empty:
+ if ( quhdu[h] == quendu[h] )
+ {
+ goto wait_que_empty;
+ }
+ save_flags(flags);
+ cli();
+ querequ[h][quendu[h]]=req_p;
+ if ( quendu[h] == 0 )
+ {
+ i=qcnt-1;
+ }
+ else
+ {
+ i=quendu[h]-1;
+ }
+ tmport = ioportu[h]+0x1c;
+ restore_flags(flags);
+ if ((inb(tmport) == 0) && (in_int[h] == 0) && (in_snd[h] == 0))
+ {
+ send_s870(h);
+ }
+ return 0;
+}
+
+void mydlyu(unsigned int dlycnt )
+{
+ unsigned int i ;
+ for ( i = 0 ; i < dlycnt ; i++ )
+ {
+ inb(0x80);
+ }
+}
+
+void send_s870(unsigned char h)
+{
+ unsigned int tmport;
+ Scsi_Cmnd *workrequ;
+ unsigned long flags;
+ unsigned int i;
+ unsigned char j,tarid;
+ unsigned char *prd;
+ unsigned short int tmpcip,w;
+ unsigned long l,bttl;
+ unsigned int workportu;
+ struct scatterlist * sgpnt;
+
+ save_flags(flags);
+ cli();
+ if ( in_snd[h] != 0 )
+ {
+ restore_flags(flags);
+ return;
+ }
+ in_snd[h]=1;
+ if ((last_cmd[h] != 0xff) && ((last_cmd[h] & 0x40) != 0))
+ {
+ last_cmd[h] &= 0x0f;
+ workrequ=curr_req[h][last_cmd[h]];
+ goto cmd_subp;
+ }
+ workingu[h]++;
+ j=quhdu[h];
+ quhdu[h]++;
+ if ( quhdu[h] >= qcnt )
+ {
+ quhdu[h]=0;
+ }
+ workrequ=querequ[h][quhdu[h]];
+ if ( curr_req[h][workrequ->target] == 0 )
+ {
+ curr_req[h][workrequ->target]=workrequ;
+ last_cmd[h]=workrequ->target;
+ goto cmd_subp;
+ }
+ quhdu[h]=j;
+ workingu[h]--;
+ in_snd[h]=0;
+ restore_flags(flags);
+ return ;
+cmd_subp:
+ workportu=ioportu[h];
+ tmport=workportu+0x1f;
+ if ((inb(tmport) & 0xb0) != 0)
+ {
+ goto abortsnd;
+ }
+ tmport=workportu+0x1c;
+ if ( inb(tmport) == 0 )
+ {
+ goto oktosend;
+ }
+abortsnd:
+ last_cmd[h] |= 0x40;
+ in_snd[h]=0;
+ restore_flags(flags);
+ return;
+oktosend:
+ memcpy(&ata_cdbu[h][0], &workrequ->cmnd[0], workrequ->cmd_len);
+ if ( ata_cdbu[h][0] == 0x25 )
+ {
+ if ( workrequ->request_bufflen > 8 )
+ {
+ workrequ->request_bufflen=0x08;
+ }
+ }
+ if ( ata_cdbu[h][0] == 0x12 )
+ {
+ if ( workrequ->request_bufflen > 0x24 )
+ {
+ workrequ->request_bufflen = 0x24;
+ ata_cdbu[h][4]=0x24;
+ }
+ }
+
+ tmport=workportu+0x1b;
+ j=inb(tmport) & 0x0e;
+ tarid=workrequ->target;
+ w=1;
+ w = w << tarid;
+ if ((w & wide_idu[h]) != 0)
+ {
+ j |= 0x01;
+ }
+ outb(j,tmport);
+ tmport=workportu;
+ outb(workrequ->cmd_len,tmport++);
+ outb(0x2c,tmport++);
+ outb(0xcf,tmport++);
+ for ( i=0 ; i < workrequ->cmd_len ; i++ )
+ {
+ outb(ata_cdbu[h][i],tmport++);
+ }
+ tmport=workportu+0x0f;
+ outb(0x00,tmport);
+ tmport+=0x02;
+ outb(devspu[h][tarid],tmport++);
+ if (workrequ->use_sg)
+ {
+
+ l=0;
+ sgpnt = (struct scatterlist *) workrequ->request_buffer;
+ for(i=0; i<workrequ->use_sg; i++)
+ {
+ if(sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER)
+ {
+ panic("Foooooooood fight!");
+ }
+ l += sgpnt[i].length;
+ }
+ }
+ else
+ {
+ l=workrequ->request_bufflen;
+ }
+ outb((unsigned char)(((unsigned char *)(&l))[2]),tmport++);
+ outb((unsigned char)(((unsigned char *)(&l))[1]),tmport++);
+ outb((unsigned char)(((unsigned char *)(&l))[0]),tmport++);
+ j=tarid;
+ last_lenu[h][j]=l;
+ tran_lenu[h][j]=0;
+ if ((j & 0x08) != 0)
+ {
+ j=(j & 0x07) | 0x40;
+ }
+ if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
+ (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15))
+ {
+ outb((unsigned char)(j | 0x20),tmport++);
+ }
+ else
+ {
+ outb(j,tmport++);
+ }
+ outb(0x80,tmport);
+ tmport=workportu + 0x1c;
+ dirctu[h][tarid]=0;
+ if ( l == 0 )
+ {
+ if ( inb(tmport) == 0 )
+ {
+ tmport=workportu+0x18;
+ outb(0x08,tmport);
+ }
+ else
+ {
+ last_cmd[h] |= 0x40;
+ }
+ in_snd[h]=0;
+ restore_flags(flags);
+ return;
+ }
+ tmpcip=pciportu[h];
+ prd=&prd_tableu[h][tarid][0];
+ prd_posu[h][tarid]=prd;
+ if (workrequ->use_sg)
+ {
+ sgpnt = (struct scatterlist *) workrequ->request_buffer;
+ i=0;
+ for(j=0; j<workrequ->use_sg; j++)
+ {
+ (unsigned long)(((unsigned long *)(prd))[i >> 1])=(unsigned long)sgpnt[j].address;
+ (unsigned short int)(((unsigned short int *)(prd))[i+2])=sgpnt[j].length;
+ (unsigned short int)(((unsigned short int *)(prd))[i+3])=0;
+ i +=0x04;
+ }
+ (unsigned short int)(((unsigned short int *)(prd))[i-1])=0x8000;
+ }
+ else
+ {
+ bttl=(unsigned long)workrequ->request_buffer;
+ l=workrequ->request_bufflen;
+ i=0;
+ while ( l > 0x10000 )
+ {
+ (unsigned short int)(((unsigned short int *)(prd))[i+3])=0x0000;
+ (unsigned short int)(((unsigned short int *)(prd))[i+2])=0x0000;
+ (unsigned long)(((unsigned long *)(prd))[i >> 1])=bttl;
+ l -= 0x10000;
+ bttl += 0x10000;
+ i += 0x04;
+ }
+ (unsigned short int)(((unsigned short int *)(prd))[i+3])=0x8000;
+ (unsigned short int)(((unsigned short int *)(prd))[i+2])=l;
+ (unsigned long)(((unsigned long *)(prd))[i >> 1])=bttl;
+ }
+ tmpcip=tmpcip+4;
+ prdaddru[h][tarid]=(unsigned long)&prd_tableu[h][tarid][0];
+ outl(prdaddru[h][tarid],tmpcip);
+ tmpcip=tmpcip-2;
+ outb(0x06,tmpcip);
+ outb(0x00,tmpcip);
+ tmpcip=tmpcip-2;
+ if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
+ (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15))
+ {
+ dirctu[h][tarid]=0x20;
+ if ( inb(tmport) == 0 )
+ {
+ tmport=workportu+0x18;
+ outb(0x08,tmport);
+ outb(0x01,tmpcip);
+ }
+ else
+ {
+ last_cmd[h] |= 0x40;
+ }
+ in_snd[h]=0;
+ restore_flags(flags);
+ return;
+ }
+ if ( inb(tmport) == 0 )
+ {
+ tmport=workportu+0x18;
+ outb(0x08,tmport);
+ outb(0x09,tmpcip);
+ }
+ else
+ {
+ last_cmd[h] |= 0x40;
+ }
+ in_snd[h]=0;
+ restore_flags(flags);
+ return;
+
+}
+
+static void internal_done(Scsi_Cmnd * SCpnt)
+{
+ SCpnt->SCp.Status++;
+}
+
+int atp870u_command(Scsi_Cmnd * SCpnt)
+{
+
+ atp870u_queuecommand(SCpnt, internal_done);
+
+ SCpnt->SCp.Status = 0;
+ while (!SCpnt->SCp.Status)
+ barrier();
+ return SCpnt->result;
+}
+
+unsigned char fun_scam ( unsigned char host,unsigned short int * val )
+{
+ unsigned int tmport ;
+ unsigned short int i,k;
+ unsigned char j;
+
+ tmport = ioportu[host]+0x1c;
+ outw(*val,tmport);
+FUN_D7:
+ for ( i=0; i < 10; i++ ) /* stable >= bus settle delay(400 ns) */
+ {
+ k=inw(tmport);
+ j= (unsigned char)(k >> 8);
+ if ((k & 0x8000) != 0) /* DB7 all release? */
+ {
+ goto FUN_D7;
+ }
+ }
+ *val |= 0x4000; /* assert DB6 */
+ outw(*val,tmport);
+ *val &= 0xdfff; /* assert DB5 */
+ outw(*val,tmport);
+FUN_D5:
+ for ( i=0; i < 10; i++ ) /* stable >= bus settle delay(400 ns) */
+ {
+ if ((inw(tmport) & 0x2000) != 0) /* DB5 all release? */
+ {
+ goto FUN_D5;
+ }
+ }
+ *val |= 0x8000; /* no DB4-0, assert DB7 */
+ *val &= 0xe0ff;
+ outw(*val,tmport);
+ *val &= 0xbfff; /* release DB6 */
+ outw(*val,tmport);
+FUN_D6:
+ for ( i=0; i < 10; i++ ) /* stable >= bus settle delay(400 ns) */
+ {
+ if ((inw(tmport) & 0x4000) != 0) /* DB6 all release? */
+ {
+ goto FUN_D6;
+ }
+ }
+
+ return j;
+}
+
+void tscam( unsigned char host )
+{
+
+ unsigned int tmport ;
+ unsigned char i,j,k;
+ unsigned long n;
+ unsigned short int m,assignid_map,val;
+ unsigned char mbuf[33],quintet[2];
+ static unsigned char g2q_tab[8]={ 0x38,0x31,0x32,0x2b,0x34,0x2d,0x2e,0x27 };
+
+
+ for ( i=0; i < 0x10; i++ )
+ {
+ mydlyu(0xffff);
+ }
+
+ tmport = ioportu[host]+1;
+ outb(0x08,tmport++);
+ outb(0x7f,tmport);
+ tmport = ioportu[host]+0x11;
+ outb(0x20,tmport);
+
+ if ((scam_on[host] & 0x40) == 0)
+ {
+ return;
+ }
+
+ m=1;
+ m <<= host_idu[host];
+ j=16;
+ if ( chip_veru[host] < 4 )
+ {
+ m |= 0xff00;
+ j=8;
+ }
+ assignid_map=m;
+ tmport = ioportu[host]+0x02;
+ outb(0x02,tmport++); /* 2*2=4ms,3EH 2/32*3E=3.9ms */
+ outb(0,tmport++);
+ outb(0,tmport++);
+ outb(0,tmport++);
+ outb(0,tmport++);
+ outb(0,tmport++);
+ outb(0,tmport++);
+
+ for ( i = 0 ; i < j ; i ++ )
+ {
+ m=1;
+ m=m<<i;
+ if ( ( m & assignid_map ) != 0 )
+ {
+ continue;
+ }
+ tmport = ioportu[host]+0x0f;
+ outb(0,tmport++);
+ tmport += 0x02;
+ outb(0,tmport++);
+ outb(0,tmport++);
+ outb(0,tmport++);
+ if ( i > 7 )
+ {
+ k=(i & 0x07) | 0x40;
+ }
+ else
+ {
+ k=i;
+ }
+ outb(k,tmport++);
+ tmport = ioportu[host]+0x1b;
+ if ( chip_veru[host] == 4 )
+ {
+ outb((unsigned char)((inb(tmport) & 0x0e) | 0x01),tmport);
+ }
+ else
+ {
+ outb((unsigned char)(inb(tmport) & 0x0e),tmport);
+ }
+wait_rdyok:
+ tmport = ioportu[host]+0x18;
+ outb(0x09,tmport);
+ tmport += 0x07;
+
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport -= 0x08;
+ k=inb(tmport);
+ if ( k != 0x16 )
+ {
+ if ((k == 0x85) || (k == 0x42))
+ {
+ continue;
+ }
+ tmport = ioportu[host]+0x10;
+ outb(0x41,tmport);
+ goto wait_rdyok;
+ }
+ assignid_map |= m;
+
+ }
+ tmport = ioportu[host]+0x02;
+ outb(0x7f,tmport);
+ tmport = ioportu[host]+0x1b;
+ outb(0x02,tmport);
+
+ outb(0,0x80);
+
+ val=0x0080; /* bsy */
+ tmport = ioportu[host]+0x1c;
+ outw(val,tmport);
+ val |=0x0040; /* sel */
+ outw(val,tmport);
+ val |=0x0004; /* msg */
+ outw(val,tmport);
+ inb(0x80); /* 2 deskew delay(45ns*2=90ns) */
+ val &=0x007f; /* no bsy */
+ outw(val,tmport);
+ mydlyu(0xffff); /* recommanded SCAM selection response time */
+ mydlyu(0xffff);
+ val &=0x00fb; /* after 1ms no msg */
+ outw(val,tmport);
+wait_nomsg:
+ if ((inb(tmport) & 0x04) != 0)
+ {
+ goto wait_nomsg;
+ }
+ outb(1,0x80);
+ mydlyu(100);
+ for ( n=0; n < 0x30000; n++ )
+ {
+ if ((inb(tmport) & 0x80) != 0) /* bsy ? */
+ {
+ goto wait_io;
+ }
+ }
+ goto TCM_SYNC;
+wait_io:
+ for ( n=0; n < 0x30000; n++ )
+ {
+ if ((inb(tmport) & 0x81) == 0x0081)
+ {
+ goto wait_io1;
+ }
+ }
+ goto TCM_SYNC;
+wait_io1:
+ inb(0x80);
+ val |=0x8003; /* io,cd,db7 */
+ outw(val,tmport);
+ inb(0x80);
+ val &=0x00bf; /* no sel */
+ outw(val,tmport);
+ outb(2,0x80);
+TCM_SYNC:
+ mydlyu(0x800);
+ if ((inb(tmport) & 0x80) == 0x00) /* bsy ? */
+ {
+ outw(0,tmport--);
+ outb(0,tmport);
+ tmport=ioportu[host] + 0x15;
+ outb(0,tmport);
+ tmport += 0x03;
+ outb(0x09,tmport);
+ tmport += 0x07;
+ while ((inb(tmport) & 0x80) == 0);
+ tmport -= 0x08;
+ inb(tmport);
+ return;
+ }
+
+ val &= 0x00ff; /* synchronization */
+ val |= 0x3f00;
+ fun_scam(host,&val);
+ outb(3,0x80);
+ val &= 0x00ff; /* isolation */
+ val |= 0x2000;
+ fun_scam(host,&val);
+ outb(4,0x80);
+ i=8;
+ j=0;
+TCM_ID:
+ if ((inw(tmport) & 0x2000) == 0)
+ {
+ goto TCM_ID;
+ }
+ outb(5,0x80);
+ val &= 0x00ff; /* get ID_STRING */
+ val |= 0x2000;
+ k=fun_scam(host,&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];
+ if ((j & 0x20) != 0) /* bit5=1:ID upto 7 */
+ {
+ 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(host,&val);
+ val &= 0x00ff; /* AssignID 2ndQuintet,AH=001xxxxx */
+ m=quintet[1] << 8;
+ val |= m;
+ fun_scam(host,&val);
+
+ goto TCM_SYNC;
+
+}
+
+void is870(unsigned long host,unsigned int wkport )
+{
+ unsigned int tmport ;
+ unsigned char i,j,k,rmb;
+ 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 };
+
+ sync_idu=0;
+ tmport=wkport+0x3a;
+ outb((unsigned char)(inb(tmport) | 0x10),tmport);
+
+ for ( i = 0 ; i < 16 ; i ++ )
+ {
+ if ((chip_veru[host] != 4) && (i > 7))
+ {
+ break;
+ }
+ m=1;
+ m=m<<i;
+ if ( ( m & active_idu[host] ) != 0 )
+ {
+ continue;
+ }
+ if ( i == host_idu[host] )
+ {
+ printk(" ID: %2d Host Adapter\n",host_idu[host]);
+ continue;
+ }
+ if ( chip_veru[host] == 4 )
+ {
+ tmport=wkport+0x1b;
+ j=(inb(tmport) & 0x0e) | 0x01;
+ outb(j,tmport);
+ }
+ tmport=wkport+1;
+ outb(0x08,tmport++);
+ outb(0x7f,tmport++);
+ outb(satn[0],tmport++);
+ outb(satn[1],tmport++);
+ outb(satn[2],tmport++);
+ outb(satn[3],tmport++);
+ outb(satn[4],tmport++);
+ outb(satn[5],tmport++);
+ tmport+=0x06;
+ outb(0,tmport);
+ tmport+=0x02;
+ outb(devspu[host][i],tmport++);
+ outb(0,tmport++);
+ outb(satn[6],tmport++);
+ outb(satn[7],tmport++);
+ j=i;
+ if ((j & 0x08) != 0)
+ {
+ j=(j & 0x07) | 0x40;
+ }
+ outb(j,tmport);
+ tmport+=0x03;
+ outb(satn[8],tmport);
+ tmport+=0x07;
+
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
+ {
+ continue;
+ }
+ while ( inb(tmport) != 0x8e );
+ active_idu[host] |= m;
+
+ tmport=wkport+0x10;
+ outb(0x30,tmport);
+ tmport=wkport+0x04;
+ outb(0x00,tmport);
+
+phase_cmd:
+ tmport=wkport+0x18;
+ outb(0x08,tmport);
+ tmport+=0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ j=inb(tmport);
+ if ( j != 0x16 )
+ {
+ tmport=wkport+0x10;
+ outb(0x41,tmport);
+ goto phase_cmd;
+ }
+sel_ok:
+ tmport=wkport+3;
+ outb(inqd[0],tmport++);
+ outb(inqd[1],tmport++);
+ outb(inqd[2],tmport++);
+ outb(inqd[3],tmport++);
+ outb(inqd[4],tmport++);
+ outb(inqd[5],tmport);
+ tmport+=0x07;
+ outb(0,tmport);
+ tmport+=0x02;
+ outb(devspu[host][i],tmport++);
+ outb(0,tmport++);
+ outb(inqd[6],tmport++);
+ outb(inqd[7],tmport++);
+ tmport+=0x03;
+ outb(inqd[8],tmport);
+ tmport+=0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
+ {
+ continue;
+ }
+ while ( inb(tmport) != 0x8e );
+ if ( chip_veru[host] == 4 )
+ {
+ tmport=wkport+0x1b;
+ j=inb(tmport) & 0x0e;
+ outb(j,tmport);
+ }
+ tmport=wkport+0x18;
+ outb(0x08,tmport);
+ tmport += 0x07;
+ j=0;
+rd_inq_data:
+ k=inb(tmport);
+ if ((k & 0x01) != 0 )
+ {
+ tmport-=0x06;
+ mbuf[j++]=inb(tmport);
+ tmport+=0x06;
+ goto rd_inq_data;
+ }
+ if ((k & 0x80) == 0 )
+ {
+ goto rd_inq_data;
+ }
+ tmport-=0x08;
+ j=inb(tmport);
+ if ( j == 0x16 )
+ {
+ goto inq_ok;
+ }
+ tmport=wkport+0x10;
+ outb(0x46,tmport);
+ tmport+=0x02;
+ outb(0,tmport++);
+ outb(0,tmport++);
+ outb(0,tmport++);
+ tmport+=0x03;
+ outb(0x08,tmport);
+ tmport+=0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ if (inb(tmport) != 0x16)
+ {
+ goto sel_ok;
+ }
+inq_ok:
+ mbuf[36]=0;
+ printk(" ID: %2d %s\n",i,&mbuf[8]);
+ devtypeu[host][i]=mbuf[0];
+ rmb=mbuf[1];
+ if ( chip_veru[host] != 4 )
+ {
+ goto not_wide;
+ }
+ if ((mbuf[7] & 0x60) == 0)
+ {
+ goto not_wide;
+ }
+ if ((global_map[host] & 0x20) == 0)
+ {
+ goto not_wide;
+ }
+ tmport=wkport+0x1b;
+ j=(inb(tmport) & 0x0e) | 0x01;
+ outb(j,tmport);
+ tmport=wkport+3;
+ outb(satn[0],tmport++);
+ outb(satn[1],tmport++);
+ outb(satn[2],tmport++);
+ outb(satn[3],tmport++);
+ outb(satn[4],tmport++);
+ outb(satn[5],tmport++);
+ tmport+=0x06;
+ outb(0,tmport);
+ tmport+=0x02;
+ outb(devspu[host][i],tmport++);
+ outb(0,tmport++);
+ outb(satn[6],tmport++);
+ outb(satn[7],tmport++);
+ tmport+=0x03;
+ outb(satn[8],tmport);
+ tmport+=0x07;
+
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
+ {
+ continue;
+ }
+ while ( inb(tmport) != 0x8e );
+try_wide:
+ j=0;
+ tmport=wkport+0x14;
+ outb(0x05,tmport);
+ tmport += 0x04;
+ outb(0x20,tmport);
+ tmport+=0x07;
+
+ while ((inb(tmport) & 0x80) == 0 )
+ {
+ if ((inb(tmport) & 0x01) != 0 )
+ {
+ tmport-=0x06;
+ outb(wide[j++],tmport);
+ tmport+=0x06;
+ }
+ }
+ tmport-=0x08;
+ while ((inb(tmport) & 0x80) == 0x00);
+ j=inb(tmport) & 0x0f;
+ if ( j == 0x0f )
+ {
+ goto widep_in;
+ }
+ if ( j == 0x0a )
+ {
+ goto widep_cmd;
+ }
+ if ( j == 0x0e )
+ {
+ goto try_wide;
+ }
+ continue;
+widep_out:
+ tmport=wkport+0x18;
+ outb(0x20,tmport);
+ tmport+=0x07;
+ while ((inb(tmport) & 0x80) == 0 )
+ {
+ if ((inb(tmport) & 0x01) != 0 )
+ {
+ tmport-=0x06;
+ outb(0,tmport);
+ tmport+=0x06;
+ }
+ }
+ tmport-=0x08;
+ j=inb(tmport) & 0x0f;
+ if ( j == 0x0f )
+ {
+ goto widep_in;
+ }
+ if ( j == 0x0a )
+ {
+ goto widep_cmd;
+ }
+ if ( j == 0x0e )
+ {
+ goto widep_out;
+ }
+ continue;
+widep_in:
+ tmport=wkport+0x14;
+ outb(0xff,tmport);
+ tmport += 0x04;
+ outb(0x20,tmport);
+ tmport+=0x07;
+ k=0;
+widep_in1:
+ j=inb(tmport);
+ if ((j & 0x01) != 0)
+ {
+ tmport-=0x06;
+ mbuf[k++]=inb(tmport);
+ tmport+=0x06;
+ goto widep_in1;
+ }
+ if ((j & 0x80) == 0x00)
+ {
+ goto widep_in1;
+ }
+ tmport-=0x08;
+ j=inb(tmport) & 0x0f;
+ if ( j == 0x0f )
+ {
+ goto widep_in;
+ }
+ if ( j == 0x0a )
+ {
+ goto widep_cmd;
+ }
+ if ( j == 0x0e )
+ {
+ goto widep_out;
+ }
+ continue;
+widep_cmd:
+ tmport=wkport+0x10;
+ outb(0x30,tmport);
+ tmport=wkport+0x14;
+ outb(0x00,tmport);
+ tmport+=0x04;
+ outb(0x08,tmport);
+ tmport+=0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ j=inb(tmport);
+ 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;
+ wide_idu[host] |= m;
+not_wide:
+ if ((devtypeu[host][i] == 0x00) || (devtypeu[host][i] == 0x07))
+ {
+ goto set_sync;
+ }
+ continue;
+set_sync:
+ tmport=wkport+0x1b;
+ j=inb(tmport) & 0x0e;
+ if ((m & wide_idu[host]) != 0 )
+ {
+ j |= 0x01;
+ }
+ outb(j,tmport);
+ tmport=wkport+3;
+ outb(satn[0],tmport++);
+ outb(satn[1],tmport++);
+ outb(satn[2],tmport++);
+ outb(satn[3],tmport++);
+ outb(satn[4],tmport++);
+ outb(satn[5],tmport++);
+ tmport+=0x06;
+ outb(0,tmport);
+ tmport+=0x02;
+ outb(devspu[host][i],tmport++);
+ outb(0,tmport++);
+ outb(satn[6],tmport++);
+ outb(satn[7],tmport++);
+ tmport+=0x03;
+ outb(satn[8],tmport);
+ tmport+=0x07;
+
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
+ {
+ continue;
+ }
+ while ( inb(tmport) != 0x8e);
+try_sync:
+ j=0;
+ tmport=wkport+0x14;
+ outb(0x06,tmport);
+ tmport += 0x04;
+ outb(0x20,tmport);
+ tmport+=0x07;
+
+ while ((inb(tmport) & 0x80) == 0 )
+ {
+ if ((inb(tmport) & 0x01) != 0 )
+ {
+ tmport-=0x06;
+ if ( rmb != 0 )
+ {
+ outb(synn[j++],tmport);
+ }
+ else
+ {
+ if ((m & wide_idu[host]) != 0)
+ {
+ outb(synw[j++],tmport);
+ }
+ else
+ {
+ if ((m & ultra_map[host]) != 0)
+ {
+ outb(synu[j++],tmport);
+ }
+ else
+ {
+ outb(synn[j++],tmport);
+ }
+ }
+ }
+ tmport+=0x06;
+ }
+ }
+ tmport-=0x08;
+ while ((inb(tmport) & 0x80) == 0x00);
+ j=inb(tmport) & 0x0f;
+ if ( j == 0x0f )
+ {
+ goto phase_ins;
+ }
+ if ( j == 0x0a )
+ {
+ goto phase_cmds;
+ }
+ if ( j == 0x0e )
+ {
+ goto try_sync;
+ }
+ continue;
+phase_outs:
+ tmport=wkport+0x18;
+ outb(0x20,tmport);
+ tmport+=0x07;
+ while ((inb(tmport) & 0x80) == 0x00)
+ {
+ if ((inb(tmport) & 0x01) != 0x00)
+ {
+ tmport-=0x06;
+ outb(0x00,tmport);
+ tmport+=0x06;
+ }
+ }
+ tmport-=0x08;
+ j=inb(tmport);
+ 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:
+ tmport=wkport+0x14;
+ outb(0xff,tmport);
+ tmport += 0x04;
+ outb(0x20,tmport);
+ tmport+=0x07;
+ k=0;
+phase_ins1:
+ j=inb(tmport);
+ if ((j & 0x01) != 0x00)
+ {
+ tmport-=0x06;
+ mbuf[k++]=inb(tmport);
+ tmport+=0x06;
+ goto phase_ins1;
+ }
+ if ((j & 0x80) == 0x00)
+ {
+ goto phase_ins1;
+ }
+ tmport-=0x08;
+ while ((inb(tmport) & 0x80) == 0x00);
+ j=inb(tmport);
+ 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:
+ tmport=wkport+0x10;
+ outb(0x30,tmport);
+tar_dcons:
+ tmport=wkport+0x14;
+ outb(0x00,tmport);
+ tmport+=0x04;
+ outb(0x08,tmport);
+ tmport+=0x07;
+ while ((inb(tmport) & 0x80) == 0x00);
+ tmport-=0x08;
+ j=inb(tmport);
+ 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;
+ }
+ devspu[host][i] = 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:
+ devspu[host][i] = (devspu[host][i] & 0x0f) | j;
+ }
+ tmport=wkport+0x3a;
+ outb((unsigned char)(inb(tmport) & 0xef),tmport);
+}
+
+/* return non-zero on detection */
+int atp870u_detect(Scsi_Host_Template * tpnt)
+{
+ unsigned char irq,h,k;
+ unsigned long flags;
+ unsigned int base_io,error,tmport;
+ unsigned short index = 0;
+ unsigned char pci_bus[3], pci_device_fn[3], chip_ver[3],host_id;
+ struct Scsi_Host * shpnt = NULL;
+ int count = 0;
+ static unsigned short devid[7]={0x8002,0x8010,0x8020,0x8030,0x8040,0x8050,0};
+ static struct pci_dev *pdev = NULL;
+
+ printk("aec671x_detect: \n");
+ if (!pci_present())
+ {
+ printk(" NO BIOS32 SUPPORT.\n");
+ return count;
+ }
+
+ tpnt->proc_dir = &proc_scsi_atp870u;
+
+ for ( h = 0 ; h < 2 ; h++ )
+ {
+ active_idu[h]=0;
+ wide_idu[h]=0;
+ host_idu[h]=0x07;
+ quhdu[h]=0;
+ quendu[h]=0;
+ pci_bus[h]=0;
+ pci_device_fn[h]=0xff;
+ chip_ver[h]=0;
+ last_cmd[h]=0xff;
+ in_snd[h]=0;
+ in_int[h]=0;
+ for ( k = 0 ; k < qcnt ; k++ )
+ {
+ querequ[h][k]=0;
+ }
+ for ( k = 0 ; k < 16 ; k++ )
+ {
+ curr_req[h][k]=0;
+ }
+ }
+ h=0;
+ while ( devid[h] != 0 )
+ {
+ pci_find_device(0x1191,devid[h],pdev);
+ if (pdev == NULL); {
+ h++;
+ index=0;
+ continue;
+ }
+ chip_ver[2]=0;
+
+ /* To avoid messing with the things below... */
+ pci_device_fn[2] = pdev->devfn;
+ pci_bus[2] = pdev->bus->number;
+
+ if ( devid[h] == 0x8002 )
+ {
+ error = pci_read_config_byte(pdev,0x08,&chip_ver[2]);
+ if ( chip_ver[2] < 2 )
+ {
+ goto nxt_devfn;
+ }
+ }
+ if ( devid[h] == 0x8010 )
+ {
+ chip_ver[2]=0x04;
+ }
+ if ( pci_device_fn[2] < pci_device_fn[0] )
+ {
+ pci_bus[1]=pci_bus[0];
+ pci_device_fn[1]=pci_device_fn[0];
+ chip_ver[1]=chip_ver[0];
+ pci_bus[0]=pci_bus[2];
+ pci_device_fn[0]=pci_device_fn[2];
+ chip_ver[0]=chip_ver[2];
+ }
+ else if ( pci_device_fn[2] < pci_device_fn[1] )
+ {
+ pci_bus[1]=pci_bus[2];
+ pci_device_fn[1]=pci_device_fn[2];
+ chip_ver[1]=chip_ver[2];
+ }
+nxt_devfn:
+ index++;
+ if ( index > 3 )
+ {
+ index=0;
+ h++;
+ }
+ }
+ for ( h=0; h < 2; h++ )
+ {
+ if ( pci_device_fn[h] == 0xff )
+ {
+ return count;
+ }
+
+ pdev->devfn = pci_device_fn[h];
+ pdev->bus->number = pci_bus[h];
+
+ /* Found an atp870u/w. */
+ error = pci_read_config_dword(pdev,0x10,&base_io);
+ error += pci_read_config_byte(pdev,0x3c,&irq);
+ error += pci_read_config_byte(pdev,0x49,&host_id);
+
+ base_io &= 0xfffffff8;
+ printk(" ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d IO:%x, IRQ:%d.\n"
+ ,h,base_io,irq);
+ ioportu[h]=base_io;
+ pciportu[h]=base_io + 0x20;
+ irqnumu[h]=irq;
+ host_id &= 0x07;
+ host_idu[h]=host_id;
+ chip_veru[h]=chip_ver[h];
+
+ tmport=base_io+0x22;
+ scam_on[h]=inb(tmport);
+ tmport += 0x0b;
+ global_map[h]=inb(tmport++);
+ ultra_map[h]=inw(tmport);
+ if ( ultra_map[h] == 0 )
+ {
+ scam_on[h]=0x00;
+ global_map[h]=0x20;
+ ultra_map[h]=0xffff;
+ }
+
+ shpnt = scsi_register(tpnt,4);
+
+ save_flags(flags);
+ cli();
+ if (request_irq(irq,atp870u_intr_handle, 0, "atp870u", NULL))
+ {
+ printk("Unable to allocate IRQ for Acard controller.\n");
+ goto unregister;
+ }
+
+ tmport=base_io+0x3a;
+ k=(inb(tmport) & 0xf3) | 0x10;
+ outb(k,tmport);
+ outb((k & 0xdf),tmport);
+ mydlyu(0x8000);
+ outb(k,tmport);
+ mydlyu(0x8000);
+ tmport=base_io;
+ outb((host_id | 0x08),tmport);
+ tmport += 0x18;
+ outb(0,tmport);
+ tmport += 0x07;
+ while ((inb(tmport) & 0x80) == 0);
+ tmport -= 0x08;
+ inb(tmport);
+ tmport = base_io +1;
+ outb(8,tmport++);
+ outb(0x7f,tmport);
+ tmport = base_io + 0x11;
+ outb(0x20,tmport);
+
+ tscam(h);
+ is870(h,base_io);
+ tmport=base_io+0x3a;
+ outb((inb(tmport) & 0xef),tmport);
+
+ atp_host[h] = shpnt;
+ if ( chip_ver[h] == 4 )
+ {
+ shpnt->max_id = 16;
+ }
+ 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 = irq;
+ restore_flags(flags);
+ request_region(base_io, 0x40,"atp870u"); /* Register the IO ports that we use */
+ count++;
+ index++;
+ continue;
+unregister:
+ scsi_unregister(shpnt);
+ restore_flags(flags);
+ index++;
+ continue;
+ }
+
+ return count;
+}
+
+/* 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. */
+
+int atp870u_abort(Scsi_Cmnd * SCpnt)
+{
+ unsigned char h,j;
+ unsigned int tmport;
+/* printk(" atp870u_abort: \n"); */
+ for ( h=0; h <= admaxu; h++ )
+ {
+ if ( SCpnt->host == atp_host[h] )
+ {
+ goto find_adp;
+ }
+ }
+ panic("Abort host not found !");
+find_adp:
+ printk(" workingu=%x last_cmd=%x ",workingu[h],last_cmd[h]);
+ printk(" quhdu=%x quendu=%x ",quhdu[h],quendu[h]);
+ tmport=ioportu[h];
+ for ( j=0; j < 0x17; j++)
+ {
+ printk(" r%2x=%2x",j,inb(tmport++));
+ }
+ tmport += 0x05;
+ printk(" r1c=%2x",inb(tmport));
+ tmport += 0x03;
+ printk(" r1f=%2x in_snd=%2x ",inb(tmport),in_snd[h]);
+ tmport++;
+ printk(" r20=%2x",inb(tmport));
+ tmport += 0x02;
+ printk(" r22=%2x \n",inb(tmport));
+ return (SCSI_ABORT_SNOOZE);
+}
+
+int atp870u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+{
+ unsigned char h;
+ /*
+ * See if a bus reset was suggested.
+ */
+/* printk("atp870u_reset: \n"); */
+ for( h=0; h <= admaxu; h++ )
+ {
+ if ( SCpnt->host == atp_host[h] )
+ {
+ goto find_host;
+ }
+ }
+ panic("Reset bus host not found !");
+find_host:
+/* SCpnt->result = 0x00080000;
+ SCpnt->scsi_done(SCpnt);
+ workingu[h]=0;
+ quhdu[h]=0;
+ quendu[h]=0;
+ return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET); */
+ return (SCSI_RESET_SNOOZE);
+}
+
+const char *
+atp870u_info(struct Scsi_Host *notused)
+{
+ static char buffer[128];
+
+ strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V1.0 ");
+
+ return buffer;
+}
+
+int
+atp870u_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
+{
+ return (-ENOSYS); /* Currently this is a no-op */
+}
+
+#define BLS buffer + len + size
+int
+atp870u_proc_info(char *buffer, char **start, off_t offset, int length,
+ int hostno, int inout)
+{
+ struct Scsi_Host *HBAptr;
+ static u8 buff[512];
+ int i;
+ int size = 0;
+ int len = 0;
+ off_t begin = 0;
+ off_t pos = 0;
+
+ HBAptr = NULL;
+ for (i = 0; i < 2; i++)
+ {
+ if ((HBAptr = atp_host[i]) != NULL)
+ {
+ if (HBAptr->host_no == hostno)
+ {
+ break;
+ }
+ HBAptr = NULL;
+ }
+ }
+
+ if (HBAptr == NULL)
+ {
+ size += sprintf(BLS, "Can't find adapter for host number %d\n", hostno);
+ len += size; pos = begin + len; size = 0;
+ goto stop_output;
+ }
+
+ if (inout == TRUE) /* Has data been written to the file? */
+ {
+ return (atp870u_set_info(buffer, length, HBAptr));
+ }
+
+ if (offset == 0)
+ {
+ memset(buff, 0, sizeof(buff));
+ }
+
+ size += sprintf(BLS, "ACARD AEC-671X Driver Version: 1.0\n");
+ len += size; pos = begin + len; size = 0;
+
+ size += sprintf(BLS, "\n");
+ size += sprintf(BLS, "Adapter Configuration:\n");
+ size += sprintf(BLS, " Base IO: %#.4lx\n", HBAptr->io_port);
+ size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq);
+ len += size; pos = begin + len; size = 0;
+
+stop_output:
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ {
+ len = length; /* Ending slop */
+ }
+
+ return (len);
+}
+
+#include "sd.h"
+
+int atp870u_biosparam(Scsi_Disk * disk, kdev_t dev, int * ip)
+{
+ int heads, sectors, cylinders;
+
+ heads = 64;
+ sectors = 32;
+ cylinders = disk->capacity / (heads * sectors);
+
+ if ( cylinders > 1024 )
+ {
+ heads = 255;
+ sectors = 63;
+ cylinders = disk->capacity / (heads * sectors);
+ }
+
+ ip[0] = heads;
+ ip[1] = sectors;
+ ip[2] = cylinders;
+
+ return 0;
+}
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = ATP870U;
+
+#include "scsi_module.c"
+#endif
+