patch-2.1.30 linux/drivers/scsi/aha1740.c

Next file: linux/drivers/scsi/aha1740.h
Previous file: linux/drivers/scsi/README.BusLogic
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.29/linux/drivers/scsi/aha1740.c linux/drivers/scsi/aha1740.c
@@ -13,6 +13,11 @@
  *  for proper handling of multiple devices courteously
  *  provided by Michael Weller, March, 1993
  *
+ *  Multiple adapter support, extended translation detection,
+ *  update to current scsi subsystem changes, proc fs support,
+ *  working (!) module support based on patches from Andreas Arens,
+ *  by Andreas Degert <ad@papyrus.hamburg.com>, 2/1997
+ *
  * aha1740_makecode may still need even more work
  * if it doesn't work for your devices, take a look.
  */
@@ -59,12 +64,52 @@
 static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1740.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
 */
 
-static unsigned int slot, base;
-static unsigned char irq_level;
+struct aha1740_hostdata {
+    unsigned int slot;
+    unsigned int translation;
+    unsigned int last_ecb_used;
+    struct ecb ecb[AHA1740_ECBS];
+};
+
+#define HOSTDATA(host) ((struct aha1740_hostdata *) &host->hostdata)
 
-static struct ecb ecb[AHA1740_ECBS];	/* One for each queued operation */
+/* One for each IRQ level (9-15) */
+static struct Scsi_Host * aha_host[8] = {NULL, };
+
+int aha1740_proc_info(char *buffer, char **start, off_t offset,
+		      int length, int hostno, int inout)
+{
+    int len;
+    struct Scsi_Host * shpnt;
+    struct aha1740_hostdata *host;
+
+    if (inout)
+	return(-ENOSYS);
+
+    for (len = 0; len < 8; len++) {
+	shpnt = aha_host[len];
+	if (shpnt && shpnt->host_no == hostno)
+	    break;
+    }
+    host = HOSTDATA(shpnt);
+
+    len = sprintf(buffer, "aha174x at IO:%x, IRQ %d, SLOT %d.\n"
+		  "Extended translation %sabled.\n",
+		  shpnt->io_port, shpnt->irq, host->slot,
+		  host->translation ? "en" : "dis");
+
+    if (offset > len) {
+	*start = buffer;
+	return 0;
+    }
+
+    *start = buffer + offset;
+    len -= offset;
+    if (len > length)
+	len = length;
+    return len;
+}
 
-static int aha1740_last_ecb_used  = 0;	/* optimization */
 
 int aha1740_makecode(unchar *sense, unchar *status)
 {
@@ -88,8 +133,9 @@
 
     status_word = * (struct statusword *) status;
 #ifdef DEBUG
-printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",status[0],status[1],status[2],status[3],
-sense[0],sense[1],sense[2],sense[3]);
+    printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",
+	   status[0], status[1], status[2], status[3],
+	   sense[0], sense[1], sense[2], sense[3]);
 #endif
     if (!status_word.don) /* Anything abnormal was detected */
     {
@@ -113,8 +159,8 @@
 		break;
 	    case 0x04:
 	    case 0x05:
-		retval=DID_ABORT; /* Either by this driver or the AHA1740
-					 itself */
+		retval=DID_ABORT;
+		/* Either by this driver or the AHA1740 itself */
 		break;
 	    default:
 		retval=DID_ERROR; /* No further diagnostics possible */
@@ -141,35 +187,35 @@
     return status[3] | retval << 16;
 }
 
-int aha1740_test_port(void)
+int aha1740_test_port(unsigned int base)
 {
-    char    name[4],tmp;
+    char name[4], tmp;
 
     /* Okay, look for the EISA ID's */
-    name[0]= 'A' -1 + ((tmp = inb(HID0)) >> 2); /* First character */
+    name[0]= 'A' -1 + ((tmp = inb(HID0(base))) >> 2); /* First character */
     name[1]= 'A' -1 + ((tmp & 3) << 3);
-    name[1]+= ((tmp = inb(HID1)) >> 5)&0x7;	/* Second Character */
+    name[1]+= ((tmp = inb(HID1(base))) >> 5)&0x7;	/* Second Character */
     name[2]= 'A' -1 + (tmp & 0x1f);		/* Third Character */
     name[3]=0;
-    tmp = inb(HID2);
-    if ( strcmp ( name, HID_MFG ) || inb(HID2) != HID_PRD )
+    tmp = inb(HID2(base));
+    if ( strcmp ( name, HID_MFG ) || inb(HID2(base)) != HID_PRD )
 	return 0;   /* Not an Adaptec 174x */
 
-/*  if ( inb(HID3) != HID_REV )
-	printk("aha1740: Warning; board revision of %d; expected %d\n",
-	    inb(HID3),HID_REV); */
+/*  if ( inb(HID3(base)) != HID_REV )
+	printk("aha174x: Warning; board revision of %d; expected %d\n",
+	    inb(HID3(base)),HID_REV); */
 
-    if ( inb(EBCNTRL) != EBCNTRL_VALUE )
+    if ( inb(EBCNTRL(base)) != EBCNTRL_VALUE )
     {
-	printk("aha1740: Board detected, but EBCNTRL = %x, so disabled it.\n",
-	    inb(EBCNTRL));
+	printk("aha174x: Board detected, but EBCNTRL = %x, so disabled it.\n",
+	    inb(EBCNTRL(base)));
 	return 0;
     }
 
-    if ( inb(PORTADR) & PORTADDR_ENH )
+    if ( inb(PORTADR(base)) & PORTADDR_ENH )
 	return 1;   /* Okay, we're all set */
 	
-    printk("aha1740: Board detected, but not in enhanced mode, so disabled it.\n");
+    printk("aha174x: Board detected, but not in enhanced mode, so disabled it.\n");
     return 0;
 }
 
@@ -181,49 +227,58 @@
     int number_serviced;
     struct ecb *ecbptr;
     Scsi_Cmnd *SCtmp;
+    unsigned int base;
 
+    if (!aha_host[irq - 9])
+	panic("aha1740.c: Irq from unknown host!\n");
+    base = aha_host[irq - 9]->io_port;
     number_serviced = 0;
 
-    while(inb(G2STAT) & G2STAT_INTPEND)
+    while(inb(G2STAT(base)) & G2STAT_INTPEND)
     {
 	DEB(printk("aha1740_intr top of loop.\n"));
-	adapstat = inb(G2INTST);
-	ecbptr = (struct ecb *) bus_to_virt(inl(MBOXIN0));
-	outb(G2CNTRL_IRST,G2CNTRL); /* interrupt reset */
+	adapstat = inb(G2INTST(base));
+	ecbptr = (struct ecb *) bus_to_virt(inl(MBOXIN0(base)));
+	outb(G2CNTRL_IRST,G2CNTRL(base)); /* interrupt reset */
       
 	switch ( adapstat & G2INTST_MASK )
 	{
 	case	G2INTST_CCBRETRY:
 	case	G2INTST_CCBERROR:
 	case	G2INTST_CCBGOOD:
-	    outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */
+	    /* Host Ready -> Mailbox in complete */
+	    outb(G2CNTRL_HRDY,G2CNTRL(base));
 	    if (!ecbptr)
 	    {
 		printk("Aha1740 null ecbptr in interrupt (%x,%x,%x,%d)\n",
-			inb(G2STAT),adapstat,inb(G2INTST),number_serviced++);
+		       inb(G2STAT(base)),adapstat,
+		       inb(G2INTST(base)), number_serviced++);
 		continue;
 	    }
 	    SCtmp = ecbptr->SCpnt;
 	    if (!SCtmp)
 	    {
 		printk("Aha1740 null SCtmp in interrupt (%x,%x,%x,%d)\n",
-			inb(G2STAT),adapstat,inb(G2INTST),number_serviced++);
+		       inb(G2STAT(base)),adapstat,
+		       inb(G2INTST(base)), number_serviced++);
 		continue;
 	    }
 	    if (SCtmp->host_scribble)
 		scsi_free(SCtmp->host_scribble, 512);
-	  /* Fetch the sense data, and tuck it away, in the required slot.  The
-	     Adaptec automatically fetches it, and there is no guarantee that
-	     we will still have it in the cdb when we come back */
+	    /* Fetch the sense data, and tuck it away, in the required slot.
+	       The Adaptec automatically fetches it, and there is no
+	       guarantee that we will still have it in the cdb when we come
+	       back */
 	    if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR )
-	      {
+	    {
 		memcpy(SCtmp->sense_buffer, ecbptr->sense, 
 		       sizeof(SCtmp->sense_buffer));
 		errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
-	      }
+	    }
 	    else
 		errstatus = 0;
-	    DEB(if (errstatus) printk("aha1740_intr_handle: returning %6x\n", errstatus));
+	    DEB(if (errstatus) printk("aha1740_intr_handle: returning %6x\n",
+				      errstatus));
 	    SCtmp->result = errstatus;
 	    my_done = ecbptr->done;
 	    memset(ecbptr,0,sizeof(struct ecb)); 
@@ -231,12 +286,14 @@
 		my_done(SCtmp);
 	    break;
 	case	G2INTST_HARDFAIL:
-	    printk("aha1740 hardware failure!\n");
+	    printk(KERN_ALERT "aha1740 hardware failure!\n");
 	    panic("aha1740.c");	/* Goodbye */
 	case	G2INTST_ASNEVENT:
-	    printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",adapstat,
-		inb(MBOXIN0),inb(MBOXIN1),inb(MBOXIN2),inb(MBOXIN3)); /* Say What? */
-	    outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */
+	    printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",
+		   adapstat, inb(MBOXIN0(base)), inb(MBOXIN1(base)),
+		   inb(MBOXIN2(base)), inb(MBOXIN3(base))); /* Say What? */
+	    /* Host Ready -> Mailbox in complete */
+	    outb(G2CNTRL_HRDY,G2CNTRL(base));
 	    break;
 	case	G2INTST_CMDGOOD:
 	    /* set immediate command success flag here: */
@@ -245,7 +302,7 @@
 	    /* Set immediate command failure flag here: */
 	    break;
 	}
-      number_serviced++;
+	number_serviced++;
     }
 }
 
@@ -254,18 +311,19 @@
     unchar direction;
     unchar *cmd = (unchar *) SCpnt->cmnd;
     unchar target = SCpnt->target;
+    struct aha1740_hostdata *host = HOSTDATA(SCpnt->host);
     unsigned long flags;
     void *buff = SCpnt->request_buffer;
     int bufflen = SCpnt->request_bufflen;
     int ecbno;
     DEB(int i);
 
-    
     if(*cmd == REQUEST_SENSE)
     {
 	if (bufflen != sizeof(SCpnt->sense_buffer))
 	{
-	    printk("Wrong buffer length supplied for request sense (%d)\n",bufflen);
+	    printk("Wrong buffer length supplied for request sense (%d)\n",
+		   bufflen);
 	}
 	SCpnt->result = 0;
 	done(SCpnt); 
@@ -279,39 +337,41 @@
 	i = scsi2int(cmd+2);
     else
 	i = -1;
-    printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+    printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ",
+	   target, *cmd, i, bufflen);
     printk("scsi cmd:");
     for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
     printk("\n");
 #endif
 
     /* locate an available ecb */
-
     save_flags(flags);
     cli();
-    ecbno = aha1740_last_ecb_used + 1;		/* An optimization */
-    if (ecbno >= AHA1740_ECBS) ecbno = 0;
-
-    do{
-      if( ! ecb[ecbno].cmdw )
-	break;
-      ecbno++;
-      if (ecbno >= AHA1740_ECBS ) ecbno = 0;
-    } while (ecbno != aha1740_last_ecb_used);
+    ecbno = host->last_ecb_used + 1;		/* An optimization */
+    if (ecbno >= AHA1740_ECBS)
+	ecbno = 0;
+    do {
+	if (!host->ecb[ecbno].cmdw)
+	    break;
+	ecbno++;
+	if (ecbno >= AHA1740_ECBS)
+	    ecbno = 0;
+    } while (ecbno != host->last_ecb_used);
 
-    if( ecb[ecbno].cmdw )
-      panic("Unable to find empty ecb for aha1740.\n");
+    if (host->ecb[ecbno].cmdw)
+	panic("Unable to find empty ecb for aha1740.\n");
 
-    ecb[ecbno].cmdw = AHA1740CMD_INIT;	/* SCSI Initiator Command doubles as reserved flag */
+    host->ecb[ecbno].cmdw = AHA1740CMD_INIT;	/* SCSI Initiator Command
+						   doubles as reserved flag */
 
-    aha1740_last_ecb_used = ecbno;    
+    host->last_ecb_used = ecbno;    
     restore_flags(flags);
 
 #ifdef DEBUG
-    printk("Sending command (%d %x)...",ecbno, done);
+    printk("Sending command (%d %x)...", ecbno, done);
 #endif
 
-    ecb[ecbno].cdblen = SCpnt->cmd_len;	/* SCSI Command Descriptor Block Length */
+    host->ecb[ecbno].cdblen = SCpnt->cmd_len;	/* SCSI Command Descriptor Block Length */
 
     direction = 0;
     if (*cmd == READ_10 || *cmd == READ_6)
@@ -319,17 +379,16 @@
     else if (*cmd == WRITE_10 || *cmd == WRITE_6)
 	direction = 0;
 
-    memcpy(ecb[ecbno].cdb, cmd, ecb[ecbno].cdblen);
+    memcpy(host->ecb[ecbno].cdb, cmd, SCpnt->cmd_len);
 
     if (SCpnt->use_sg)
     {
 	struct scatterlist * sgpnt;
 	struct aha1740_chain * cptr;
 	int i;
-#ifdef DEBUG
-	unsigned char * ptr;
-#endif
-	ecb[ecbno].sg = 1;	  /* SCSI Initiator Command  w/scatter-gather*/
+	DEB(unsigned char * ptr);
+
+	host->ecb[ecbno].sg = 1;  /* SCSI Initiator Command  w/scatter-gather*/
 	SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
 	sgpnt = (struct scatterlist *) SCpnt->request_buffer;
 	cptr = (struct aha1740_chain *) SCpnt->host_scribble; 
@@ -339,8 +398,8 @@
 	    cptr[i].datalen = sgpnt[i].length;
 	    cptr[i].dataptr = virt_to_bus(sgpnt[i].address);
 	}
-	ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
-	ecb[ecbno].dataptr = virt_to_bus(cptr);
+	host->ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
+	host->ecb[ecbno].dataptr = virt_to_bus(cptr);
 #ifdef DEBUG
 	printk("cptr %x: ",cptr);
 	ptr = (unsigned char *) cptr;
@@ -350,144 +409,161 @@
     else
     {
 	SCpnt->host_scribble = NULL;
-	ecb[ecbno].datalen = bufflen;
-	ecb[ecbno].dataptr = virt_to_bus(buff);
+	host->ecb[ecbno].datalen = bufflen;
+	host->ecb[ecbno].dataptr = virt_to_bus(buff);
     }
-    ecb[ecbno].lun = SCpnt->lun;
-    ecb[ecbno].ses = 1;	/* Suppress underrun errors */
-    ecb[ecbno].dir= direction;
-    ecb[ecbno].ars=1;  /* Yes, get the sense on an error */
-    ecb[ecbno].senselen = 12;
-    ecb[ecbno].senseptr = virt_to_bus(ecb[ecbno].sense);
-    ecb[ecbno].statusptr = virt_to_bus(ecb[ecbno].status);
-    ecb[ecbno].done = done;
-    ecb[ecbno].SCpnt = SCpnt;
+    host->ecb[ecbno].lun = SCpnt->lun;
+    host->ecb[ecbno].ses = 1;	/* Suppress underrun errors */
+    host->ecb[ecbno].dir = direction;
+    host->ecb[ecbno].ars = 1;  /* Yes, get the sense on an error */
+    host->ecb[ecbno].senselen = 12;
+    host->ecb[ecbno].senseptr = virt_to_bus(host->ecb[ecbno].sense);
+    host->ecb[ecbno].statusptr = virt_to_bus(host->ecb[ecbno].status);
+    host->ecb[ecbno].done = done;
+    host->ecb[ecbno].SCpnt = SCpnt;
 #ifdef DEBUG
     {
 	int i;
 	printk("aha1740_command: sending.. ");
-	for (i = 0; i < sizeof(ecb[ecbno])-10; i++)
-	    printk("%02x ", ((unchar *)&ecb[ecbno])[i]);
+	for (i = 0; i < sizeof(host->ecb[ecbno]) - 10; i++)
+	    printk("%02x ", ((unchar *)&host->ecb[ecbno])[i]);
     }
     printk("\n");
 #endif
     if (done)
-    { /*  You may question the code below, which contains potentially
-	  non-terminating while loops with interrupts disabled.  So did
-	  I when I wrote it, but the Adaptec Spec says the card is so fast,
-	  that this problem virtually never occurs so I've kept it.  We
-	  do printk a warning first, so that you'll know if it happens.
-	  In practice the only time we've seen this message is when some-
-	  thing else is in the driver was broken, like _makecode(), or
-	  when a scsi device hung the scsi bus.  Even under these conditions,
-	  The loop actually only cycled < 3 times (we instrumented it). */
-
+    { /*  The Adaptec Spec says the card is so fast that the loops will
+	  only be executed once in the code below. Even if this was true
+	  with the fastest processors when the spec was written, it doesn't
+	  seem to be true with todays fast processors. We print a warning
+	  if the code is executed more often than LOOPCNT_WARN. If this
+	  happens, it should be investigated. If the count reaches
+	  LOOPCNT_MAX, we assume something is broken; since there is no
+	  way to return an error (the return value is ignored by the
+	  mid-level scsi layer) we have to panic (and maybe that's the
+	  best thing we can do then anyhow). */
+
+#define LOOPCNT_WARN 10		/* excessive mbxout wait -> syslog-msg */
+#define LOOPCNT_MAX 1000000	/* mbxout deadlock -> panic() after ~ 2 sec. */
+	int loopcnt;
+	unsigned int base = SCpnt->host->io_port;
 	DEB(printk("aha1740[%d] critical section\n",ecbno));
 	save_flags(flags);
 	cli();
-	if ( ! (inb(G2STAT) & G2STAT_MBXOUT) )
-	{
-	    printk("aha1740[%d]_mbxout wait!\n",ecbno);
-	    cli(); /* printk may have done a sti()! */
+	for (loopcnt = 0; ; loopcnt++) {
+	    if (inb(G2STAT(base)) & G2STAT_MBXOUT) break;
+	    if (loopcnt == LOOPCNT_WARN) {
+		printk("aha1740[%d]_mbxout wait!\n",ecbno);
+		cli(); /* printk may have done a sti()! */
+	    }
+	    if (loopcnt == LOOPCNT_MAX)
+		panic("aha1740.c: mbxout busy!\n");
 	}
-	mb();
-	while ( ! (inb(G2STAT) & G2STAT_MBXOUT) );	/* Oh Well. */
-	outl(virt_to_bus(ecb+ecbno), MBOXOUT0);
-	if ( inb(G2STAT) & G2STAT_BUSY )
-	{
-	    printk("aha1740[%d]_attn wait!\n",ecbno);
-	    cli();
+	outl(virt_to_bus(host->ecb + ecbno), MBOXOUT0(base));
+	for (loopcnt = 0; ; loopcnt++) {
+	    if (! (inb(G2STAT(base)) & G2STAT_BUSY)) break;
+	    if (loopcnt == LOOPCNT_WARN) {
+		printk("aha1740[%d]_attn wait!\n",ecbno);
+		cli();
+	    }
+	    if (loopcnt == LOOPCNT_MAX)
+		panic("aha1740.c: attn wait failed!\n");
 	}
-	while ( inb(G2STAT) & G2STAT_BUSY );		/* And Again! */
-	outb(ATTN_START | (target & 7), ATTN);	/* Start it up */
+	outb(ATTN_START | (target & 7), ATTN(base)); /* Start it up */
 	restore_flags(flags);
 	DEB(printk("aha1740[%d] request queued.\n",ecbno));
     }
     else
-      printk("aha1740_queuecommand: done can't be NULL\n");
-    
+	printk(KERN_ALERT "aha1740_queuecommand: done can't be NULL\n");
     return 0;
 }
 
-static volatile int internal_done_flag = 0;
-static volatile int internal_done_errcode = 0;
-
 static void internal_done(Scsi_Cmnd * SCpnt)
 {
-    internal_done_errcode = SCpnt->result;
-    ++internal_done_flag;
+    SCpnt->SCp.Status++;
 }
 
 int aha1740_command(Scsi_Cmnd * SCpnt)
 {
     aha1740_queuecommand(SCpnt, internal_done);
-
-    while (!internal_done_flag);
-    internal_done_flag = 0;
-    return internal_done_errcode;
+    SCpnt->SCp.Status = 0;
+    while (!SCpnt->SCp.Status)
+	barrier();
+    return SCpnt->result;
 }
 
 /* Query the board for its irq_level.  Nothing else matters
    in enhanced mode on an EISA bus. */
 
-void aha1740_getconfig(void)
+void aha1740_getconfig(unsigned int base, unsigned int *irq_level,
+		       unsigned int *translation)
 {
-  static int intab[] = { 9,10,11,12,0,14,15,0 };
+    static int intab[] = { 9, 10, 11, 12, 0, 14, 15, 0 };
 
-  irq_level = intab [ inb(INTDEF)&0x7 ];
-  outb(inb(INTDEF) | 0x10, INTDEF);
+    *irq_level = intab[inb(INTDEF(base)) & 0x7];
+    *translation = inb(RESV1(base)) & 0x1;
+    outb(inb(INTDEF(base)) | 0x10, INTDEF(base));
 }
 
 int aha1740_detect(Scsi_Host_Template * tpnt)
 {
-    tpnt->proc_dir = &proc_scsi_aha1740;
+    int count = 0, slot;
 
-    memset(&ecb, 0, sizeof(struct ecb));
     DEB(printk("aha1740_detect: \n"));
-    
+
     for ( slot=MINEISA; slot <= MAXEISA; slot++ )
     {
-	base = SLOTBASE(slot);
+	int slotbase;
+	unsigned int irq_level, translation;
+	struct Scsi_Host *shpnt;
+	struct aha1740_hostdata *host;
+	slotbase = SLOTBASE(slot);
 	/*
 	 * The ioports for eisa boards are generally beyond that used in the
 	 * check/allocate region code, but this may change at some point,
 	 * so we go through the motions.
 	 */
-	if(check_region(base, 0x5c)) continue;  /* See if in use */
-	if ( aha1740_test_port())  break;
-    }
-    if ( slot > MAXEISA )
-	return 0;
-
-    aha1740_getconfig();
-
-    if ( (inb(G2STAT) & (G2STAT_MBXOUT | G2STAT_BUSY) ) != G2STAT_MBXOUT )
-    {	/* If the card isn't ready, hard reset it */
-	outb(G2CNTRL_HRST,G2CNTRL);
-	outb(0,G2CNTRL);    
-    }
-
-    printk("Configuring Adaptec at IO:%x, IRQ %d\n",base,
-	   irq_level);
-
-    DEB(printk("aha1740_detect: enable interrupt channel %d\n", irq_level));
-
-    if (request_irq(irq_level,aha1740_intr_handle, 0, "aha1740", NULL))
-    {
-	printk("Unable to allocate IRQ for adaptec controller.\n");
-	return 0;
+	if (check_region(slotbase, SLOTSIZE))  /* See if in use */
+	    continue;
+	if (!aha1740_test_port(slotbase))
+	    continue;
+	aha1740_getconfig(slotbase,&irq_level,&translation);
+	if ((inb(G2STAT(slotbase)) &
+	     (G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT)
+	{	/* If the card isn't ready, hard reset it */
+	    outb(G2CNTRL_HRST, G2CNTRL(slotbase));
+	    outb(0, G2CNTRL(slotbase));
+	}
+	printk("Configuring aha174x at IO:%x, IRQ %d\n", slotbase, irq_level);
+	printk("aha174x: Extended translation %sabled.\n",
+	       translation ? "en" : "dis");
+	DEB(printk("aha1740_detect: enable interrupt channel %d\n",irq_level));
+	if (request_irq(irq_level,aha1740_intr_handle,0,"aha1740",NULL)) {
+	    printk("Unable to allocate IRQ for adaptec controller.\n");
+	    continue;
+	}
+	shpnt = scsi_register(tpnt, sizeof(struct aha1740_hostdata));
+	request_region(slotbase, SLOTSIZE, "aha1740");
+	shpnt->base = 0;
+	shpnt->io_port = slotbase;
+	shpnt->n_io_port = SLOTSIZE;
+	shpnt->irq = irq_level;
+	shpnt->dma_channel = 0xff;
+	host = HOSTDATA(shpnt);
+	host->slot = slot;
+	host->translation = translation;
+	aha_host[irq_level - 9] = shpnt;
+	count++;
     }
-    request_region(base, 0x5c,"aha1740");  /* Reserve the space that we need to use */
-    return 1;
+    return count;
 }
 
 /* Note:  They following two functions do not apply very well to the Adaptec,
-which basically manages its own affairs quite well without our interference,
-so I haven't put anything into them.  I can faintly imagine someone with a
-*very* badly behaved SCSI target (perhaps an old tape?) wanting the abort(),
-but it hasn't happened yet, and doing aborts brings the Adaptec to its
-knees.  I cannot (at this moment in time) think of any reason to reset the
-card once it's running.  So there. */
+   which basically manages its own affairs quite well without our interference,
+   so I haven't put anything into them.  I can faintly imagine someone with a
+   *very* badly behaved SCSI target (perhaps an old tape?) wanting the abort(),
+   but it hasn't happened yet, and doing aborts brings the Adaptec to its
+   knees.  I cannot (at this moment in time) think of any reason to reset the
+   card once it's running.  So there. */
 
 int aha1740_abort(Scsi_Cmnd * SCpnt)
 {
@@ -507,13 +583,23 @@
 
 int aha1740_biosparam(Disk * disk, kdev_t dev, int* ip)
 {
-  int size = disk->capacity;
-DEB(printk("aha1740_biosparam\n"));
-  ip[0] = 64;
-  ip[1] = 32;
-  ip[2] = size >> 11;
-/*  if (ip[2] >= 1024) ip[2] = 1024; */
-  return 0;
+    int size = disk->capacity;
+    int extended = HOSTDATA(disk->device->host)->translation;
+
+    DEB(printk("aha1740_biosparam\n"));
+    if (extended && (ip[2] > 1024))
+    {
+	ip[0] = 255;
+	ip[1] = 63;
+	ip[2] = size / (255 * 63);
+    }
+    else
+    {
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;
+    }
+    return 0;
 }
 
 #ifdef MODULE

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov