Commit a89a2558 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.3.41

parent c6545c79
VERSION = 1
PATCHLEVEL = 3
SUBLEVEL = 40
SUBLEVEL = 41
ARCH = i386
......@@ -323,5 +323,5 @@ include Rules.make
.hdepend: dummy
rm -f $@
$(AWK) -f scripts/depend.awk `find $(HPATH) -name \*.h -print` > .$@
$(AWK) -f scripts/depend.awk `find $(HPATH) -name \*.h ! -name modversions.h -print` > .$@
mv .$@ $@
......@@ -6,10 +6,19 @@
# General setup
#
CONFIG_NATIVE=y
# CONFIG_ALPHA_AVANTI is not set
# CONFIG_ALPHA_JENSEN is not set
# CONFIG_ALPHA_NONAME is not set
CONFIG_ALPHA_CABRIOLET=y
# CONFIG_ALPHA_EB66 is not set
# CONFIG_ALPHA_EB66P is not set
# CONFIG_ALPHA_EB64 is not set
# CONFIG_ALPHA_EB64P is not set
# CONFIG_ALPHA_SRM is not set
CONFIG_PCI=y
CONFIG_ALPHA_APECS=y
# CONFIG_SERIAL_ECHO is not set
# CONFIG_TGA_CONSOLE is not set
CONFIG_PCI_OPTIMIZE=y
CONFIG_NET=y
CONFIG_SYSVIPC=y
......@@ -31,8 +40,8 @@ CONFIG_ST506=y
#
# CONFIG_BLK_DEV_HD is not set
CONFIG_BLK_DEV_IDE=y
# CONFIG_BLK_DEV_TRITON is not set
# CONFIG_BLK_DEV_IDECD is not set
# CONFIG_BLK_DEV_TRITON is not set
# CONFIG_BLK_DEV_XD is not set
#
......@@ -43,7 +52,6 @@ CONFIG_INET=y
# CONFIG_IP_FORWARD is not set
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ACCT is not set
# CONFIG_NET_IPIP is not set
#
# (it is safe to leave these untouched)
......@@ -120,6 +128,7 @@ CONFIG_DUMMY=m
CONFIG_NET_EISA=y
# CONFIG_APRICOT is not set
CONFIG_DE4X5=y
# CONFIG_ETH16 is not set
# CONFIG_ZNET is not set
# CONFIG_NET_POCKET is not set
# CONFIG_TR is not set
......
......@@ -9,7 +9,6 @@
#define __ASSEMBLY__
#include <asm/system.h>
#include <linux/fd.h>
#define halt .long PAL_halt
......
......@@ -21,6 +21,7 @@
#include <linux/a.out.h>
#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/config.h> /* CONFIG_ALPHA_LCA etc */
#include <asm/segment.h>
#include <asm/system.h>
......@@ -66,24 +67,6 @@ struct screen_info screen_info = {
16 /* orig-video-points */
};
/*
* Initialize Programmable Interval Timers with standard values. Some
* drivers depend on them being initialized (e.g., joystick driver).
*/
static void init_pit (void)
{
outb(0x54, 0x43); /* counter 1: refresh timer */
outb(0x18, 0x41);
outb(0x36, 0x43); /* counter 0: system timer */
outb(0x00, 0x40);
outb(0x00, 0x40);
outb(0xb6, 0x43); /* counter 2: speaker */
outb(0x31, 0x42);
outb(0x13, 0x42);
}
static unsigned long find_end_memory(void)
{
int i;
......@@ -110,8 +93,6 @@ void setup_arch(char **cmdline_p,
{
extern int _end;
init_pit();
hwrpb = (struct hwrpb_struct*)(IDENT_ADDR + INIT_HWRPB->phys_addr);
set_hae(hae.cache); /* sync HAE register w/hae_cache */
......
......@@ -4,7 +4,6 @@
* Copyright (C) 1995 Linus Torvalds
*/
#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/head.h>
......
......@@ -3015,7 +3015,7 @@ static inline void clear_write_error(int drive)
CLEARSTRUCT(UDRWE);
}
static inline int set_geometry(int cmd, struct floppy_struct *g,
static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
int drive, int type, int device)
{
int cnt;
......@@ -3114,14 +3114,14 @@ static inline int normalize_0x02xx_ioctl(int *cmd, int *size)
{
int i, orig_size, ocmd;
orig_size = IOC_SIZE(*cmd);
orig_size = _IOC_SIZE(*cmd);
ocmd = *cmd;
for (i=0; i < ARRAY_SIZE(translation_table); i++) {
if ((*cmd & 0xff3f) == (translation_table[i].newcmd & 0xff3f)){
*cmd = translation_table[i].newcmd;
if (!orig_size && IOC_SIZE(*cmd)) {
/* kernels 1.3.34 to 1.3.37 : */
*size = IOC_SIZE(*cmd);
if (!orig_size && _IOC_SIZE(*cmd)) {
/* kernels 1.3.34 to 1.3.39 : */
*size = _IOC_SIZE(*cmd);
DPRINT1("warning: obsolete ioctl 0x%x\n",ocmd);
DPRINT("please recompile your program\n");
/* these ioctls only existed
......@@ -3132,7 +3132,7 @@ static inline int normalize_0x02xx_ioctl(int *cmd, int *size)
*/
} else {
*size = orig_size;
if (*size > IOC_SIZE(*cmd)) {
if (*size > _IOC_SIZE(*cmd)) {
printk("ioctl not yet supported\n");
return -EFAULT;
}
......@@ -3261,7 +3261,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
case FDGETDRVTYP:
outparam = drive_name(type,drive);
SUPBOUND(size,strlen(outparam));
SUPBOUND(size,strlen(outparam)+1);
break;
IN(FDSETDRVPRM, UDP, dp);
......
......@@ -60,20 +60,25 @@
17 June 95 Modifications By Andrew J. Kroll <ag784@freenet.buffalo.edu>
07 July 1995 Modifications by Andrew J. Kroll
0.6
8 November 95 More Modifications By Andrew J. Kroll
Media change detect now works :) That means that SuperMount and
other programs that depend on this will now work!
You are welcome in advance! You will notice, however that you don't
always get the kernel message saying "VFS: Disk change detected on
device", so I'm not sure that it's *PERFECT* but it does seem to
actually work! What else should I add?
*/
#include <linux/config.h>
*/
#ifdef MODULE
# include <linux/module.h>
#endif
#include <linux/version.h>
#include <linux/module.h>
#ifdef MODULE
# ifndef CONFIG_MODVERSIONS
char kernel_version[]= UTS_RELEASE;
# endif
#define mcd_init init_module
#else
# define MOD_INC_USE_COUNT
# define MOD_DEC_USE_COUNT
#endif
#include <linux/errno.h>
#include <linux/signal.h>
......@@ -138,16 +143,18 @@ static int mcdPresent = 0;
#endif
/* #define DOUBLE_QUICK_ONLY */
#define CURRENT_VALID \
#if LINUX_VERSION_CODE < 66338
#define CURRENT_VALID \
(CURRENT && MAJOR(CURRENT -> dev) == MAJOR_NR && CURRENT -> cmd == READ \
&& CURRENT -> sector != -1)
#else
#define CURRENT_VALID \
(CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
&& CURRENT -> sector != -1)
#endif
#define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
#define MCD_BUF_SIZ 16
static volatile int mcd_transfer_is_active;
/* Are you sleeping, Are you sleeping, Brother John, Brother John? ;) */
static volatile int sleeping_for_status;
static char mcd_buf[2048*MCD_BUF_SIZ]; /* buffer for block size conversion */
static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
static volatile int mcd_buf_in, mcd_buf_out = -1;
......@@ -215,89 +222,54 @@ void mcd_setup(char *str, int *ints)
#endif /* WORK_AROUND_MITSUMI_BUG_93 */
}
/*
* Do a 'get status' command and get the result. Only use from the top half
* because it calls 'getMcdStatus' which sleeps.
*/
static int
statusCmd(void)
#if LINUX_VERSION_CODE < 66338
check_mcd_change(dev_t full_dev)
#else
check_mcd_change(kdev_t full_dev)
#endif
{
int st, retry;
int retval, target;
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
outb(MCMD_GET_STATUS, MCDPORT(0)); /* send get-status cmd */
st = getMcdStatus(MCD_STATUS_DELAY);
if (st != -1)
break;
#if 1 /* the below is not reliable */
return 0;
#endif
target = MINOR(full_dev);
if (target > 0) {
printk("mcd: Mitsumi CD-ROM request error: invalid device.\n");
return 0;
}
return st;
retval = mcdDiskChanged;
mcdDiskChanged = 0;
return retval;
}
/*
* This detects a media change on the CD ROM.
* We need to grab the status right off the drive in here.
* Before, it ALWAYS returned a value of 0, which was not right!
* Do a 'get status' command and get the result. Only use from the top half
* because it calls 'getMcdStatus' which sleeps.
*/
static int
check_mcd_change(dev_t full_dev)
statusCmd(void)
{
int retval, target, st, count;
st = -1;
target = MINOR(full_dev);
int st, retry;
if (target > 0)
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
printk("mcd: Mitsumi CD-ROM request error: invalid device.\n");
return 0;
}
/*
* SOMETIMES it changes, sometimes not! Well, here we FIX that little nasty!
* All we need to do is read the status from the drive without spamming the
* kernel! In other words, this routine CANNOT sleep!
* The kernel will automagically picks up on this now.
* Devilishly sneaky it is! 8) -- AJK
*/
if ((!mcd_transfer_is_active) &&
(!sleeping_for_status) &&
(mcd_state == MCD_S_IDLE)) /* YES I'm paraniod! :) */
{
outb(MCMD_GET_STATUS, MCDPORT(0)); /* send get-status cmd */
for (count = 0; count < 3000; count++) /* wait for the status */
{
if (!(inb(MCDPORT(1)) & MFL_STATUS))
st = getMcdStatus(MCD_STATUS_DELAY);
if (st != -1)
break;
}
if (count >= 3000) /* Did we time out? */
{
retval = mcdDiskChanged; /* We can just jump out of here */
mcdDiskChanged = 0; /* as it's not needed all the time. */
return retval; /* So we pretend nothing happened here! ;) */
}
st=inb(MCDPORT(0)) & 0xFF ; /* Read the status in... */
/* okay... here's that magic part! Muhuhuhuh...*/
if (st & MST_DSK_CHG) /* Devil made me do it! O];) */
{
mcdDiskChanged = 1; /* Show a change. */
audioStatus = CDROM_AUDIO_NO_STATUS; /* just incase... */
tocUpToDate = 0; /* Frantic laughing continues... */
mcd_invalidate_buffers(); /* 666 wins! */
} /* Stupid comments are fun! */
}
retval = mcdDiskChanged; /* Indicate status. */
mcdDiskChanged = 0; /* Go, now. Enjoy a good beer! */
return retval; /* The End. */
return st;
}
......@@ -1217,7 +1189,7 @@ mcd_init(void)
{
int count;
unsigned char result[3];
sleeping_for_status = 0;
if (mcd_port <= 0 || mcd_irq <= 0) {
printk("skip mcd_init\n");
return -EIO;
......@@ -1419,14 +1391,10 @@ getMcdStatus(int timeout)
McdTimeout = timeout;
SET_TIMER(mcdStatTimer, 1);
sleeping_for_status = 1;
sleep_on(&mcd_waitq);
if (McdTimeout <= 0)
{
sleeping_for_status = 0;
return -1;
}
sleeping_for_status = 0;
st = inb(MCDPORT(0)) & 0xFF;
if (st == 0xFF)
return -1;
......@@ -1662,13 +1630,11 @@ Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
}
#ifdef MODULE
int init_module(void)
{
return mcd_init();
}
void cleanup_module(void)
{
{ if (MOD_IN_USE)
{ printk("mcd module in use - can't remove it.\n");
return;
}
if ((unregister_blkdev(MAJOR_NR, "mcd") == -EINVAL))
{ printk("What's that: can't unregister mcd\n");
return;
......
/*
* The Mitsumi CDROM interface
* Copyright (C) 1995 Heiko Schlittermann
* VERSION: 1.0a
* Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
* VERSION: 1.3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -34,10 +34,26 @@
#if RCS
static const char *mcdx_c_version
= "mcdx.c,v 1.7 1995/08/27 01:46:41 heiko Exp";
= "mcdx.c,v 1.17 1995/11/06 01:07:57 heiko Exp";
#endif
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#endif
#include <linux/version.h>
#ifdef MODULE
#ifndef CONFIG_MODVERSIONS
char kernel_version[] = UTS_RELEASE;
#endif
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#define MOD_IN_USE 1
#endif MODULE
#include <linux/errno.h>
#include <linux/signal.h>
......@@ -56,9 +72,11 @@ static const char *mcdx_c_version
#include <linux/major.h>
#ifndef MITSUMI_X_CDROM_MAJOR /* old kernel (doesn't know about MCDX) */
/* old kernel (doesn't know about MCDX) */
#ifndef MITSUMI_X_CDROM_MAJOR
#define MITSUMI_X_CDROM_MAJOR 20
#define DEVICE_NAME "Mitsumi CD-ROM"
#define DEVICE_NAME "mcdx"
/* #define DEVICE_INTR do_mcdx */
#define DEVICE_REQUEST do_mcdx_request
#define DEVICE_NR(device) (MINOR(device))
......@@ -68,13 +86,20 @@ static const char *mcdx_c_version
#define MAJOR_NR MITSUMI_X_CDROM_MAJOR
#include <linux/blk.h>
#define mcdx_drive_map mcdx /* for compatible parameter passing with "insmod" */
/* for compatible parameter passing with "insmod" */
#define mcdx_drive_map mcdx
#include <linux/mcdx.h>
#ifndef HZ
#error HZ not defined
#endif
/* CONSTANTS *******************************************************/
const int REQUEST_SIZE = 200;
const int DIRECT_SIZE = 200;
const unsigned long ACLOSE_INHIBIT = 800; /* 1/100 s of autoclose inhibit */
enum drivemodes { TOC, DATA, RAW, COOKED };
enum datamodes { MODE0, MODE1, MODE2 };
......@@ -134,6 +159,8 @@ struct s_drive_stuff {
volatile int introk; /* status of last irq operation */
volatile int busy; /* drive performs an operation */
volatile int lock; /* exclusive usage */
int eject_sw; /* 1 - eject on last close (default 0) */
int autoclose; /* 1 - close the door on open (default 1) */
/* cd infos */
struct s_diskinfo di;
......@@ -166,10 +193,10 @@ struct s_drive_stuff {
char playcmd; /* play should always be single speed */
unsigned long changed; /* last jiff the media was changed */
unsigned long xxx; /* last jiff it was asked for media change */
unsigned long ejected; /* time we called the eject function */
int users; /* keeps track of open/close */
int lastsector; /* last block accessible */
int errno; /* last operation's error */
};
......@@ -180,10 +207,18 @@ struct s_drive_stuff {
changed elsewhere. */
/* declared in blk.h */
#if LINUX_VERSION_CODE < 66338
unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end);
#else
int mcdx_init(void);
#endif
void do_mcdx_request(void);
#if LINUX_VERSION_CODE < 66338
int check_mcdx_media_change(dev_t);
#else
int check_mcdx_media_change(kdev_t);
#endif
/* already declared in init/main */
void mcdx_setup(char *, int *);
......@@ -229,17 +264,17 @@ static int mcdx_requestmultidiskinfo(struct s_drive_stuff*, struct s_multi*, int
static int mcdx_requesttocdata(struct s_drive_stuff*, struct s_diskinfo*, int);
static int mcdx_getstatus(struct s_drive_stuff*, int);
static int mcdx_getval(struct s_drive_stuff*, int to, int delay, char*);
static int mcdx_talk(struct s_drive_stuff*,
const unsigned char* cmd, size_t, void *buffer,
size_t size, unsigned int timeout, int);
const unsigned char* cmd, size_t,
void *buffer, size_t size,
unsigned int timeout, int);
static int mcdx_readtoc(struct s_drive_stuff*);
static int mcdx_playtrk(struct s_drive_stuff*, const struct cdrom_ti*);
static int mcdx_playmsf(struct s_drive_stuff*, const struct cdrom_msf*);
static int mcdx_setattentuator(struct s_drive_stuff*, struct cdrom_volctrl*, int);
/* static variables ************************************************/
static int dummy0;
static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES];
static struct s_drive_stuff* mcdx_irq_map[16] =
......@@ -301,7 +336,7 @@ mcdx_ioctl(
|| (ti.cdti_trk1 < stuffp->di.n_first))
return -EINVAL;
if (ti.cdti_trk1 > stuffp->di.n_last) ti.cdti_trk1 = stuffp->di.n_last;
TRACE((IOCTL, "ioctl() track %d to %d\n", ti.cdti_trk0, ti.cdti_trk1));
TRACE((PLAYTRK, "ioctl() track %d to %d\n", ti.cdti_trk0, ti.cdti_trk1));
return mcdx_playtrk(stuffp, &ti);
}
......@@ -388,20 +423,20 @@ mcdx_ioctl(
if (-1 == mcdx_requestsubqcode(stuffp, &q, 2)) return -EIO;
TRACE((IOCTL, "audiostatus: %x\n", stuffp->audiostatus));
TRACE((SUBCHNL, "audiostatus: %x\n", stuffp->audiostatus));
sub.cdsc_audiostatus = stuffp->audiostatus;
sub.cdsc_adr = q.control;
sub.cdsc_ctrl = q.control >> 4;
sub.cdsc_trk = bcd2uint(q.tno);
sub.cdsc_ind = bcd2uint(q.index);
TRACE((IOCTL, "trk %d, ind %d\n",
TRACE((SUBCHNL, "trk %d, ind %d\n",
sub.cdsc_trk, sub.cdsc_ind));
if (sub.cdsc_format == CDROM_LBA) {
sub.cdsc_absaddr.lba = msf2log(&q.dt);
sub.cdsc_reladdr.lba = msf2log(&q.tt);
TRACE((IOCTL, "lba: abs %d, rel %d\n",
TRACE((SUBCHNL, "lba: abs %d, rel %d\n",
sub.cdsc_absaddr.lba,
sub.cdsc_reladdr.lba));
} else if (sub.cdsc_format == CDROM_MSF) {
......@@ -411,7 +446,7 @@ mcdx_ioctl(
sub.cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute);
sub.cdsc_reladdr.msf.second = bcd2uint(q.tt.second);
sub.cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
TRACE((IOCTL,
TRACE((SUBCHNL,
"msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
sub.cdsc_absaddr.msf.minute,
sub.cdsc_absaddr.msf.second,
......@@ -438,7 +473,7 @@ mcdx_ioctl(
toc.cdth_trk0 = stuffp->di.n_first;
toc.cdth_trk1 = stuffp->di.n_last;
memcpy_tofs((void*) arg, &toc, sizeof toc);
TRACE((IOCTL, "ioctl() track0 = %d, track1 = %d\n",
TRACE((TOCHDR, "ioctl() track0 = %d, track1 = %d\n",
stuffp->di.n_first, stuffp->di.n_last));
return 0;
}
......@@ -447,10 +482,9 @@ mcdx_ioctl(
TRACE((IOCTL, "ioctl() PAUSE\n"));
if (stuffp->audiostatus != CDROM_AUDIO_PLAY) return -EINVAL;
if (-1 == mcdx_stop(stuffp, 1)) return -EIO;
stuffp->audiostatus = CDROM_AUDIO_PAUSED;
if (-1 == mcdx_requestsubqcode(stuffp, &stuffp->start, 1))
return -EIO;
stuffp->audiostatus = CDROM_AUDIO_PAUSED;
return 0;
}
......@@ -479,7 +513,7 @@ mcdx_ioctl(
memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession));
if (ms.addr_format == CDROM_MSF)
TRACE((IOCTL,
TRACE((MS,
"ioctl() (%d, %02x:%02x.%02x [%02x:%02x.%02x])\n",
ms.xa_flag,
ms.addr.msf.minute,
......@@ -490,8 +524,7 @@ mcdx_ioctl(
stuffp->multi.msf_last.frame));
else
{
dummy0=0;
TRACE((IOCTL,
TRACE((MS,
"ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
ms.xa_flag,
ms.addr.lba,
......@@ -509,11 +542,26 @@ mcdx_ioctl(
return 0;
}
case CDROMVOLCTRL: {
TRACE((IOCTL, "ioctl() volctrl\n"));
case CDROMEJECT_SW: {
stuffp->eject_sw = arg;
return 0;
}
case CDROMVOLCTRL: {
int ans;
struct cdrom_volctrl volctrl;
TRACE((IOCTL, "ioctl() VOLCTRL\n"));
if ((ans = verify_area(
VERIFY_READ,
(void*) arg,
sizeof(volctrl))))
return ans;
memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
return mcdx_setattentuator(stuffp, &volctrl, 1);
}
default:
WARN(("ioctl(): unknown request 0x%04x\n", cmd));
return -EINVAL;
......@@ -529,20 +577,36 @@ void do_mcdx_request()
TRACE((REQUEST, "do_request()\n"));
#if LINUX_VERSION_CODE < 66338
if ((CURRENT == NULL) || (CURRENT->dev < 0)) {
#else
if ((CURRENT == NULL) || (CURRENT->rq_status == RQ_INACTIVE)) {
#endif
TRACE((REQUEST, "do_request() done\n"));
return;
}
#if LINUX_VERSION_CODE < 66338
stuffp = mcdx_stuffp[MINOR(CURRENT->dev)];
#else
stuffp = mcdx_stuffp[MINOR(CURRENT->rq_dev)];
#endif
TRACE((REQUEST, "do_request() stuffp = %p\n", stuffp));
INIT_REQUEST;
#if LINUX_VERSION_CODE < 66338
dev = MINOR(CURRENT->dev);
#else
dev = MINOR(CURRENT->rq_dev);
#endif
if ((dev < 0) || (dev >= MCDX_NDRIVES) || (!stuffp->present)) {
#if LINUX_VERSION_CODE < 66338
WARN(("do_request(): bad device: 0x%04x\n", CURRENT->dev));
#else
WARN(("do_request(): bad device: %s\n",
kdevname(CURRENT->rq_dev)));
#endif
end_request(0);
goto again;
}
......@@ -596,6 +660,8 @@ void do_mcdx_request()
static int
mcdx_open(struct inode *ip, struct file *fp)
/* actions done on open:
* 1) get the drives status */
{
struct s_drive_stuff *stuffp;
......@@ -603,14 +669,21 @@ mcdx_open(struct inode *ip, struct file *fp)
stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
if (!stuffp->present) return -ENXIO;
/* this is only done to test if the drive talks with us */
if (-1 == mcdx_getstatus(stuffp, 1)) return -EIO;
/* close the door, if necessary (get the door information
from the hardware status register) */
if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR)
mcdx_closedoor(stuffp, 1);
from the hardware status register).
If the last eject is too recent, an autoclose wouldn't probably
be what we want ..., if we can't read the CD after an autoclose
no further autclose's will be tried */
if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR) {
if (jiffies - stuffp->ejected < ACLOSE_INHIBIT) return -EIO;
if (stuffp->autoclose) mcdx_closedoor(stuffp, 1);
else return -EIO;
}
/* if the media changed we will have to little more */
/* if the media changed we will have to do a little more */
if (stuffp->xxx < stuffp->changed) {
TRACE((OPENCLOSE, "open() media changed\n"));
......@@ -619,18 +692,23 @@ mcdx_open(struct inode *ip, struct file *fp)
talk() will detect a media change ... (I think, config()
is the reason. */
/*
TRACE((OPENCLOSE, "open() hardware reset\n"));
if (-1 == mcdx_reset(stuffp, HARD, 1)) return -EIO;
*/
stuffp->audiostatus = CDROM_AUDIO_INVALID;
/* get the multisession information */
{
int ans;
TRACE((OPENCLOSE, "open() Request multisession info\n"));
if (-1 == mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
ans = mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6);
if (ans == -1) {
stuffp->autoclose = 0;
mcdx_eject(stuffp, 1);
return -EIO;
}
/* we succeeded, so on next open(2) we could try auto close
again */
stuffp->autoclose = 1;
if (stuffp->multi.multi > 2)
WARN(("open() unknown multisession value (%d)\n", stuffp->multi.multi));
......@@ -743,23 +821,36 @@ mcdx_close(struct inode *ip, struct file *fp)
/* invalidate_inodes(ip->i_rdev); */
invalidate_buffers(ip->i_rdev);
if (-1 == mcdx_lockdoor(stuffp, 0, 1))
printk(MCDX ": Cannot unlock the door\n");
if (-1 == mcdx_lockdoor(stuffp, 0, 3))
INFO(("close() Cannot unlock the door\n"));
/* eject if wished */
if (stuffp->eject_sw) mcdx_eject(stuffp, 1);
}
MOD_DEC_USE_COUNT;
return;
}
#if LINUX_VERSION_CODE < 66338
int check_mcdx_media_change(dev_t full_dev)
#else
int check_mcdx_media_change(kdev_t full_dev)
#endif
/* Return: 1 if media changed since last call to
this function
0 else
Setting flag to 0 resets the changed state. */
{
#if LINUX_VERSION_CODE < 66338
INFO(("check_mcdx_media_change called for device %x\n",
full_dev));
#else
INFO(("check_mcdx_media_change called for device %s\n",
kdevname(full_dev)));
#endif
return 0;
}
......@@ -813,8 +904,8 @@ mcdx_intr(int irq, struct pt_regs* regs)
stuffp = mcdx_irq_map[irq];
if (!stuffp->busy) {
INFO(("intr() unexpected interrupt @ irq %d\n", irq));
if (stuffp == NULL || !stuffp->busy) {
TRACE((IRQ, "intr() unexpected interrupt @ irq %d\n", irq));
return;
}
......@@ -825,8 +916,8 @@ mcdx_intr(int irq, struct pt_regs* regs)
irq, x, inb((unsigned int) stuffp->rreg_data)));
else
{
dummy0=0;
TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, x));
}
stuffp->busy = 0;
wake_up_interruptible(&stuffp->busyq);
......@@ -841,12 +932,16 @@ mcdx_talk (
unsigned int timeout, int tries)
/* Send a command to the drive, wait for the result.
* returns -1 on timeout, drive status otherwise
* If buffer is not zero, the result (length size) is stored there.
* If buffer is zero the size should be the number of bytes to read
* from the drive. These bytes are discarded.
*/
{
char c;
int st;
char c;
int disgard;
if (!buffer || size == 0) buffer = &c, size = 1;
if ((disgard = (buffer == NULL))) buffer = &c;
while (stuffp->lock)
interruptible_sleep_on(&stuffp->lockq);
......@@ -881,18 +976,20 @@ mcdx_talk (
/* get the status byte */
if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
WARN(("talk() %02x timed out (status), %d tr%s left\n",
INFO(("talk() %02x timed out (status), %d tr%s left\n",
cmd[0], tries - 1, tries == 2 ? "y" : "ies"));
continue;
}
st = *bp++;
st = *bp;
sz--;
if (!disgard) bp++;
TRACE((TALK, "talk() got status 0x%02x\n", st));
/* command error? */
if (e_cmderr(st)) {
WARN(("command error %02x (%d)\n", cmd[0], cmdlen));
WARN(("command error cmd = %02x %s \n",
cmd[0], cmdlen > 1 ? "..." : ""));
st = -1;
continue;
}
......@@ -901,6 +998,9 @@ mcdx_talk (
if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
stuffp->audiostatus =
e_audiobusy(st) ? CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;
else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
&& e_audiobusy(st) == 0)
stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
/* media change? */
if (e_changed(st)) {
......@@ -910,18 +1010,17 @@ mcdx_talk (
/* now actually get the data */
while (sz--) {
if (-1 == mcdx_getval(stuffp, timeout, -1, bp++)) {
WARN(("talk() %02x timed out (data), %d tr%s left\n",
if (-1 == mcdx_getval(stuffp, timeout, -1, bp)) {
INFO(("talk() %02x timed out (data), %d tr%s left\n",
cmd[0], tries - 1, tries == 2 ? "y" : "ies"));
st = -1; break;
}
if (!disgard) bp++;
TRACE((TALK, "talk() got 0x%02x\n", *(bp - 1)));
}
}
#if QUIET == 0
if (!tries && st == -1) INFO(("talk() giving up\n"));
#endif
if (!tries && st == -1) WARN(("talk() giving up\n"));
stuffp->lock = 0;
wake_up_interruptible(&stuffp->lockq);
......@@ -938,7 +1037,11 @@ int init_module(void)
int i;
int drives = 0;
#if LINUX_VERSION_CODE < 66338
mcdx_init(0, 0);
#else
mcdx_init();
#endif
for (i = 0; i < MCDX_NDRIVES; i++) {
if (mcdx_stuffp[i]) {
TRACE((INIT, "init_module() drive %d stuff @ %p\n",
......@@ -950,6 +1053,7 @@ int init_module(void)
if (!drives)
return -EIO;
register_symtab(0);
return 0;
}
......@@ -1009,12 +1113,18 @@ void warn(const char* fmt, ...)
}
#if LINUX_VERSION_CODE < 66338
unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end)
#else
int mcdx_init(void)
#endif
{
int drive;
INFO((": Version 1.0a "
"mcdx.c,v 1.7 1995/08/27 01:46:41 heiko Exp\n"));
WARN(("Version 1.3 "
"mcdx.c,v 1.17 1995/11/06 01:07:57 heiko Exp\n"));
INFO((": Version 1.3 "
"mcdx.c,v 1.17 1995/11/06 01:07:57 heiko Exp\n"));
/* zero the pointer array */
for (drive = 0; drive < MCDX_NDRIVES; drive++)
......@@ -1030,16 +1140,24 @@ int mcdx_init(void)
TRACE((INIT, "init() try drive %d\n", drive));
#if defined(MODULE) || LINUX_VERSION_CODE > 66338
TRACE((INIT, "kmalloc space for stuffpt's\n"));
TRACE((MALLOC, "init() malloc %d bytes\n", size));
if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
WARN(("init() malloc failed\n"));
break;
}
#else
TRACE((INIT, "adjust mem_start\n"));
stuffp = (struct s_drive_stuff *) mem_start;
mem_start += size;
#endif
TRACE((INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp));
/* zero the stuff */
/* set default values */
memset(stuffp, 0, sizeof(*stuffp));
stuffp->autoclose = 1; /* close the door on open(2) */
stuffp->present = 0; /* this should be 0 already */
stuffp->toc = NULL; /* this should be NULL already */
......@@ -1165,7 +1283,11 @@ int mcdx_init(void)
TRACE((INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp));
}
#if MODULE || LINUX_VERSION_CODE > 66338
return 0;
#else
return mem_start;
#endif
}
......@@ -1210,25 +1332,17 @@ static int mcdx_transfer(struct s_drive_stuff *stuffp,
current->timeout = jiffies + 5*HZ;
while (stuffp->busy) {
interruptible_sleep_on(&stuffp->busyq);
if ((sig = (current->signal && ~current->blocked))
|| (to = (current->timeout == 0))) {
break;
}
}
current->timeout = 0;
/* test for possible errors */
if (((stuffp->busy == 0) && !stuffp->introk)
|| sig
|| to) {
if ((stuffp->busy == 0) && !stuffp->introk)
WARN(("mcdx_transfer() failure in data request\n"));
else if (to)
WARN(("mcdx_transfer(): timeout\n"));
else if (sig)
WARN(("mcdx_transfer(): got signal 0x%lx\n", current->signal));
stuffp->lock = 0;
stuffp->busy = 0;
wake_up_interruptible(&stuffp->lockq);
......@@ -1365,16 +1479,16 @@ int mcdx_readtoc(struct s_drive_stuff* stuffp)
{
if (stuffp->toc) {
TRACE((IOCTL, "ioctl() toc already read\n"));
TRACE((READTOC, "ioctl() toc already read\n"));
return 0;
}
TRACE((IOCTL, "ioctl() readtoc for %d tracks\n",
TRACE((READTOC, "ioctl() readtoc for %d tracks\n",
stuffp->di.n_last - stuffp->di.n_first + 1));
if (-1 == mcdx_hold(stuffp, 1)) return -1;
TRACE((IOCTL, "ioctl() tocmode\n"));
TRACE((READTOC, "ioctl() tocmode\n"));
if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) return -EIO;
/* all seems to be ok so far ... malloc */
......@@ -1417,7 +1531,7 @@ int mcdx_readtoc(struct s_drive_stuff* stuffp)
&& (q.tno == 0)
&& (stuffp->toc[idx - stuffp->di.n_first].index == 0)) {
stuffp->toc[idx - stuffp->di.n_first] = q;
TRACE((IOCTL, "ioctl() toc idx %d (trk %d)\n", idx, trk));
TRACE((READTOC, "ioctl() toc idx %d (trk %d)\n", idx, trk));
trk--;
}
if (trk == 0) break;
......@@ -1429,16 +1543,16 @@ int mcdx_readtoc(struct s_drive_stuff* stuffp)
}
/* unset toc mode */
TRACE((IOCTL, "ioctl() undo toc mode\n"));
TRACE((READTOC, "ioctl() undo toc mode\n"));
if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
return -EIO;
#if MCDX_DEBUG && IOCTL
#if MCDX_DEBUG && READTOC
{ int trk;
for (trk = 0;
trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
trk++)
TRACE((IOCTL, "ioctl() %d readtoc %02x %02x %02x"
TRACE((READTOC, "ioctl() %d readtoc %02x %02x %02x"
" %02x:%02x.%02x %02x:%02x.%02x\n",
trk + stuffp->di.n_first,
stuffp->toc[trk].control, stuffp->toc[trk].tno, stuffp->toc[trk].index,
......@@ -1466,14 +1580,14 @@ mcdx_playmsf(struct s_drive_stuff* stuffp, const struct cdrom_msf* msf)
cmd[5] = msf->cdmsf_sec1;
cmd[6] = msf->cdmsf_frame1;
TRACE((IOCTL, "ioctl(): play %x "
TRACE((PLAYMSF, "ioctl(): play %x "
"%02x:%02x:%02x -- %02x:%02x:%02x\n",
cmd[0], cmd[1], cmd[2], cmd[3],
cmd[4], cmd[5], cmd[6]));
outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
if (-1 == mcdx_getval(stuffp, 1*HZ, 0, NULL)) {
if (-1 == mcdx_getval(stuffp, 3*HZ, 0, NULL)) {
WARN(("playmsf() timeout\n"));
return -1;
}
......@@ -1516,26 +1630,26 @@ static int
mcdx_closedoor(struct s_drive_stuff *stuffp, int tries)
{
if (stuffp->present & DOOR)
return mcdx_talk(stuffp, "\xf8", 1, NULL, 0, 5*HZ, tries);
return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5*HZ, tries);
else
return 0;
}
static int
mcdx_stop(struct s_drive_stuff *stuffp, int tries)
{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 0, 2*HZ, tries); }
{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2*HZ, tries); }
static int
mcdx_hold(struct s_drive_stuff *stuffp, int tries)
{ return mcdx_talk(stuffp, "\x70", 1, NULL, 0, 2*HZ, tries); }
{ return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2*HZ, tries); }
static int
mcdx_eject(struct s_drive_stuff *stuffp, int tries)
{
if (stuffp->present & DOOR)
return mcdx_talk(stuffp, "\xf6", 1, NULL, 0, 5*HZ, tries);
else
return 0;
if (stuffp->present & DOOR) {
stuffp->ejected = jiffies;
return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5*HZ, tries);
} else return 0;
}
static int
......@@ -1618,7 +1732,7 @@ mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, int tries)
default: break;
}
cmd[0] = 0x50;
return mcdx_talk(stuffp, cmd, 2, NULL, 0, 5*HZ, tries);
return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5*HZ, tries);
}
......@@ -1633,7 +1747,7 @@ mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries)
case MODE2: cmd[1] = 0x02; break;
default: return -EINVAL;
}
return mcdx_talk(stuffp, cmd, 2, NULL, 0, 5*HZ, tries);
return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5*HZ, tries);
}
static int
......@@ -1648,13 +1762,13 @@ mcdx_config(struct s_drive_stuff *stuffp, int tries)
cmd[1] = 0x10; /* irq enable */
cmd[2] = 0x05; /* pre, err irq enable */
if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 0, 1*HZ, tries))
if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1*HZ, tries))
return -1;
cmd[1] = 0x02; /* dma select */
cmd[2] = 0x00; /* no dma */
return mcdx_talk(stuffp, cmd, 3, NULL, 0, 1*HZ, tries);
return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1*HZ, tries);
}
static int
......@@ -1679,7 +1793,7 @@ mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
outb(0, (unsigned int) stuffp->wreg_chn); /* no dma, no irq -> hardware */
outb(0, (unsigned int) stuffp->wreg_reset); /* hw reset */
return 0;
} else return mcdx_talk(stuffp, "\x60", 1, NULL, 0, 5*HZ, tries);
} else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5*HZ, tries);
}
static int
......@@ -1688,14 +1802,14 @@ mcdx_lockdoor(struct s_drive_stuff *stuffp, int lock, int tries)
char cmd[2] = { 0xfe };
if (stuffp->present & DOOR) {
cmd[1] = lock ? 0x01 : 0x00;
return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 0, 5*HZ, tries);
return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5*HZ, tries);
} else
return 0;
}
static int
mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
{ return mcdx_talk(stuffp, "\x40", 1, NULL, 0, 5*HZ, tries); }
{ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5*HZ, tries); }
static int
mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf)
......@@ -1714,3 +1828,20 @@ mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf)
return 0;
}
static int
mcdx_setattentuator(
struct s_drive_stuff* stuffp,
struct cdrom_volctrl* vol,
int tries)
{
char cmd[5];
cmd[0] = 0xae;
cmd[1] = vol->channel0;
cmd[2] = 0;
cmd[3] = vol->channel1;
cmd[4] = 0;
return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
}
......@@ -4,7 +4,7 @@
mainmenu_option next_comment
comment 'character devices'
bool 'Cyclades async mux support' CONFIG_CYCLADES
tristate 'Cyclades async mux support' CONFIG_CYCLADES
bool 'Stallion multiport serial support' CONFIG_STALDRV
if [ "$CONFIG_STALDRV" = "y" ]; then
tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION
......
......@@ -20,8 +20,12 @@ L_OBJS := tty_io.o n_tty.o console.o keyboard.o serial.o \
tty_ioctl.o pty.o vt.o mem.o vc_screen.o random.o \
defkeymap.o consolemap.o selection.o
ifdef CONFIG_CYCLADES
ifeq ($(CONFIG_CYCLADES),y)
L_OBJS += cyclades.o
else
ifeq ($(CONFIG_CYCLADES),m)
M_OBJS += cyclades.o
endif
endif
ifeq ($(CONFIG_STALLION),y)
......
......@@ -223,6 +223,8 @@ static char rcsid[] =
*
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
......@@ -404,7 +406,6 @@ static int startup (struct cyclades_port *);
static void cy_throttle(struct tty_struct *);
static void cy_unthrottle(struct tty_struct *);
static void config_setup(struct cyclades_port *);
extern void console_print(const char *);
#ifdef CYCLOM_SHOW_STATUS
static void show_status(int);
#endif
......@@ -466,7 +467,6 @@ void CP2(int data) { CP1((data>>4) & 0x0f); CP1( data & 0x0f); }/* CP2 */
void CP4(int data) { CP2((data>>8) & 0xff); CP2(data & 0xff); }/* CP4 */
void CP8(long data) { CP4((data>>16) & 0xffff); CP4(data & 0xffff); }/* CP8 */
/* This routine waits up to 1000 micro-seconds for the previous
command to the Cirrus chip to complete and then issues the
new command. An error is returned if the previous command
......@@ -583,6 +583,7 @@ cy_sched_event(struct cyclades_port *info, int event)
} /* cy_sched_event */
static int probe_ready;
/*
* This interrupt routine is used
......@@ -594,6 +595,9 @@ cy_probe(int irq, struct pt_regs *regs)
int save_xir, save_car;
int index = 0; /* probing interrupts is only for ISA */
if (!probe_ready)
return;
cy_irq_triggered = irq;
cy_triggered |= 1 << irq;
......@@ -1107,6 +1111,7 @@ get_auto_irq(unsigned char *address)
base_addr[CyCAR<<index] = 0;
write_cy_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
base_addr[CySRER<<index] |= CyTxMpty;
probe_ready = 1;
sti();
timeout = jiffies+2;
......@@ -1114,6 +1119,7 @@ get_auto_irq(unsigned char *address)
if (cy_irq_triggered)
break;
}
probe_ready = 0;
return(cy_irq_triggered);
} /* get_auto_irq */
......@@ -1132,6 +1138,8 @@ do_auto_irq(unsigned char *address)
/* Turn on interrupts (they may be off) */
save_flags(flags); sti();
probe_ready = 0;
cy_wild_int_mask = check_wild_interrupts();
irq_lines = grab_all_interrupts(cy_wild_int_mask);
......@@ -2286,6 +2294,7 @@ static void
cy_close(struct tty_struct * tty, struct file * filp)
{
struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
/* CP('C'); */
#ifdef SERIAL_DEBUG_OTHER
......@@ -2300,6 +2309,14 @@ cy_close(struct tty_struct * tty, struct file * filp)
printk("cy_close ttyC%d, count = %d\n", info->line, info->count);
#endif
save_flags(flags); cli();
/* If the TTY is being hung up, nothing to do */
if (tty_hung_up_p(filp)) {
restore_flags(flags);
return;
}
if ((tty->count == 1) && (info->count != 1)) {
/*
* Uh, oh. tty->count is 1, which means that the tty
......@@ -2313,7 +2330,7 @@ cy_close(struct tty_struct * tty, struct file * filp)
info->count = 1;
}
#ifdef SERIAL_DEBUG_COUNT
printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count - 1);
printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count - 1);
#endif
if (--info->count < 0) {
#ifdef SERIAL_DEBUG_COUNT
......@@ -2322,7 +2339,11 @@ cy_close(struct tty_struct * tty, struct file * filp)
info->count = 0;
}
if (info->count)
{
MOD_DEC_USE_COUNT;
restore_flags(flags);
return;
}
info->flags |= ASYNC_CLOSING;
/*
* Save the termios structure, since this port may have
......@@ -2341,14 +2362,6 @@ cy_close(struct tty_struct * tty, struct file * filp)
tty->ldisc.flush_buffer(tty);
info->event = 0;
info->tty = 0;
if (tty->ldisc.num != ldiscs[N_TTY].num) {
if (tty->ldisc.close)
(tty->ldisc.close)(tty);
tty->ldisc = ldiscs[N_TTY];
tty->termios->c_line = N_TTY;
if (tty->ldisc.open)
(tty->ldisc.open)(tty);
}
if (info->blocked_open) {
if (info->close_delay) {
current->state = TASK_INTERRUPTIBLE;
......@@ -2365,6 +2378,8 @@ cy_close(struct tty_struct * tty, struct file * filp)
printk("cy_close done\n");
#endif
MOD_DEC_USE_COUNT;
restore_flags(flags);
return;
} /* cy_close */
......@@ -2384,14 +2399,12 @@ cy_hangup(struct tty_struct *tty)
return;
shutdown(info);
#if 0
info->event = 0;
info->count = 0;
#ifdef SERIAL_DEBUG_COUNT
printk("cyc: %d: setting count to 0\n", __LINE__);
printk("cyc: %d(%d): setting count to 0\n", __LINE__, current->pid);
#endif
info->tty = 0;
#endif
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
wake_up_interruptible(&info->open_wait);
} /* cy_hangup */
......@@ -2477,7 +2490,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
#endif
info->count--;
#ifdef SERIAL_DEBUG_COUNT
printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);
printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count);
#endif
info->blocked_open++;
......@@ -2537,7 +2550,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
if (!tty_hung_up_p(filp)){
info->count++;
#ifdef SERIAL_DEBUG_COUNT
printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count);
#endif
}
info->blocked_open--;
......@@ -2581,7 +2594,7 @@ cy_open(struct tty_struct *tty, struct file * filp)
#endif
info->count++;
#ifdef SERIAL_DEBUG_COUNT
printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count);
#endif
tty->driver_data = info;
info->tty = tty;
......@@ -2622,6 +2635,7 @@ cy_open(struct tty_struct *tty, struct file * filp)
#ifdef SERIAL_DEBUG_OPEN
printk("cy_open done\n");/**/
#endif
MOD_INC_USE_COUNT;
return 0;
} /* cy_open */
......@@ -2736,7 +2750,6 @@ cy_init(void)
struct cyclades_card *cinfo;
int board,port,i;
scrn[1] = '\0';
show_version();
/* Initialize the tty_driver structure */
......@@ -2877,6 +2890,33 @@ scrn[1] = '\0';
} /* cy_init */
#ifdef MODULE
int
init_module(void)
{
return(cy_init());
}
void
cleanup_module(void)
{
int i;
if (tty_unregister_driver(&cy_callout_driver))
printk("Couldn't unregister Cyclom callout driver\n");
if (tty_unregister_driver(&cy_serial_driver))
printk("Couldn't unregister Cyclom serial driver\n");
for (i = 0; i < NR_CARDS; i++) {
if (cy_card[i].base_addr != 0)
{
free_irq(cy_card[i].irq);
}
}
}
#endif
/*
* ---------------------------------------------------------------------
* cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
......
......@@ -10,7 +10,7 @@
* be here without 3C505 technical reference provided by
* 3Com.
*
* Version: @(#)3c505.c 0.8.1 26-Jun-95
* Version: @(#)3c505.c 0.8.3 12-Nov-95
*
* Authors: Linux 3c505 device driver by
* Craig Southeren, <craigs@ineluki.apana.org.au>
......@@ -103,7 +103,7 @@ static int elp_debug = 0;
* 3 = messages when interrupts received
*/
#define ELP_VERSION "0.8.1"
#define ELP_VERSION "0.8.3"
/*****************************************************************
*
......@@ -473,9 +473,13 @@ static void
adapter_hard_reset (struct device * dev)
{
int timeout;
long flags;
CHECK_NULL(dev);
save_flags(flags);
sti();
if (elp_debug > 0)
printk("%s: Resetting the adapter, please wait (approx 20 s)\n",
dev->name);
......@@ -507,6 +511,7 @@ adapter_hard_reset (struct device * dev)
for (timeout = jiffies + (100 * 15); jiffies <= timeout; )
if (GET_ASF(dev->base_addr) != ASF_PCB_END)
break;
restore_flags(flags);
}
/******************************************************
......@@ -1272,6 +1277,7 @@ elp_sense (struct device * dev)
int timeout;
int addr=dev->base_addr;
const char *name=dev->name;
long flags;
byte orig_HCR=inb_control(addr),
orig_HSR=inb_status(addr);
......@@ -1286,6 +1292,10 @@ elp_sense (struct device * dev)
return -1; /* It can't be 3c505 if HCR.DIR != HSR.DIR */
}
/* Enable interrupts - we need timers! */
save_flags(flags);
sti();
/* Wait for a while; the adapter may still be booting up */
if (elp_debug > 0)
printk(stilllooking_msg);
......@@ -1299,6 +1309,7 @@ elp_sense (struct device * dev)
timeout = jiffies+30;
while (jiffies < timeout)
;
restore_flags(flags);
if (inb_status(addr) & DIR) {
outb_control(orig_HCR,addr);
if (elp_debug > 0)
......@@ -1311,6 +1322,7 @@ elp_sense (struct device * dev)
timeout = jiffies+300;
while (jiffies < timeout)
;
restore_flags(flags);
if (!(inb_status(addr) & DIR)) {
outb_control(orig_HCR,addr);
if (elp_debug > 0)
......@@ -1462,8 +1474,8 @@ static struct device dev_3c505 = {
0, 0,
0, 0, 0, NULL, elplus_probe };
static int io = 0x300;
static int irq = 0;
int io = 0x300;
int irq = 0;
int init_module(void)
{
......
/* arcnet.c
Written 1994-95 by Avery Pennarun, derived from skeleton.c by
Donald Becker.
Written 1994-95 by Avery Pennarun, derived from skeleton.c by Donald
Becker.
Contact Avery at: apenwarr@foxnet.net or
RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
......@@ -17,6 +17,38 @@
**********************
v2.20 ALPHA (95/11/12)
- Added a bit of protocol confusion to the arc0 code to allow
trxnet-compatible IPX support - and the use of all that new
Linux-IPX stuff (including lwared). Just tell the ipx_interface
command that arc0 uses 802.3 (other protocols will probably also
work).
- Fixed lp->stats to update tx_packets on all devices, not just
arc0. Also, changed a lot of the error counting to make more
sense.
- rx_packets on arc0 was being updated for each completely received
packet. It now updates for each segment received, which makes
more sense.
- Removed unneeded extra check of dev->start in arcnet_inthandler.
- Included someone else's fixes from kernel 1.3.39. Does it still
work with kernel 1.2?
- Added a new define to disable PRINTING (not checking) of RECON
messages.
- Separated the duplicated error checking code from the various
arcnet??_send_packet routines into a new function.
- Cleaned up lock variables and ping-pong buffers a bit. This
should mean more stability, fewer missing packets, and less ugly
debug messages. Assuming it works.
- Changed the format of debug messages to always include the actual
device name instead of just "arcnet:". Used more macros to
shorten debugging code even more.
- Finally squashed the "startup NULL pointer" bug. irq2dev_map
wasn't being cleared to NULL when the driver was closed.
- Improved RECON checking; if a certain number of RECON messages
are received within one minute, a warning message is printed
to the effect of "cabling problem." One-log-message-per-recon
now defaults to OFF.
v2.12 ALPHA (95/10/27)
- Tried to improve skb handling and init code to fix problems with
the latest 1.3.x kernels. (We no longer use ether_setup except
......@@ -94,13 +126,14 @@
if there aren't any ARCnet cards in the system. And why shouldn't
it work as a module again?
- Rewrite autoprobe.
- Make sure RESET flag is cleared during an IRQ even if dev->start==0;
mainly a portability fix. This will confuse autoprobe a bit, so
test that too.
- What about cards with shared memory that can be "turned off?"
- NFS mount freezes after several megabytes to SOSS for DOS.
unmount/remount fixes it. Is this arcnet-specific? I don't know.
- Some newer ARCnets support promiscuous mode, supposedly.
If someone sends me information, I'll try to implement it.
- Find and remove excess lock variables that are probably not
necessary anymore due to the changes in Linux 1.2.9.
- Some newer ARCnets support promiscuous mode, supposedly. If
someone sends me information, I'll try to implement it.
- Dump Linux 1.2 support and its ugly #ifdefs.
- Add support for the new 1.3.x IP header cache features.
- ATA protocol support??
......@@ -123,11 +156,14 @@
*/
static const char *version =
"arcnet.c:v2.12 ALPHA 95/10/27 Avery Pennarun <apenwarr@foxnet.net>\n";
"arcnet.c: v2.20 ALPHA 95/11/12 Avery Pennarun <apenwarr@foxnet.net>\n";
#include <linux/module.h>
#include <linux/module.h>
#include <linux/config.h>
#include <linux/version.h>
/* are we Linux 1.2.x? */
#if LINUX_VERSION_CODE < 0x10300
#define LINUX12
......@@ -152,7 +188,7 @@ static const char *version =
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/config.h> /* for CONFIG_INET */
/*#include <linux/config.h>*/ /* For CONFIG_INET */
#include <asm/system.h>
#include <asm/bitops.h>
......@@ -167,18 +203,34 @@ static const char *version =
/**************************************************************************/
/* Define this if you want to detect network reconfigurations.
* They may be a real nuisance on a larger ARCnet network: but if you are
* a network administrator you probably would like to count them.
* Reconfigurations will be recorded in stats.tx_carrier_errors
* (the last field of the /proc/net/dev file).
*
* The card sends the reconfiguration signal when it loses the connection
* to the rest of its network. It is a 'Hello, is anybody there?' cry. This
/* The card sends the reconfiguration signal when it loses the connection to
* the rest of its network. It is a 'Hello, is anybody there?' cry. This
* usually happens when a new computer on the network is powered on or when
* the cable is broken.
*
* Define DETECT_RECONFIGS if you want to detect network reconfigurations.
* They may be a real nuisance on a larger ARCnet network; if you are a
* network administrator you probably would like to count them.
* Reconfigurations will be recorded in stats.tx_carrier_errors (the last
* field of the /proc/net/dev file).
*
* Define SHOW_RECONFIGS if you really want to see a log message whenever
* a RECON occurs.
*/
#define DETECT_RECONFIGS
#undef SHOW_RECONFIGS
/* RECON_THRESHOLD is the maximum number of RECON messages to receive within
* one minute before printing a "cabling problem" warning. You must have
* DETECT_RECONFIGS enabled if you want to use this. The default value
* should be fine.
*
* After that, a "cabling restored" message will be printed on the next IRQ
* if no RECON messages have been received for 10 seconds.
*
* Do not define RECON_THRESHOLD at all if you want to disable this feature.
*/
#define RECON_THRESHOLD 30
/* Define this if you want to make sure transmitted packets are "acknowledged"
* by the destination host, as long as they're not to the broadcast address.
......@@ -190,26 +242,33 @@ static const char *version =
*/
#define VERIFY_ACK
/* Define this to the minimum "timeout" value. If a transmit takes longer
* than TX_TIMEOUT jiffies, Linux will abort the TX and retry. On a large
* network, or one with heavy network traffic, this timeout may need to be
* increased.
*/
#define TX_TIMEOUT 20
/* Define this if you want to make it easier to use the "call trace" when
* a kernel NULL pointer assignment occurs. Hopefully unnecessary, most of
* the time. It will make all the function names (and other things) show
* up as kernel symbols. (especially handy when using arcnet as a module)
*/
#define static
#undef static
/**************************************************************************/
/* new debugging bitflags: each option can be enabled individually.
/* New debugging bitflags: each option can be enabled individually.
*
* these can be set while the driver is running by typing:
* These can be set while the driver is running by typing:
* ifconfig arc0 down metric 1xxx HOSTNAME
* where 1xxx is 1000 + the debug level you want
* and HOSTNAME is your hostname/ip address
* and then resetting your routes.
*
* Note: only debug flags included in the ARCNET_DEBUG_MAX define will
* actually be available. GCC (at least 2.7.0) will notice lines
* using a BUGLVL not in ARCNET_DEBUG_MAX and automatically optimize
* actually be available. GCC will (at least, GCC 2.7.0 will) notice
* lines using a BUGLVL not in ARCNET_DEBUG_MAX and automatically optimize
* them out.
*/
#define D_NORMAL 1 /* D_NORMAL normal operational info */
......@@ -233,8 +292,9 @@ static const char *version =
#endif
int arcnet_debug = ARCNET_DEBUG;
/* macro to simplify debug checking */
/* macros to simplify debug checking */
#define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x))
#define BUGMSG(x,msg,args...) BUGLVL(x) printk("%6s: " msg, dev->name , ## args);
#ifndef HAVE_AUTOIRQ
/* From auto_irq.c, in ioport.h for later versions. */
......@@ -257,12 +317,14 @@ extern struct device *irq2dev_map[16];
#define IF_TBUSY (lp->adev->tbusy \
|| lp->edev->tbusy \
|| lp->sdev->tbusy)
#define INTERRUPT lp->adev->interrupt \
=lp->edev->interrupt \
=lp->sdev->interrupt
#define IF_INTERRUPT (lp->adev->interrupt \
|| lp->edev->interrupt \
|| lp->sdev->interrupt)
#define START lp->adev->start \
=lp->edev->start \
=lp->sdev->start
......@@ -343,7 +405,7 @@ extern struct device *irq2dev_map[16];
#define NORMALconf 0x00 /* 1-249 byte packets */
#define EXTconf 0x08 /* 250-504 byte packets */
/* buffers (4 total) used for receive and xmit.
/* Starts receiving packets into recbuf.
*/
#define EnableReceiver() outb(RXcmd|(recbuf<<3)|RXbcasts,COMMAND)
......@@ -361,7 +423,7 @@ extern struct device *irq2dev_map[16];
#define ARC_P_ETHER 0xE8
/* Unsupported/indirectly supported protocols */
#define ARC_P_LANSOFT 251 /* 0xFB */
#define ARC_P_LANSOFT 251 /* 0xFB - what is this? */
#define ARC_P_ATALK 0xDD
/* the header required by the card itself */
......@@ -461,6 +523,13 @@ struct arcnet_local {
sending; /* transmit in progress? */
short tx_left; /* segments of split packet left to TX */
#if defined(DETECT_RECONFIGS) && defined(RECON_THRESHOLD)
time_t first_recon, /* time of "first" RECON message to count */
last_recon; /* time of most recent RECON */
int num_recons, /* number of RECONs between first and last. */
network_down; /* do we think the network is down? */
#endif
struct timer_list timer; /* the timer interrupt struct */
struct Incoming incoming[256]; /* one from each address */
struct Outgoing outgoing; /* packet currently being sent */
......@@ -485,13 +554,14 @@ static int arcnet_open(struct device *dev);
static int arcnet_close(struct device *dev);
static int arcnet_reset(struct device *dev);
static int arcnet_send_packet_bad(struct sk_buff *skb,struct device *dev);
static int arcnetA_send_packet(struct sk_buff *skb, struct device *dev);
static int arcnetE_send_packet(struct sk_buff *skb, struct device *dev);
static int arcnetS_send_packet(struct sk_buff *skb, struct device *dev);
static void arcnetA_continue_tx(struct device *dev);
static void arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
char *data,int length,int daddr,int exceptA);
static void arcnetAS_go_tx(struct device *dev);
static int arcnet_go_tx(struct device *dev,int enable_irq);
static void arcnet_interrupt(int irq,struct pt_regs *regs);
static void arcnet_inthandler(struct device *dev);
......@@ -608,8 +678,7 @@ arcnet_probe(struct device *dev)
}
#endif
BUGLVL(D_INIT)
printk("arcnet: given: base %lXh, IRQ %Xh, shmem %lXh\n",
BUGMSG(D_INIT,"given: base %lXh, IRQ %Xh, shmem %lXh\n",
dev->base_addr,dev->irq,dev->mem_start);
#ifndef MODULE
......@@ -622,8 +691,7 @@ arcnet_probe(struct device *dev)
int ioaddr = *port;
if (check_region(ioaddr, ARCNET_TOTAL_SIZE))
{
BUGLVL(D_INIT)
printk("arcnet: Skipping %Xh because of check_region...\n",
BUGMSG(D_INIT,"Skipping %Xh because of check_region...\n",
ioaddr);
continue;
}
......@@ -637,13 +705,11 @@ arcnet_probe(struct device *dev)
/* ioprobe turned out okay. Now give it a couple seconds to finish
* initializing...
*/
BUGLVL(D_INIT)
printk("arcnet: ioprobe okay! Waiting for reset...\n");
BUGMSG(D_INIT,"ioprobe okay! Waiting for reset...\n");
JIFFER(100);
/* okay, now we have to find the shared memory area. */
BUGLVL(D_INIT)
printk("arcnet: starting memory probe, given %lXh\n",
BUGMSG(D_INIT,"starting memory probe, given %lXh\n",
dev->mem_start);
if (dev->mem_start) /* value given - probe just that one */
{
......@@ -663,9 +729,11 @@ arcnet_probe(struct device *dev)
if (!dev->base_addr || !dev->irq || !dev->mem_start
|| !dev->rmem_start)
{
printk("arcnet: loadable modules can't autoprobe!\n");
printk("arcnet: try using io=, irqnum=, and shmem= on the insmod line.\n");
printk("arcnet: you may also need num= to change the device name. (ie. num=1 for arc1)\n");
printk("%6s: loadable modules can't autoprobe!\n",dev->name);
printk("%6s: try using io=, irqnum=, and shmem= on the insmod line.\n",
dev->name);
printk("%6s: you may also need num= to change the device name. (ie. num=1 for arc1)\n",
dev->name);
return ENODEV;
}
#endif
......@@ -674,7 +742,7 @@ arcnet_probe(struct device *dev)
int irqval = request_irq(dev->irq, &arcnet_interrupt, 0,
"arcnet");
if (irqval) {
printk("%s: unable to get IRQ %d (irqval=%d).\n",
printk("%6s: unable to get IRQ %d (irqval=%d).\n",
dev->name,dev->irq, irqval);
return EAGAIN;
}
......@@ -683,7 +751,7 @@ arcnet_probe(struct device *dev)
/* Grab the region so we can find another board if autoIRQ fails. */
request_region(dev->base_addr, ARCNET_TOTAL_SIZE,"arcnet");
printk("%s: ARCnet card found at %03lXh, IRQ %d, ShMem at %lXh.\n",
printk("%6s: ARCnet card found at %03lXh, IRQ %d, ShMem at %lXh.\n",
dev->name, dev->base_addr, dev->irq, dev->mem_start);
/* Initialize the device structure. */
......@@ -709,24 +777,26 @@ arcnet_probe(struct device *dev)
/* And now fill particular fields with arcnet values */
dev->mtu=1500; /* completely arbitrary - agrees with ether, though */
dev->hard_header_len=sizeof(struct ClientData);
BUGLVL(D_DURING)
printk("arcnet: ClientData header size is %d.\narcnet: HardHeader size is %d.\n",
sizeof(struct ClientData),sizeof(struct HardHeader));
BUGMSG(D_DURING,"ClientData header size is %d.\n",
sizeof(struct ClientData));
BUGMSG(D_DURING,"HardHeader size is %d.\n",
sizeof(struct HardHeader));
/* since we strip EXTRA_CLIENTDATA bytes off before sending,
* we let Linux add that many bytes to the packet data...
*/
BUGLVL(D_INIT) printk("arcnet: arcnet_probe: resetting card.\n");
BUGMSG(D_INIT,"arcnet_probe: resetting card.\n");
arcnet_reset(dev);
JIFFER(50);
BUGLVL(D_NORMAL)
printk("arcnet: We appear to be station %d (%02Xh)\n",
BUGMSG(D_NORMAL,"We appear to be station %d (%02Xh)\n",
lp->arcnum,lp->arcnum);
if (lp->arcnum==0)
printk("arcnet: WARNING! Station address 0 is reserved for broadcasts!\n");
printk("%6s: WARNING! Station address 0 is reserved for broadcasts!\n",
dev->name);
if (lp->arcnum==255)
printk("arcnet: WARNING! Station address 255 may confuse DOS networking programs!\n");
printk("%6s: WARNING! Station address 255 may confuse DOS networking programs!\n",
dev->name);
dev->dev_addr[0]=lp->arcnum;
lp->sequence=1;
lp->recbuf=0;
......@@ -747,11 +817,8 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
{
int delayval,airq;
BUGLVL(D_INIT)
{
printk("arcnet: probing address %Xh\n",ioaddr);
printk("arcnet: status1=%Xh\n",inb(STATUS));
}
BUGMSG(D_INIT,"probing address %Xh\n",ioaddr);
BUGMSG(D_INIT," status1=%Xh\n",inb(STATUS));
/* very simple - all we have to do is reset the card, and if there's
......@@ -766,8 +833,7 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
/* if status port is FF, there's certainly no arcnet... give up. */
if (inb(STATUS)==0xFF)
{
BUGLVL(D_INIT)
printk("arcnet: probe failed. Status port empty.\n");
BUGMSG(D_INIT," probe failed. Status port empty.\n");
return ENODEV;
}
......@@ -787,22 +853,20 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
if (curval==initval)
{
printk("arcnet: probe failed. never-changing command port (%02Xh).\n",
BUGLVL(D_INIT," probe failed. never-changing command port (%02Xh).\n",
initval);
return ENODEV;
}
}
#endif
BUGLVL(D_INIT)
printk("arcnet: status2=%Xh\n",inb(STATUS));
BUGMSG(D_INIT," status2=%Xh\n",inb(STATUS));
/* now we turn the reset bit off so we can IRQ next reset... */
outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
if (inb(STATUS) & RESETflag) /* reset flag STILL on */
{
BUGLVL(D_INIT)
printk("arcnet: probe failed. eternal reset flag1...(status=%Xh)\n",
BUGMSG(D_INIT," probe failed. eternal reset flag1...(status=%Xh)\n",
inb(STATUS));
return ENODEV;
}
......@@ -827,15 +891,14 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
airq = autoirq_report(0);
BUGLVL(D_INIT) if (airq)
printk("arcnet: autoirq is %d\n", airq);
printk("%6s: autoirq is %d\n", dev->name, airq);
/* if there was no autoirq AND the user hasn't set any defaults,
* give up.
*/
if (!airq && !(dev->base_addr && dev->irq))
{
BUGLVL(D_INIT)
printk("arcnet: probe failed. no autoirq...\n");
BUGMSG(D_INIT," probe failed. no autoirq...\n");
return ENODEV;
}
......@@ -849,8 +912,7 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
if (inb(STATUS) & RESETflag) /* reset flag STILL on */
{
BUGLVL(D_INIT)
printk("arcnet: probe failed. eternal reset flag...(status=%Xh)\n",
BUGMSG(D_INIT," probe failed. eternal reset flag...(status=%Xh)\n",
inb(STATUS));
return ENODEV;
}
......@@ -865,13 +927,11 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
}
else if (dev->irq == 2)
{
BUGLVL(D_NORMAL)
printk("arcnet: IRQ2 == IRQ9, don't worry.\n");
BUGMSG(D_NORMAL,"IRQ2 == IRQ9, don't worry.\n");
dev->irq = 9;
}
BUGLVL(D_INIT)
printk("arcnet: irq and base address seem okay. (%lXh, IRQ %d)\n",
BUGMSG(D_INIT,"irq and base address seem okay. (%lXh, IRQ %d)\n",
dev->base_addr,dev->irq);
return 0;
}
......@@ -883,16 +943,14 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
*/
int arcnet_memprobe(struct device *dev,u_char *addr)
{
BUGLVL(D_INIT)
printk("arcnet: probing memory at %lXh\n",(u_long)addr);
BUGMSG(D_INIT,"probing memory at %lXh\n",(u_long)addr);
dev->mem_start=0;
/* ARCnet memory byte 0 is TESTvalue */
if (addr[0]!=TESTvalue)
{
BUGLVL(D_INIT)
printk("arcnet: probe failed. addr=%lXh, addr[0]=%Xh (not %Xh)\n",
BUGMSG(D_INIT," probe failed. addr=%lXh, addr[0]=%Xh (not %Xh)\n",
(unsigned long)addr,addr[0],TESTvalue);
return ENODEV;
}
......@@ -901,8 +959,7 @@ int arcnet_memprobe(struct device *dev,u_char *addr)
addr[0]=0x42;
if (addr[0]!=0x42)
{
BUGLVL(D_INIT)
printk("arcnet: probe failed. addr=%lXh, addr[0]=%Xh (not 42h)\n",
BUGMSG(D_INIT," probe failed. addr=%lXh, addr[0]=%Xh (not 42h)\n",
(unsigned long)addr,addr[0]);
return ENODEV;
}
......@@ -930,8 +987,7 @@ int arcnet_reset(struct device *dev)
outb(0,INTMASK); /* no IRQ's, please! */
BUGLVL(D_INIT)
printk("arcnet: Resetting %s (status=%Xh)\n",
BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
dev->name,inb(STATUS));
inb(RESET); /* Reset by reading this port */
......@@ -946,8 +1002,7 @@ int arcnet_reset(struct device *dev)
cardmem = (u_char *) dev->mem_start;
if (cardmem[0] != TESTvalue)
{
BUGLVL(D_INIT)
printk("arcnet: reset failed: TESTvalue not present.\n");
BUGMSG(D_INIT,"reset failed: TESTvalue not present.\n");
return 1;
}
lp->arcnum=cardmem[1]; /* save address for later use */
......@@ -1016,9 +1071,7 @@ static int arcnetE_init(struct device *dev)
dev->stop=NULL;
dev->hard_start_xmit=arcnetE_send_packet;
BUGLVL(D_EXTRA)
printk("%s: ARCnet Ethernet-Encap protocol initialized.\n",
dev->name);
BUGMSG(D_EXTRA,"ARCnet Ethernet-Encap protocol initialized.\n");
return 0;
}
......@@ -1044,9 +1097,7 @@ static int arcnetS_init(struct device *dev)
#ifdef LINUX12
dev->type_trans=arcnetS_type_trans;
#endif
BUGLVL(D_EXTRA)
printk("%s: ARCnet RFC1051 (NetBsd, AmiTCP) protocol initialized.\n",
dev->name);
BUGMSG(D_EXTRA,"ARCnet RFC1051 (NetBsd, AmiTCP) protocol initialized.\n");
return 0;
}
......@@ -1075,7 +1126,7 @@ arcnet_open(struct device *dev)
if (dev->metric>=1000)
{
arcnet_debug=dev->metric-1000;
printk("arcnet: debug level set to %d\n",arcnet_debug);
printk("%6s: debug level set to %d\n",dev->name,arcnet_debug);
dev->metric=1;
}
......@@ -1083,7 +1134,7 @@ arcnet_open(struct device *dev)
irq2dev_map[dev->irq] = dev;
BUGLVL(D_EXTRA) printk("arcnet: arcnet_open: resetting card.\n");
BUGMSG(D_EXTRA,"arcnet_open: resetting card.\n");
/* try to reset - twice if it fails the first time */
if (arcnet_reset(dev) && arcnet_reset(dev))
......@@ -1096,9 +1147,7 @@ arcnet_open(struct device *dev)
/* The RFC1201 driver is the default - just store */
lp->adev=dev;
BUGLVL(D_EXTRA)
printk("%s: ARCnet RFC1201 protocol initialized.\n",
lp->adev->name);
BUGMSG(D_EXTRA,"ARCnet RFC1201 protocol initialized.\n");
/* Initialize the ethernet-encap protocol driver */
lp->edev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL);
......@@ -1135,7 +1184,6 @@ arcnet_open(struct device *dev)
outb(NORXflag|RECON_flag,INTMASK);
MOD_INC_USE_COUNT;
return 0;
}
......@@ -1151,6 +1199,10 @@ arcnet_close(struct device *dev)
TBUSY=1;
START=0;
/* very important! */
irq2dev_map[dev->irq] = NULL;
/* Flush TX and disable RX */
outb(0,INTMASK); /* no IRQ's (except RESET, of course) */
outb(NOTXcmd,COMMAND); /* stop transmit */
......@@ -1178,10 +1230,9 @@ arcnet_close(struct device *dev)
kfree(lp->sdev);
lp->sdev=NULL;
/* Update the statistics here. */
/* Update the statistics here. (not necessary in ARCnet) */
MOD_DEC_USE_COUNT;
return 0;
}
......@@ -1193,25 +1244,28 @@ arcnet_close(struct device *dev)
* *
****************************************************************************/
/* Called by the kernel in order to transmit a packet.
/* Generic error checking routine for arcnet??_send_packet
*/
static int
arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr;
lp->intx++;
BUGLVL(D_DURING)
printk("arcnet: transmit requested (status=%Xh, inTX=%d)\n",
BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
inb(STATUS),lp->intx);
if (lp->in_txhandler)
{
printk("arcnet: send_packet called while in txhandler!\n");
lp->intx--;
BUGMSG(D_NORMAL,"send_packet called while in txhandler!\n");
lp->stats.tx_dropped++;
return 1;
}
if (lp->intx>1)
{
BUGMSG(D_NORMAL,"send_packet called while intx!\n");
lp->stats.tx_dropped++;
return 1;
}
......@@ -1220,34 +1274,37 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
/* If we get here, some higher level has decided we are broken.
There should really be a "kick me" function call instead. */
int tickssofar = jiffies - dev->trans_start;
int recbuf=lp->recbuf;
/*int recbuf=lp->recbuf;*/
int status=inb(STATUS);
if (tickssofar < 5)
if (tickssofar < TX_TIMEOUT)
{
BUGLVL(D_DURING)
printk("arcnet: premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n",
BUGMSG(D_DURING,"premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n",
status,tickssofar,lp->outgoing.skb,
lp->outgoing.numsegs,
lp->outgoing.segnum);
lp->intx--;
return 1;
}
BUGLVL(D_EXTRA)
printk("arcnet: transmit timed out (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n",
status,lp->intx,lp->in_txhandler,tickssofar);
outb(0,INTMASK);
if (status&TXFREEflag) /* transmit _DID_ finish */
{
BUGMSG(D_EXTRA,"tx timed out - missed IRQ? (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n",
status,lp->intx,
lp->in_txhandler,tickssofar);
lp->stats.tx_errors++;
}
else
{
BUGMSG(D_NORMAL,"tx timed out (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n",
status,lp->intx,
lp->in_txhandler,tickssofar);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
/* Try to restart the adaptor. */
/*arcnet_reset(dev);*/
outb(0,INTMASK);
if (status&NORXflag) EnableReceiver();
if (!(status&TXFREEflag))
outb(NOTXcmd,COMMAND);
/*dev->trans_start = jiffies;*/
}
if (lp->outgoing.skb)
{
......@@ -1257,12 +1314,8 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
lp->outgoing.skb=NULL;
TBUSY=0;
lp->intx--;
/*lp->intx=0;*/
/*lp->in_txhandler=0;*/
lp->txready=0;
lp->sending=0;
/*mark_bh(NET_BH);*/
outb(NORXflag|RECON_flag,INTMASK);
......@@ -1273,23 +1326,22 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
we are passed NULL. Caution: dev_tint() handles the cli()/sti()
itself. */
if (skb == NULL) {
printk("arcnet: tx passed null skb (status=%Xh, inTX=%d, tickssofar=%ld)\n",
inb(STATUS),lp->intx,jiffies-dev->trans_start);
printk("%6s: tx passed null skb (status=%Xh, inTX=%d, tickssofar=%ld)\n",
dev->name,inb(STATUS),lp->intx,jiffies-dev->trans_start);
lp->stats.tx_errors++;
dev_tint(dev);
lp->intx--;
return 0;
}
if (lp->txready) /* transmit already in progress! */
{
printk("arcnet: trying to start new packet while busy! (status=%Xh)\n",
inb(STATUS));
/*printk("arcnet: marking as not ready.\n");*/
printk("%6s: trying to start new packet while busy! (status=%Xh)\n",
dev->name,inb(STATUS));
outb(0,INTMASK);
outb(NOTXcmd,COMMAND); /* abort current send */
arcnet_inthandler(dev); /* fake an interrupt */
lp->stats.tx_errors++;
lp->intx--;
lp->stats.tx_fifo_errors++;
lp->txready=0; /* we definitely need this line! */
return 1;
......@@ -1299,14 +1351,38 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (set_bit(0, (void*)&dev->tbusy) != 0)
{
printk("arcnet: transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
inb(STATUS),lp->intx,jiffies-dev->trans_start);
lp->intx--;
printk("%6s: transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
dev->name,inb(STATUS),lp->intx,jiffies-dev->trans_start);
lp->stats.tx_errors++;
lp->stats.tx_fifo_errors++;
return -EBUSY;
}
else {
return 0;
}
/* Called by the kernel in order to transmit a packet.
*/
static int
arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr,bad;
struct Outgoing *out=&(lp->outgoing);
BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
inb(STATUS),lp->intx);
lp->intx++;
bad=arcnet_send_packet_bad(skb,dev);
if (bad)
{
lp->intx--;
return bad;
}
TBUSY=1;
out->length = 1 < skb->len ? skb->len : 1;
......@@ -1326,18 +1402,16 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
out->hdr->sequence=(lp->sequence++);
if (lp->txready && inb(STATUS)&TXFREEflag)
arcnetAS_go_tx(dev);
/*arcnet_go_tx(dev);*/ /* Make sure buffers are clear */
/* fits in one packet? */
if (out->length-EXTRA_CLIENTDATA<=XMTU)
{
BUGLVL(D_DURING)
printk("arcnet: not splitting %d-byte packet. (split_flag=%d)\n",
BUGMSG(D_DURING,"not splitting %d-byte packet. (split_flag=%d)\n",
out->length,out->hdr->split_flag);
BUGLVL(D_EXTRA) if (out->hdr->split_flag)
printk("arcnet: short packet has split_flag set?! (split_flag=%d)\n",
out->hdr->split_flag);
printk("%6s: short packet has split_flag set?! (split_flag=%d)\n",
dev->name,out->hdr->split_flag);
out->numsegs=1;
out->segnum=1;
arcnetAS_prepare_tx(dev,
......@@ -1351,10 +1425,8 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
dev_kfree_skb(out->skb,FREE_WRITE);
out->skb=NULL;
if (!lp->sending)
if (arcnet_go_tx(dev,1))
{
arcnetAS_go_tx(dev);
/* inform upper layers */
TBUSY=0;
mark_bh(NET_BH);
......@@ -1371,12 +1443,11 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
out->segnum=0;
BUGLVL(D_TX) printk("arcnet: packet (%d bytes) split into %d fragments:\n",
BUGMSG(D_TX,"packet (%d bytes) split into %d fragments:\n",
out->length,out->numsegs);
/* if a packet waiting, launch it */
if (lp->txready && inb(STATUS)&TXFREEflag)
arcnetAS_go_tx(dev);
arcnet_go_tx(dev,1);
if (!lp->txready)
{
......@@ -1384,12 +1455,10 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
* another.
*/
arcnetA_continue_tx(dev);
if (!lp->sending)
if (arcnet_go_tx(dev,1))
{
arcnetAS_go_tx(dev);
arcnetA_continue_tx(dev);
if (!lp->sending)
arcnetAS_go_tx(dev);
arcnet_go_tx(dev,1);
}
}
......@@ -1405,147 +1474,101 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
out->skb=NULL;
}
}
}
lp->intx--;
lp->stats.tx_packets++;
dev->trans_start=jiffies;
lp->intx--;
return 0;
}
/* After an RFC1201 split packet has been set up, this function calls
* arcnetAS_prepare_tx to load the next segment into the card. This function
* does NOT automatically call arcnetAS_go_tx to allow for easier double-
* buffering.
/* Called by the kernel in order to transmit an ethernet-type packet.
*/
static void arcnetA_continue_tx(struct device *dev)
static int
arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int maxsegsize=XMTU-4;
struct Outgoing *out=&(lp->outgoing);
int bad;
union ArcPacket *arcpacket =
(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
u_char *arcsoft,daddr;
short offset,length=skb->len+1;
if (lp->txready)
{
printk("arcnet: continue_tx: called with packet in buffer!\n");
return;
}
BUGMSG(D_DURING,"in arcnetE_send_packet (skb=%p)\n",skb);
if (out->segnum>=out->numsegs)
lp->intx++;
bad=arcnet_send_packet_bad(skb,dev);
if (bad)
{
printk("arcnet: continue_tx: building segment %d of %d!\n",
out->segnum+1,out->numsegs);
lp->intx--;
return bad;
}
if (!out->segnum) /* first packet */
out->hdr->split_flag=((out->numsegs-2)<<1)+1;
else
out->hdr->split_flag=out->segnum<<1;
out->seglen=maxsegsize;
if (out->seglen>out->dataleft) out->seglen=out->dataleft;
BUGLVL(D_TX) printk("arcnet: building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n",
out->segnum+1,out->seglen,out->numsegs,
out->length,out->hdr->split_flag);
arcnetAS_prepare_tx(dev,((char *)out->hdr)+EXTRA_CLIENTDATA,
sizeof(struct ClientData)-EXTRA_CLIENTDATA,
out->data,out->seglen,out->hdr->daddr,1);
out->dataleft-=out->seglen;
out->data+=out->seglen;
out->segnum++;
}
TBUSY=1;
/* Given an skb, copy a packet into the ARCnet buffers for later transmission
* by arcnetAS_go_tx.
*/
static void
arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
char *data,int length,int daddr,int exceptA)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
struct ClientData *arcsoft;
union ArcPacket *arcpacket =
(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
int offset;
if (length>XMTU)
{
printk("%6s: MTU must be <= 493 for ethernet encap (length=%d).\n",
dev->name,length);
printk("%6s: transmit aborted.\n",dev->name);
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */
dev_kfree_skb(skb,FREE_WRITE);
return 0;
}
length+=hdrlen;
BUGMSG(D_DURING,"starting tx sequence...\n");
BUGLVL(D_TX)
printk("arcnet: arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
hdr,length,data);
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate btw 2 & 3 */
/* clean out the page to make debugging make more sense :) */
BUGLVL(D_DURING)
memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
arcpacket->hardheader.destination=daddr;
/* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF)
daddr=arcpacket->hardheader.destination=0;
else
daddr=arcpacket->hardheader.destination=
((struct ethhdr*)(skb->data))->h_dest[5];
/* load packet into shared memory */
if (length<=MTU) /* Normal (256-byte) Packet */
{
arcpacket->hardheader.offset1=offset=256-length;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset]);
}
else if (length>=MinTU) /* Extended (512-byte) Packet */
offset=512-length;
if (length>MTU) /* long/exception packet */
{
if (length<MinTU) offset-=3;
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=512-length;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset]);
arcpacket->hardheader.offset2=offset;
}
else if (exceptA) /* RFC1201 Exception Packet */
else /* short packet */
{
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=512-length-4;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset+4]);
/* exception-specific stuff - these four bytes
* make the packet long enough to fit in a 512-byte
* frame.
*/
arcpacket->raw[offset+0]=hdr[0];
arcpacket->raw[offset+1]=0xFF; /* FF flag */
arcpacket->raw[offset+2]=0xFF; /* FF padding */
arcpacket->raw[offset+3]=0xFF; /* FF padding */
arcpacket->hardheader.offset1=(offset-=256);
}
else /* "other" Exception packet */
{
/* RFC1051 - set 4 trailing bytes to 0 */
memset(&arcpacket->raw[508],0,4);
/* now round up to MinTU */
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=512-MinTU;
arcsoft=(struct ClientData *)(&arcpacket->raw[offset]);
}
BUGMSG(D_DURING," length=%Xh, offset=%Xh, offset1=%Xh, offset2=%Xh\n",
length,offset,arcpacket->hardheader.offset1,
arcpacket->hardheader.offset2);
arcsoft=&arcpacket->raw[offset];
arcsoft[0]=ARC_P_ETHER;
arcsoft++;
/* copy the packet into ARCnet shmem
* - the first bytes of ClientData header are skipped
*/
memcpy((u_char*)arcsoft,
(u_char*)hdr,hdrlen);
memcpy((u_char*)arcsoft+hdrlen,
data,length-hdrlen);
BUGMSG(D_DURING,"ready to memcpy\n");
memcpy(arcsoft,skb->data,skb->len);
BUGLVL(D_DURING) printk("arcnet: transmitting packet to station %02Xh (%d bytes)\n",
BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
daddr,length);
BUGLVL(D_TX)
{
int countx,county;
printk("arcnet: packet dump [tx] follows:");
printk("%6s: packet dump [tx] follows:",dev->name);
for (county=0; county<16+(length>MTU)*16; county++)
for (county=0; county<16+(length>=240)*16; county++)
{
printk("\n[%04X] ",county*16);
for (countx=0; countx<16; countx++)
......@@ -1560,151 +1583,229 @@ arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
lp->outgoing.lastload_dest=daddr;
#endif
lp->txready=lp->txbuf; /* packet is ready for sending */
}
/* Actually start transmitting a packet that was placed in the card's
* buffer by arcnetAS_prepare_tx.
*/
static void
arcnetAS_go_tx(struct device *dev)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr;
BUGLVL(D_DURING)
printk("arcnet: go_tx: status=%Xh\n",
inb(STATUS));
dev_kfree_skb(skb,FREE_WRITE);
if (!(inb(STATUS)&TXFREEflag) || !lp->txready) return;
if (arcnet_go_tx(dev,1))
{
/* inform upper layers */
TBUSY=0;
mark_bh(NET_BH);
}
/* start sending */
outb(TXcmd|(lp->txready<<3),COMMAND);
dev->trans_start=jiffies;
lp->intx--;
return 0;
}
outb(TXFREEflag|NORXflag|RECON_flag,INTMASK);
dev->trans_start = jiffies;
lp->txready=0;
lp->sending++;
#ifdef VERIFY_ACK
lp->outgoing.lasttrans_dest=lp->outgoing.lastload_dest;
lp->outgoing.lastload_dest=0;
#endif
}
/* Called by the kernel in order to transmit an ethernet-type packet.
/* Called by the kernel in order to transmit an RFC1051-type packet.
*/
static int
arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr,bad,length;
struct S_ClientData *hdr=(struct S_ClientData *)skb->data;
BUGLVL(D_DURING)
printk("%s: in arcnetE_send_packet (skb=%p)\n",dev->name,skb);
lp->intx++;
if (IF_TBUSY)
{
/* If we get here, some higher level has decided we are broken.
There should really be a "kick me" function call instead. */
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 10)
return 1;
printk("%s: transmit timed out\n",dev->name);
BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
inb(STATUS),lp->intx);
/* Try to restart the adaptor. */
TBUSY=0;
/*dev->trans_start = jiffies;*/
return 0;
bad=arcnet_send_packet_bad(skb,dev);
if (bad)
{
lp->intx--;
return bad;
}
/* If some higher layer thinks we've missed an tx-done interrupt
we are passed NULL. Caution: dev_tint() handles the cli()/sti()
itself. */
if (skb == NULL)
TBUSY=1;
length = 1 < skb->len ? skb->len : 1;
BUGLVL(D_SKB)
{
dev_tint(dev);
return 0;
short i;
for(i=0; i<skb->len; i++)
{
if( i%16 == 0 ) printk("\n[%04hX] ",i);
printk("%02hX ",((unsigned char*)skb->data)[i]);
}
printk("\n");
}
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else
/*if (lp->txready && inb(STATUS)&TXFREEflag)
arcnet_go_tx(dev);*/
/* fits in one packet? */
if (length-S_EXTRA_CLIENTDATA<=XMTU)
{
union ArcPacket *arcpacket =
(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
u_char *arcsoft,daddr;
short offset,length=skb->len+1;
arcnetAS_prepare_tx(dev,
skb->data+S_EXTRA_CLIENTDATA,
sizeof(struct S_ClientData)-S_EXTRA_CLIENTDATA,
skb->data+sizeof(struct S_ClientData),
length-sizeof(struct S_ClientData),
hdr->daddr,0);
TBUSY=1;
/* done right away */
dev_kfree_skb(skb,FREE_WRITE);
if (length>XMTU)
if (arcnet_go_tx(dev,1))
{
printk("arcnet: MTU for %s and %s must be <= 493 for ethernet encap.\n",
lp->adev->name,lp->edev->name);
printk("arcnet: transmit aborted.\n");
/* inform upper layers */
TBUSY=0;
mark_bh(NET_BH);
}
}
else /* too big for one - not accepted */
{
printk("arcnetS: packet too long (length=%d)\n",
length);
dev_kfree_skb(skb,FREE_WRITE);
lp->stats.tx_dropped++;
TBUSY=0;
mark_bh(NET_BH);
}
dev->trans_start=jiffies;
lp->intx--;
return 0;
}
/* After an RFC1201 split packet has been set up, this function calls
* arcnetAS_prepare_tx to load the next segment into the card. This function
* does NOT automatically call arcnet_go_tx.
*/
static void arcnetA_continue_tx(struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int maxsegsize=XMTU-4;
struct Outgoing *out=&(lp->outgoing);
if (lp->txready)
{
printk("%6s: continue_tx: called with packet in buffer!\n",
dev->name);
return;
}
BUGLVL(D_DURING)
printk("arcnet: starting tx sequence...\n");
if (out->segnum>=out->numsegs)
{
printk("%6s: continue_tx: building segment %d of %d!\n",
dev->name,out->segnum+1,out->numsegs);
}
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate btw 2 & 3 */
if (!out->segnum) /* first packet */
out->hdr->split_flag=((out->numsegs-2)<<1)+1;
else
out->hdr->split_flag=out->segnum<<1;
out->seglen=maxsegsize;
if (out->seglen>out->dataleft) out->seglen=out->dataleft;
BUGMSG(D_TX,"building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n",
out->segnum+1,out->seglen,out->numsegs,
out->length,out->hdr->split_flag);
arcnetAS_prepare_tx(dev,((char *)out->hdr)+EXTRA_CLIENTDATA,
sizeof(struct ClientData)-EXTRA_CLIENTDATA,
out->data,out->seglen,out->hdr->daddr,1);
out->dataleft-=out->seglen;
out->data+=out->seglen;
out->segnum++;
}
/* Given an skb, copy a packet into the ARCnet buffers for later transmission
* by arcnet_go_tx.
*/
static void
arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
char *data,int length,int daddr,int exceptA)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
struct ClientData *arcsoft;
union ArcPacket *arcpacket =
(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
int offset;
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */
length+=hdrlen;
BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
hdr,length,data);
/* clean out the page to make debugging make more sense :) */
BUGLVL(D_DURING)
memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
/* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF)
daddr=arcpacket->hardheader.destination=0;
else
daddr=arcpacket->hardheader.destination=
((struct ethhdr*)(skb->data))->h_dest[5];
arcpacket->hardheader.destination=daddr;
/* load packet into shared memory */
offset=512-length;
if (length>MTU) /* long/exception packet */
if (length<=MTU) /* Normal (256-byte) Packet */
{
arcpacket->hardheader.offset1=offset=256-length;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset]);
}
else if (length>=MinTU) /* Extended (512-byte) Packet */
{
if (length<MinTU) offset-=3;
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset;
arcpacket->hardheader.offset2=offset=512-length;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset]);
}
else /* short packet */
else if (exceptA) /* RFC1201 Exception Packet */
{
arcpacket->hardheader.offset1=(offset-=256);
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=512-length-4;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset+4]);
/* exception-specific stuff - these four bytes
* make the packet long enough to fit in a 512-byte
* frame.
*/
arcpacket->raw[offset+0]=hdr[0];
arcpacket->raw[offset+1]=0xFF; /* FF flag */
arcpacket->raw[offset+2]=0xFF; /* FF padding */
arcpacket->raw[offset+3]=0xFF; /* FF padding */
}
else /* "other" Exception packet */
{
/* RFC1051 - set 4 trailing bytes to 0 */
memset(&arcpacket->raw[508],0,4);
BUGLVL(D_DURING)
printk("arcnet: length=%Xh, offset=%Xh, offset1=%Xh, offset2=%Xh\n",
length,offset,arcpacket->hardheader.offset1,
arcpacket->hardheader.offset2);
/* now round up to MinTU */
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=512-MinTU;
arcsoft=(struct ClientData *)(&arcpacket->raw[offset]);
}
arcsoft=&arcpacket->raw[offset];
arcsoft[0]=ARC_P_ETHER;
arcsoft++;
/* copy the packet into ARCnet shmem
* - the first bytes of ClientData header are skipped
*/
BUGLVL(D_DURING) printk("arcnet: ready to memcpy\n");
memcpy(arcsoft,skb->data,skb->len);
memcpy((u_char*)arcsoft,
(u_char*)hdr,hdrlen);
memcpy((u_char*)arcsoft+hdrlen,
data,length-hdrlen);
BUGLVL(D_DURING)
printk("arcnet: transmitting packet to station %02Xh (%d bytes)\n",
BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
daddr,length);
BUGLVL(D_TX)
{
int countx,county;
printk("arcnet: packet dump [tx] follows:");
printk("%6s: packet dump [tx] follows:",dev->name);
for (county=0; county<16+(length>=240)*16; county++)
for (county=0; county<16+(length>MTU)*16; county++)
{
printk("\n[%04X] ",county*16);
for (countx=0; countx<16; countx++)
......@@ -1715,194 +1816,57 @@ arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
printk("\n");
}
#ifdef VERIFY_ACK
#ifdef VERIFY_ACK
lp->outgoing.lastload_dest=daddr;
#endif
#endif
lp->txready=lp->txbuf; /* packet is ready for sending */
arcnetAS_go_tx(dev);
dev->trans_start = jiffies;
}
dev_kfree_skb(skb,FREE_WRITE);
return 0;
}
/* Called by the kernel in order to transmit an RFC1051-type packet.
/* Actually start transmitting a packet that was placed in the card's
* buffer by arcnetAS_prepare_tx. Returns 1 if a Tx is really started.
*/
static int
arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
arcnet_go_tx(struct device *dev,int enable_irq)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr;
lp->intx++;
BUGLVL(D_DURING)
printk("arcnetS: transmit requested (status=%Xh, inTX=%d)\n",
inb(STATUS),lp->intx);
if (lp->in_txhandler)
{
printk("arcnetS: send_packet called while in txhandler!\n");
lp->intx--;
return 1;
}
if (IF_TBUSY)
{
/* If we get here, some higher level has decided we are broken.
There should really be a "kick me" function call instead. */
int tickssofar = jiffies - dev->trans_start;
int recbuf=lp->recbuf;
int status=inb(STATUS);
if (tickssofar < 5)
{
BUGLVL(D_DURING)
printk("arcnetS: premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n",
status,tickssofar,lp->outgoing.skb,
lp->outgoing.numsegs,
lp->outgoing.segnum);
lp->intx--;
return 1;
}
BUGLVL(D_EXTRA)
printk("arcnetS: transmit timed out (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n",
status,lp->intx,lp->in_txhandler,tickssofar);
lp->stats.tx_errors++;
/* Try to restart the adaptor. */
/*arcnet_reset(dev);*/
BUGMSG(D_DURING,"go_tx: status=%Xh\n",
inb(STATUS));
outb(0,INTMASK);
if (status&NORXflag) EnableReceiver();
if (!(status&TXFREEflag)) outb(NOTXcmd,COMMAND);
/*dev->trans_start = jiffies;*/
if (lp->outgoing.skb)
if (lp->sending || !lp->txready)
{
dev_kfree_skb(lp->outgoing.skb,FREE_WRITE);
lp->stats.tx_dropped++;
}
lp->outgoing.skb=NULL;
TBUSY=0;
lp->intx--;
/*lp->intx=0;*/
/*lp->in_txhandler=0;*/
lp->txready=0;
lp->sending=0;
/*mark_bh(NET_BH);*/
if (enable_irq)
{
if (lp->sending)
outb(TXFREEflag|NORXflag|RECON_flag,INTMASK);
else
outb(NORXflag|RECON_flag,INTMASK);
return 1;
}
/* If some higher layer thinks we've missed a tx-done interrupt
we are passed NULL. Caution: dev_tint() handles the cli()/sti()
itself. */
if (skb == NULL) {
printk("arcnetS: tx passed null skb (status=%Xh, inTX=%d, tickssofar=%ld)\n",
inb(STATUS),lp->intx,jiffies-dev->trans_start);
dev_tint(dev);
lp->intx--;
return 0;
}
if (lp->txready) /* transmit already in progress! */
{
printk("arcnetS: trying to start new packet while busy! (status=%Xh)\n",
inb(STATUS));
/*printk("arcnetS: marking as not ready.\n");*/
outb(0,INTMASK);
outb(NOTXcmd,COMMAND); /* abort current send */
arcnet_inthandler(dev); /* fake an interrupt */
lp->stats.tx_errors++;
lp->intx--;
lp->txready=0; /* we definitely need this line! */
return 1;
}
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (set_bit(0, (void*)&dev->tbusy) != 0)
{
printk("arcnetS: transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
inb(STATUS),lp->intx,jiffies-dev->trans_start);
lp->intx--;
return -EBUSY;
}
else {
int length;
struct S_ClientData *hdr=(struct S_ClientData *)skb->data;
TBUSY=1;
length = 1 < skb->len ? skb->len : 1;
BUGLVL(D_SKB)
{
short i;
for(i=0; i<skb->len; i++)
{
if( i%16 == 0 ) printk("\n[%04hX] ",i);
printk("%02hX ",((unsigned char*)skb->data)[i]);
}
printk("\n");
}
if (lp->txready && inb(STATUS)&TXFREEflag)
arcnetAS_go_tx(dev);
/* fits in one packet? */
if (length-S_EXTRA_CLIENTDATA<=XMTU)
{
arcnetAS_prepare_tx(dev,
skb->data+S_EXTRA_CLIENTDATA,
sizeof(struct S_ClientData)-S_EXTRA_CLIENTDATA,
skb->data+sizeof(struct S_ClientData),
length-sizeof(struct S_ClientData),
hdr->daddr,0);
/* start sending */
outb(TXcmd|(lp->txready<<3),COMMAND);
/* done right away */
dev_kfree_skb(skb,FREE_WRITE);
lp->stats.tx_packets++;
lp->txready=0;
lp->sending++;
if (!lp->sending)
{
arcnetAS_go_tx(dev);
#ifdef VERIFY_ACK
lp->outgoing.lasttrans_dest=lp->outgoing.lastload_dest;
lp->outgoing.lastload_dest=0;
#endif
/* inform upper layers */
TBUSY=0;
mark_bh(NET_BH);
}
}
else /* too big for one - not accepted */
{
printk("arcnetS: packet too long (length=%d)\n",
length);
dev_kfree_skb(skb,FREE_WRITE);
lp->stats.tx_dropped++;
TBUSY=0;
mark_bh(NET_BH);
}
}
if (enable_irq)
outb(TXFREEflag|NORXflag|RECON_flag,INTMASK);
lp->intx--;
lp->stats.tx_packets++;
dev->trans_start=jiffies;
return 0;
return 1;
}
/****************************************************************************
* *
* Interrupt handler *
......@@ -1944,14 +1908,14 @@ arcnet_inthandler(struct device *dev)
if (IF_INTERRUPT)
{
printk("arcnet: DRIVER PROBLEM! Nested arcnet interrupts!\n");
printk("%6s: DRIVER PROBLEM! Nested arcnet interrupts!\n",
dev->name);
return; /* don't even try. */
}
outb(0,INTMASK);
INTERRUPT = 1;
BUGLVL(D_DURING)
printk("arcnet: in net_interrupt (status=%Xh)\n",inb(STATUS));
BUGMSG(D_DURING,"in net_interrupt (status=%Xh)\n",inb(STATUS));
#if 1 /* Whatever you do, don't set this to 0. */
do
......@@ -1959,17 +1923,22 @@ arcnet_inthandler(struct device *dev)
status = inb(STATUS);
didsomething=0;
#if 0 /* no longer necessary - doing checking in arcnet_interrupt now */
if (!dev->start)
{
BUGLVL(D_DURING)
printk("arcnet: ARCnet not yet initialized. irq ignored. (status=%Xh)\n",
BUGMSG(D_DURING,"ARCnet not yet initialized. irq ignored. (status=%Xh)\n",
status);
if (!(status&NORXflag))
outb(NORXflag|RECON_flag,INTMASK);
/* using dev->interrupt here instead of INTERRUPT
* because if dev->start is 0, the other devices
* probably do not exist.
*/
dev->interrupt=0;
return;
}
#endif
/* RESET flag was enabled - card is resetting and if RX
* is disabled, it's NOT because we just got a packet.
......@@ -1977,28 +1946,89 @@ arcnet_inthandler(struct device *dev)
if (status & RESETflag)
{
outb(CFLAGScmd|RESETclear,COMMAND);
BUGLVL(D_INIT)
printk("arcnet: reset irq (status=%Xh)\n",
BUGMSG(D_INIT,"reset irq (status=%Xh)\n",
status);
}
#ifdef DETECT_RECONFIGS
if (status & RECONflag)
{
outb(CFLAGScmd|CONFIGclear,COMMAND);
BUGLVL(D_EXTRA)
printk("arcnet: Network reconfiguration detected (status=%Xh)\n",
status);
lp->stats.tx_carrier_errors++;
#ifdef SHOW_RECONFIGS
BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n",
status);
#endif /* SHOW_RECONFIGS */
#ifdef RECON_THRESHOLD
/* is the RECON info empty or old? */
if (!lp->first_recon || !lp->last_recon ||
jiffies-lp->last_recon > HZ*10)
{
if (lp->network_down)
printk("%6s: reconfiguration detected: cabling restored?\n",
dev->name);
lp->first_recon=lp->last_recon=jiffies;
lp->num_recons=lp->network_down=0;
BUGMSG(D_DURING,"recon: clearing counters.\n");
}
#endif
else /* add to current RECON counter */
{
lp->last_recon=jiffies;
lp->num_recons++;
BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
lp->num_recons,
(lp->last_recon-lp->first_recon)/HZ,
lp->network_down);
/* if network is marked up;
* and first_recon and last_recon are 60+ sec
* apart;
* and the average no. of recons counted is
* > RECON_THRESHOLD/min;
* then print a warning message.
*/
if (!lp->network_down
&& (lp->last_recon-lp->first_recon)<=HZ*60
&& lp->num_recons >= RECON_THRESHOLD)
{
lp->network_down=1;
printk("%6s: many reconfigurations detected: cabling problem?\n",
dev->name);
}
else if (!lp->network_down
&& lp->last_recon-lp->first_recon > HZ*60)
{
/* reset counters if we've gone for
* over a minute.
*/
lp->first_recon=lp->last_recon;
lp->num_recons=1;
}
}
#endif
}
#ifdef RECON_THRESHOLD
else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
{
if (lp->network_down)
printk("%6s: cabling restored?\n",dev->name);
lp->first_recon=lp->last_recon=0;
lp->num_recons=lp->network_down=0;
BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
}
#endif
#endif /* DETECT_RECONFIGS */
/* RX is inhibited - we must have received something. */
if (status & NORXflag)
{
int recbuf=lp->recbuf=!lp->recbuf;
BUGLVL(D_DURING)
printk("arcnet: receive irq (status=%Xh)\n",
BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
status);
/* enable receive of our next packet */
......@@ -2017,8 +2047,7 @@ arcnet_inthandler(struct device *dev)
lp->in_txhandler++;
lp->sending--;
BUGLVL(D_DURING)
printk("arcnet: TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
status,out->numsegs,out->segnum,out->skb);
#ifdef VERIFY_ACK
......@@ -2026,27 +2055,23 @@ arcnet_inthandler(struct device *dev)
{
if (lp->outgoing.lasttrans_dest != 0)
{
printk("arcnet: transmit was not acknowledged! (status=%Xh, dest=%d)\n",
status,
printk("%6s: transmit was not acknowledged! (status=%Xh, dest=%d)\n",
dev->name,status,
lp->outgoing.lasttrans_dest);
lp->stats.tx_errors++;
lp->stats.tx_carrier_errors++;
}
else
{
BUGLVL(D_DURING)
printk("arcnet: broadcast was not acknowledged; that's normal (status=%Xh, dest=%d)\n",
BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%d)\n",
status,
lp->outgoing.lasttrans_dest);
}
}
#endif
/* send packet if there is one */
if (lp->txready)
{
arcnetAS_go_tx(dev);
arcnet_go_tx(dev,0);
didsomething++;
}
if (lp->intx)
{
......@@ -2056,8 +2081,7 @@ arcnet_inthandler(struct device *dev)
if (!lp->outgoing.skb)
{
BUGLVL(D_DURING)
printk("arcnet: TX IRQ done: no split to continue.\n");
BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n");
/* inform upper layers */
if (!lp->txready && IF_TBUSY)
......@@ -2070,15 +2094,12 @@ arcnet_inthandler(struct device *dev)
continue;
}
/*lp->stats.tx_packets++;*/
/* if more than one segment, and not all segments
* are done, then continue xmit.
*/
if (out->segnum<out->numsegs)
arcnetA_continue_tx(dev);
if (lp->txready && !lp->sending)
arcnetAS_go_tx(dev);
arcnet_go_tx(dev,0);
/* if segnum==numsegs, the transmission is finished;
* free the skb.
......@@ -2102,13 +2123,19 @@ arcnet_inthandler(struct device *dev)
lp->in_txhandler--;
}
else if (lp->txready && !lp->sending && !lp->intx)
{
BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n",
status);
arcnet_go_tx(dev,0);
didsomething++;
}
} while (--boguscount && didsomething);
BUGLVL(D_DURING)
printk("arcnet: net_interrupt complete (status=%Xh, count=%d)\n\n",
BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n\n",
inb(STATUS),boguscount);
if (dev->start && lp->sending)
if (dev->start && (lp->sending || (lp->txready && !lp->intx)))
outb(NORXflag|TXFREEflag|RECON_flag,INTMASK);
else
outb(NORXflag|RECON_flag,INTMASK);
......@@ -2146,14 +2173,16 @@ arcnet_rx(struct device *dev,int recbuf)
short length,offset;
u_char daddr,saddr;
lp->stats.rx_packets++;
saddr=arcpacket->hardheader.source;
daddr=arcpacket->hardheader.destination;
/* if source is 0, it's a "used" packet! */
if (saddr==0)
{
printk("arcnet: discarding old packet. (status=%Xh)\n",
inb(STATUS));
printk("%6s: discarding old packet. (status=%Xh)\n",
dev->name,inb(STATUS));
lp->stats.rx_errors++;
return;
}
......@@ -2173,8 +2202,7 @@ arcnet_rx(struct device *dev,int recbuf)
length=512-offset;
}
BUGLVL(D_DURING)
printk("arcnet: received packet from %02Xh to %02Xh (%d bytes)\n",
BUGMSG(D_DURING,"received packet from %02Xh to %02Xh (%d bytes)\n",
saddr,daddr,length);
/* call the right receiver for the protocol */
......@@ -2194,8 +2222,10 @@ arcnet_rx(struct device *dev,int recbuf)
arcnetS_rx(lp->sdev,arcsoft,length,saddr,daddr);
break;
default:
printk("arcnet: received unknown protocol %d (%Xh)\n",
arcsoft[0],arcsoft[0]);
printk("%6s: received unknown protocol %d (%Xh)\n",
dev->name,arcsoft[0],arcsoft[0]);
lp->stats.rx_errors++;
lp->stats.rx_crc_errors++;
break;
}
......@@ -2203,7 +2233,7 @@ arcnet_rx(struct device *dev,int recbuf)
{
int countx,county;
printk("arcnet: packet dump [rx] follows:");
printk("%6s: packet dump [rx] follows:",dev->name);
for (county=0; county<16+(length>240)*16; county++)
{
......@@ -2239,8 +2269,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
struct sk_buff *skb;
struct ClientData *arcsoft,*soft;
BUGLVL(D_DURING)
printk("arcnet: it's an RFC1201 packet (length=%d)\n",
BUGMSG(D_DURING,"it's an RFC1201 packet (length=%d)\n",
length);
/* compensate for EXTRA_CLIENTDATA (which isn't actually in the
......@@ -2251,8 +2280,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
if (arcsoft->split_flag==0xFF) /* Exception Packet */
{
BUGLVL(D_DURING)
printk("arcnet: compensating for exception packet\n");
BUGMSG(D_DURING,"compensating for exception packet\n");
/* skip over 4-byte junkola */
arcsoft=(struct ClientData *)
......@@ -2264,17 +2292,17 @@ arcnetA_rx(struct device *dev,u_char *buf,
{
struct Incoming *in=&lp->incoming[saddr];
BUGLVL(D_RX) printk("arcnet: incoming is not split (splitflag=%d)\n",
BUGMSG(D_RX,"incoming is not split (splitflag=%d)\n",
arcsoft->split_flag);
if (in->skb) /* already assembling one! */
{
BUGLVL(D_EXTRA) printk("arcnet: aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
BUGMSG(D_EXTRA,"aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
in->sequence,arcsoft->split_flag,
arcsoft->sequence);
kfree_skb(in->skb,FREE_WRITE);
lp->stats.tx_dropped++;
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
in->skb=NULL;
}
......@@ -2282,7 +2310,8 @@ arcnetA_rx(struct device *dev,u_char *buf,
skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) {
printk("arcnet: Memory squeeze, dropping packet.\n");
printk("%6s: Memory squeeze, dropping packet.\n",
dev->name);
lp->stats.rx_dropped++;
return;
}
......@@ -2314,22 +2343,23 @@ arcnetA_rx(struct device *dev,u_char *buf,
if (!*cptr) /* is saddr = 00? */
{
BUGLVL(D_EXTRA)
printk("arcnet: ARP source address was 00h, set to %02Xh.\n",
BUGMSG(D_EXTRA,"ARP source address was 00h, set to %02Xh.\n",
saddr);
lp->stats.rx_crc_errors++;
*cptr=saddr;
}
else BUGLVL(D_DURING)
else
{
printk("arcnet: ARP source address (%Xh) is fine.\n",
BUGMSG(D_DURING,"ARP source address (%Xh) is fine.\n",
*cptr);
}
}
else
{
printk("arcnet: funny-shaped ARP packet. (%Xh, %Xh)\n",
arp->ar_hln,arp->ar_pln);
lp->stats.rx_frame_errors++;
printk("%6s: funny-shaped ARP packet. (%Xh, %Xh)\n",
dev->name,arp->ar_hln,arp->ar_pln);
lp->stats.rx_errors++;
lp->stats.rx_crc_errors++;
}
}
......@@ -2349,7 +2379,6 @@ arcnetA_rx(struct device *dev,u_char *buf,
#endif
netif_rx(skb);
lp->stats.rx_packets++;
}
else /* split packet */
{
......@@ -2372,32 +2401,32 @@ arcnetA_rx(struct device *dev,u_char *buf,
struct Incoming *in=&lp->incoming[saddr];
BUGLVL(D_RX) printk("arcnet: packet is split (splitflag=%d, seq=%d)\n",
BUGMSG(D_RX,"packet is split (splitflag=%d, seq=%d)\n",
arcsoft->split_flag,in->sequence);
if (in->skb && in->sequence!=arcsoft->sequence)
{
BUGLVL(D_EXTRA) printk("arcnet: wrong seq number, aborting assembly (expected=%d, seq=%d, splitflag=%d)\n",
BUGMSG(D_EXTRA,"wrong seq number, aborting assembly (expected=%d, seq=%d, splitflag=%d)\n",
in->sequence,arcsoft->sequence,
arcsoft->split_flag);
kfree_skb(in->skb,FREE_WRITE);
in->skb=NULL;
lp->stats.tx_dropped++;
lp->stats.rx_fifo_errors++;
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
in->lastpacket=in->numpackets=0;
}
if (arcsoft->split_flag & 1) /* first packet in split */
{
BUGLVL(D_RX) printk("arcnet: brand new splitpacket (splitflag=%d)\n",
BUGMSG(D_RX,"brand new splitpacket (splitflag=%d)\n",
arcsoft->split_flag);
if (in->skb) /* already assembling one! */
{
BUGLVL(D_EXTRA) printk("arcnet: aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
BUGMSG(D_EXTRA,"aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
in->sequence,arcsoft->split_flag,
arcsoft->sequence);
lp->stats.tx_dropped++;
lp->stats.rx_over_errors++;
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
kfree_skb(in->skb,FREE_WRITE);
}
......@@ -2407,9 +2436,10 @@ arcnetA_rx(struct device *dev,u_char *buf,
if (in->numpackets>16)
{
BUGLVL(D_EXTRA) printk("arcnet: incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
BUGMSG(D_EXTRA,"incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
arcsoft->split_flag);
lp->stats.rx_dropped++;
lp->stats.rx_errors++;
lp->stats.rx_length_errors++;
return;
}
......@@ -2417,7 +2447,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
+ sizeof(struct ClientData),
GFP_ATOMIC);
if (skb == NULL) {
printk("%s: (split) memory squeeze, dropping packet.\n",
printk("%6s: (split) memory squeeze, dropping packet.\n",
dev->name);
lp->stats.rx_dropped++;
return;
......@@ -2447,9 +2477,10 @@ arcnetA_rx(struct device *dev,u_char *buf,
*/
if (!in->skb)
{
BUGLVL(D_EXTRA) printk("arcnet: can't continue split without starting first! (splitflag=%d, seq=%d)\n",
BUGMSG(D_EXTRA,"can't continue split without starting first! (splitflag=%d, seq=%d)\n",
arcsoft->split_flag,arcsoft->sequence);
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
return;
}
......@@ -2459,19 +2490,21 @@ arcnetA_rx(struct device *dev,u_char *buf,
/* harmless duplicate? ignore. */
if (packetnum<=in->lastpacket-1)
{
BUGLVL(D_EXTRA) printk("arcnet: duplicate splitpacket ignored! (splitflag=%d)\n",
BUGMSG(D_EXTRA,"duplicate splitpacket ignored! (splitflag=%d)\n",
arcsoft->split_flag);
lp->stats.rx_errors++;
lp->stats.rx_frame_errors++;
return;
}
/* "bad" duplicate, kill reassembly */
BUGLVL(D_EXTRA) printk("arcnet: out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
BUGMSG(D_EXTRA,"out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
in->sequence,arcsoft->split_flag,
arcsoft->sequence);
kfree_skb(in->skb,FREE_WRITE);
in->skb=NULL;
lp->stats.tx_dropped++;
lp->stats.rx_fifo_errors++;
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
in->lastpacket=in->numpackets=0;
return;
}
......@@ -2494,8 +2527,12 @@ arcnetA_rx(struct device *dev,u_char *buf,
if (in->lastpacket == in->numpackets)
{
if (!skb || !in->skb)
printk("arcnet: ?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n",
skb,in->skb);
{
printk("%6s: ?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n",
dev->name,skb,in->skb);
}
else
{
in->skb=NULL;
in->lastpacket=in->numpackets=0;
......@@ -2516,7 +2553,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
#endif
netif_rx(skb);
lp->stats.rx_packets++;
}
}
}
}
......@@ -2531,13 +2568,12 @@ arcnetE_rx(struct device *dev,u_char *arcsoft,
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
struct sk_buff *skb;
BUGLVL(D_DURING)
printk("arcnet: it's an ethernet-encap packet (length=%d)\n",
BUGMSG(D_DURING,"it's an ethernet-encap packet (length=%d)\n",
length);
skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) {
printk("arcnet: Memory squeeze, dropping packet.\n");
printk("%6s: Memory squeeze, dropping packet.\n",dev->name);
lp->stats.rx_dropped++;
return;
}
......@@ -2550,7 +2586,7 @@ arcnetE_rx(struct device *dev,u_char *arcsoft,
BUGLVL(D_SKB)
{
short i;
printk("arcnet: rx skb dump follows:\n");
printk("%6s: rx skb dump follows:\n",dev->name);
for(i=0; i<skb->len; i++)
{
if (i%16==0)
......@@ -2566,7 +2602,6 @@ arcnetE_rx(struct device *dev,u_char *arcsoft,
#endif
netif_rx(skb);
lp->stats.rx_packets++;
}
/* Packet receiver for RFC1051 packets;
......@@ -2582,8 +2617,7 @@ arcnetS_rx(struct device *dev,u_char *buf,
arcsoft=(struct S_ClientData *)(buf-S_EXTRA_CLIENTDATA);
length+=S_EXTRA_CLIENTDATA;
BUGLVL(D_DURING)
printk("arcnetS: it's an RFC1051 packet (length=%d)\n",
BUGMSG(D_DURING,"it's an RFC1051 packet (length=%d)\n",
length);
......@@ -2625,7 +2659,6 @@ arcnetS_rx(struct device *dev,u_char *buf,
#endif
netif_rx(skb);
lp->stats.rx_packets++;
}
}
......@@ -2659,7 +2692,7 @@ arcnet_get_stats(struct device *dev)
static void
set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
#if 0 /* no promiscuous mode at all on most ARCnet models */
#if 0 /* no promiscuous mode at all on most (all?) ARCnet models */
struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
short ioaddr = dev->base_addr;
......@@ -2690,10 +2723,9 @@ int arcnetA_header(struct sk_buff *skb,struct device *dev,
#else
skb_push(skb,dev->hard_header_len);
#endif
/* struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);*/
struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
BUGLVL(D_DURING)
printk("arcnetA: create header from %d to %d; protocol %d (%Xh); size %u.\n",
BUGMSG(D_DURING,"create header from %d to %d; protocol %d (%Xh); size %u.\n",
saddr ? *(u_char*)saddr : -1,
daddr ? *(u_char*)daddr : -1,
type,type,len);
......@@ -2711,14 +2743,18 @@ int arcnetA_header(struct sk_buff *skb,struct device *dev,
head->protocol_id=ARC_P_RARP;
break;
case ETH_P_IPX:
case ETH_P_802_3:
case ETH_P_802_2:
head->protocol_id=ARC_P_IPX;
break;
case ETH_P_ATALK:
head->protocol_id=ARC_P_ATALK;
break;
default:
printk("arcnet: I don't understand protocol %d (%Xh)\n",
type,type);
printk("%6s: I don't understand protocol %d (%Xh)\n",
dev->name,type,type);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
return 0;
}
......@@ -2771,24 +2807,24 @@ int arcnetS_header(struct sk_buff *skb,struct device *dev,
#else
skb_push(skb,dev->hard_header_len);
#endif
/* struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);*/
struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
/* set the protocol ID according to RFC1051 */
switch(type)
{
case ETH_P_IP:
head->protocol_id=ARC_P_IP_RFC1051;
BUGLVL(D_DURING)
printk("arcnetS: S_header: IP_RFC1051 packet.\n");
BUGMSG(D_DURING,"S_header: IP_RFC1051 packet.\n");
break;
case ETH_P_ARP:
head->protocol_id=ARC_P_ARP_RFC1051;
BUGLVL(D_DURING)
printk("arcnetS: S_header: ARP_RFC1051 packet.\n");
BUGMSG(D_DURING,"S_header: ARP_RFC1051 packet.\n");
break;
default:
printk("arcnetS: I don't understand protocol %d (%Xh)\n",
type,type);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
return 0;
}
......@@ -2827,6 +2863,7 @@ int arcnetA_rebuild_header(void *buff,struct device *dev,unsigned long dst,
struct sk_buff *skb)
{
struct ClientData *head = (struct ClientData *)buff;
struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
int status;
/*
......@@ -2835,8 +2872,10 @@ int arcnetA_rebuild_header(void *buff,struct device *dev,unsigned long dst,
if(head->protocol_id != ARC_P_IP)
{
printk("arcnet: I don't understand protocol type %d (%Xh) addresses!\n",
head->protocol_id,head->protocol_id);
printk("%6s: I don't understand protocol type %d (%Xh) addresses!\n",
dev->name,head->protocol_id,head->protocol_id);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
head->daddr=0;
/*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/
return 0;
......@@ -2846,12 +2885,10 @@ int arcnetA_rebuild_header(void *buff,struct device *dev,unsigned long dst,
* Try and get ARP to resolve the header.
*/
#ifdef CONFIG_INET
BUGLVL(D_DURING)
printk("arcnetA: rebuild header from %d to %d; protocol %Xh\n",
BUGMSG(D_DURING,"rebuild header from %d to %d; protocol %Xh\n",
head->saddr,head->daddr,head->protocol_id);
status=arp_find(&(head->daddr), dst, dev, dev->pa_addr, skb)? 1 : 0;
BUGLVL(D_DURING)
printk("arcnetA: rebuilt: from %d to %d; protocol %Xh\n",
BUGMSG(D_DURING," rebuilt: from %d to %d; protocol %Xh\n",
head->saddr,head->daddr,head->protocol_id);
return status;
#else
......@@ -2864,6 +2901,7 @@ int arcnetS_rebuild_header(void *buff,struct device *dev,unsigned long dst,
struct sk_buff *skb)
{
struct S_ClientData *head = (struct S_ClientData *)buff;
struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
/*
* Only ARP and IP are currently supported
......@@ -2873,6 +2911,8 @@ int arcnetS_rebuild_header(void *buff,struct device *dev,unsigned long dst,
{
printk("arcnetS: I don't understand protocol type %d (%Xh) addresses!\n",
head->protocol_id,head->protocol_id);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
head->daddr=0;
/*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/
return 0;
......@@ -2922,14 +2962,14 @@ unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev)
case ARC_P_IP: return htons(ETH_P_IP);
case ARC_P_ARP: return htons(ETH_P_ARP);
case ARC_P_RARP: return htons(ETH_P_RARP);
case ARC_P_IPX: return htons(ETH_P_IPX);
case ARC_P_IPX: return htons(ETH_P_802_3);
case ARC_P_ATALK: return htons(ETH_P_ATALK); /* untested appletalk */
case ARC_P_LANSOFT: /* don't understand. fall through. */
default:
BUGLVL(D_EXTRA)
printk("arcnet: received packet of unknown protocol id %d (%Xh)\n",
BUGMSG(D_EXTRA,"received packet of unknown protocol id %d (%Xh)\n",
head->protocol_id,head->protocol_id);
lp->stats.rx_frame_errors++;
lp->stats.rx_errors++;
lp->stats.rx_crc_errors++;
return 0;
}
......@@ -2943,7 +2983,7 @@ unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev)
struct arcnet_local *lp=(struct arcnet_local *) (dev->priv);
#ifdef LINUX12
head=(struct ClientData *)skb->data;
head=(struct S_ClientData *)skb->data;
#else
/* Pull off the arcnet header. */
skb->mac.raw=skb->data;
......@@ -2966,10 +3006,10 @@ unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev)
case ARC_P_IP_RFC1051: return htons(ETH_P_IP);
case ARC_P_ARP_RFC1051: return htons(ETH_P_ARP);
default:
BUGLVL(D_EXTRA)
printk("arcnetS: received packet of unknown protocol id %d (%Xh)\n",
BUGMSG(D_EXTRA,"received packet of unknown protocol id %d (%Xh)\n",
head->protocol_id,head->protocol_id);
lp->stats.rx_frame_errors++;
lp->stats.rx_errors++;
lp->stats.rx_crc_errors++;
return 0;
}
......
......@@ -1170,7 +1170,6 @@ static void eth16i_select_regbank(unsigned char banknbr, short ioaddr)
}
#ifdef MODULE
char kernel_version[] = UTS_RELEASE;
static char devicename[9] = { 0, };
static struct device dev_eth16i = {
devicename,
......
......@@ -168,8 +168,9 @@ struct pci_dev_info dev_info[] = {
DEVICE( ADAPTEC, ADAPTEC_7870, "AIC-7870"),
DEVICE( ADAPTEC, ADAPTEC_7871, "AIC-7871"),
DEVICE( ADAPTEC, ADAPTEC_7872, "AIC-7872"),
DEVICE( ADAPTEC, ADAPTEC_7880, "AIC-7880"),
DEVICE( ADAPTEC, ADAPTEC_7881, "AIC-7881"),
DEVICE( ADAPTEC, ADAPTEC_7880, "AIC-7880U"),
DEVICE( ADAPTEC, ADAPTEC_7881, "AIC-7881U"),
DEVICE( ADAPTEC, ADAPTEC_7882, "AIC-7882U"),
DEVICE( ATRONICS, ATRONICS_2015, "IDE-2015PL"),
DEVICE( HER, HER_STING, "Stingray"),
DEVICE( HER, HER_STINGARK, "Stingray ARK 2000PV")
......
......@@ -41,7 +41,7 @@
*
* -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 04/03/95
*
* $Id: aic7xxx.c,v 2.5 1995/09/20 05:18:18 deang Exp $
* $Id: aic7xxx.c,v 2.10 1995/11/10 10:49:14 deang Exp $
*-M*************************************************************************/
#ifdef MODULE
......@@ -73,7 +73,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
S_IFDIR | S_IRUGO | S_IXUGO, 2
};
#define AIC7XXX_C_VERSION "$Revision: 2.5 $"
#define AIC7XXX_C_VERSION "$Revision: 2.10 $"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) ((a < b) ? a : b)
......@@ -163,7 +163,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
* Define this to use polling rather than using kernel support for waking
* up a waiting process.
*/
#undef AIC7XXX_POLL
#define AIC7XXX_POLL
/*
* Controller type and options
......@@ -172,9 +172,11 @@ typedef enum {
AIC_NONE,
AIC_274x, /* EISA aic7770 */
AIC_284x, /* VLB aic7770 */
AIC_7870, /* PCI aic7870 */
AIC_7870, /* PCI aic7870/aic7871 motherboard or 294x */
AIC_7850, /* PCI aic7850 */
AIC_7872 /* PCI aic7870 on 394x */
AIC_7872, /* PCI aic7870 on 394x */
AIC_7880, /* PCI aic7880/aic7881 motherboard or 294x Ultra */
AIC_7882, /* PCI aic7870 on 394x Ultra */
} aha_type;
typedef enum {
......@@ -247,6 +249,21 @@ typedef enum {
#define ENAUTOATNP 0x02
#define SCSIRSTO 0x01
/*
* SCSI Transfer Control 0 Register (pp. 3-13).
* Controls the SCSI module data path.
*/
#define SXFRCTL0(x) ((x) + 0xC01ul)
#define DFON 0x80
#define DFPEXP 0x40
#define ULTRAEN 0x20
#define CLRSTCNT 0x10
#define SPIOEN 0x08
#define SCAMEN 0x04
#define CLRCHN 0x02
/* UNUSED 0x01 */
/*
* SCSI Transfer Control 1 Register (pp. 3-14,15).
* Controls the SCSI module data path.
......@@ -394,28 +411,6 @@ typedef enum {
#define ONEBIT 0x08
/* UNUSED 0x07 */
/*
* Serial EEPROM Control (p. 4-92 in 7870 Databook)
* Controls the reading and writing of an external serial 1-bit
* EEPROM Device. In order to access the serial EEPROM, you must
* first set the SEEMS bit that generates a request to the memory
* port for access to the serial EEPROM device. When the memory
* port is not busy servicing another request, it reconfigures
* to allow access to the serial EEPROM. When this happens, SEERDY
* gets set high to verify that the memory port access has been
* granted. See aic7xxx_read_eprom for detailed information on
* the protocol necessary to read the serial EEPROM.
*/
#define SEECTL(x) ((x) + 0xC1Eul)
#define EXTARBACK 0x80
#define EXTARBREQ 0x40
#define SEEMS 0x20
#define SEERDY 0x10
#define SEECS 0x08
#define SEECK 0x04
#define SEEDO 0x02
#define SEEDI 0x01
/*
* SCSI Block Control (p. 3-32)
* Controls Bus type and channel selection. In a twin channel configuration
......@@ -425,8 +420,11 @@ typedef enum {
*/
#define SBLKCTL(x) ((x) + 0xC1Ful)
/* UNUSED 0xC0 */
#define DIAGLEDEN 0x80
#define DIAGLEDON 0x40
#define AUTOFLUSHDIS 0x20 /* used for Rev C check */
/* UNUSED 0x10 */
#define SELBUS_MASK 0x0F
#define SELBUSB 0x08
/* UNUSED 0x04 */
#define SELWIDE 0x02
......@@ -503,7 +501,7 @@ typedef enum {
#define PAUSE 0x04
#define INTEN 0x02
#define CHIPRST 0x01
#define REQ_PAUSE IRQMS | PAUSE | INTEN
#define REQ_PAUSE IRQMS | INTEN | PAUSE
#define UNPAUSE_274X IRQMS | INTEN
#define UNPAUSE_284X INTEN
#define UNPAUSE_294X IRQMS | INTEN
......@@ -603,11 +601,64 @@ typedef enum {
/* ---------------- END AIC-7770 Register Definitions ----------------- */
/* --------------------- AHA-2840-only definitions -------------------- */
#define SEECTL_2840(x) ((x) + 0xCC0ul)
/* UNUSED 0xF8 */
#define CS_2840 0x04
#define CK_2840 0x02
#define DO_2840 0x01
#define STATUS_2840(x) ((x) + 0xCC1ul)
#define EEPROM_TF 0x80
#define BIOS_SEL 0x60
#define ADSEL 0x1E
#define DI_2840 0x01
/* --------------------- AIC-7870-only definitions -------------------- */
#define DSPCISTATUS(x) ((x) + 0xC86ul)
#define DFTHRESH 0xC0
/*
* Serial EEPROM Control (p. 4-92 in 7870 Databook)
* Controls the reading and writing of an external serial 1-bit
* EEPROM Device. In order to access the serial EEPROM, you must
* first set the SEEMS bit that generates a request to the memory
* port for access to the serial EEPROM device. When the memory
* port is not busy servicing another request, it reconfigures
* to allow access to the serial EEPROM. When this happens, SEERDY
* gets set high to verify that the memory port access has been
* granted. See aic7xxx_read_eprom for detailed information on
* the protocol necessary to read the serial EEPROM.
*/
#define SEECTL(x) ((x) + 0xC1Eul)
#define EXTARBACK 0x80
#define EXTARBREQ 0x40
#define SEEMS 0x20
#define SEERDY 0x10
#define SEECS 0x08
#define SEECK 0x04
#define SEEDO 0x02
#define SEEDI 0x01
#define DEVREVID 0x08ul
#define DEVSTATUS 0x40ul
#define MPORTMODE 0x04 /* aic7870 only */
#define RAMPSM 0x02 /* aic7870 only */
#define VOLSENSE 0x01
#define DEVCONFIG 0x41ul
#define SCBRAMSEL 0x80
#define MRDCEN 0x40
#define EXTSCBTIME 0x20 /* aic7870 only */
#define EXTSCBPEN 0x10 /* aic7870 only */
#define BERREN 0x08
#define DACEN 0x04
#define STPWLEVEL 0x02
#define DIFACTNEGEN 0x01 /* aic7870 only */
/* Scratch RAM offset definitions */
/* ---------------------- Scratch RAM Offsets ------------------------- */
......@@ -726,9 +777,10 @@ struct seeprom_config {
/*
* Host Adapter Control Bits
*/
/* UNUSED 0x0003 */
#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */
/* UNUSED 0x0001 */
#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable (Ultra cards) */
#define CFSTERM 0x0004 /* SCSI low byte termination (non-wide cards) */
#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */
#define CFSPARITY 0x0010 /* SCSI parity */
/* UNUSED 0x0020 */
#define CFRESETB 0x0040 /* reset SCSI bus at IC initialization */
......@@ -905,13 +957,13 @@ struct aic7xxx_scb {
/*-----------------end of hardware supported fields----------------*/
struct aic7xxx_scb *next; /* next ptr when in free list */
Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
int state; /* current state of scb */
#define SCB_FREE 0x00
#define SCB_ACTIVE 0x01
#define SCB_ABORTED 0x02
#define SCB_DEVICE_RESET 0x04
#define SCB_IMMED 0x08
#define SCB_SENSE 0x10
int state; /* current state of scb */
unsigned int position; /* Position in scb array */
struct scatterlist sg;
struct scatterlist sense_sg;
......@@ -947,7 +999,7 @@ generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
* of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
* SEQUENCER CODE IF THIS IS MODIFIED!
*/
#define AIC7XXX_MAXSCB 16
#define AIC7XXX_MAXSCB 255
/*
* Define a structure used for each host adapter, only one per IRQ.
......@@ -958,6 +1010,8 @@ struct aic7xxx_host {
int numscb; /* current number of scbs */
int extended; /* extended xlate? */
aha_type type; /* card type */
int ultra_enabled; /* Ultra SCSI speed enabled */
int chan_num; /* for 3940/3985, channel number */
aha_bus_type bus_type; /* normal/twin/wide bus */
unsigned char a_scanned; /* 0 not scanned, 1 scanned */
unsigned char b_scanned; /* 0 not scanned, 1 scanned */
......@@ -1010,7 +1064,10 @@ struct aic7xxx_host_config {
int scsi_id_b; /* host SCSI ID B channel for twin cards */
int extended; /* extended xlate? */
int busrtime; /* bus release time */
int walk_scbs; /* external SCB RAM detected; walk the scb array */
aha_type type; /* card type */
int ultra_enabled; /* Ultra SCSI speed enabled */
int chan_num; /* for 3940/3985, channel number */
aha_bus_type bus_type; /* normal/twin/wide bus */
aha_status_type parity; /* bus parity enabled/disabled */
aha_status_type low_term; /* bus termination low byte */
......@@ -1024,22 +1081,30 @@ struct aic7xxx_host_config {
*/
static struct {
short period;
/* Rates in Ultra mode have bit 8 of sxfr set */
#define ULTRA_SXFR 0x100
short rate;
const char *english;
} aic7xxx_syncrates[] = {
{ 100, 0, "10.0" },
{ 125, 1, "8.0" },
{ 150, 2, "6.67" },
{ 175, 3, "5.7" },
{ 200, 4, "5.0" },
{ 225, 5, "4.4" },
{ 250, 6, "4.0" },
{ 275, 7, "3.6" }
{ 50, 0x100, "20.0" },
{ 62, 0x110, "16.0" },
{ 75, 0x120, "13.4" },
{ 100, 0x140, "10.0" },
{ 100, 0x000, "10.0" },
{ 125, 0x010, "8.0" },
{ 150, 0x020, "6.67" },
{ 175, 0x030, "5.7" },
{ 200, 0x040, "5.0" },
{ 225, 0x050, "4.4" },
{ 250, 0x060, "4.0" },
{ 275, 0x070, "3.6" }
};
static int num_aic7xxx_syncrates =
sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
static int number_of_3940s = 0;
#ifdef AIC7XXX_DEBUG
static void
......@@ -1101,7 +1166,7 @@ debug_config(struct aic7xxx_host_config *p)
break;
case AIC_7870:
printk("AIC7870%s (PCI-bus):\n", BUSW[p->bus_type]);
printk("AIC7870/7871%s (PCI-bus):\n", BUSW[p->bus_type]);
break;
case AIC_7850:
......@@ -1112,6 +1177,14 @@ debug_config(struct aic7xxx_host_config *p)
printk("AIC7872%s (PCI-bus):\n", BUSW[p->bus_type]);
break;
case AIC_7880:
printk("AIC7880/7881%s (PCI-bus):\n", BUSW[p->bus_type]);
break;
case AIC_7882:
printk("AIC7882%s (PCI-bus):\n", BUSW[p->bus_type]);
break;
default:
panic("aic7xxx debug_config: internal error\n");
}
......@@ -1160,6 +1233,7 @@ debug_config(struct aic7xxx_host_config *p)
}
}
#if 0
static void
debug_scb(struct aic7xxx_scb *scb)
{
......@@ -1183,6 +1257,7 @@ debug_scb(struct aic7xxx_scb *scb)
(unsigned long) scb->next, (unsigned long) scb->cmd, scb->state,
scb->position);
}
#endif
#else
# define debug(fmt, args...)
......@@ -1195,41 +1270,51 @@ debug_scb(struct aic7xxx_scb *scb)
* cards in the system. This should be fixed, but then,
* does anyone really have more than one in a machine?
*/
static int aic7xxx_extended = 0; /* extended translation on? */
static int aic7xxx_no_reset = 0; /* no resetting of SCSI bus */
static unsigned int aic7xxx_extended = 0; /* extended translation on? */
static unsigned int aic7xxx_no_reset = 0; /* no resetting of SCSI bus */
/*+F*************************************************************************
* Function:
* aic7xxx_setup
*
* Description:
* Handle Linux boot parameters.
* Handle Linux boot parameters. This routine allows for assigning a value
* to a parameter with a ':' between the parameter and the value.
* ie. aic7xxx=unpause:0x0A,extended
*-F*************************************************************************/
void
aic7xxx_setup(char *s, int *dummy)
{
int i;
int i, n;
char *p;
static struct {
const char *name;
int *flag;
unsigned int *flag;
} options[] = {
{ "extended", &aic7xxx_extended },
{ "no_reset", &aic7xxx_no_reset },
{ NULL, NULL}
{ NULL, NULL }
};
for (p = strtok(s, ","); p; p = strtok(NULL, ","))
{
for (i = 0; options[i].name; i++)
{
if (!strcmp(options[i].name, p))
n = strlen(options[i].name);
if (!strncmp(options[i].name, p, n))
{
if (p[n] == ':')
{
*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
}
else
{
*(options[i].flag) = !0;
}
}
}
}
}
/*+F*************************************************************************
......@@ -1532,8 +1617,9 @@ aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
* Look up the valid period to SCSIRATE conversion in our table
*-F*************************************************************************/
static void
aic7xxx_scsirate(unsigned char *scsirate, unsigned char period,
unsigned char offset, int target, char channel)
aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
unsigned char period, unsigned char offset,
int target, char channel)
{
int i;
......@@ -1541,8 +1627,38 @@ aic7xxx_scsirate(unsigned char *scsirate, unsigned char period,
{
if ((aic7xxx_syncrates[i].period - period) >= 0)
{
*scsirate = (aic7xxx_syncrates[i].rate << 4) | (offset & 0x0F);
printk("aic7xxx: target %d, channel %c, now synchronous at %sMb/s, "
/*
* Watch out for Ultra speeds when ultra is not enabled and
* vice-versa.
*/
if (p->ultra_enabled)
{
if (! (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
{
printk ("aic7xxx: target %d, channel %c, requests %sMB/s transfers, "
"but adapter in Ultra mode can only sync at 10MB/s or "
"above.\n", target, channel, aic7xxx_syncrates[i].english);
break; /* Use asynchronous transfers. */
}
}
else
{
/*
* Check for an Ultra device trying to negotiate an Ultra rate
* on an adapter with Ultra mode disabled.
*/
if (aic7xxx_syncrates[i].rate & ULTRA_SXFR)
{
/*
* This should only happen if the driver is the first to negotiate
* and chooses a high rate. We'll just move down the table until
* we hit a non Ultra speed.
*/
continue;
}
}
*scsirate = (aic7xxx_syncrates[i].rate) | (offset & 0x0F);
printk("aic7xxx: target %d, channel %c, now synchronous at %sMB/s, "
"offset = 0x%x\n",
target, channel, aic7xxx_syncrates[i].english, offset);
return;
......@@ -2079,6 +2195,7 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel,
outb(sblkctl ^ SELBUSB, SBLKCTL(base));
aic7xxx_reset_current_bus(base);
outb(sblkctl, SBLKCTL(base));
UNPAUSE_SEQUENCER(p);
}
/*
......@@ -2280,7 +2397,7 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
{
max_offset = 0x0F;
}
aic7xxx_scsirate(&rate, transfer, MIN(offset, max_offset), scsi_id, channel);
aic7xxx_scsirate(p, &rate, transfer, MIN(offset, max_offset), scsi_id, channel);
/*
* Preserve the wide transfer flag.
*/
......@@ -3002,6 +3119,152 @@ aic7xxx_probe(int slot, int base)
return (AIC_NONE);
}
/*+F*************************************************************************
* Function:
* read_2840_seeprom
*
* Description:
* Reads the 2840 serial EEPROM and returns 1 if successful and 0 if
* not successful.
*
* See read_seeprom (for the 2940) for the instruction set of the 93C46
* chip.
*
* The 2840 interface to the 93C46 serial EEPROM is through the
* STATUS_2840 and SEECTL_2840 registers. The CS_2840, CK_2840, and
* DO_2840 bits of the SEECTL_2840 register are connected to the chip
* select, clock, and data out lines respectively of the serial EEPROM.
* The DI_2840 bit of the STATUS_2840 is connected to the data in line
* of the serial EEPROM. The EEPROM_TF bit of STATUS_2840 register is
* useful in that it gives us an 800 nsec timer. After a read from the
* SEECTL_2840 register the timing flag is cleard and goes high 800 nsec
* later.
*
*-F*************************************************************************/
static int
read_2840_seeprom(int base, struct seeprom_config *sc)
{
int i = 0, k = 0;
unsigned char temp;
unsigned short checksum = 0;
unsigned short *seeprom = (unsigned short *) sc;
struct seeprom_cmd {
unsigned char len;
unsigned char bits[3];
};
struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
#define CLOCK_PULSE(p) \
while ((inb(STATUS_2840(base)) & EEPROM_TF) == 0) \
{ \
; /* Do nothing */ \
} \
(void) inb(SEECTL_2840(base));
/*
* Read the first 32 registers of the seeprom. For the 2840,
* the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
* but only the first 32 are used by Adaptec BIOS. The loop
* will range from 0 to 31.
*/
for (k = 0; k < (sizeof(*sc) / 2); k++)
{
/*
* Send chip select for one clock cycle.
*/
outb(CK_2840 | CS_2840, SEECTL_2840(base));
CLOCK_PULSE(base);
/*
* Now we're ready to send the read command followed by the
* address of the 16-bit register we want to read.
*/
for (i = 0; i < seeprom_read.len; i++)
{
temp = CS_2840 | seeprom_read.bits[i];
outb(temp, SEECTL_2840(base));
CLOCK_PULSE(base);
temp = temp ^ CK_2840;
outb(temp, SEECTL_2840(base));
CLOCK_PULSE(base);
}
/*
* Send the 6 bit address (MSB first, LSB last).
*/
for (i = 5; i >= 0; i--)
{
temp = k;
temp = (temp >> i) & 1; /* Mask out all but lower bit. */
temp = CS_2840 | temp;
outb(temp, SEECTL_2840(base));
CLOCK_PULSE(base);
temp = temp ^ CK_2840;
outb(temp, SEECTL_2840(base));
CLOCK_PULSE(base);
}
/*
* Now read the 16 bit register. An initial 0 precedes the
* register contents which begins with bit 15 (MSB) and ends
* with bit 0 (LSB). The initial 0 will be shifted off the
* top of our word as we let the loop run from 0 to 16.
*/
for (i = 0; i <= 16; i++)
{
temp = CS_2840;
outb(temp, SEECTL_2840(base));
CLOCK_PULSE(base);
temp = temp ^ CK_2840;
seeprom[k] = (seeprom[k] << 1) | (inb(STATUS_2840(base)) & DI_2840);
outb(temp, SEECTL_2840(base));
CLOCK_PULSE(base);
}
/*
* The serial EEPROM has a checksum in the last word. Keep a
* running checksum for all words read except for the last
* word. We'll verify the checksum after all words have been
* read.
*/
if (k < (sizeof(*sc) / 2) - 1)
{
checksum = checksum + seeprom[k];
}
/*
* Reset the chip select for the next command cycle.
*/
outb(0, SEECTL_2840(base));
CLOCK_PULSE(base);
outb(CK_2840, SEECTL_2840(base));
CLOCK_PULSE(base);
outb(0, SEECTL_2840(base));
CLOCK_PULSE(base);
}
#if 0
printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
printk("Serial EEPROM:");
for (k = 0; k < (sizeof(*sc) / 2); k++)
{
if (((k % 8) == 0) && (k != 0))
{
printk("\n ");
}
printk(" 0x%x", seeprom[k]);
}
printk("\n");
#endif
if (checksum != sc->checksum)
{
printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n");
return (0);
}
return (1);
#undef CLOCK_PULSE
}
/*+F*************************************************************************
* Function:
* read_seeprom
......@@ -3052,9 +3315,9 @@ aic7xxx_probe(int slot, int base)
*
*-F*************************************************************************/
static int
read_seeprom(int base, struct seeprom_config *sc)
read_seeprom(int base, int offset, struct seeprom_config *sc)
{
int i = 0, k = 0;
int i = 0, k;
unsigned long timeout;
unsigned char temp;
unsigned short checksum = 0;
......@@ -3122,7 +3385,7 @@ read_seeprom(int base, struct seeprom_config *sc)
*/
for (i = 5; i >= 0; i--)
{
temp = k;
temp = k + offset;
temp = (temp >> i) & 1; /* Mask out all but lower bit. */
temp = SEEMS | SEECS | (temp << 1);
outb(temp, SEECTL(base));
......@@ -3197,6 +3460,7 @@ read_seeprom(int base, struct seeprom_config *sc)
}
return (1);
#undef CLOCK_PULSE
}
/*+F*************************************************************************
......@@ -3207,10 +3471,10 @@ read_seeprom(int base, struct seeprom_config *sc)
* Return the maximum number of SCB's allowed for a given controller.
*-F*************************************************************************/
static int
detect_maxscb(aha_type type, int base)
detect_maxscb(aha_type type, int base, int walk_scbs)
{
unsigned char sblkctl_reg;
int maxscb = 0;
unsigned char sblkctl_reg, scb_byte;
int maxscb = 0, i;
switch (type)
{
......@@ -3248,14 +3512,15 @@ detect_maxscb(aha_type type, int base)
break;
case AIC_7870:
case AIC_7880:
maxscb = 16;
break;
case AIC_7872:
case AIC_7882:
/*
* Really has 255, but we'll wait to verify that we access
* them the same way and do not have to set the card to
* use the memory port to access external SCB RAM.
* Is suppose to have 255 SCBs, but we'll walk the SCBs
* looking for more if external RAM is detected.
*/
maxscb = 16;
break;
......@@ -3266,6 +3531,26 @@ detect_maxscb(aha_type type, int base)
*/
break;
}
if (walk_scbs)
{
/*
* This adapter has external SCB memory.
* Walk the SCBs to determine how many there are.
*/
i = 0;
while (i < AIC7XXX_MAXSCB)
{
outb(i, SCBPTR(base));
scb_byte = ~(inb(SCBARRAY(base))); /* complement the byte */
outb(scb_byte, SCBARRAY(base)); /* write it back out */
if (inb(SCBARRAY(base)) != scb_byte)
{
break;
}
i++;
}
maxscb = i;
}
return (maxscb);
}
......@@ -3278,41 +3563,35 @@ detect_maxscb(aha_type type, int base)
* Register a Adaptec aic7xxx chip SCSI controller with the kernel.
*-F*************************************************************************/
static int
aic7xxx_register(Scsi_Host_Template *template, aha_type type,
int base, unsigned char irq)
aic7xxx_register(Scsi_Host_Template *template,
struct aic7xxx_host_config *config)
{
static const char * board_name[] = {"", "274x", "284x", "7870", "7850", "7872"};
static const char * board_name[] = {"", "274x", "284x", "7870", "7850",
"7872", "7881"};
int i;
unsigned char sblkctl;
int max_targets;
int found = 1;
int found = 1, base;
int bios_disabled = 0;
unsigned char target_settings;
unsigned char scsi_conf, host_conf;
int have_seeprom = 0;
struct Scsi_Host *host;
struct aic7xxx_host *p;
struct aic7xxx_host_config config;
struct seeprom_config sc;
config.type = type;
config.base = base;
config.irq = irq;
config.parity = AIC_UNKNOWN;
config.low_term = AIC_UNKNOWN;
config.high_term = AIC_UNKNOWN;
config.busrtime = 0;
base = config->base;
/*
* Lock out other contenders for our i/o space.
*/
request_region(MINREG(base), MAXREG(base) - MINREG(base), "aic7xxx");
switch (type)
switch (config->type)
{
case AIC_274x:
#if 0
printk("aha274x: aic7770 hcntrl=0x%x\n", inb(HCNTRL(config.base)));
printk("aha274x: HCNTRL:0x%x\n", inb(HCNTRL(base)));
#endif
/*
* For some 274x boards, we must clear the CHIPRST bit
......@@ -3324,147 +3603,157 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
* trigger type (level or edge) and use this value
* for pausing and unpausing the sequencer.
*/
config.unpause = (inb(HCNTRL(config.base)) & IRQMS) | INTEN;
config.pause = config.unpause | PAUSE;
config.extended = aic7xxx_extended;
/*
* I don't think we need to kick the reset again, the initial probe
* does a reset, it seems that this is kicking a dead horse here.
* So... I will try to just verify that the chip has come out of the
* reset state and continue the same as the 284x.
* In the Calgary version of the driver:
* 1) Chip Reset
* 2) Set unpause to IRQMS | INTEN
* 3) If an interrupt occured without any commands queued, the
* unpause was set to just INTEN
* I changed the initial reset code to just mask in the CHIPRST bit
* and try to leave the other settings alone.
*
* I don't think we need the warning about chip reset not being clear.
* On both my test machines (2842 & 2940), they work just fine with a
* HCNTRL() of 0x5 (PAUSE | CHIPRST). Notice though, the 274x also
* adds the INTEN flag, where neither the 284x or 294x do.
*/
outb(config.pause | CHIPRST, HCNTRL(config.base));
config->unpause = (inb(HCNTRL(base)) & IRQMS) | INTEN;
config->pause = config->unpause | PAUSE;
config->extended = aic7xxx_extended;
outb(config->pause | CHIPRST, HCNTRL(base));
aic7xxx_delay(1);
if (inb(HCNTRL(config.base)) & CHIPRST)
if (inb(HCNTRL(base)) & CHIPRST)
{
printk("aic7xxx_register: Chip reset not cleared; clearing manually.\n");
}
outb(config.pause, HCNTRL(config.base));
outb(config->pause, HCNTRL(base));
/*
* Just to be on the safe side with the 274x, we will re-read the irq
* since there was some issue about reseting the board.
*/
config.irq = inb(HA_INTDEF(config.base)) & 0x0F;
config->irq = inb(HA_INTDEF(base)) & 0x0F;
if ((inb(HA_274_BIOSCTRL(base)) & BIOSMODE) == BIOSDISABLED)
{
bios_disabled = 1;
}
host_conf = inb(HA_HOSTCONF(config.base));
config.busrtime = host_conf & 0x3C;
host_conf = inb(HA_HOSTCONF(base));
config->busrtime = host_conf & 0x3C;
/* XXX Is this valid for motherboard based controllers? */
/* Setup the FIFO threshold and the bus off time */
outb(host_conf & DFTHRSH, BUSSPD(config.base));
outb((host_conf << 2) & BOFF, BUSTIME(config.base));
outb(host_conf & DFTHRSH, BUSSPD(base));
outb((host_conf << 2) & BOFF, BUSTIME(base));
/*
* A reminder until this can be detected automatically.
*/
printk("aha274x: extended translation %sabled\n",
config.extended ? "en" : "dis");
printk("aha274x: Extended translation %sabled\n",
config->extended ? "en" : "dis");
break;
case AIC_284x:
#if 0
printk("aha284x: aic7770 hcntrl=0x%x\n", inb(HCNTRL(config.base)));
printk("aha284x: HCNTRL:0x%x\n", inb(HCNTRL(base)));
#endif
outb(CHIPRST, HCNTRL(config.base));
config.unpause = UNPAUSE_284X;
config.pause = REQ_PAUSE; /* DWG would like to be like the rest */
config.extended = aic7xxx_extended;
config.irq = inb(HA_INTDEF(config.base)) & 0x0F;
outb(CHIPRST, HCNTRL(base));
config->unpause = UNPAUSE_284X;
config->pause = REQ_PAUSE; /* DWG would like to be like the rest */
aic7xxx_delay(1);
outb(config->pause, HCNTRL(base));
config->extended = aic7xxx_extended;
config->irq = inb(HA_INTDEF(base)) & 0x0F;
if ((inb(HA_274_BIOSCTRL(base)) & BIOSMODE) == BIOSDISABLED)
{
bios_disabled = 1;
}
host_conf = inb(HA_HOSTCONF(config.base));
config.busrtime = host_conf & 0x3C;
host_conf = inb(HA_HOSTCONF(base));
printk("aha284x: Reading SEEPROM...");
have_seeprom = read_2840_seeprom(base, &sc);
if (!have_seeprom)
{
printk("aha284x: Unable to read SEEPROM\n");
config->busrtime = host_conf & 0x3C;
}
else
{
printk("done.\n");
config->extended = ((sc.bios_control & CFEXTEND) >> 7);
config->scsi_id = (sc.brtime_id & CFSCSIID);
config->parity = (sc.adapter_control & CFSPARITY) ?
AIC_ENABLED : AIC_DISABLED;
config->low_term = (sc.adapter_control & CFSTERM) ?
AIC_ENABLED : AIC_DISABLED;
config->high_term = (sc.adapter_control & CFWSTERM) ?
AIC_ENABLED : AIC_DISABLED;
config->busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
}
/* XXX Is this valid for motherboard based controllers? */
/* Setup the FIFO threshold and the bus off time */
outb(host_conf & DFTHRSH, BUSSPD(config.base));
outb((host_conf << 2) & BOFF, BUSTIME(config.base));
outb(host_conf & DFTHRSH, BUSSPD(base));
outb((host_conf << 2) & BOFF, BUSTIME(base));
/*
* A reminder until this can be detected automatically.
*/
printk("aha284x: extended translation %sabled\n",
config.extended ? "en" : "dis");
printk("aha284x: Extended translation %sabled\n",
config->extended ? "en" : "dis");
break;
case AIC_7850:
case AIC_7870:
case AIC_7872:
case AIC_7880:
case AIC_7882:
#if 0
printk("aic%s hcntrl=0x%x\n", board_name[type], inb(HCNTRL(config.base)));
printk("aic%s HCNTRL:0x%x\n", board_name[config->type], inb(HCNTRL(base)));
#endif
outb(CHIPRST, HCNTRL(config.base));
config.unpause = UNPAUSE_294X;
config.pause = config.unpause | PAUSE;
config.extended = aic7xxx_extended;
config.scsi_id = 7;
outb(CHIPRST, HCNTRL(base));
config->unpause = UNPAUSE_294X;
config->pause = config->unpause | PAUSE;
aic7xxx_delay(1);
outb(config->pause, HCNTRL(base));
config->extended = aic7xxx_extended;
config->scsi_id = 7;
printk("aic78xx: Reading SEEPROM... ");
have_seeprom = read_seeprom(base, &sc);
printk("aic78xx: Reading SEEPROM...");
have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2), &sc);
if (!have_seeprom)
{
printk("aic78xx: unable to read SEEPROM\n");
printk("aic78xx: Unable to read SEEPROM\n");
}
else
{
printk("done\n");
config.extended = ((sc.bios_control & CFEXTEND) >> 7);
config.scsi_id = (sc.brtime_id & CFSCSIID);
config.parity = (sc.adapter_control & CFSPARITY) ?
printk("done.\n");
config->extended = ((sc.bios_control & CFEXTEND) >> 7);
config->scsi_id = (sc.brtime_id & CFSCSIID);
config->parity = (sc.adapter_control & CFSPARITY) ?
AIC_ENABLED : AIC_DISABLED;
config.low_term = (sc.adapter_control & CFSTERM) ?
config->low_term = (sc.adapter_control & CFSTERM) ?
AIC_ENABLED : AIC_DISABLED;
config.high_term = (sc.adapter_control & CFWSTERM) ?
config->high_term = (sc.adapter_control & CFWSTERM) ?
AIC_ENABLED : AIC_DISABLED;
config.busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
config->busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
if (((config->type == AIC_7880) || (config->type == AIC_7882)) &&
(sc.adapter_control & CFULTRAEN))
{
printk ("aic7xxx: Enabling support for Ultra SCSI speed.\n");
config->ultra_enabled = TRUE;
}
}
/*
* XXX - force data fifo threshold to 100%. Why does this
* need to be done?
*/
outb(inb(DSPCISTATUS(config.base)) | DFTHRESH, DSPCISTATUS(config.base));
outb(config.scsi_id | DFTHRESH, HA_SCSICONF(config.base));
outb(inb(DSPCISTATUS(base)) | DFTHRESH, DSPCISTATUS(base));
outb(config->scsi_id | DFTHRESH, HA_SCSICONF(base));
/*
* In case we are a wide card, place scsi ID in second conf byte.
*/
outb(config.scsi_id, (HA_SCSICONF(config.base) + 1));
outb(config->scsi_id, (HA_SCSICONF(base) + 1));
/*
* A reminder until this can be detected automatically.
*/
printk("aic%s: extended translation %sabled\n", board_name[type],
config.extended ? "en" : "dis");
printk("aic%s: Extended translation %sabled\n", board_name[config->type],
config->extended ? "en" : "dis");
break;
default:
panic("aic7xxx_register: internal error\n");
}
config.maxscb = detect_maxscb(type, base);
config->maxscb = detect_maxscb(config->type, base, config->walk_scbs);
if ((config.type == AIC_274x) || (config.type == AIC_284x))
if ((config->type == AIC_274x) || (config->type == AIC_284x))
{
if (config.pause & IRQMS)
if (config->pause & IRQMS)
{
printk("aic7xxx: Using Level Sensitive Interrupts\n");
}
......@@ -3478,35 +3767,35 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
* Read the bus type from the SBLKCTL register. Set the FLAGS
* register in the sequencer for twin and wide bus cards.
*/
sblkctl = inb(SBLKCTL(base)) & 0x0F; /* mask out upper two bits */
switch (sblkctl)
sblkctl = inb(SBLKCTL(base));
switch (sblkctl & SELBUS_MASK)
{
case SELSINGLE: /* narrow/normal bus */
config.scsi_id = inb(HA_SCSICONF(base)) & 0x07;
config.bus_type = AIC_SINGLE;
config->scsi_id = inb(HA_SCSICONF(base)) & 0x07;
config->bus_type = AIC_SINGLE;
outb(SINGLE_BUS, HA_FLAGS(base));
break;
case SELWIDE: /* Wide bus */
config.scsi_id = inb(HA_SCSICONF(base) + 1) & 0x0F;
config.bus_type = AIC_WIDE;
config->scsi_id = inb(HA_SCSICONF(base) + 1) & 0x0F;
config->bus_type = AIC_WIDE;
printk("aic7xxx: Enabling wide channel of %s-Wide\n",
board_name[config.type]);
board_name[config->type]);
outb(WIDE_BUS, HA_FLAGS(base));
break;
case SELBUSB: /* Twin bus */
config.scsi_id = inb(HA_SCSICONF(base)) & 0x07;
config->scsi_id = inb(HA_SCSICONF(base)) & 0x07;
#ifdef AIC7XXX_TWIN_SUPPORT
config.scsi_id_b = inb(HA_SCSICONF(base) + 1) & 0x07;
config.bus_type = AIC_TWIN;
config->scsi_id_b = inb(HA_SCSICONF(base) + 1) & 0x07;
config->bus_type = AIC_TWIN;
printk("aic7xxx: Enabled channel B of %s-Twin\n",
board_name[config.type]);
board_name[config->type]);
outb(TWIN_BUS, HA_FLAGS(base));
#else
config.bus_type = AIC_SINGLE;
config->bus_type = AIC_SINGLE;
printk("aic7xxx: Channel B of %s-Twin will be ignored\n",
board_name[config.type]);
board_name[config->type]);
outb(0, HA_FLAGS(base));
#endif
break;
......@@ -3519,12 +3808,11 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
}
/*
* Clear the upper two bits. For the 294x cards, clearing the
* upper two bits, will take the card out of diagnostic mode
* and make the host adatper LED follow bus activity (will not
* always be on).
* For the 294x cards, clearing DIAGLEDEN and DIAGLEDON, will
* take the card out of diagnostic mode and make the host adatper
* LED follow bus activity (will not always be on).
*/
outb(sblkctl, SBLKCTL(base));
outb(sblkctl & ~(DIAGLEDEN | DIAGLEDON), SBLKCTL(base));
/*
* The IRQ level in i/o port 4 maps directly onto the real
......@@ -3536,10 +3824,10 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
*
* The 294x cards (PCI) get their interrupt from PCI BIOS.
*/
if (((config.type == AIC_274x) || (config.type == AIC_284x))
&& (config.irq < 9 || config.irq > 15))
if (((config->type == AIC_274x) || (config->type == AIC_284x)) &&
(config->irq < 9 || config->irq > 15))
{
printk("aic7xxx uses unsupported IRQ level, ignoring\n");
printk("aic7xxx uses unsupported IRQ level, ignoring.\n");
return (0);
}
......@@ -3551,7 +3839,7 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
* proceed.
*/
#ifndef AIC7XXX_SHARE_IRQS
if (aic7xxx_boards[config.irq] != NULL)
if (aic7xxx_boards[config->irq] != NULL)
{
printk("aic7xxx_register: Sharing of IRQs is not configured.\n");
return (0);
......@@ -3563,7 +3851,7 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
* the card - a lot of registers on it can't be read
* when the sequencer is active.
*/
debug_config(&config);
debug_config(config);
/*
* Before registry, make sure that the offsets of the
......@@ -3579,7 +3867,7 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
if (SG_STRUCT_CHECK(sg))
{
printk("aic7xxx warning: kernel scatter-gather "
"structures changed, disabling it\n");
"structures changed, disabling it.\n");
template->sg_tablesize = SG_NONE;
}
}
......@@ -3593,15 +3881,15 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
* information when an IRQ is triggered.
*/
host = scsi_register(template, sizeof(struct aic7xxx_host));
host->can_queue = config.maxscb;
host->can_queue = config->maxscb;
host->cmd_per_lun = AIC7XXX_CMDS_PER_LUN;
host->this_id = config.scsi_id;
host->irq = config.irq;
if (config.bus_type == AIC_WIDE)
host->this_id = config->scsi_id;
host->irq = config->irq;
if (config->bus_type == AIC_WIDE)
{
host->max_id = 16;
}
if (config.bus_type == AIC_TWIN)
if (config->bus_type == AIC_TWIN)
{
host->max_channel = 1;
}
......@@ -3621,21 +3909,23 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
p->isr_count = 0;
p->a_scanned = 0;
p->b_scanned = 0;
p->base = config.base;
p->maxscb = config.maxscb;
p->base = base;
p->maxscb = config->maxscb;
p->numscb = 0;
p->extended = config.extended;
p->type = config.type;
p->bus_type = config.bus_type;
p->extended = config->extended;
p->type = config->type;
p->ultra_enabled = config->ultra_enabled;
p->chan_num = config->chan_num;
p->bus_type = config->bus_type;
p->have_seeprom = have_seeprom;
p->seeprom = sc;
p->free_scb = NULL;
p->next = NULL;
p->unpause = config.unpause;
p->pause = config.pause;
p->unpause = config->unpause;
p->pause = config->pause;
if (aic7xxx_boards[config.irq] == NULL)
if (aic7xxx_boards[config->irq] == NULL)
{
/*
* Warning! This must be done before requesting the irq. It is
......@@ -3644,15 +3934,15 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
* kernel, an interrupt is triggered immediately. Therefore, we
* must ensure the board data is correctly set before the request.
*/
aic7xxx_boards[config.irq] = host;
aic7xxx_boards[config->irq] = host;
/*
* Register IRQ with the kernel.
*/
if (request_irq(config.irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx"))
if (request_irq(config->irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx"))
{
printk("aic7xxx couldn't register irq %d, ignoring\n", config.irq);
aic7xxx_boards[config.irq] = NULL;
printk("aic7xxx couldn't register irq %d, ignoring\n", config->irq);
aic7xxx_boards[config->irq] = NULL;
return (0);
}
}
......@@ -3663,8 +3953,8 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
* registered host adapter. Add this host adapter's Scsi_Host
* to the beginning of the linked list of hosts at the same IRQ.
*/
p->next = aic7xxx_boards[config.irq];
aic7xxx_boards[config.irq] = host;
p->next = aic7xxx_boards[config->irq];
aic7xxx_boards[config->irq] = host;
}
/*
......@@ -3674,7 +3964,7 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
* but then your mailing address is dynamically assigned
* so no one can find you anyway :-)
*/
printk("aic7xxx: Downloading sequencer code..");
printk("aic7xxx: Downloading sequencer code...");
aic7xxx_loadseq(base);
/*
......@@ -3690,27 +3980,37 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
printk("done.\n");
/*
* Set the SCSI Id, SXFRCTL1, and SIMODE1, for both channels
* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
*/
if (p->bus_type == AIC_TWIN)
{
/*
* The device is gated to channel B after a chip reset,
* so set those values first.
* Select Channel B.
*/
outb(config.scsi_id_b, SCSIID(base));
outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL(base));
outb(config->scsi_id_b, SCSIID(base));
scsi_conf = inb(HA_SCSICONF(base) + 1) & (ENSPCHK | STIMESEL);
outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1(base));
outb(ENSELTIMO | ENSCSIPERR, SIMODE1(base));
if (p->ultra_enabled)
{
outb(ULTRAEN, SXFRCTL0(base));
}
/*
* Select Channel A
*/
outb(SELSINGLE, SBLKCTL(base));
outb((sblkctl & ~SELBUS_MASK) | SELSINGLE, SBLKCTL(base));
}
outb(config.scsi_id, SCSIID(base));
outb(config->scsi_id, SCSIID(base));
scsi_conf = inb(HA_SCSICONF(base)) & (ENSPCHK | STIMESEL);
outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1(base));
outb(ENSELTIMO | ENSCSIPERR, SIMODE1(base));
if (p->ultra_enabled)
{
outb(ULTRAEN, SXFRCTL0(base));
}
/*
* Look at the information that board initialization or the board
......@@ -3732,6 +4032,7 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
{
max_targets = 16;
}
/*
* Grab the disconnection disable table and invert it for our needs
*/
......@@ -3749,7 +4050,8 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
}
else
{
p->discenable = ~(inw(HA_DISC_DSB(base)));
p->discenable = ~((inb(HA_DISC_DSB(base + 1)) << 8) |
inb(HA_DISC_DSB(base)));
}
}
......@@ -3807,7 +4109,7 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
* Clear the control byte for every SCB so that the sequencer
* doesn't get confused and think that one of them is valid
*/
for (i = 0; i < config.maxscb; i++)
for (i = 0; i < config->maxscb; i++)
{
outb(i, SCBPTR(base));
outb(0, SCBARRAY(base));
......@@ -3817,7 +4119,7 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
* For reconnecting targets, the sequencer code needs to
* know how many SCBs it has to search through.
*/
outb(config.maxscb, HA_SCBCOUNT(base));
outb(config->maxscb, HA_SCBCOUNT(base));
/*
* Clear the active flags - no targets are busy.
......@@ -3846,26 +4148,31 @@ aic7xxx_register(Scsi_Host_Template *template, aha_type type,
if (!aic7xxx_no_reset)
{
printk("Resetting the SCSI bus...\n");
printk("aic7xxx: Resetting the SCSI bus...");
if (p->bus_type == AIC_TWIN)
{
/*
* Select channel B.
* Select Channel B.
*/
outb(SELBUSB, SBLKCTL(base));
outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL(base));
outb(SCSIRSTO, SCSISEQ(base));
udelay(1000);
outb(0, SCSISEQ(base));
/*
* Select channel A.
* Select Channel A.
*/
outb(SELSINGLE, SBLKCTL(base));
outb((sblkctl & ~SELBUS_MASK) | SELSINGLE, SBLKCTL(base));
}
outb(SCSIRSTO, SCSISEQ(base));
udelay(1000);
outb(0, SCSISEQ(base));
aic7xxx_delay(AIC7XXX_RESET_DELAY);
printk("done.\n");
}
/*
......@@ -3891,8 +4198,10 @@ aic7xxx_detect(Scsi_Host_Template *template)
int found = 0, slot, base;
unsigned char irq = 0;
int i;
struct aic7xxx_host_config config;
template->proc_dir = &proc_scsi_aic7xxx;
config.chan_num = 0;
/*
* Since we may allow sharing of IRQs, it is imperative
......@@ -3936,9 +4245,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
aic7xxx_spurious_count = 1;
#if 0
printk("aic7xxx: hcntrl=0x%x\n", inb(HCNTRL(base)));
printk("aic7xxx: HCNTRL:0x%x\n", inb(HCNTRL(base)));
outb(inb(HCNTRL(base)) | CHIPRST, HCNTRL(base));
irq = inb(HA_INTDEF(base)) & 0x0F;
#endif
/*
......@@ -3946,7 +4254,16 @@ aic7xxx_detect(Scsi_Host_Template *template)
* signature and we can set it up and register
* it with the kernel without incident.
*/
found += aic7xxx_register(template, type, base, irq);
config.type = type;
config.base = base;
config.irq = irq;
config.parity = AIC_UNKNOWN;
config.low_term = AIC_UNKNOWN;
config.high_term = AIC_UNKNOWN;
config.busrtime = 0;
config.walk_scbs = FALSE;
config.ultra_enabled = FALSE;
found += aic7xxx_register(template, &config);
/*
* Disallow spurious interrupts.
......@@ -3957,11 +4274,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
#ifdef CONFIG_PCI
#define DEVREVID 0x08
#define DEVCONFIG 0x40
#define DEVSTATUS 0x41
#define RAMPSM 0x02
/*
* PCI-bus probe.
*/
......@@ -4001,6 +4313,27 @@ aic7xxx_detect(Scsi_Host_Template *template)
index, &pci_bus, &pci_device_fn))
{
type = AIC_7872;
config.chan_num = number_of_3940s & 0x1;
number_of_3940s++;
}
else
{
if ((!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
PCI_DEVICE_ID_ADAPTEC_7881,
index, &pci_bus, &pci_device_fn)) ||
(!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
PCI_DEVICE_ID_ADAPTEC_7880,
index, &pci_bus, &pci_device_fn)))
{
type = AIC_7880;
}
else
{
if (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
PCI_DEVICE_ID_ADAPTEC_7882,
index, &pci_bus, &pci_device_fn))
{
type = AIC_7882;
}
else
{
......@@ -4009,6 +4342,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
}
}
}
}
}
if (!done)
{
......@@ -4017,7 +4352,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
*/
error = pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_0, &io_port);
if (error)
{
panic("aic7xxx_detect: error 0x%x reading i/o port.\n", error);
......@@ -4030,42 +4364,62 @@ aic7xxx_detect(Scsi_Host_Template *template)
panic("aic7xxx_detect: error %d reading irq.\n", error);
}
/*
* Make the base I/O register look like EISA and VL-bus.
*/
base = io_port - 0xC01;
/*
* I don't think we need to bother with allowing
* spurious interrupts for the 787x/7850, but what
* the hey.
*/
aic7xxx_spurious_count = 1;
#if 0
printk("aic7xxx: hcntrl=0x%x\n", inb(HCNTRL(base)));
#endif
outb(inb(HCNTRL(base)) | CHIPRST, HCNTRL(base));
error = pcibios_read_config_byte(pci_bus, pci_device_fn,
DEVREVID, &devrevid);
if (error)
{
panic("aic7xxx_detect: error %d reading device revision id.\n", error);
}
if (devrevid < 3)
{
printk("aic7xxx_detect: AIC-7870 Rev %c\n", rev_id[devrevid]);
}
error = pcibios_read_config_byte(pci_bus, pci_device_fn,
DEVCONFIG, &devconfig);
if (error)
{
panic("aic7xxx_detect: error %d reading device configuration.\n", error);
}
error = pcibios_read_config_byte(pci_bus, pci_device_fn,
DEVSTATUS, &devstatus);
if (error)
{
panic("aic7xxx_detect: error %d reading device status.\n", error);
}
printk("aic7xxx_detect: devconfig 0x%x, devstatus 0x%x\n",
devconfig, devstatus);
if (devstatus & RAMPSM)
/*
* Make the base I/O register look like EISA and VL-bus.
*/
base = io_port - 0xC01;
/*
* I don't think we need to bother with allowing
* spurious interrupts for the 787x/7850, but what
* the hey.
*/
aic7xxx_spurious_count = 1;
config.type = type;
config.base = base;
config.irq = irq;
config.parity = AIC_UNKNOWN;
config.low_term = AIC_UNKNOWN;
config.high_term = AIC_UNKNOWN;
config.busrtime = 0;
config.walk_scbs = FALSE;
config.ultra_enabled = FALSE;
if ((devstatus & RAMPSM) || (devconfig & SCBRAMSEL) ||
(type == AIC_7872))
{
printk("aic7xxx_detect: detected external SCB RAM, "
"mail deang@ims.com for test patch");
config.walk_scbs = TRUE;
}
found += aic7xxx_register(template, type, base, irq);
found += aic7xxx_register(template, &config);
/*
* Disable spurious interrupts.
......@@ -4530,8 +4884,24 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
save_flags(flags);
cli();
if (scb->state & SCB_ACTIVE)
{
if (scb->state & SCB_IMMED)
{
/*
* Don't know how set the number of retries to 0.
*/
/* cmd->retries = 0; */
aic7xxx_done (p, scb);
}
else
{
/*
* Abort the operation.
*/
aic7xxx_abort_scb(p, scb);
}
}
restore_flags(flags);
return (0);
}
......
......@@ -25,13 +25,14 @@
# optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
##-M#########################################################################
VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 2.1 1995/08/30 07:47:07 deang Exp $"
VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 2.3 1995/11/10 10:51:22 deang Exp $"
SCBMASK = 0xff
SCSISEQ = 0x00
ENRSELI = 0x10
SXFRCTL0 = 0x01
ULTRAEN = 0x20
SXFRCTL1 = 0x02
SCSISIGI = 0x03
SCSISIGO = 0x03
......@@ -229,7 +230,6 @@ ACTIVE_B = 0x55
SAVED_TCL = 0x56 # Temporary storage for the
# target/channel/lun of a
# reconnecting target
# After starting the selection hardware, we return to the "poll_for_work"
# loop so that we can check for reconnecting targets as well as for our
# selection to complete just in case the reselection wins bus arbitration.
......@@ -444,6 +444,7 @@ ITloop:
and A,0xe0,SCSISIGI # CDI|IOI|MSGI
mov A call scsisig
cmp ALLZEROS,A je p_dataout
cmp A,0x40 je p_datain
cmp A,0x80 je p_command
......@@ -454,7 +455,6 @@ ITloop:
mvi INTSTAT,BAD_PHASE # unknown - signal driver
p_dataout:
mvi 0 call scsisig # !CDO|!IOO|!MSGO
mvi DMAPARAMS,0x7d # WIDEODD|SCSIEN|SDMAEN|HDMAEN|
# DIRECTION|FIFORESET
jmp data_phase_init
......@@ -469,8 +469,7 @@ data_phase_reinit:
# Reads should not use WIDEODD since it may make the last byte for a SG segment
# go to the next segment.
p_datain:
mvi 0x40 call scsisig # !CDO|IOO|!MSGO
mvi DMAPARAMS,0x39 # SCSIEN|SDMAEN|HDMAEN|
mvi DMAPARAMS,0x79 # WIDEODD|SCSIEN|SDMAEN|HDMAEN|
# !DIRECTION|FIFORESET
data_phase_init:
call assert
......@@ -574,7 +573,6 @@ data_phase_finish:
# so we can copy those three bytes directly into HCNT.
#
p_command:
mvi 0x80 call scsisig # CDO|!IOO|!MSGO
call assert
# Load HADDR and HCNT. We can do this in one bcopy since they are neighbors
......@@ -592,7 +590,6 @@ p_command:
# and store it into the SCB.
#
p_status:
mvi 0xc0 call scsisig # CDO|IOO|!MSGO
mvi SCBARRAY+14 call inb_first
jmp mesgin_done
......@@ -601,7 +598,6 @@ p_status:
# took us into this phase anyway, build a no-op message and send it.
#
p_mesgout:
mvi 0xa0 call scsisig # CDO|!IOO|MSGO
mvi 0x8 call mk_mesg # build NOP message
clr STCNT+2
......@@ -661,7 +657,8 @@ p_mesgout5:
and A,0xe0,SCSISIGI # CDI|IOI|MSGI
cmp A,0xa0 jne p_mesgout6
mvi 0x10 call scsisig # ATNO - re-assert ATN
or SINDEX,0x10,SIGSTATE # turn on ATNO
call scsisig # ATNO - re-assert ATN
jmp ITloop
......@@ -679,7 +676,6 @@ p_mesgout6:
# to a data I/O phase.
#
p_mesgin:
mvi 0xe0 call scsisig # CDO|IOO|MSGO
mvi A call inb_first # read the 1st message byte
mvi REJBYTE,A # save it for the driver
......@@ -742,11 +738,12 @@ status_ok:
mov A,FUNCTION1
test SCBARRAY+1,0x88 jz clear_a
xor ACTIVE_B,A
jmp complete
jmp immediate
clear_a:
xor ACTIVE_A,A
immediate:
test SCBARRAY+11,0xff jnz complete # Immediate message complete
# Pause the sequencer until the driver gets around to handling the command
# complete. This is so that any action that might require carefull timing
......@@ -1011,7 +1008,8 @@ dma4:
# actually off first lest we get an ILLSADDR.
#
dma5:
clr DFCNTRL # disable DMA
and DFCNTRL, 0x40, SINDEX # disable DMA, but maintain
# WIDEODD
dma6:
test DFCNTRL,0x38 jnz dma6 # SCSIENACK|SDMAENACK|HDMAENACK
......@@ -1044,7 +1042,7 @@ initialize_for_target:
#
clr SIGSTATE
mvi SXFRCTL0,0x8a # DFON|SPIOEN|CLRCHN
or SXFRCTL0,0x8a # DFON|SPIOEN|CLRCHN
# Make sure that the system knows we have not been through a DATA
# phase.
......@@ -1205,7 +1203,8 @@ sdtr_to_rate_loop:
jmp sdtr_to_rate_loop
sdtr_to_rate_done:
shr RETURN_1,0x2
add RETURN_1,0x18 ret
add RETURN_1,0x18
test SXFRCTL0,ULTRAEN jz return
shr RETURN_1,0x1
return:
ret
......@@ -796,6 +796,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid)
*/
printk("Unable to reset scsi host %d - ", SCpnt->host->host_no);
printk("probably a SCSI bus hang.\n");
SCpnt->internal_timeout &= ~IN_RESET;
scsi_reset (SCpnt, TRUE);
return;
......@@ -1834,6 +1835,26 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid)
}
}
/* Mark a single SCSI Device as having been reset. */
static inline void scsi_mark_device_reset(Scsi_Device *Device)
{
Device->was_reset = 1;
Device->expecting_cc_ua = 1;
}
/* Mark all SCSI Devices on a specific Host as having been reset. */
void scsi_mark_host_bus_reset(struct Scsi_Host *Host)
{
Scsi_Cmnd *SCpnt;
for(SCpnt = Host->host_queue; SCpnt; SCpnt = SCpnt->next)
scsi_mark_device_reset(SCpnt->device);
}
int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
{
int temp, oldto;
......@@ -1935,27 +1956,20 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
printk("scsi reset function returned %d\n", temp);
#endif
if( temp & SCSI_RESET_BUS_RESET )
{
/*
* The low level driver did a bus reset, so we should
* go through and mark all of the devices on that bus
* as having been reset.
*/
SCpnt1 = host->host_queue;
while(SCpnt1) {
SCpnt1->device->was_reset = 1;
SCpnt1->device->expecting_cc_ua = 1;
SCpnt1 = SCpnt1->next;
}
}
/*
* Now figure out what we need to do, based upon
* what the low level driver said that it did.
* If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING,
* or SCSI_RESET_WAKEUP, then the low level driver did a
* bus device reset or bus reset, so we should go through
* and mark one or all of the devices on that bus
* as having been reset.
*/
switch(temp & SCSI_RESET_ACTION) {
case SCSI_RESET_SUCCESS:
if (temp & SCSI_RESET_BUS_RESET)
scsi_mark_host_bus_reset(host);
else scsi_mark_device_reset(SCpnt->device);
save_flags(flags);
cli();
SCpnt->internal_timeout &= ~IN_RESET;
......@@ -1963,12 +1977,18 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
restore_flags(flags);
return 0;
case SCSI_RESET_PENDING:
if (temp & SCSI_RESET_BUS_RESET)
scsi_mark_host_bus_reset(host);
else scsi_mark_device_reset(SCpnt->device);
return 0;
case SCSI_RESET_PUNT:
SCpnt->internal_timeout &= ~IN_RESET;
scsi_request_sense (SCpnt);
return 0;
case SCSI_RESET_WAKEUP:
if (temp & SCSI_RESET_BUS_RESET)
scsi_mark_host_bus_reset(host);
else scsi_mark_device_reset(SCpnt->device);
SCpnt->internal_timeout &= ~IN_RESET;
scsi_request_sense (SCpnt);
/*
......
......@@ -449,6 +449,7 @@ extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int);
extern void print_command(unsigned char *);
extern void print_sense(const char *, Scsi_Cmnd *);
extern void scsi_mark_host_bus_reset(struct Scsi_Host *Host);
#if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
#include "hosts.h"
......
......@@ -1134,6 +1134,12 @@ static int sd_init_onedisk(int i)
rscsi_disks[i].sector_size = (buffer[4] << 24) |
(buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
if (rscsi_disks[i].sector_size == 0) {
rscsi_disks[i].sector_size = 512;
printk("sd%c : sector size 0 reported, assuming 512.\n", 'a' + i);
}
if (rscsi_disks[i].sector_size != 512 &&
rscsi_disks[i].sector_size != 1024 &&
rscsi_disks[i].sector_size != 256)
......
......@@ -157,9 +157,9 @@ static int parse_options (char * options, unsigned long * sb_block,
clear_opt (*mount_options, CHECK_NORMAL);
clear_opt (*mount_options, CHECK_STRICT);
}
else if (strcmp (value, "normal"))
else if (!strcmp (value, "normal"))
set_opt (*mount_options, CHECK_NORMAL);
else if (strcmp (value, "strict")) {
else if (!strcmp (value, "strict")) {
set_opt (*mount_options, CHECK_NORMAL);
set_opt (*mount_options, CHECK_STRICT);
}
......
......@@ -81,7 +81,7 @@ static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
*check = 'n';
*conversion = 'b';
*dotsOK =1;
*dotsOK =0;
*uid = current->uid;
*gid = current->gid;
*umask = current->fs->umask;
......
......@@ -100,37 +100,39 @@ __old_ipl; })
/*
* Give prototypes to shut up gcc.
*/
extern inline unsigned long xchg_u32 (volatile int * m, unsigned long new_val);
extern inline unsigned long xchg_u64 (volatile long * m, unsigned long new_val);
extern inline unsigned long xchg_u32 (volatile int * m, unsigned long val);
extern inline unsigned long xchg_u64 (volatile long * m, unsigned long val);
extern inline unsigned long xchg_u32(volatile int * m, unsigned long new_val)
extern inline unsigned long xchg_u32(volatile int * m, unsigned long val)
{
unsigned long old_val;
__asm__ __volatile__("\n1:\t"
"ldl_l %0,%2\n\t"
"bis %3,%3,$25\n\t"
"stl_c $25,%1\n\t"
"beq $25,1b\n"
: "=r"(old_val), "=m"(*m)
: "m"(*m), "r"(new_val)
: "$25");
return old_val;
unsigned long dummy, dummy2;
__asm__ __volatile__(
"\n1:\t"
"ldl_l %0,0(%1)\n\t"
"bis %2,%2,%3\n\t"
"stl_c %3,0(%1)\n\t"
"beq %3,1b\n"
: "=r" (val), "=r" (m), "=r" (dummy), "=r" (dummy2)
: "1" (m), "2" (val)
: "memory");
return val;
}
extern inline unsigned long xchg_u64(volatile long * m, unsigned long new_val)
extern inline unsigned long xchg_u64(volatile long * m, unsigned long val)
{
unsigned long old_val;
__asm__ __volatile__("\n1:\t"
"ldq_l %0,%2\n\t"
"bis %3,%3,$25\n\t"
"stq_c $25,%1\n\t"
"beq $25,1b\n"
: "=r"(old_val), "=m"(*m)
: "m"(*m), "r"(new_val)
: "$25");
return old_val;
unsigned long dummy, dummy2;
__asm__ __volatile__(
"\n1:\t"
"ldq_l %0,0(%1)\n\t"
"bis %2,%2,%3\n\t"
"stq_c %3,0(%1)\n\t"
"beq %3,1b\n"
: "=r" (val), "=r" (m), "=r" (dummy), "=r" (dummy2)
: "1" (m), "2" (val)
: "memory");
return val;
}
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
......
......@@ -6,8 +6,6 @@
#ifndef _ASMI386_IOCTL_H
#define _ASMI386_IOCTL_H
#include <asm/page.h> /* for PAGE_SIZE */
/* ioctl command encoding: 32 bits total, command in lower 16 bits,
* size of the parameter structure in the lower 14 bits of the
* upper 16 bits.
......@@ -18,38 +16,6 @@
* NOTE: This limits the max parameter size to 16kB -1 !
*/
#define IOC_VOID 0x00000000 /* param in size field */
#define IOC_IN 0x40000000 /* user --> kernel */
#define IOC_OUT 0x80000000 /* kernel --> user */
#define IOC_INOUT (IOC_IN | IOC_OUT) /* both */
#define IOCSIZE_MASK 0x3fff0000 /* size (max 16k-1 bytes) */
#define IOCSIZE_SHIFT 16 /* how to get the size */
#define IOCSIZE_MAX ((PAGE_SIZE-1)&(IOCSIZE_MASK >> IOCSIZE_SHIFT))
#define IOCCMD_MASK 0x0000ffff /* command code */
#define IOCCMD_SHIFT 0
#define IOCPARM_MASK IOCCMD_MASK
#define IOCPARM_SHIFT IOCCMD_SHIFT
#define IOC_SIZE(cmd) (((cmd) & IOCSIZE_MASK) >> IOCSIZE_SHIFT)
#define IOCBASECMD(cmd) ((cmd) & ~IOCPARM_MASK)
#define IOCGROUP(cmd) (((cmd) >> 8) & 0xFF)
/* _IO(magic, subcode); size field is zero and the
* subcode determines the command.
*/
#define _IO(c,d) (IOC_VOID | ((c)<<8) | (d)) /* param encoded */
/* _IOXX(magic, subcode, arg_t); where arg_t is the type of the
* (last) argument field in the ioctl call, if present.
*/
#define _IOW(c,d,t) (IOC_IN | ((sizeof(t)<<16) & IOCSIZE_MASK) | \
((c)<<8) | (d))
#define _IOR(c,d,t) (IOC_OUT | ((sizeof(t)<<16) & IOCSIZE_MASK) | \
((c)<<8) | (d))
/* WR rather than RW to avoid conflict with stdio.h */
#define _IOWR(c,d,t) (IOC_INOUT | ((sizeof(t)<<16) & IOCSIZE_MASK) | \
((c)<<8) | (d))
/*
* The following is for compatibility across the various Linux
* platforms. The i386 ioctl numbering scheme doesn't really enforce
......@@ -80,10 +46,30 @@
#define _IOC_READ 1U
#define _IOC_WRITE 2U
#define _IOC(dir,type,nr,size) \
(((dir) << _IOC_DIRSHIFT) | \
((type) << _IOC_TYPESHIFT) | \
((nr) << _IOC_NRSHIFT) | \
((size) << _IOC_SIZESHIFT))
/* used to create numbers */
#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
/* used to decode ioctl numbers.. */
#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
/* ...and for the drivers/sound files... */
#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT)
#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT)
#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT)
#define IOCSIZE_SHIFT (_IOC_SIZESHIFT)
#endif /* _ASMI386_IOCTL_H */
......@@ -127,7 +127,7 @@ extern void enable_irq(unsigned int);
#define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr)
#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr)
#ifdef ___SMP__
#ifdef __SMP__
#define GET_PROCESSOR_ID \
"movl "SYMBOL_NAME_STR(apic_reg)", %edx\n\t" \
......
......@@ -110,8 +110,7 @@ struct mcd_Toc {
struct msf diskTime;
};
#if 0
#ifndef I_WAS_HERE
#error Please edit this file first.
#endif
#warning You have not edited mcd.h
#warning Perhaps irq and i/o settings are wrong.
#endif
/*
* Definitions for the Mitsumi CDROM interface
* Copyright (C) 1995 Heiko Schlittermann
* VERSION: 1.0a
* Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
* VERSION: 1.3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -92,10 +92,16 @@
#define INIT 0
#define MALLOC 0
#define IOCTL 0
#define PLAYTRK 0
#define SUBCHNL 0
#define TOCHDR 0
#define MS 0
#define PLAYMSF 0
#define READTOC 0
#define OPENCLOSE 0
#define HW 0
#define TALK 0
#define IRQ 0
#define IRQ 1
#define TRANSFER 0
#define REQUEST 0
#else
......@@ -173,8 +179,7 @@
#define MCDX_E 1 /* unspec error */
#define MCDX_EOM 2 /* end of media */
#if 0
#ifndef I_WAS_HERE
#error Please edit this file first.
#endif
#warning You have not edited mcdx.h
#warning Perhaps irq and i/o settings are wrong.
#endif
......@@ -454,6 +454,7 @@
#define PCI_DEVICE_ID_ADAPTEC_7872 0x7278
#define PCI_DEVICE_ID_ADAPTEC_7880 0x8078
#define PCI_DEVICE_ID_ADAPTEC_7881 0x8178
#define PCI_DEVICE_ID_ADAPTEC_7882 0x8278
#define PCI_VENDOR_ID_ATRONICS 0x907f
#define PCI_DEVICE_ID_ATRONICS_2015 0x2015
......
......@@ -328,6 +328,7 @@ extern int pty_open(struct tty_struct * tty, struct file * filp);
extern int con_open(struct tty_struct * tty, struct file * filp);
extern void update_screen(int new_console);
extern void console_print(const char *);
/* vt.c */
......
......@@ -266,6 +266,8 @@ struct symbol_table symbol_table = {
X(tty_wait_until_sent),
X(tty_check_change),
X(tty_hung_up_p),
X(do_SAK),
X(console_print),
/* filesystem registration */
X(register_filesystem),
......
......@@ -111,8 +111,8 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
}
len += sprintf(buffer+len, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d %d\n",
i, src, srcp, dest, destp, sp->state,
format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc,
format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
format==0?sp->write_seq-sp->rcv_ack_seq:sp->wmem_alloc,
format==0?sp->acked_seq-sp->copied_seq:sp->rmem_alloc,
timer_active, timer_expires-jiffies, (unsigned) sp->retransmits,
(sp->socket&&SOCK_INODE(sp->socket))?SOCK_INODE(sp->socket)->i_uid:0,
timer_active?sp->timeout:0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment