S: Victoria 3163
S: Australia
+N: Pauline Middelink
+E: middelin@polyware.iaf.nl
+D: General low-level bug fixes, /proc fixes, identd support
+S: Boterkorfhoek 34
+S: 7546 JA Enschede
+S: Netherlands
+
N: Rick Miller
E: rick@discus.mil.wi.us
D: Linux Device Registrar (Major/minor numbers), "au-play", "bwBASIC"
VERSION = 1
PATCHLEVEL = 1
-SUBLEVEL = 67
+SUBLEVEL = 68
ARCH = i386
{
irq_used = ints[2];
}
- if (*strings != '\0')
+ if ((strings != NULL) && (*strings != '\0'))
{
if (strcmp(strings, "PAS") == 0)
{
}
lock = 1;
#ifdef CONFIG_SELECTION
- highlight_pointer(fg_console,-1);
+ clear_selection();
#endif /* CONFIG_SELECTION */
if (!console_blanked)
get_scrmem(fg_console);
/* mode 0 needs 2+wd*ht, modes 1 and 2 need 4+2*wd*ht */
chcount=video_num_columns*video_num_lines;
l = verify_area(mode==2 ? VERIFY_READ :VERIFY_WRITE,
- buf, (2+chcount)*(1+mode!=0));
+ buf, (2+chcount)*(mode ? 2 : 1));
if (l)
return l;
if (mode<2) {
put_fs_byte(*sptr++,buf++);
break;
case 1:
+#ifdef CONFIG_SELECTION
+ clear_selection();
+#endif
put_fs_byte((char)x,buf++); put_fs_byte((char)y,buf++);
memcpy_tofs(buf,(char *)origin,2*chcount);
break;
case 2:
- buf+=2; /* skip the the numnber 9 and console number */
- x=get_fs_byte(buf++); y=get_fs_byte(buf++);
+ buf+=4; /* ioctl#, console#, x,y */
memcpy_fromfs((char *)origin,buf,2*chcount);
break;
}
case 3: /* pointer highlight */
if (sel_cons != currcons)
{
- highlight_pointer(sel_cons,-1);
clear_selection();
sel_cons = currcons;
}
*/
#define colourmap ((char *)0xa0000)
-/* Pauline Middelink reports that we should use 0xA0000 for the bwmap as well.. */
+/* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
+ should use 0xA0000 for the bwmap as well.. */
#define blackwmap ((char *)0xa0000)
#define cmapsz 8192
#define seq_port_reg (0x3c4)
de600.o \
de620.o \
3c501.o \
+ eexpress.o \
plip.o \
8390.o
Move the theory of operation and memory map documentation.
Rework the board error reset
The statistics need to be updated correctly.
+
+ Modularized my Pauline Middelink <middelin@polyware.iaf.nl>
*/
static char *version =
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#ifdef MODULE
+#include <linux/module.h>
+#include "../../tools/version.h"
+#endif
#include <linux/malloc.h>
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
return 0;
}
/* Update the statistics here. */
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
return 0;
}
outw(saved_write_ptr, ioaddr + WRITE_PTR);
}
\f
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+static struct device dev_eexpress = {
+ " " /*"eexpress"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe };
+
+int
+init_module(void)
+{
+ if (register_netdev(&dev_eexpress) != 0)
+ return -EIO;
+ return 0;
+}
+
+void
+cleanup_module(void)
+{
+ if (MOD_IN_USE)
+ printk("express: device busy, remove delayed\n");
+ else
+ {
+ unregister_netdev(&dev_eexpress);
+ kfree_s(dev_eexpress.priv,sizeof(struct net_local));
+ dev_eexpress.priv=NULL;
+ }
+}
+#endif /* MODULE */
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -I/usr/src/linux/drivers/net -Wall -Wstrict-prototypes -O6 -m486 -c eexpress.c"
enable_irq(dev->irq);
}
-/* PLIP_ERROR --- wait til other end setteled */
+/* PLIP_ERROR --- wait til other end settled */
static int
plip_error(struct device *dev)
{
tmp->select[0] = IDENTIFY (0, cmd->lun);
#endif
patch_dsa_32(tmp->dsa, dsa_msgout, 1, tmp->select);
- patch_dsa_32(tmp->dsa, dsa_cmdout, 0, COMMAND_SIZE(cmd->cmnd[0]));
+ patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
patch_dsa_32(tmp->dsa, dsa_cmdout, 1, cmd->cmnd);
patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ?
cmd_dataout : hostdata->script + hostdata->E_other_transfer /
return SCSI_RESET_SNOOZE;
}
-const char *NCR53c7xx_info (void) {
- return("More info here\n");
-}
-
/*
* The NCR SDMS bios follows Annex A of the SCSI-CAM draft, and
* therefore shares the scsicam_bios_param function.
#include <linux/scsicam.h>
extern int NCR53c7xx_abort(Scsi_Cmnd *);
extern int NCR53c7xx_detect(Scsi_Host_Template *tpnt);
-extern const char *NCR53c7xx_info(void);
extern int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
extern int NCR53c7xx_reset(Scsi_Cmnd *);
-#define NCR53c7xx {NULL, "NCR53c{7,8}xx (rel 3)", NCR53c7xx_detect, \
- NULL, NCR53c7xx_info, \
+#define NCR53c7xx {NULL, NULL, "NCR53c{7,8}xx (rel 3)", NCR53c7xx_detect, \
+ NULL, NULL, \
NULL, NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset,\
NULL, scsicam_bios_param, \
/* can queue */ 1, /* id */ 7, 255 /* old SG_ALL */, \
msgout = NOP;
break;
case PHASE_CMDOUT:
- len = COMMAND_SIZE(cmd->cmnd[0]);
+ len = cmd->cmd_len;
data = cmd->cmnd;
/*
* XXX for performance reasons, on machines with a
#define P_BUSFREE 1
#define P_PARITY 2
-static char *aha152x_id = AHA152X_REVID;
-
static int port_base = 0;
static int this_host = 0;
static int can_disconnect = 0;
return 1;
}
-/*
- * return the name of the thing
- */
-const char *aha152x_info(void)
-{
- return(aha152x_id);
-}
-
/*
* Queue a command and setup interrupts for a free bus.
*/
if(aha152x_debug & debug_cmd)
{
printk("DFIFOEMP, outsw (%d words), ",
- COMMAND_SIZE(current_SC->cmnd[0])>>1);
+ current_SC->cmd_len >>1 );
disp_ports();
}
#endif
outsw( DATAPORT,
¤t_SC->cmnd,
- COMMAND_SIZE(current_SC->cmnd[0])>>1 );
+ current_SC->cmd_len >>1 );
#if defined(DEBUG_CMD)
if(aha152x_debug & debug_cmd)
#if defined(DEBUG_CMD) || defined(DEBUG_INTR)
if(debug_cmd & debug_intr)
printk("sent %d/%d command bytes, ", GETSTCNT(),
- COMMAND_SIZE(current_SC->cmnd[0]));
+ current_SC->cmd_len);
#endif
}
#include <asm/io.h>
int aha152x_detect(Scsi_Host_Template *);
-const char *aha152x_info(void);
int aha152x_command(Scsi_Cmnd *);
int aha152x_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int aha152x_abort(Scsi_Cmnd *);
/* Initial value of Scsi_Host entry */
#define AHA152X { /* next */ NULL, \
+ /* usage_count */ NULL, \
/* name */ AHA152X_REVID, \
/* detect */ aha152x_detect, \
/* release */ NULL, \
- /* info */ aha152x_info, \
+ /* info */ NULL, \
/* command */ aha152x_command, \
/* queuecommand */ aha152x_queue, \
/* abort */ aha152x_abort, \
* have the bios enabled to use the aha1542.
* Modified by David Gentzel
* Don't call request_dma if dma mask is 0 (for BusLogic BT-445S VL-Bus controller).
+ * Modified by Matti Aarnio
+ * Accept parameters from LILO cmd-line. -- 1-Oct-94
*/
#include <linux/kernel.h>
/* The adaptec can be configured for quite a number of addresses, but
I generally do not want the card poking around at random. We allow
two addresses - this allows people to use the Adaptec with a Midi
-card, which also used 0x330 */
+card, which also used 0x330 -- can be overriden with LILO! */
+
+#define MAXBOARDS 2 /* Increase this and the sizes of the
+ arrays below, if you need more.. */
+
+static unsigned int bases[MAXBOARDS]={0x330, 0x334};
+
+/* set by aha1542_setup according to the command line */
+static int setup_called[MAXBOARDS] = {0,0};
+static int setup_buson[MAXBOARDS] = {0,0};
+static int setup_busoff[MAXBOARDS] = {0,0};
+static int setup_dmaspeed[MAXBOARDS] = {-1,-1};
+
+static char *setup_str[MAXBOARDS] = {(char *)NULL,(char *)NULL};
+
+/*
+ * LILO params: aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]
+ *
+ * Where: <PORTBASE> is any of the valid AHA addresses:
+ * 0x130, 0x134, 0x230, 0x234, 0x330, 0x334
+ * <BUSON> is the time (in microsecs) that AHA spends on the AT-bus
+ * when transferring data. 1542A power-on default is 11us,
+ * valid values are in range: 2..15 (decimal)
+ * <BUSOFF> is the time that AHA spends OFF THE BUS after while
+ * it is transferring data (not to monopolize the bus).
+ * Power-on default is 4us, valid range: 1..64 microseconds.
+ * <DMASPEED> Default is jumper selected (1542A: on the J1),
+ * but experimenter can alter it with this.
+ * Valid values: 5, 6, 7, 8, 10 (MB/s)
+ * Factory default is 5 MB/s.
+ */
-static unsigned int bases[]={0x330, 0x334};
/* The DMA-Controller. We need to fool with this because we want to
be able to use the aha1542 without having to have the bios enabled */
/* In case some other card was probing here, reset interrupts */
aha1542_intr_reset(bse); /* reset interrupts, so they don't block */
+
outb(SRST|IRST/*|SCRST*/, CONTROL(bse));
i = jiffies + 2;
return 0; /* 0 = not ok */
}
-static const char aha_ident[] = "Adaptec 1542";
-
-/* What's this little function for? */
-const char *aha1542_info(void)
-{
- return aha_ident;
-}
-
/* A "high" level interrupt handler */
static void aha1542_intr_handle(int foo)
{
printk("aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
aha1542_stat();
printk("aha1542_queuecommand: dumping scsi cmd:");
- for (i = 0; i < (COMMAND_SIZE(*cmd)); i++) printk("%02x ", cmd[i]);
+ for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
printk("\n");
if (*cmd == WRITE_10 || *cmd == WRITE_6)
return 0; /* we are still testing, so *don't* write */
memset(&ccb[mbo], 0, sizeof(struct ccb));
- ccb[mbo].cdblen = COMMAND_SIZE(*cmd); /* SCSI Command Descriptor Block Length */
+ ccb[mbo].cdblen = SCpnt->cmd_len;
direction = 0;
if (*cmd == READ_10 || *cmd == READ_6)
any2scsi(cptr[i].datalen, sgpnt[i].length);
};
any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
- if(((unsigned int) buff & 0xff000000)) goto baddma;
any2scsi(ccb[mbo].dataptr, cptr);
#ifdef DEBUG
printk("cptr %x: ",cptr);
ccb[mbo].op = 0; /* SCSI Initiator Command */
SCpnt->host_scribble = NULL;
any2scsi(ccb[mbo].datalen, bufflen);
+ if(((unsigned int) buff & 0xff000000)) goto baddma;
any2scsi(ccb[mbo].dataptr, buff);
};
ccb[mbo].idlun = (target&7)<<5 | direction | (lun & 7); /*SCSI Target Id*/
return 0;
}
+/* called from init/main.c */
+void aha1542_setup( char *str, int *ints)
+{
+ char *ahausage = "aha1542: usage: aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]\n";
+ static int setup_idx = 0;
+ int setup_portbase;
+
+ if(setup_idx >= MAXBOARDS)
+ {
+ printk("aha1542: aha1542_setup called too many times! Bad LILO params ?\n");
+ printk(" Entryline 1: %s\n",setup_str[0]);
+ printk(" Entryline 2: %s\n",setup_str[1]);
+ printk(" This line: %s\n",str);
+ return;
+ }
+ if (ints[0] < 1 || ints[0] > 4)
+ {
+ printk("aha1542: %s\n", str );
+ printk(ahausage);
+ printk("aha1542: Wrong parameters may cause system malfunction.. We try anyway..\n");
+ }
+
+ setup_called[setup_idx]=ints[0];
+ setup_str[setup_idx]=str;
+
+ setup_portbase = ints[0] >= 1 ? ints[1] : 0; /* Preserve the default value.. */
+ setup_buson [setup_idx] = ints[0] >= 2 ? ints[2] : 7;
+ setup_busoff [setup_idx] = ints[0] >= 3 ? ints[3] : 5;
+ if (ints[0] >= 4) {
+ int atbt = -1;
+ switch (ints[4]) {
+ case 5:
+ atbt = 0x00;
+ break;
+ case 6:
+ atbt = 0x04;
+ break;
+ case 7:
+ atbt = 0x01;
+ break;
+ case 8:
+ atbt = 0x02;
+ break;
+ case 10:
+ atbt = 0x03;
+ break;
+ default:
+ printk("aha1542: %s\n", str );
+ printk(ahausage);
+ printk("aha1542: Valid values for DMASPEED are 5-8, 10 MB/s. Using jumper defaults.\n");
+ break;
+ }
+ setup_dmaspeed[setup_idx] = atbt;
+ }
+
+ if (setup_portbase != 0)
+ bases[setup_idx] = setup_portbase;
+
+ ++setup_idx;
+}
/* return non-zero on detection */
int aha1542_detect(Scsi_Host_Template * tpnt)
int indx;
DEB(printk("aha1542_detect: \n"));
-
+
for(indx = 0; indx < sizeof(bases)/sizeof(bases[0]); indx++)
- if(!check_region(bases[indx], 4)) {
+ if(bases[indx] != 0 && !check_region(bases[indx], 4)) {
shpnt = scsi_register(tpnt,
sizeof(struct aha1542_hostdata));
+ /* For now we do this - until kmalloc is more intelligent
+ we are resigned to stupid hacks like this */
+ if ((unsigned int) shpnt > 0xffffff) {
+ printk("Invalid address for shpnt with 1542.\n");
+ goto unregister;
+ }
+
if(!aha1542_test_port(bases[indx], shpnt)) goto unregister;
{
unchar oncmd[] = {CMD_BUSON_TIME, 7};
unchar offcmd[] = {CMD_BUSOFF_TIME, 5};
+
+ if(setup_called[indx])
+ {
+ oncmd[1] = setup_buson[indx];
+ offcmd[1] = setup_busoff[indx];
+ }
aha1542_intr_reset(base_io);
aha1542_out(base_io, oncmd, 2);
aha1542_intr_reset(base_io);
aha1542_out(base_io, offcmd, 2);
WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+ if (setup_dmaspeed[indx] >= 0)
+ {
+ unchar dmacmd[] = {CMD_DMASPEED, 0};
+ dmacmd[1] = setup_dmaspeed[indx];
+ aha1542_intr_reset(base_io);
+ aha1542_out(base_io, dmacmd, 2);
+ WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+ }
while (0) {
fail:
printk("aha1542_detect: setting bus on/off-time failed\n");
}
aha_host[irq_level - 9] = shpnt;
shpnt->io_port = base_io;
+ shpnt->n_io_port = 4; /* Number of bytes of I/O space used */
shpnt->dma_channel = dma_chan;
shpnt->irq = irq_level;
HOSTDATA(shpnt)->bios_translation = trans;
/* if (ip[2] >= 1024) ip[2] = 1024; */
return 0;
}
+
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = AHA1542;
+
+#include "scsi_module.c"
+#endif
+
#define CMD_EMBOI 0x05 /* Enable MailBox Out Interrupt */
#define CMD_BUSON_TIME 0x07 /* Set Bus-On Time */
#define CMD_BUSOFF_TIME 0x08 /* Set Bus-Off Time */
+#define CMD_DMASPEED 0x09 /* Set AT Bus Transfer Speed */
#define CMD_RETDEVS 0x0a /* Return Installed Devices */
#define CMD_RETCONF 0x0b /* Return Configuration Data */
#define CMD_RETSETUP 0x0d /* Return Setup Data */
int aha1542_command(Scsi_Cmnd *);
int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int aha1542_abort(Scsi_Cmnd *);
-const char *aha1542_info(void);
int aha1542_reset(Scsi_Cmnd *);
int aha1542_biosparam(Disk *, int, int*);
#define NULL 0
#endif
-#define AHA1542 { NULL, \
+#define AHA1542 { NULL, NULL, \
"Adaptec 1542", \
aha1542_detect, \
NULL, \
- aha1542_info, \
+ NULL, \
aha1542_command, \
aha1542_queuecommand, \
aha1542_abort, \
return 0;
}
-const char *aha1740_info(void)
-{
- static char buffer[] = "Adaptec 174x (EISA)";
- return buffer;
-}
-
/* A "high" level interrupt handler */
void aha1740_intr_handle(int foo)
{
i = -1;
printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
printk("scsi cmd:");
- for (i = 0; i < (COMMAND_SIZE(*cmd)); i++) printk("%02x ", cmd[i]);
+ for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
printk("\n");
#endif
printk("Sending command (%d %x)...",ecbno, done);
#endif
- ecb[ecbno].cdblen = COMMAND_SIZE(*cmd); /* SCSI Command Descriptor Block Length */
+ ecb[ecbno].cdblen = SCpnt->cmd_len; /* SCSI Command Descriptor Block Length */
direction = 0;
if (*cmd == READ_10 || *cmd == READ_6)
int aha1740_command(Scsi_Cmnd *);
int aha1740_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int aha1740_abort(Scsi_Cmnd *);
-const char *aha1740_info(void);
int aha1740_reset(Scsi_Cmnd *);
int aha1740_biosparam(Disk *, int, int*);
#define NULL 0
#endif
-#define AHA1740 {NULL, \
- "Adaptec 1740", \
+#define AHA1740 {NULL, NULL, \
+ "Adaptec 174x (EISA)", \
aha1740_detect, \
NULL, \
- aha1740_info, \
+ NULL, \
aha1740_command, \
aha1740_queuecommand, \
aha1740_abort, \
found += aha274x_register(template, type, base);
}
}
- template->name = (char *)aha274x_info();
+ template->name = (char *)aha274x_info(NULL);
return(found);
}
-const char *aha274x_info(void)
+const char *aha274x_info(struct Scsi_Host * shost)
{
return("Adaptec AHA274x/284x (EISA/VL-bus -> Fast SCSI) "
AHA274X_SEQ_VERSION "/"
* little-endian format.
*/
addr = cmd->cmnd;
- scb->SCSI_cmd_length = COMMAND_SIZE(cmd->cmnd[0]);
+ scb->SCSI_cmd_length = cmd->cmd_len;
memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
if (cmd->use_sg) {
#if 0
debug("aha274x_queue: cmd 0x%x (size %u), target %d, lun %d\n",
cmd->cmnd[0],
- COMMAND_SIZE(cmd->cmnd[0]),
+ cmd->cmd_len,
cmd->target,
cmd->lun);
#endif
*/
#define AHA274X { \
NULL, \
- "", \
+ NULL, \
+ NULL, \
aha274x_detect, \
NULL, \
aha274x_info, \
extern int aha274x_command(Scsi_Cmnd *);
extern int aha274x_abort(Scsi_Cmnd *);
extern int aha274x_reset(Scsi_Cmnd *);
-extern const char *aha274x_info(void);
+extern const char *aha274x_info(struct Scsi_Host *);
#endif
* The original version of this driver was derived from aha1542.[ch] which
* is Copyright (C) 1992 Tommy Thorn. Much has been reworked, but most of
* basic structure and substantial chunks of code still remain.
+ *
+ * Thanks to the following individuals who have made contributions (of
+ * (code, information, support, or testing) to this driver:
+ * Eric Youngdale Leonard Zubkoff
+ * Tomas Hurka Andrew Walker
*/
/*
* TODO:
- * 1. Cleanup error handling & reporting.
+ * 1. Clean up error handling & reporting.
* 2. Find out why scatter/gather is limited to 16 requests per command.
- * 3. Add multiple outstanding requests.
- * 4. See if we can make good use of having more than one command per lun.
- * 5. Test/improve/fix abort & reset functions.
- * 6. Look at command linking.
- * 7. Allow multiple boards to share an IRQ if the bus allows (e.g. EISA).
+ * 3. Test/improve/fix abort & reset functions.
+ * 4. Look at command linking.
+ * 5. Allow multiple boards to share an IRQ if the bus allows (EISA, MCA,
+ * and PCI).
+ * 6. Avoid using the 445S workaround for board revs >= D.
+ * 7. Get cmd_per_lun put in the Scsi_Host structure.
*/
/*
* BT-542B - ISA first-party DMA with floppy support.
* BT-545S - 542B + FAST SCSI and active termination.
* BT-545D - 545S + differential termination.
- * BT-445S - VESA bus-master FAST SCSI with active termination and floppy
- * support.
* BT-640A - MCA bus-master with floppy support.
* BT-646S - 640A + FAST SCSI and active termination.
* BT-646D - 646S + differential termination.
* BT-747D - 747S + differential termination.
* BT-757S - 747S + WIDE SCSI.
* BT-757D - 747D + WIDE SCSI.
+ * BT-445S - VESA bus-master FAST SCSI with active termination and floppy
+ * support.
+ * BT-445C - 445S + enhanced BIOS & firmware options.
* BT-946C - PCI bus-master FAST SCSI. (??? Nothing else known.)
*
- * Should you require further information on any of these boards, BusLogic
- * can be reached at (408)492-9090.
+ * ??? I believe other boards besides the 445 now have a "C" model, but I
+ * have no facts on them.
*
* This driver SHOULD support all of these boards. It has only been tested
* with a 747S and 445S.
*
+ * Should you require further information on any of these boards, BusLogic
+ * can be reached at (408)492-9090. Their BBS # is (408)492-1984 (maybe BBS
+ * stands for "Big Brother System"?).
+ *
* Places flagged with a triple question-mark are things which are either
* unfinished, questionable, or wrong.
*/
#include "buslogic.h"
#ifndef BUSLOGIC_DEBUG
-# define BUSLOGIC_DEBUG UD_ABORT
+# define BUSLOGIC_DEBUG 0
#endif
-#define BUSLOGIC_VERSION "1.00"
+/* If different port addresses are needed (e.g. to install more than two
+ cards), you must define BUSLOGIC_PORT_OVERRIDE to be a comma-separated list
+ of the addresses which will be checked. This can also be used to resolve a
+ conflict if the port-probing at a standard port causes problems with
+ another board. */
+/* #define BUSLOGIC_PORT_OVERRIDE 0x330, 0x334, 0x130, 0x134, 0x230, 0x234 */
+
+/* Define this to be either BIOS_TRANSLATION_DEFAULT or BIOS_TRANSLATION_BIG
+ if you wish to bypass the test for this, which uses an undocumented port.
+ The test is believed to fail on at least some AMI BusLogic clones. */
+/* #define BIOS_TRANSLATION_OVERRIDE BIOS_TRANSLATION_BIG */
+
+#define BUSLOGIC_VERSION "1.13"
/* Not a random value - if this is too large, the system hangs for a long time
waiting for something to happen if a board is not installed. */
+/* ??? I don't really like this as it will wait longer on slow machines.
+ Perhaps we should base this on the loops_per_second "Bogomips" value? */
#define WAITNEXTTIMEOUT 3000000
/* This is for the scsi_malloc call in buslogic_queuecommand. */
/* Since the SG list is malloced, we have to limit the length. */
#define BUSLOGIC_MAX_SG (BUSLOGIC_SG_MALLOC / sizeof (struct chain))
-/* The DMA-Controller. We need to fool with this because we want to be able to
- use an ISA BusLogic without having to have the BIOS enabled. */
-#define DMA_MODE_REG 0xD6
-#define DMA_MASK_REG 0xD4
-#define CASCADE 0xC0
+/* ??? Arbitrary. If we can dynamically allocate the mailbox arrays, I may
+ bump up this number. */
+#define BUSLOGIC_MAILBOXES 16
-#define BUSLOGIC_MAILBOXES 16 /* ??? Arbitrary? */
+#define BUSLOGIC_NONISA_CMDLUN 4 /* ??? Arbitrary (> 1) */
/* BusLogic boards can be configured for quite a number of port addresses (six
to be exact), but I generally do not want the driver poking around at
random. We allow two port addresses - this allows people to use a BusLogic
- with a MIDI card, which frequently also uses 0x330. If different port
- addresses are needed (e.g. to install more than two cards), you must define
- BUSLOGIC_PORT_OVERRIDE to be a list of the addresses which will be checked.
- This can also be used to resolve a conflict if the port-probing at a
- standard port causes problems with another board. */
+ with a MIDI card, which frequently also uses 0x330. */
static const unsigned int bases[] = {
#ifdef BUSLOGIC_PORT_OVERRIDE
BUSLOGIC_PORT_OVERRIDE
#define BIOS_TRANSLATION_BIG 1 /* Big disk (> 1G) case */
struct hostdata {
- unsigned char bus_type;
- int bios_translation; /* Mapping bios uses - for compatibility */
+ unsigned int bus_type;
+ unsigned int bios_translation: 1; /* BIOS mapping (for compatibility) */
size_t last_mbi_used;
size_t last_mbo_used;
+ char model[7];
+ char firmware_rev[6];
Scsi_Cmnd *sc[BUSLOGIC_MAILBOXES];
struct mailbox mb[2 * BUSLOGIC_MAILBOXES];
struct ccb ccbs[BUSLOGIC_MAILBOXES];
#define CHECK(cond) if (cond) ; else goto fail
-#define WAIT(port, mask, allof, noneof) \
- CHECK(wait(port, mask, allof, noneof, WAITNEXTTIMEOUT, FALSE))
-#define WAIT_WHILE(port, mask) WAIT(port, mask, 0, mask)
-#define WAIT_UNTIL(port, mask) WAIT(port, mask, mask, 0)
-#define WAIT_FAST(port, mask, allof, noneof) \
- CHECK(wait(port, mask, allof, noneof, 100, TRUE))
-#define WAIT_WHILE_FAST(port, mask) WAIT_FAST(port, mask, 0, mask)
-#define WAIT_UNTIL_FAST(port, mask) WAIT_FAST(port, mask, mask, 0)
+#define WAIT(port, allof, noneof) \
+ CHECK(wait(port, allof, noneof, WAITNEXTTIMEOUT, FALSE))
+#define WAIT_WHILE(port, mask) WAIT(port, 0, mask)
+#define WAIT_UNTIL(port, mask) WAIT(port, mask, 0)
+#define WAIT_FAST(port, allof, noneof) \
+ CHECK(wait(port, allof, noneof, 100, TRUE))
+#define WAIT_WHILE_FAST(port, mask) WAIT_FAST(port, 0, mask)
+#define WAIT_UNTIL_FAST(port, mask) WAIT_FAST(port, mask, 0)
/* If delay != 0, we use the udelay call to regulate the amount of time we
- wait. */
-static __inline__ int wait(unsigned short port, unsigned char mask,
+ wait.
+
+ This is inline as it is always called with constant arguments and hence
+ will be very well optimized. */
+static __inline__ int wait(unsigned short port,
unsigned char allof, unsigned char noneof,
unsigned int timeout, int delay)
{
int bits;
for (;;) {
- bits = inb(port) & mask;
+ bits = inb(port);
if ((bits & allof) == allof && (bits & noneof) == 0)
return TRUE;
if (delay)
printk("BusLogic SCSI: ");
}
-#if BUSLOGIC_DEBUG
static void buslogic_stat(unsigned int base)
{
int s = inb(STATUS(base)), i = inb(INTERRUPT(base));
- printk("status=%02X intrflags=%02X\n", s, i);
+ buslogic_printk("status=%02X intrflags=%02X\n", s, i);
}
-#else
-# define buslogic_stat(base)
-#endif
/* This is a bit complicated, but we need to make sure that an interrupt
routine does not send something out while we are in the middle of this.
}
/* Only used at boot time, so we do not need to worry about latency as much
- here. */
+ here. This waits a very short period of time. We use this if we are not
+ sure whether the board will respond to the command we just sent. */
static int buslogic_in(unsigned int base, unsigned char *cmdp, size_t len)
{
cli();
while (len--) {
- WAIT_UNTIL(STATUS(base), DIRRDY);
+ WAIT_UNTIL_FAST(STATUS(base), DIRRDY);
*cmdp++ = inb(DATA_IN(base));
}
sti();
return FALSE;
fail:
sti();
+#if (BUSLOGIC_DEBUG & BD_IO)
buslogic_printk("buslogic_in failed(%u): ", len + 1);
buslogic_stat(base);
+#endif
return TRUE;
}
-#if 0
-/* Similar to buslogic_in, except that we wait a very short period of time.
- We use this if we know the board is alive and awake, but we are not sure
- whether the board will respond the the command we are about to send. */
-static int buslogic_in_fast(unsigned int base, unsigned char *cmdp, size_t len)
+static unsigned int makecode(unsigned int haerr, unsigned int scsierr)
{
- cli();
- while (len--) {
- WAIT_UNTIL_FAST(STATUS(base), DIRRDY);
- *cmdp++ = inb(DATA_IN(base));
- }
- sti();
- return FALSE;
- fail:
- sti();
- return TRUE;
-}
+ unsigned int hosterr;
+ const char *errstr = NULL;
+#if (BUSLOGIC_DEBUG & BD_ERRORS) && defined(CONFIG_SCSI_CONSTANTS)
+ static const char *const buslogic_status[] = {
+ /* 00 */ "Command completed normally",
+ /* 01-07 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ /* 08-09 */ NULL, NULL,
+ /* 0A */ "Linked command completed normally",
+ /* 0B */ "Linked command completed normally, interrupt generated",
+ /* 0C-0F */ NULL, NULL, NULL, NULL,
+ /* 10 */ NULL,
+ /* 11 */ "Selection timed out",
+ /* 12 */ "Data overrun/underrun",
+ /* 13 */ "Unexpected bus free",
+ /* 14 */ "Target bus phase sequence failure",
+ /* 15 */ "First byte of outgoing MB was invalid",
+ /* 16 */ "Invalid CCB Operation Code",
+ /* 17 */ "Linked CCB does not have the same LUN",
+ /* 18 */ "Invalid Target Direction received from Host",
+ /* 19 */ "Duplicate CCB Received in Target Mode",
+ /* 1A */ "Invalid CCB or Segment List Parameter",
+ /* 1B */ "Auto request sense failed",
+ /* 1C */ "SCSI-2 tagged queueing message was rejected by the target",
+ /* 1D-1F */ NULL, NULL, NULL,
+ /* 20 */ "Host adapter hardware failure",
+ /* 21 */ "Target did not respond to SCSI ATN and the HA SCSI bus reset",
+ /* 22 */ "Host adapter asserted a SCSI bus reset",
+ /* 23 */ "Other SCSI devices asserted a SCSI bus reset",
+ };
#endif
-static unsigned int makecode(unsigned int hosterr, unsigned int scsierr)
-{
- switch (hosterr) {
+ switch (haerr) {
case 0x00: /* Normal completion. */
case 0x0A: /* Linked command complete without error and linked
normally. */
case 0x11: /* Selection time out: the initiator selection or
target reselection was not complete within the SCSI
- Time out period. */
+ time out period. */
hosterr = DID_TIME_OUT;
break;
target. The host adapter will generate a SCSI
Reset Condition, notifying the host with a RSTS
interrupt. */
+ case 0x21: /* The target did not respond to SCSI ATN and the host
+ adapter consequently issued a SCSI bus reset to
+ clear up the failure. */
+ case 0x22: /* The host adapter asserted a SCSI bus reset. */
hosterr = DID_RESET;
break;
case 0x1C: /* SCSI-2 tagged queueing message was rejected by the
target. */
case 0x20: /* The host adapter hardware failed. */
- case 0x21: /* The target did not respond to SCSI ATN and the host
- adapter consequently issued a SCSI bus reset to
- clear up the failure. */
- case 0x22: /* The host adapter asserted a SCSI bus reset. */
case 0x23: /* Other SCSI devices asserted a SCSI bus reset. */
-#if BUSLOGIC_DEBUG
- buslogic_printk("%X %X\n", hosterr, scsierr);
-#endif
hosterr = DID_ERROR; /* ??? Couldn't find any better. */
break;
default:
- buslogic_printk("makecode: unknown hoststatus %X\n", hosterr);
+#ifndef CONFIG_SCSI_CONSTANTS
+ errstr = "unknown hoststatus";
+#endif
+ hosterr = DID_ERROR;
break;
}
- return (hosterr << 16) | scsierr;
-}
-
-static int test_port(unsigned int base, struct Scsi_Host *shpnt)
-{
- unsigned int i;
- unsigned char inquiry_cmd[] = { CMD_INQUIRY };
- unsigned char inquiry_result[4];
- unsigned char *cmdp;
- int len;
- volatile int debug = 0;
-
- /* Quick and dirty test for presence of the card. */
- if (inb(STATUS(base)) == 0xFF)
- return TRUE;
-
- /* Reset the adapter. I ought to make a hard reset, but it's not really
- necessary. */
-
-#if BUSLOGIC_DEBUG
- buslogic_printk("test_port called\n");
-#endif
-
- /* In case some other card was probing here, reset interrupts. */
- INTR_RESET(base); /* reset interrupts, so they don't block */
-
- outb(RSOFT | RINT/* | RSBUS*/, CONTROL(base));
-
- /* Wait a little bit for things to settle down. */
- i = jiffies + 2;
- while (i > jiffies);
-
- debug = 1;
- /* Expect INREQ and HARDY, any of the others are bad. */
- WAIT(STATUS(base), STATMASK, INREQ | HARDY,
- DACT | DFAIL | CMDINV | DIRRDY | CPRBSY);
-
- debug = 2;
- /* Shouldn't have generated any interrupts during reset. */
- if (inb(INTERRUPT(base)) & INTRMASK)
- goto fail;
-
- /* Perform a host adapter inquiry instead so we do not need to set up the
- mailboxes ahead of time. */
- buslogic_out(base, inquiry_cmd, 1);
-
- debug = 3;
- len = 4;
- cmdp = &inquiry_result[0];
- while (len--) {
- WAIT(STATUS(base), DIRRDY, DIRRDY, 0);
- *cmdp++ = inb(DATA_IN(base));
+#if (BUSLOGIC_DEBUG & BD_ERRORS)
+# ifdef CONFIG_SCSI_CONSTANTS
+ if (hosterr != DID_OK) {
+ if (haerr < ARRAY_SIZE(buslogic_status))
+ errstr = buslogic_status[haerr];
+ if (errstr == NULL)
+ errstr = "unknown hoststatus";
}
-
- debug = 4;
- /* Reading port should reset DIRRDY. */
- if (inb(STATUS(base)) & DIRRDY)
- goto fail;
-
- debug = 5;
- /* When CMDC, command is completed, and we're though testing. */
- WAIT_UNTIL(INTERRUPT(base), CMDC);
-
- /* now initialize adapter. */
-
- debug = 6;
- /* Clear interrupts. */
- outb(RINT, CONTROL(base));
-
- debug = 7;
-
- return FALSE; /* 0 = ok */
- fail:
- return TRUE; /* 1 = not ok */
+# else
+ if (hosterr == DID_ERROR)
+ errstr = "";
+# endif
+#endif
+ if (errstr != NULL)
+ buslogic_printk("makecode: %s (%02X)\n", errstr, haerr);
+ return (hosterr << 16) | scsierr;
}
const char *buslogic_info(void)
{
- return "BusLogic SCSI Driver version " BUSLOGIC_VERSION;
+ return "BusLogic SCSI driver version " BUSLOGIC_VERSION;
}
/* A "high" level interrupt handler. */
ccb = HOSTDATA(shpnt)->ccbs;
base = shpnt->io_port;
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_INTERRUPT)
flag = inb(INTERRUPT(base));
buslogic_printk("buslogic_interrupt: ");
probably do something special, but for now just printing a message
is sufficient. A SCSI reset detected is something that we really
need to deal with in some way. */
- if (flag & ~IMBL) {
+ if (flag & (MBOR | CMDC | RSTS)) {
+ buslogic_printk("Unusual flag:");
if (flag & MBOR)
- printk("MBOR ");
+ printk(" MBOR");
if (flag & CMDC)
- printk("CMDC ");
+ printk(" CMDC");
if (flag & RSTS) {
needs_restart = 1;
- printk("RSTS ");
+ printk(" RSTS");
}
+ printk("\n");
}
INTR_RESET(base);
return;
}
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_INTERRUPT)
if (ccb[mbo].tarstat || ccb[mbo].hastat)
buslogic_printk("buslogic_interrupt: returning %08X (status %d)\n",
((int)ccb[mbo].hastat << 16) | ccb[mbo].tarstat,
if (mbistatus == MBX_COMPLETION_NOT_FOUND)
continue;
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_INTERRUPT)
buslogic_printk("...done %u %u\n", mbo, mbi);
#endif
if (!sctmp || !sctmp->scsi_done) {
buslogic_printk("buslogic_interrupt: Unexpected interrupt\n");
- buslogic_printk("tarstat=%02X, hastat=%02X id=%d lun=%d ccb#=%d\n",
+ buslogic_printk("tarstat=%02X, hastat=%02X id=%d lun=%d ccb#=%u\n",
ccb[mbo].tarstat, ccb[mbo].hastat,
ccb[mbo].id, ccb[mbo].lun, mbo);
return;
if (sctmp->host_scribble)
scsi_free(sctmp->host_scribble, BUSLOGIC_SG_MALLOC);
-#if 0 /* ??? */
- /* Fetch the sense data, and tuck it away, in the required slot. The
- BusLogic automatically fetches it, and there is no guarantee that we
- will still have it in the cdb when we come back. */
- if (ccb[mbo].tarstat == 2) /* ??? */
- memcpy(sctmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
- sizeof sctmp->sense_buffer);
-#endif
-
/* ??? more error checking left out here */
- if (mbistatus != MBX_COMPLETION_OK)
+ if (mbistatus != MBX_COMPLETION_OK) {
/* ??? This is surely wrong, but I don't know what's right. */
errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
- else
+ } else
errstatus = 0;
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_INTERRUPT)
if (errstatus)
- buslogic_printk("error: %08X %04X %04X\n",
- errstatus, ccb[mbo].hastat, ccb[mbo].tarstat);
+ buslogic_printk("error: %04X %04X\n",
+ ccb[mbo].hastat, ccb[mbo].tarstat);
if (status_byte(ccb[mbo].tarstat) == CHECK_CONDITION) {
size_t i;
}
}
+/* ??? Why does queuecommand return a value? scsi.c never looks at it... */
int buslogic_queuecommand(Scsi_Cmnd *scpnt, void (*done)(Scsi_Cmnd *))
{
static const unsigned char buscmd[] = { CMD_START_SCSI };
struct mailbox *mb;
struct ccb *ccb;
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_COMMAND)
if (target > 1) {
scpnt->result = DID_TIME_OUT << 16;
done(scpnt);
#endif
if (*cmd == REQUEST_SENSE) {
-#ifndef DEBUG
+#if (BUSLOGIC_DEBUG & (BD_COMMAND | BD_ERRORS))
if (bufflen != sizeof scpnt->sense_buffer) {
buslogic_printk("Wrong buffer length supplied for request sense"
" (%d)\n",
return 0;
}
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_COMMAND)
{
int i;
mbo = 0;
} while (mbo != HOSTDATA(scpnt->host)->last_mbo_used);
- if (mb[mbo].status != MBX_NOT_IN_USE
- || HOSTDATA(scpnt->host)->sc[mbo]) {
+ if (mb[mbo].status != MBX_NOT_IN_USE || HOSTDATA(scpnt->host)->sc[mbo]) {
/* ??? Instead of panicing, should we enable OMBR interrupts and
sleep until we get one? */
panic("buslogic.c: unable to find empty mailbox");
sti();
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_COMMAND)
buslogic_printk("sending command (%d %08X)...", mbo, done);
#endif
}
ccb[mbo].datalen = scpnt->use_sg * sizeof (struct chain);
ccb[mbo].dataptr = cptr;
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_COMMAND)
{
unsigned char *ptr;
ccb[mbo].linkptr = NULL;
ccb[mbo].commlinkid = 0;
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_COMMAND)
{
size_t i;
#endif
if (done) {
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_COMMAND)
buslogic_printk("buslogic_queuecommand: now waiting for interrupt: ");
buslogic_stat(scpnt->host->io_port);
#endif
mb[mbo].status = MBX_ACTION_START;
/* start scsi command */
buslogic_out(scpnt->host->io_port, buscmd, sizeof buscmd);
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_COMMAND)
buslogic_stat(scpnt->host->io_port);
#endif
} else
int buslogic_command(Scsi_Cmnd *scpnt)
{
-#if BUSLOGIC_DEBUG
- buslogic_printk("buslogic_command: ..calling buslogic_queuecommand\n");
+#if (BUSLOGIC_DEBUG & BD_COMMAND)
+ buslogic_printk("buslogic_command: calling buslogic_queuecommand\n");
#endif
buslogic_queuecommand(scpnt, internal_done);
}
INTR_RESET(base); /* reset interrupts, so they don't block */
- /* If this fails, this must be an Adaptec board */
if (buslogic_out(base, (unsigned char *)&cmd, sizeof cmd))
- goto must_be_adaptec;
+ goto fail;
+ WAIT_UNTIL(INTERRUPT(base), CMDC);
- /* Wait until host adapter is done messing around, and then check to see
- if the command was accepted. If it failed, this must be an Adaptec
- board. */
- WAIT_UNTIL(STATUS(base), HARDY);
- if (inb(STATUS(base)) & CMDINV)
- goto must_be_adaptec;
+ ok = TRUE;
- WAIT_UNTIL(INTERRUPT(base), CMDC);
while (0) {
fail:
buslogic_printk("buslogic_detect: failed setting up mailboxes\n");
}
- ok = TRUE;
- must_be_adaptec:
+
INTR_RESET(base);
- if (!ok)
- printk("- must be Adaptec\n"); /* So that the adaptec detect looks
- clean */
- return ok;
+
+ return !ok;
}
static int getconfig(unsigned int base, unsigned char *irq,
unsigned char *dma, unsigned char *id,
- unsigned char *bus_type, unsigned short *max_sg)
+ char *bus_type, unsigned short *max_sg,
+ const unsigned char **bios)
{
unsigned char inquiry_cmd[2];
unsigned char inquiry_result[4];
int i;
+#if (BUSLOGIC_DEBUG & BD_DETECT)
+ buslogic_printk("getconfig: called\n");
+#endif
+
i = inb(STATUS(base));
if (i & DIRRDY)
i = inb(DATA_IN(base));
inquiry_cmd[0] = CMD_RETCONF;
buslogic_out(base, inquiry_cmd, 1);
- buslogic_in(base, inquiry_result, 3);
- WAIT_UNTIL(INTERRUPT(base), CMDC);
+ if (buslogic_in(base, inquiry_result, 3))
+ goto fail;
+ WAIT_UNTIL_FAST(INTERRUPT(base), CMDC);
INTR_RESET(base);
/* Defer using the DMA value until we know the bus type. */
*dma = inquiry_result[0];
default:
buslogic_printk("Unable to determine BusLogic IRQ level."
" Disabling board.\n");
- return TRUE;
+ goto fail;
}
*id = inquiry_result[2] & 0x7;
+ /* I expected Adaptec boards to fail on this, but it doesn't happen... */
inquiry_cmd[0] = CMD_INQEXTSETUP;
inquiry_cmd[1] = 4;
- if (buslogic_out(base, inquiry_cmd, 2)
- || buslogic_in(base, inquiry_result, 4))
- return TRUE;
- WAIT_UNTIL(INTERRUPT(base), CMDC);
+ if (buslogic_out(base, inquiry_cmd, 2))
+ goto fail;
+ if (buslogic_in(base, inquiry_result, inquiry_cmd[1]))
+ goto fail;
+ WAIT_UNTIL_FAST(INTERRUPT(base), CMDC);
+ if (inb(STATUS(base)) & CMDINV)
+ goto fail;
INTR_RESET(base);
-#ifdef BUSLOGIC_BUS_TYPE_OVERRIDE
- *bus_type = BUS_TYPE_OVERRIDE;
-#else
*bus_type = inquiry_result[0];
-#endif
CHECK(*bus_type == 'A' || *bus_type == 'E' || *bus_type == 'M');
-#ifdef BUSLOGIC_BUS_TYPE_OVERRIDE
- if (inquiry_result[0] != BUS_TYPE_OVERRIDE)
- buslogic_printk("Overriding bus type %c with %c\n",
- inquiry_result[0], BUS_TYPE_OVERRIDE);
-#endif
+
+ *bios = (const unsigned char *)((unsigned int)inquiry_result[1] << 12);
+
*max_sg = (inquiry_result[3] << 8) | inquiry_result[2];
/* We only need a DMA channel for ISA boards. Some other types of boards
default:
buslogic_printk("Unable to determine BusLogic DMA channel."
" Disabling board.\n");
- return TRUE;
+ goto fail;
}
else
*dma = 0;
while (0) {
fail:
+#if (BUSLOGIC_DEBUG & BD_DETECT)
buslogic_printk("buslogic_detect: query board settings\n");
+#endif
return TRUE;
}
return FALSE;
}
-static int get_translation(unsigned int base)
+/* Query the board. This acts both as part of the detection sequence and as a
+ means to get necessary configuration information. */
+static int buslogic_query(unsigned int base, unsigned char *trans,
+ unsigned char *irq, unsigned char *dma,
+ unsigned char *id, char *bus_type,
+ unsigned short *max_sg, const unsigned char **bios,
+ char *model, char *firmware_rev)
{
- /* ??? Unlike UltraStor, I see no way of determining whether > 1G mapping
- has been enabled. However, it appears that BusLogic uses a mapping
- scheme which varies with the disk size when > 1G mapping is enabled.
- For disks <= 1G, this mapping is the same regardless of the setting of
- > 1G mapping. Therefore, we should be safe in always assuming that > 1G
- mapping has been enabled. */
- return BIOS_TRANSLATION_BIG;
-}
+ unsigned char inquiry_cmd[2];
+ unsigned char inquiry_result[6];
+ unsigned char geo;
+ unsigned int i;
-/* Query the board to find out the model. */
-static int buslogic_query(unsigned int base, int *trans)
-{
- static const unsigned char inquiry_cmd[] = { CMD_INQUIRY };
- unsigned char inquiry_result[4];
- int i;
+#if (BUSLOGIC_DEBUG & BD_DETECT)
+ buslogic_printk("buslogic_query: called\n");
+#endif
- i = inb(STATUS(base));
- if (i & DIRRDY)
- i = inb(DATA_IN(base));
- buslogic_out(base, inquiry_cmd, sizeof inquiry_cmd);
- buslogic_in(base, inquiry_result, 4);
- WAIT_UNTIL(INTERRUPT(base), CMDC);
+ /* Quick and dirty test for presence of the card. */
+ if (inb(STATUS(base)) == 0xFF)
+ goto fail;
+
+ /* Check the GEOMETRY port early for quick bailout on Adaptec boards. */
+ geo = inb(GEOMETRY(base));
+#if (BUSLOGIC_DEBUG & BD_DETECT)
+ buslogic_printk("geometry bits: %02X\n", geo);
+#endif
+ /* Here is where we tell the men from the boys (i.e. Adaptec's don't
+ support the GEOMETRY port, the men do :-) */
+ if (geo == 0xFF)
+ goto fail;
+
+ /* In case some other card was probing here, reset interrupts. */
INTR_RESET(base);
-#if 1 /* ??? Temporary */
- buslogic_printk("Inquiry Bytes: %02X %02X %02X %02X\n",
- inquiry_result[0], inquiry_result[1],
- inquiry_result[2], inquiry_result[3]);
+ /* Reset the adapter. I ought to make a hard reset, but it's not really
+ necessary. */
+ outb(RSOFT | RINT/* | RSBUS*/, CONTROL(base));
+
+ /* Wait a little bit for things to settle down. */
+ i = jiffies + 2;
+ while (i > jiffies);
+
+ /* Expect INREQ and HARDY, any of the others are bad. */
+ WAIT(STATUS(base), INREQ | HARDY, DACT | DFAIL | CMDINV | DIRRDY | CPRBSY);
+
+ /* Shouldn't have generated any interrupts during reset. */
+ if (inb(INTERRUPT(base)) & INTRMASK)
+ goto fail;
+
+ /* Getting the BusLogic firmware revision level is a bit tricky. We get
+ the first two digits (d.d) from CMD_INQUIRY and then use two undocumented
+ commands to get the remaining digit and letter (d.ddl as in 3.31C). */
+
+ inquiry_cmd[0] = CMD_INQUIRY;
+ buslogic_out(base, inquiry_cmd, 1);
+ if (buslogic_in(base, inquiry_result, 4))
+ goto fail;
+ /* Reading port should reset DIRRDY. */
+ if (inb(STATUS(base)) & DIRRDY)
+ goto fail;
+ WAIT_UNTIL_FAST(INTERRUPT(base), CMDC);
+ INTR_RESET(base);
+ firmware_rev[0] = inquiry_result[2];
+ firmware_rev[1] = '.';
+ firmware_rev[2] = inquiry_result[3];
+ firmware_rev[3] = '\0';
+#if 0
+ buslogic_printk("Inquiry Bytes: %02X(%c) %02X(%c)\n",
+ inquiry_result[0], inquiry_result[0],
+ inquiry_result[1], inquiry_result[1]);
#endif
+ if (getconfig(base, irq, dma, id, bus_type, max_sg, bios))
+ goto fail;
+
+ /* Set up defaults */
+#ifdef BIOS_TRANSLATION_OVERRIDE
+ *trans = BIOS_TRANSLATION_OVERRIDE;
+#else
+ *trans = BIOS_TRANSLATION_DEFAULT;
+#endif
+ model[0] = '\0';
+ model[6] = 0;
+
+ /* ??? Begin undocumented command use.
+ These may not be supported by clones. */
+
+ do {
+ /* ??? It appears as though AMI BusLogic clones don't implement this
+ feature. As an experiment, if we read a 00 we ignore the GEO_GT_1GB
+ bit and skip all further undocumented commands. */
+ if (geo == 0x00)
+ break;
+#ifndef BIOS_TRANSLATION_OVERRIDE
+ *trans = ((geo & GEO_GT_1GB)
+ ? BIOS_TRANSLATION_BIG : BIOS_TRANSLATION_DEFAULT);
+#endif
+
+ inquiry_cmd[0] = CMD_VER_NO_LAST;
+ buslogic_out(base, inquiry_cmd, 1);
+ if (buslogic_in(base, inquiry_result, 1))
+ break;
+ WAIT_UNTIL_FAST(INTERRUPT(base), CMDC);
+ INTR_RESET(base);
+ firmware_rev[3] = inquiry_result[0];
+ firmware_rev[4] = '\0';
+
+ inquiry_cmd[0] = CMD_VER_NO_LETTER;
+ buslogic_out(base, inquiry_cmd, 1);
+ if (buslogic_in(base, inquiry_result, 1))
+ break;
+ WAIT_UNTIL_FAST(INTERRUPT(base), CMDC);
+ INTR_RESET(base);
+ firmware_rev[4] = inquiry_result[0];
+ firmware_rev[5] = '\0';
+
+ /* Use undocumented command to get model number and revision. */
+
+ inquiry_cmd[0] = CMD_RET_MODEL_NO;
+ inquiry_cmd[1] = 6;
+ buslogic_out(base, inquiry_cmd, 2);
+ if (buslogic_in(base, inquiry_result, inquiry_cmd[1]))
+ break;
+ WAIT_UNTIL_FAST(INTERRUPT(base), CMDC);
+ INTR_RESET(base);
+ memcpy(model, inquiry_result, 5);
+ model[5] = '\0';
+ model[6] = inquiry_result[5];
+ } while (0);
+
+ /* ??? End undocumented command use. */
+
+ /* bus_type from getconfig doesn't differentiate between EISA/VESA. We
+ override using the model number here. */
+ /* ??? What bus_type gets returned for PCI? */
+ switch (*bus_type) {
+ case 'E':
+ switch (model[0]) {
+ case '4':
+ *bus_type = 'V';
+ break;
+ case '7':
+ break;
+ default:
+ *bus_type = 'X';
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
while (0) {
fail:
+#if (BUSLOGIC_DEBUG & BD_DETECT)
buslogic_printk("buslogic_query: query board settings\n");
+#endif
return TRUE;
}
- *trans = get_translation(base);
-
return FALSE;
}
{
unsigned char dma;
unsigned char irq;
- unsigned int base = 0;
+ unsigned int base;
unsigned char id;
- unsigned char bus_type;
+ char bus_type;
unsigned short max_sg;
- int trans;
- struct Scsi_Host *shpnt = NULL;
+ unsigned char bios_translation;
+ const unsigned char *bios;
+ char *model;
+ char *firmware_rev;
+ struct Scsi_Host *shpnt;
+ size_t indx;
int count = 0;
- int indx;
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_DETECT)
buslogic_printk("buslogic_detect:\n");
#endif
tpnt->can_queue = BUSLOGIC_MAILBOXES;
for (indx = 0; indx < ARRAY_SIZE(bases); indx++)
- if (!check_region(bases[indx], 3)) {
+ if (!check_region(bases[indx], 4)) {
shpnt = scsi_register(tpnt, sizeof (struct hostdata));
base = bases[indx];
- if (test_port(base, shpnt))
+ model = HOSTDATA(shpnt)->model;
+ firmware_rev = HOSTDATA(shpnt)->firmware_rev;
+ if (buslogic_query(base, &bios_translation, &irq, &dma, &id,
+ &bus_type, &max_sg, &bios, model, firmware_rev))
goto unregister;
- /* Set the Bus on/off-times as not to ruin floppy performance. */
- {
+#if (BUSLOGIC_DEBUG & BD_DETECT)
+ buslogic_stat(base);
+#endif
+
+ if (setup_mailboxes(base, shpnt))
+ goto unregister;
+
+ /* Set the Bus on/off-times as not to ruin floppy performance.
+ CMD_BUSOFF_TIME is a noop for EISA boards (and possibly
+ others???). */
+ if (bus_type != 'E') {
/* The default ON/OFF times for BusLogic adapters is 7/4. */
static const unsigned char oncmd[] = { CMD_BUSON_TIME, 7 };
static const unsigned char offcmd[] = { CMD_BUSOFF_TIME, 5 };
INTR_RESET(base);
buslogic_out(base, oncmd, sizeof oncmd);
WAIT_UNTIL(INTERRUPT(base), CMDC);
- /* CMD_BUSOFF_TIME is a noop for EISA boards, but as there is
- no way to to differentiate EISA from VESA we send it
- unconditionally. */
INTR_RESET(base);
buslogic_out(base, offcmd, sizeof offcmd);
WAIT_UNTIL(INTERRUPT(base), CMDC);
INTR_RESET(base);
}
- if (buslogic_query(base, &trans))
- goto unregister;
-
- if (getconfig(base, &irq, &dma, &id, &bus_type, &max_sg))
- goto unregister;
-
-#if BUSLOGIC_DEBUG
- buslogic_stat(base);
-#endif
- /* Here is where we tell the men from the boys (i.e. an Adaptec
- will fail in setup_mailboxes, the men will not :-) */
- if (!setup_mailboxes(base, shpnt))
- goto unregister;
-
- printk("Configuring BusLogic %s HA at port 0x%03X, IRQ %u",
- (bus_type == 'A' ? "ISA"
- : (bus_type == 'E' ? "EISA/VESA" : "MCA")),
- base, irq);
+ buslogic_printk("Configuring %s HA at port 0x%03X, IRQ %u",
+ (bus_type == 'A' ? "ISA"
+ : (bus_type == 'E' ? "EISA"
+ : (bus_type == 'M' ? "MCA"
+ : (bus_type == 'P' ? "PCI"
+ : (bus_type == 'V' ? "VESA"
+ : (bus_type == 'X' ? "EISA/VESA"
+ : "Unknown")))))),
+ base, irq);
+ if (bios != NULL)
+ printk(", BIOS 0x%05X", (unsigned int)bios);
if (dma != 0)
printk(", DMA %u", dma);
printk(", ID %u\n", id);
+ buslogic_printk("Model Number: %s",
+ (model[0] ? model : "Unknown"));
+ if (model[0])
+ printk(" (revision %d)", model[6]);
+ printk("\n");
+ buslogic_printk("Firmware revision: %s\n", firmware_rev);
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_DETECT)
buslogic_stat(base);
#endif
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_DETECT)
buslogic_printk("buslogic_detect: enable interrupt channel %d\n",
irq);
#endif
}
if (dma) {
- if (request_dma(dma,"buslogic")) {
+ if (request_dma(dma, "buslogic")) {
buslogic_printk("Unable to allocate DMA channel for "
"BusLogic controller.\n");
free_irq(irq);
goto unregister;
}
- if (dma >= 5) {
- outb((dma - 4) | CASCADE, DMA_MODE_REG);
- outb(dma - 4, DMA_MASK_REG);
- }
+ /* The DMA-Controller. We need to fool with this because we
+ want to be able to use an ISA BusLogic without having to
+ have the BIOS enabled. */
+ set_dma_mode(dma, DMA_MODE_CASCADE);
+ enable_dma(dma);
}
host[irq - 9] = shpnt;
shpnt->this_id = id;
-#ifdef CONFIG_NO_BUGGY_BUSLOGIC
/* Only type 'A' (AT/ISA) bus adapters use unchecked DMA. */
shpnt->unchecked_isa_dma = (bus_type == 'A');
+#ifndef CONFIG_NO_BUGGY_BUSLOGIC
+ /* There is a hardware bug in the BT-445S prior to revision D.
+ When the BIOS is enabled and you have more than 16MB of memory,
+ the card mishandles memory transfers over 16MB which (if viewed
+ as a 24-bit address) overlap with the BIOS address space. For
+ example if you have the BIOS located at physical address
+ 0xDC000 and a DMA transfer from the card to RAM starts at
+ physical address 0x10DC000 then the transfer is messed up. To
+ be more precise every fourth byte of the transfer is messed up.
+ (This analysis courtesy of Tomas Hurka, author of the NeXTSTEP
+ BusLogic driver.) */
+
+ if (bus_type == 'V' /* 445 */
+ && firmware_rev[0] <= '3' /* S */
+ && bios != NULL) { /* BIOS enabled */
+#if 0
+ /* ??? Once LNZ's forbidden_addr stuff makes it into the higher
+ level scsi code, we can use this instead. */
+ /* Avoid addresses which "mirror" the BIOS for DMA. */
+ shpnt->forbidden_addr = bios;
+ shpnt->forbidden_size = 16 * 1024;
#else
- /* Bugs in the firmware of the 445S with >16M. This does not seem
- to affect Revision E boards with firmware 3.37. */
- shpnt->unchecked_isa_dma = 1;
+ /* Use double-buffering. */
+ shpnt->unchecked_isa_dma = TRUE;
#endif
+ }
+#endif
+ /* Have to keep cmd_per_lun at 1 for ISA machines otherwise lots
+ of memory gets sucked up for bounce buffers. */
+ /* ??? Unfortunately, cmd_per_lun is only in the
+ Scsi_Host_Template structure, not the Scsi_Host structure.
+ Therefore, this could cause high memory consumption if a system
+ has multiple BusLogic adapters which are a mix of ISA and
+ non-ISA. */
+ if (!shpnt->unchecked_isa_dma)
+ shpnt->hostt->cmd_per_lun = BUSLOGIC_NONISA_CMDLUN;
shpnt->sg_tablesize = max_sg;
if (shpnt->sg_tablesize > BUSLOGIC_MAX_SG)
shpnt->sg_tablesize = BUSLOGIC_MAX_SG;
- /* ??? If we can dynamically allocate the mailbox arrays, I'll
- probably bump up this number. */
- shpnt->hostt->can_queue = BUSLOGIC_MAILBOXES;
- /* No known way to determine BIOS base address, but we don't
- care since we don't use it anyway. */
- shpnt->base = NULL;
+ /* ??? shpnt->base should really be "const unsigned char *"... */
+ shpnt->base = (unsigned char *)bios;
shpnt->io_port = base;
shpnt->dma_channel = dma;
shpnt->irq = irq;
- HOSTDATA(shpnt)->bios_translation = trans;
- if (trans == BIOS_TRANSLATION_BIG)
+ HOSTDATA(shpnt)->bios_translation = bios_translation;
+ if (bios_translation == BIOS_TRANSLATION_BIG)
buslogic_printk("Using extended bios translation.\n");
HOSTDATA(shpnt)->last_mbi_used = 2 * BUSLOGIC_MAILBOXES - 1;
HOSTDATA(shpnt)->last_mbo_used = BUSLOGIC_MAILBOXES - 1;
= { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
size_t i;
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_DETECT)
buslogic_printk("*** READ CAPACITY ***\n");
#endif
for (i = 0; i < sizeof buf; i++)
i, *(int *)(buf + 4), *(int *)buf);
}
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_DETECT)
buslogic_printk("*** NOW RUNNING MY OWN TEST ***\n");
#endif
for (i = 0; i < 4; i++) {
}
#endif
- snarf_region(bases[indx], 3); /* Register the IO ports that
+ snarf_region(bases[indx], 4); /* Register the IO ports that
we use */
count++;
continue;
static const unsigned char buscmd[] = { CMD_START_SCSI };
unsigned int i;
-#if BUSLOGIC_DEBUG
+#if (BUSLOGIC_DEBUG & BD_RESET)
buslogic_printk("buslogic_reset\n");
#endif
#if 0
/* First locate the ccb for this command. */
for (i = 0; i < BUSLOGIC_MAILBOXES; i++)
if (HOSTDATA(scpnt->host)->sc[i] == scpnt) {
- HOSTDATA(scpnt->host)->ccbs[i].op = 0x81; /* ??? BUS DEVICE
- RESET */
+ HOSTDATA(scpnt->host)->ccbs[i].op = CCB_OP_BUS_RESET;
/* Now tell the BusLogic to flush all pending commands for this
target. */
sctmp->result = DID_RESET << 16;
if (sctmp->host_scribble)
scsi_free(sctmp->host_scribble, BUSLOGIC_SG_MALLOC);
- printk("Sending DID_RESET for target %d\n", scpnt->target);
+ buslogic_printk("Sending DID_RESET for target %d\n",
+ scpnt->target);
sctmp->scsi_done(scpnt);
HOSTDATA(scpnt->host)->sc[i] = NULL;
return SCSI_RESET_PUNT;
}
+/* ??? This is probably not correct for series "C" boards. I believe these
+ support separate mappings for each disk. We would need to issue a
+ CMD_READ_FW_LOCAL_RAM command to check for the particular drive being
+ queried. Note that series "C" boards can be differentiated by having
+ HOSTDATA(disk->device->host)->firmware_rev[0] >= '4'. */
int buslogic_biosparam(Disk *disk, int dev, int *ip)
{
- /* ??? This truncates. Should we round up to next MB? */
- unsigned int mb = disk->capacity >> 11;
+ unsigned int size = disk->capacity;
/* ip[0] == heads, ip[1] == sectors, ip[2] == cylinders */
if (HOSTDATA(disk->device->host)->bios_translation == BIOS_TRANSLATION_BIG
- && mb > 1024) {
- if (mb > 4096) {
+ && size >= 0x200000) { /* 1GB */
+ if (size >= 0x400000) { /* 2GB */
+#if 0 /* ??? Used in earlier kernels, but disagrees with BusLogic info. */
+ if (mb >= 0x800000) { /* 4GB */
+ ip[0] = 256;
+ ip[1] = 64;
+ } else {
+ ip[0] = 256;
+ ip[1] = 32;
+ }
+#else
ip[0] = 256;
ip[1] = 64;
- ip[2] = mb >> 3;
-/* if (ip[2] > 1024)
- ip[2] = 1024; */
- } else if (mb > 2048) {
- ip[0] = 256;
- ip[1] = 32;
- ip[2] = mb >> 2;
+#endif
} else {
ip[0] = 128;
ip[1] = 32;
- ip[2] = mb >> 1;
}
} else {
ip[0] = 64;
ip[1] = 32;
- ip[2] = mb;
-/* if (ip[2] > 1024)
- ip[2] = 1024; */
}
+ ip[2] = size / (ip[0] * ip[1]);
+/* if (ip[2] > 1024)
+ ip[2] = 1024; */
return 0;
}
int buslogic_biosparam(Disk *, int, int *);
#define BUSLOGIC_CMDLUN 1 /* Do not set this too high. It sucks
- up lots of memory on machines with > 16Mb
- because of the huge number of bounce
- buffers that need to be allocated.
+ up lots of memory on ISA machines
+ with > 16MB because of the huge number of
+ bounce buffers that need to be allocated.
For boards that use non-ISA bus, we can
bump this in the board detect routine.
- 10/8/94 ERY */
-
+ 10/8/94 ERY */
-#define BUSLOGIC { NULL, \
+#define BUSLOGIC { NULL, \
"BusLogic", \
buslogic_detect, \
NULL, \
#define BD_ABORT 0x0001
#define BD_COMMAND 0x0002
#define BD_DETECT 0x0004
-#define BD_INTERRUPT 0x0008
-#define BD_RESET 0x0010
+#define BD_ERRORS 0x0008
+#define BD_INTERRUPT 0x0010
+#define BD_IO 0x0020
+#define BD_RESET 0x0040
+#define BD_UNDOCUMENTED 0x0080
/* I/O Port interface */
/* READ */
#define HARDY 0x10 /* Host Adapter Ready */
#define CPRBSY 0x08 /* Command/Parameter Register Busy */
#define DIRRDY 0x04 /* Data In Register Ready */
+ /* 0x02 is reserved */
#define CMDINV 0x01 /* Command Invalid */
-#define STATMASK 0xFD /* 0x02 is reserved */
#define DATA_IN(base) (STATUS(base) + 1)
#define INTERRUPT(base) (STATUS(base) + 2)
#define INTV 0x80 /* Interrupt Valid */
+ /* 0x70 are reserved */
#define RSTS 0x08 /* SCSI Reset State */
#define CMDC 0x04 /* Command Complete */
#define MBOR 0x02 /* Mailbox Out Ready */
#define IMBL 0x01 /* Incoming Mailbox Loaded */
-#define INTRMASK 0x8F /* 0x70 are reserved */
+#define INTRMASK 0x8F
+
+/* This undocumented port returns a bitmask indicating geometry translation. */
+#define GEOMETRY(base) (STATUS(base) + 3)
+#define GEO_GT_1GB 0x80 /* > 1GB under DOS geometry mapping */
+ /* 0x70 are unknown */
+#define GEO_XLATION_S_D1 0x0C /* Disk 1 geometry ("S" models only) */
+#define GEO_XLATION_S_D0 0x03 /* Disk 0 geometry ("S" models only) */
+
/* WRITE */
#define CONTROL(base) STATUS(base)
#define RSOFT 0x40 /* Soft Reset */
#define RINT 0x20 /* Interrupt Reset */
#define RSBUS 0x10 /* SCSI Bus Reset */
+ /* 0x0F are reserved */
#define COMMAND_PARAMETER(base) (STATUS(base) + 1)
#define CMD_TSTCMDCINT 0x00 /* Test CMDC Interrupt */
#define CMD_HA_DIAG 0x20 /* Host Adapter Diagnostic */
#define CMD_HA_OPTIONS 0x21 /* Host Adapter Options */
#define CMD_INITEXTMB 0x81 /* Initialize Extended Mailbox */
+#define CMD_VER_NO_LAST 0x84 /* Version Number Last Byte (undocumented) */
+#define CMD_VER_NO_LETTER 0x85 /* Version Number One Letter (undocumented) */
+#define CMD_RET_MODEL_NO 0x8B /* Return Model Number (undocumented) */
#define CMD_INQEXTSETUP 0x8D /* Inquire Extended Set-up Information */
+#define CMD_ROUND_ROBIN 0x8F /* Enable strict vs. half-assed round-robin
+ mailbox filling (undocumented) */
+#define CMD_READ_FW_LCL_RAM 0x91/* Read Firmware Local RAM (undocumented) */
#define CMD_WRITE_INQ_BUF 0x9A /* Write Inquiry Data Buffer
(Target Mode Only) */
#define CMD_READ_INQ_BUF 0x9B /* Read Inquiry Data Buffer
return j;
}
-const char *eata_info (void) {
- return driver_name;
-}
-
static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
unsigned int k;
struct scatterlist * sgpnt;
cpp->data_len = htonl(SCpnt->request_bufflen);
}
- memcpy(cpp->cdb, SCpnt->cmnd, COMMAND_SIZE(*SCpnt->cmnd));
+ memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
/* Send control packet to the board */
if (do_dma(sh[j]->io_port, (unsigned int) cpp, SEND_CP_DMA)) {
int eata_detect(Scsi_Host_Template *);
int eata_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int eata_abort(Scsi_Cmnd *);
-const char *eata_info(void);
int eata_reset(Scsi_Cmnd *);
int eata_bios_param(Disk *, int, int*);
#define EATA { NULL, /* Ptr for modules */ \
+ NULL, /* usage count for modules */ \
"EISA EATA 2.0A rev. " EATA_VERSION " by " \
- "Dario_Ballabio@milano.europe.dg.com.",\
+ "Dario_Ballabio@milano.europe.dg.com.", \
eata_detect, \
NULL, /* Release */ \
- eata_info, \
+ NULL, \
NULL, \
eata_queuecommand, \
eata_abort, \
#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
-static void print_banner( void )
+static void print_banner( struct Scsi_Host * shpnt )
{
- printk( "%s", fdomain_16x0_info() );
+ printk( "%s", fdomain_16x0_info(shpnt) );
printk( "Future Domain: BIOS version %d.%d, %s\n",
bios_major, bios_minor,
chip == tmc1800 ? "TMC-1800"
return 0; /* Cannot find valid set of ports */
}
- print_banner();
+ print_banner(NULL);
SCSI_Mode_Cntl_port = port_base + SCSI_Mode_Cntl;
FIFO_Data_Count_port = port_base + FIFO_Data_Count;
return 1;
}
-const char *fdomain_16x0_info(void)
+const char *fdomain_16x0_info(struct Scsi_Host * shpnt)
{
static char buffer[80];
char *pt;
if (chip == tmc1800
&& !current_SC->SCp.have_data_in
&& (current_SC->SCp.sent_command
- >= COMMAND_SIZE( current_SC->cmnd[ 0 ] ))) {
+ >= current_SC->cmd_len)) {
/* We have to get the FIFO direction
correct, so I've made a table based
on the SCSI Standard of which commands
unsigned int irr;
unsigned int isr;
- print_banner();
+ print_banner(SCpnt->host);
switch (SCpnt->SCp.phase) {
case in_arbitration: printk( "arbitration " ); break;
case in_selection: printk( "selection " ); break;
int fdomain_16x0_detect( Scsi_Host_Template * );
int fdomain_16x0_command( Scsi_Cmnd * );
int fdomain_16x0_abort( Scsi_Cmnd * );
-const char *fdomain_16x0_info( void );
+const char *fdomain_16x0_info( struct Scsi_Host * );
int fdomain_16x0_reset( Scsi_Cmnd * );
int fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
int fdomain_16x0_biosparam( Disk *, int, int * );
-#define FDOMAIN_16X0 { NULL, \
- "Future Domain TMC-16x0", \
+#define FDOMAIN_16X0 { NULL, NULL, \
+ NULL, \
fdomain_16x0_detect, \
NULL, \
fdomain_16x0_info, \
#ifndef ASM
int generic_NCR5380_abort(Scsi_Cmnd *);
int generic_NCR5380_detect(Scsi_Host_Template *);
-const char *generic_NCR5380_info(void);
int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int generic_NCR5380_reset(Scsi_Cmnd *);
#ifdef HOSTS_C
-#define GENERIC_NCR5380 {NULL, "Trantor T128/T128F/T228", \
- generic_NCR5380_detect, NULL, generic_NCR5380_info, NULL, \
+#define GENERIC_NCR5380 {NULL, NULL, "Trantor T128/T128F/T228", \
+ generic_NCR5380_detect, NULL, NULL, NULL, \
generic_NCR5380_queue_command, generic_NCR5380_abort, \
generic_NCR5380_reset, NULL, \
NULL, /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
struct Scsi_Host * retval, *shpnt;
retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j);
retval->host_busy = 0;
+ retval->block = NULL;
if(j > 0xffff) panic("Too many extra bytes requested\n");
retval->extra_bytes = j;
retval->loaded_as_module = scsi_loadable_module_flag;
/* Used with loadable modules so we can construct a linked list. */
struct SHT * next;
+ /* Used with loadable modules so that we know when it is safe to unload */
+ int * usage_count;
+
/*
The name pointer is a pointer to the name of the SCSI
device detected.
int (* detect)(struct SHT *);
- /* Used with loadable modules to unload the host structures */
+ /* Used with loadable modules to unload the host structures. Note:
+ there is a default action built into the modules code which may
+ be sufficient for most host adapters. Thus you may not have to supply
+ this at all. */
int (*release)(struct Scsi_Host *);
/*
The info function will return whatever useful
- information the developer sees fit.
+ information the developer sees fit. If not provided, then
+ the name field will be used instead.
*/
- const char *(* info)(void);
+ const char *(* info)(struct Scsi_Host *);
/*
The command function takes a target, a command (this is a SCSI
be two Scsi_Host entries, but only 1 Scsi_Host_Template entries.
*/
+#define SCSI_HOST_BLOCK 0x800
+
struct Scsi_Host
{
struct Scsi_Host * next;
Scsi_Cmnd *host_queue;
Scsi_Host_Template * hostt;
+ /* Pointer to a circularly linked list - this indicates the hosts
+ that should be locked out of performing I/O while we have an active
+ command on this host. */
+ struct Scsi_Host * block;
+
/* These parameters should be set by the detect routine */
unsigned char *base;
short unsigned int io_port;
+ unsigned char n_io_port;
unsigned char irq;
unsigned char dma_channel;
/*
} /* end while intrpt active */
}
-static int in2000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+int in2000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
{
unchar direction;
unchar *cmd = (unchar *) SCpnt->cmnd;
++internal_done_flag;
}
-static int in2000_command(Scsi_Cmnd * SCpnt)
+int in2000_command(Scsi_Cmnd * SCpnt)
{
in2000_queuecommand(SCpnt, internal_done);
return internal_done_errcode;
}
-static int in2000_detect(Scsi_Host_Template * tpnt)
+int in2000_detect(Scsi_Host_Template * tpnt)
{
/* Order chosen to reduce conflicts with some multi-port serial boards */
int base_tab[] = { 0x220,0x200,0x110,0x100 };
return 1;
}
-static int in2000_abort(Scsi_Cmnd * SCpnt)
+int in2000_abort(Scsi_Cmnd * SCpnt)
{
DEB(printk("in2000_abort\n"));
/*
while (jiffies < time) ;
}
-static int in2000_reset(Scsi_Cmnd * SCpnt)
+int in2000_reset(Scsi_Cmnd * SCpnt)
{
DEB(printk("in2000_reset called\n"));
/*
#endif
}
-static int in2000_biosparam(Disk * disk, int dev, int* iinfo)
+int in2000_biosparam(Disk * disk, int dev, int* iinfo)
{
int size = disk->capacity;
DEB(printk("in2000_biosparam\n"));
#define MAX_SENSE 14
#define MAX_STATUS 32
-static int in2000_detect(Scsi_Host_Template *);
-static int in2000_command(Scsi_Cmnd *);
-static int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-static int in2000_abort(Scsi_Cmnd *);
-static int in2000_reset(Scsi_Cmnd *);
-static int in2000_biosparam(Disk *, int, int*);
+int in2000_detect(Scsi_Host_Template *);
+int in2000_command(Scsi_Cmnd *);
+int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int in2000_abort(Scsi_Cmnd *);
+int in2000_reset(Scsi_Cmnd *);
+int in2000_biosparam(Disk *, int, int*);
#ifndef NULL
/* next may be "SG_NONE" or "SG_ALL" or nr. of (1k) blocks per R/W Cmd. */
#define IN2000_SG SG_ALL
-#define IN2000 {NULL, "Always IN2000", in2000_detect, NULL, \
+#define IN2000 {NULL, NULL, "Always IN2000", in2000_detect, NULL, \
NULL, in2000_command, \
in2000_queuecommand, \
in2000_abort, \
return 0;
}
-/*
- * Function : const char *pas16_info(void)
- *
- * Purpose : provide further information about this driver.
- *
- * Returns : an empty string.
- */
-
-const char *pas16_info (void) {
- static const char string[]="";
- return string;
-}
-
#include "NCR5380.c"
int pas16_abort(Scsi_Cmnd *);
int pas16_biosparam(Disk *, int, int*);
int pas16_detect(Scsi_Host_Template *);
-const char *pas16_info(void);
int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int pas16_reset(Scsi_Cmnd *);
#ifdef HOSTS_C
-#define MV_PAS16 {NULL, "Pro Audio Spectrum-16 SCSI", \
- pas16_detect, NULL, pas16_info, \
+#define MV_PAS16 {NULL, NULL, "Pro Audio Spectrum-16 SCSI", \
+ pas16_detect, NULL, NULL, \
NULL, pas16_queue_command, pas16_abort, pas16_reset, NULL, \
pas16_biosparam, \
/* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
outb(0x99, qbase + 5); /* timer */
outb(cmd->target, qbase + 4);
- for (i = 0; i < COMMAND_SIZE(cmd->cmnd[0]); i++)
+ for (i = 0; i < cmd->cmd_len; i++)
outb(cmd->cmnd[i], qbase + 2);
qlcmd = cmd;
outb(0x41, qbase + 3); /* select and send command */
/*----------------------------------------------------------------*/
/* return info string */
-const char *qlogic_info()
+const char *qlogic_info(struct Scsi_Host * host)
{
return qinfo;
}
#define _QLOGIC_H
int qlogic_detect(Scsi_Host_Template * );
-const char * qlogic_info(void);
+const char * qlogic_info(struct Scsi_Host *);
int qlogic_command(Scsi_Cmnd *);
int qlogic_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
int qlogic_abort(Scsi_Cmnd *);
#endif
#define QLOGIC { \
+ NULL, \
NULL, \
NULL, \
qlogic_detect, \
SCmd.target = dev;
SCmd.lun = lun;
+ SCmd.request.sem = NULL; /* Used for mutex if loading devices after boot */
SCmd.request.dev = 0xffff; /* Mark not busy */
SCmd.use_sg = 0;
+ SCmd.cmd_len = 0;
SCmd.old_use_sg = 0;
SCmd.transfersize = 0;
SCmd.underflow = 0;
scsi_cmd[5] = 0;
SCmd.request.dev = 0xffff; /* Mark not busy */
+ SCmd.cmd_len = 0;
scsi_do_cmd (&SCmd,
(void *) scsi_cmd, (void *)
scsi_cmd[5] = 0;
SCmd.request.dev = 0xffff; /* Mark not busy */
+ SCmd.cmd_len = 0;
scsi_do_cmd (&SCmd,
(void *) scsi_cmd, (void *)
{
case NORMAL_TIMEOUT:
if (!in_scan_scsis) {
- printk("scsi : aborting command due to timeout : pid %lu, scsi%d, id %d, lun %d ",
- SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->target, (int)
- SCpnt->lun);
- print_command (SCpnt->cmnd);
#ifdef DEBUG_TIMEOUT
scsi_dump_status();
#endif
struct buffer_head * bh, *bhp;
if (!device)
- panic ("No device passed to allocate_device().\n");
+ panic ("No device passed to request_queueable().\n");
if (req && req->dev <= 0)
- panic("Invalid device in allocate_device");
+ panic("Invalid device in request_queueable");
SCpnt = device->host->host_queue;
while(SCpnt){
SCpnt->old_use_sg = 0;
SCpnt->transfersize = 0;
SCpnt->underflow = 0;
+ SCpnt->cmd_len = 0;
return SCpnt;
}
SCpnt->use_sg = 0; /* Reset the scatter-gather flag */
SCpnt->old_use_sg = 0;
SCpnt->transfersize = 0; /* No default transfer size */
+ SCpnt->cmd_len = 0;
SCpnt->underflow = 0; /* Do not flag underflow conditions */
return SCpnt;
}
SCpnt->request_buffer = &SCpnt->sense_buffer;
SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
SCpnt->use_sg = 0;
+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
internal_cmnd (SCpnt);
SCpnt->use_sg = SCpnt->old_use_sg;
+ SCpnt->cmd_len = SCpnt->old_cmd_len;
}
(host->host_busy >= host->can_queue));
} else {
host->host_busy++;
+ if (host->block) {
+ struct Scsi_Host * block;
+ for(block = host->block; block != host; block = block->block)
+ block->host_busy |= ~SCSI_HOST_BLOCK;
+ }
sti();
break;
};
SCpnt->request_buffer = buffer;
SCpnt->request_bufflen = bufflen;
SCpnt->old_use_sg = SCpnt->use_sg;
+ if (SCpnt->cmd_len == 0)
+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+ SCpnt->old_cmd_len = SCpnt->cmd_len;
/* Start the timer ticking. */
SCpnt->request_buffer = SCpnt->buffer;
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->use_sg = SCpnt->old_use_sg;
+ SCpnt->cmd_len = SCpnt->old_cmd_len;
internal_cmnd (SCpnt);
};
break;
}
if (status == FINISHED)
- {
- #ifdef DEBUG
- printk("Calling done function - at address %08x\n", SCpnt->done);
- #endif
+ {
+#ifdef DEBUG
+ printk("Calling done function - at address %08x\n", SCpnt->done);
+#endif
host->host_busy--; /* Indicate that we are free */
+ if (host->host_busy == 0 && host->block) {
+ struct Scsi_Host * block;
+ /*
+ * Now remove the locks for all of the related hosts.
+ */
+ for(block = host->block; block != host; block = block->block)
+ block->host_busy &= ~SCSI_HOST_BLOCK;
+ /*
+ * Now wake them up. We do this in two separate stages to prevent
+ * race conditions.
+ */
+ for(block = host->block; block != host; block = block->block)
+ wake_up(&block->host_wait);
+ }
wake_up(&host->host_wait);
SCpnt->result = result | ((exit & 0xff) << 24);
SCpnt->use_sg = SCpnt->old_use_sg;
+ SCpnt->cmd_len = SCpnt->old_cmd_len;
SCpnt->done (SCpnt);
}
update_timeout(SCpnt, oldto);
return 0;
}
+ printk("scsi : aborting command due to timeout : pid %lu, scsi%d, id %d, lun %d ",
+ SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->target, (int)
+ SCpnt->lun);
+ print_command (SCpnt->cmnd);
SCpnt->abort_reason = why;
switch(host->hostt->abort(SCpnt)) {
/* We do not know how to abort. Try waiting another
SCpnt->request.dev = -1; /* Mark not busy */
SCpnt->use_sg = 0;
SCpnt->old_use_sg = 0;
+ SCpnt->old_cmd_len = 0;
+ SCpnt->timeout = 0;
SCpnt->underflow = 0;
SCpnt->transfersize = 0;
SCpnt->host_scribble = NULL;
struct Scsi_Host * host;
Scsi_Device * device;
unsigned char target, lun;
+ unsigned char cmd_len;
+ unsigned char old_cmd_len;
struct scsi_cmnd *next, *prev;
/* These elements define the operation we are about to perform */
int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int scsi_debug_abort(Scsi_Cmnd *);
int scsi_debug_biosparam(Disk *, int, int[]);
-const char *scsi_debug_info(void);
int scsi_debug_reset(Scsi_Cmnd *);
#ifndef NULL
#define SCSI_DEBUG_MAILBOXES 8
-#define SCSI_DEBUG {NULL, "SCSI DEBUG", scsi_debug_detect, NULL, \
- scsi_debug_info, scsi_debug_command, \
+#define SCSI_DEBUG {NULL, NULL, "SCSI DEBUG", scsi_debug_detect, NULL, \
+ NULL, scsi_debug_command, \
scsi_debug_queuecommand, \
scsi_debug_abort, \
scsi_debug_reset, \
if ((temp = host->hostt->present) && buffer) {
len = get_fs_long ((unsigned long *) buffer);
- string = host->hostt->info();
- slen = strlen(string);
- if (len > slen)
- len = slen + 1;
- verify_area(VERIFY_WRITE, buffer, len);
- memcpy_tofs (buffer, string, len);
+ if(host->hostt->info)
+ string = host->hostt->info(host);
+ else
+ string = host->hostt->name;
+ if(string) {
+ slen = strlen(string);
+ if (len > slen)
+ len = slen + 1;
+ verify_area(VERIFY_WRITE, buffer, len);
+ memcpy_tofs (buffer, string, len);
+ }
}
return temp;
}
cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
memset ((void *) &cmd[2], 0, 8);
SCpnt->request.dev = 0xffff; /* Mark as really busy again */
+ SCpnt->cmd_len = 0;
SCpnt->sense_buffer[0] = 0;
SCpnt->sense_buffer[2] = 0;
memset ((void *) &cmd[2], 0, 8);
cmd[4] = 1; /* Start spin cycle */
SCpnt->request.dev = 0xffff; /* Mark as really busy again */
+ SCpnt->cmd_len = 0;
SCpnt->sense_buffer[0] = 0;
SCpnt->sense_buffer[2] = 0;
memset ((void *) &cmd[2], 0, 8);
memset ((void *) buffer, 0, 8);
SCpnt->request.dev = 0xffff; /* Mark as really busy again */
+ SCpnt->cmd_len = 0;
SCpnt->sense_buffer[0] = 0;
SCpnt->sense_buffer[2] = 0;
unsigned char sector_bit_shift; /* power of 2 sectors per FS block */
unsigned ten:1; /* support ten byte read / write */
unsigned remap:1; /* support remapping */
+ unsigned has_part_table:1; /* has partition table */
} Scsi_Disk;
extern Scsi_Disk * rscsi_disks;
}
}
-const char *seagate_st0x_info(void) {
+const char *seagate_st0x_info(struct Scsi_Host * shpnt) {
static char buffer[256];
sprintf(buffer, "scsi%d : %s at irq %d address %p options :"
#ifdef ARBITRATE
* Set linked command bit in control field of SCSI command.
*/
- current_cmnd[COMMAND_SIZE(current_cmnd[0])] |= 0x01;
+ current_cmnd[SCpnt->cmd_len] |= 0x01;
if (linked_connected) {
#if (DEBUG & DEBUG_LINKED)
printk("scsi%d : using linked commands, current I_T_L nexus is ",
int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int seagate_st0x_abort(Scsi_Cmnd *);
-const char *seagate_st0x_info(void);
+const char *seagate_st0x_info(struct Scsi_Host *);
int seagate_st0x_reset(Scsi_Cmnd *);
#ifndef NULL
int seagate_st0x_biosparam(Disk *, int, int*);
-#define SEAGATE_ST0X {NULL, "Seagate ST-01/ST-02", seagate_st0x_detect, \
+#define SEAGATE_ST0X {NULL, NULL, NULL, seagate_st0x_detect, \
NULL, \
seagate_st0x_info, seagate_st0x_command, \
seagate_st0x_queue_command, seagate_st0x_abort, \
int dev=MINOR(inode->i_rdev);
Scsi_Cmnd *SCpnt;
int bsize,size,amt,i;
+ unsigned char opcode;
unsigned char cmnd[MAX_COMMAND_SIZE];
struct scsi_generic *device=&scsi_generics[dev];
SCpnt->request.dev=dev;
SCpnt->sense_buffer[0]=0;
size=COMMAND_SIZE(get_fs_byte(buf));
+ size=COMMAND_SIZE(opcode);
+ if (opcode >= 0xc0 && device->header.twelve_byte) size = 12;
+ SCpnt->cmd_len = size;
memcpy_fromfs(cmnd,buf,size);
buf+=size;
memcpy_fromfs(device->buff,buf,device->header.pack_len-size-sizeof(struct sg_header));
int reply_len; /* maximum length <4096 of expected reply */
int pack_id; /* id number of packet */
int result; /* 0==ok, otherwise refer to errno codes */
- int flags; /* for future use */
+ unsigned int twelve_byte:1; /* Force 12 byte command length for group 6 & 7 commands */
+ unsigned int other_flags:31; /* for future use */
unsigned char sense_buffer[16]; /* used only by reads */
/* command follows then data for command */
};
sec = (unsigned long)buffer[16]/16*10 + (unsigned long)buffer[16]%16;
frame = (unsigned long)buffer[17]/16*10 + (unsigned long)buffer[17]%16;
sector = min*60*75 + sec*75 + frame;
- sector-=CD_BLOCK_OFFSET;
if (sector) {
- printk("sr_photocd: multisession PhotoCD detected\n"); }}
+ sector -= CD_BLOCK_OFFSET;
+ printk("sr_photocd: multisession PhotoCD detected\n");
+ }
+ }
scsi_free(buffer,512);
SCpnt->request.dev = -1;
break;
sec = (unsigned long)buffer[2]/16*10 + (unsigned long)buffer[2]%16;
frame = (unsigned long)buffer[3]/16*10 + (unsigned long)buffer[3]%16;
sector = min*60*75 + sec*75 + frame;
- sector-=CD_BLOCK_OFFSET;
if (sector) {
- printk("sr_photocd: multisession PhotoCD detected: %lu\n",sector); }}
+ sector -= CD_BLOCK_OFFSET;
+ printk("sr_photocd: multisession PhotoCD detected: %lu\n",sector);
+ }
+ }
scsi_free(buffer,512);
SCpnt->request.dev = -1;
break;
static void get_sectorsize(int i){
unsigned char cmd[10];
- unsigned char buffer[513];
+ unsigned char *buffer;
int the_result, retries;
Scsi_Cmnd * SCpnt;
+ buffer = (unsigned char *) scsi_malloc(512);
SCpnt = allocate_device(NULL, scsi_CDs[i].device, 1);
retries = 3;
cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
memset ((void *) &cmd[2], 0, 8);
SCpnt->request.dev = 0xffff; /* Mark as really busy */
+ SCpnt->cmd_len = 0;
memset(buffer, 0, 8);
scsi_CDs[i].capacity *= 4;
scsi_CDs[i].needs_sector_size = 0;
};
+ scsi_free(buffer, 512);
}
static void sr_init()
return 0;
}
-/*
- * Function : const char *t128_info(void)
- *
- * Purpose : provide further information about this driver.
- *
- * Returns : an empty string.
- */
-
-const char *t128_info (void) {
- static const char string[]="";
- return string;
-}
-
#include "NCR5380.c"
int t128_abort(Scsi_Cmnd *);
int t128_biosparam(Disk *, int, int*);
int t128_detect(Scsi_Host_Template *);
-const char *t128_info(void);
int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int t128_reset(Scsi_Cmnd *);
#ifdef HOSTS_C
-#define TRANTOR_T128 {NULL, "Trantor T128/T128F/T228", t128_detect, NULL, \
- t128_info, \
+#define TRANTOR_T128 {NULL, NULL, "Trantor T128/T128F/T228", t128_detect, NULL, \
+ NULL, \
NULL, t128_queue_command, t128_abort, t128_reset, NULL, \
t128_biosparam, \
/* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
return j;
}
-const char *u14_34f_info(void) {
- return driver_name;
-}
-
static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
unsigned int k, data_len = 0;
struct scatterlist * sgpnt;
cpp->data_len = SCpnt->request_bufflen;
}
- cpp->scsi_cdbs_len = COMMAND_SIZE(*(unsigned char *)SCpnt->cmnd);
+ cpp->scsi_cdbs_len = SCpnt->cmd_len;
memcpy(cpp->scsi_cdbs, SCpnt->cmnd, cpp->scsi_cdbs_len);
if (wait_on_busy(sh[j]->io_port)) {
#define _U14_34F_H
int u14_34f_detect(Scsi_Host_Template *);
-const char *u14_34f_info(void);
int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int u14_34f_abort(Scsi_Cmnd *);
int u14_34f_reset(Scsi_Cmnd *);
#define U14_34F_VERSION "1.10.01"
#define ULTRASTOR_14_34F { \
+ NULL, \
NULL, \
"UltraStor 14F/34F rev. " U14_34F_VERSION " by " \
"Dario_Ballabio@milano.europe.dg.com.",\
u14_34f_detect, \
NULL, \
- u14_34f_info, \
+ NULL, \
NULL, \
u14_34f_queuecommand, \
u14_34f_abort, \
return ultrastor_14f_detect(tpnt) || ultrastor_24f_detect(tpnt);
}
-const char *ultrastor_info(void)
+const char *ultrastor_info(struct Scsi_Host * shpnt)
{
static char buf[64];
my_mscp->command_link = 0; /*???*/
my_mscp->scsi_command_link_id = 0; /*???*/
my_mscp->length_of_sense_byte = sizeof SCpnt->sense_buffer;
- my_mscp->length_of_scsi_cdbs = COMMAND_SIZE(*(unsigned char *)SCpnt->cmnd);
+ my_mscp->length_of_scsi_cdbs = SCpnt->cmd_len;
memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs);
my_mscp->adapter_status = 0;
my_mscp->target_status = 0;
#define _ULTRASTOR_H
int ultrastor_detect(Scsi_Host_Template *);
-const char *ultrastor_info(void);
+const char *ultrastor_info(struct Scsi_Host * shpnt);
int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int ultrastor_abort(Scsi_Cmnd *);
int ultrastor_reset(Scsi_Cmnd *);
#define ULTRASTOR_24F_PORT 0xC80
-#define ULTRASTOR_14F { NULL, /* Ptr for modules*/ \
- "UltraStor 14F/24F/34F", \
+#define ULTRASTOR_14F { NULL, NULL, /* Ptr for modules*/ \
+ NULL, \
ultrastor_detect, \
NULL, /* Release */ \
ultrastor_info, \
register short cdblen;
Adapter *host = (Adapter *) SCpnt->host->hostdata;
- cdblen = COMMAND_SIZE(cdb[0]);
+ cdblen = SCpnt->cmd_len;
idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);
SCpnt->scsi_done = done;
SCpnt->SCp.phase = 1;
}
-/*
- * The info routine in the WD7000 structure isn't per-adapter, so it can't
- * really return any useful information about an adapter. Because of this,
- * I'm no longer using it to return rev. level.
- */
-const char *wd7000_info(void)
-{
- static char info[] = "Western Digital WD-7000";
- return info;
-}
-
-
/*
* This was borrowed directly from aha1542.c, but my disks are organized
* this way, so I think it will work OK. Someone who is ambitious can
int wd7000_command(Scsi_Cmnd *);
int wd7000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int wd7000_abort(Scsi_Cmnd *);
-const char *wd7000_info(void);
int wd7000_reset(Scsi_Cmnd *);
int wd7000_biosparam(Disk *, int, int*);
#define WD7000_Q 16
#define WD7000_SG 16
-#define WD7000 { NULL, \
+#define WD7000 { NULL, NULL, \
"Western Digital WD-7000", \
wd7000_detect, \
NULL, \
- wd7000_info, \
+ NULL, \
wd7000_command, \
wd7000_queuecommand, \
wd7000_abort, \
if (ret_val) return -EDEADLOCK;
}
dlock_wait = dlock_wait->next;
- } while (dlock_wait != fl->fl_wait);
+ } while (dlock_wait != NULL);
}
return 0;
}
* make sure SET_PROCTITLE works. Also removed
* bad '!' which forced address recalculation for
* EVERY character on the current page.
- * <middelin@calvin.iaf.nl>
+ * <middelin@polyware.iaf.nl>
*/
#include <linux/types.h>
int count)
{
int ret;
+ int old_fs = get_fs();
set_fs (KERNEL_DS);
ret = msdos_readdir(inode,filp,dirent,count);
- set_fs (USER_DS);
+ set_fs (old_fs);
return ret;
}
/*
char *buf,
int count)
{
- int ret;
+ int ret;
+ int old_fs = get_fs();
set_fs (KERNEL_DS);
ret = msdos_file_read(inode,filp,buf,count);
- set_fs (USER_DS);
+ set_fs (old_fs);
return ret;
}
/*
int count)
{
int ret;
+ int old_fs = get_fs();
set_fs (KERNEL_DS);
ret = msdos_file_write(inode,filp,buf,count);
- set_fs (USER_DS);
+ set_fs (old_fs);
return ret;
}
return ret;
}
-#define CHUNK_SIZE (16*UMSDOS_REC_SIZE)
+#define CHUNK_SIZE (8*UMSDOS_REC_SIZE)
struct find_buffer{
char buffer[CHUNK_SIZE];
int pos; /* read offset in buffer */
#define MAX_DMA_CHANNELS 8
+/* The maximum address that we can perform a DMA transfer to on this platform */
+#define MAX_DMA_ADDRESS 0xffffff
+
/* 8237 DMA controllers */
#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */
#ifndef _LINUX_INET_H
#define _LINUX_INET_H
-#ifdef __i386__
+#if defined(__i386__)
#define NET16(x) ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00))
-#endif
-#ifdef __mc680x0__
+#elif defined(__mc68000__)
#define NET16(x) (x)
+#elif defined(__alpha__)
+#define NET16(x) ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00))
+#else
+#error change this to match your machine
#endif
#ifdef __KERNEL__
/*
* Call check_region() before probing for your hardware.
* Once you have found you hardware, register it with snarf_region().
+ * If you unload the driver, use release_region to free ports.
*/
extern void reserve_setup(char *str, int *ints);
extern int check_region(unsigned int from, unsigned int extent);
extern void snarf_region(unsigned int from, unsigned int extent);
+extern void release_region(unsigned int from, unsigned int extent);
#define HAVE_AUTOIRQ
#if defined(__i386__)
u8 flags:4,
overflow:4;
-#elif defined(__mc680x0__)
+#elif defined(__mc68000__)
u8 overflow:4,
flags:4;
#elif defined(__alpha__)
#if defined(__i386__)
u8 ihl:4,
version:4;
-#elif defined (__mc680x0__)
+#elif defined (__mc68000__)
u8 version:4,
ihl:4;
#elif defined (__alpha__)
#define GFP_NOBUFFER 0x04
#define GFP_NFS 0x05
+/* Flag - indicates that the buffer will be suitable for DMA. Ignored on some
+ platforms, used as appropriate on others */
+
+#define GFP_DMA 0x80
+
/*
* vm_ops not present page codes for shared memory.
*
ack:1,
urg:1,
res2:2;
-#elif defined(__mc680x0__)
+#elif defined(__mc68000__)
u16 res2:2,
urg:1,
ack:1,
extern void pas16_setup(char *str, int *ints);
extern void generic_NCR5380_setup(char *str, int *intr);
extern void aha152x_setup(char *str, int *ints);
+extern void aha1542_setup(char *str, int *ints);
extern void aha274x_setup(char *str, int *ints);
extern void scsi_luns_setup(char *str, int *ints);
extern void sound_setup(char *str, int *ints);
#ifdef CONFIG_SCSI_AHA152X
{ "aha152x=", aha152x_setup},
#endif
+#ifdef CONFIG_SCSI_AHA1542
+ { "aha1542=", aha1542_setup},
+#endif
#ifdef CONFIG_SCSI_AHA274X
{ "aha274x=", aha274x_setup},
#endif
return;
}
+void release_region(unsigned int from, unsigned int num)
+{
+ if (from > IO_BITMAP_SIZE*32)
+ return;
+ if (from + num > IO_BITMAP_SIZE*32)
+ num = IO_BITMAP_SIZE*32 - from;
+ set_bitmap(ioport_registrar, from, num, 0);
+ return;
+}
+
int check_region(unsigned int from, unsigned int num)
{
if (from > IO_BITMAP_SIZE*32)
-3c509.o de600.o de620.o 3c501.o plip.o 8390.o
+3c509.o de600.o de620.o 3c501.o eexpress.o plip.o 8390.o
* Fixes:
* Alan Cox : UDP sockets show the rxqueue/txqueue
* using hint flag for the netinfo.
- * Pauline Middelink : Pidentd support
+ * Pauline Middelink : identd support
* Alan Cox : Make /proc safer.
* Erik Schoenfelder : /proc/net/snmp
* Alan Cox : Handle dead sockets properly.
* Alan Cox : Added RCVBUF,SNDBUF size setting. It suddenly occurred to me how easy it was so...
* Rick Sladkey : Relaxed UDP rules for matching packets.
* C.E.Hawkins : IFF_PROMISC/SIOCGHWADDR support
- * Pauline Middelink : Pidentd support
+ * Pauline Middelink : identd support
* Alan Cox : Fixed connect() taking signals I think.
* Alan Cox : SO_LINGER supported
* Alan Cox : Error reporting fixes