From 6d58893f09031791fc5a4164314703a885e22445 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:11:17 -0500 Subject: [PATCH] Import 2.0.16 --- Documentation/Changes | 22 +- Makefile | 2 +- drivers/block/floppy.c | 4 +- drivers/isdn/icn/icn.c | 47 ++- drivers/isdn/icn/icn.h | 7 +- drivers/isdn/isdn_net.c | 63 +--- drivers/isdn/isdn_ppp.c | 490 +++++++++++++++++-------------- drivers/isdn/isdn_ppp.h | 1 + drivers/isdn/teles/card.c | 22 +- drivers/scsi/ChangeLog.ncr53c8xx | 7 + drivers/scsi/ncr53c8xx.c | 47 ++- drivers/scsi/ncr53c8xx.h | 4 +- drivers/scsi/sg.c | 35 ++- drivers/scsi/wd7000.c | 480 ++++++++++++++++++++---------- drivers/sound/dmabuf.c | 2 +- fs/buffer.c | 13 +- fs/locks.c | 22 +- include/linux/isdn.h | 8 +- include/linux/sched.h | 29 +- include/linux/soundcard.h | 23 +- include/linux/wait.h | 13 + init/main.c | 4 + ipc/msg.c | 20 +- ipc/sem.c | 6 +- ipc/shm.c | 9 +- kernel/fork.c | 1 + kernel/sched.c | 64 ++-- net/core/net_alias.c | 2 + net/ipv4/tcp_output.c | 2 + 29 files changed, 890 insertions(+), 559 deletions(-) diff --git a/Documentation/Changes b/Documentation/Changes index 285bb6534f51..f4b70841f5eb 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -20,20 +20,21 @@ prefer a HTML-ized shopping list. Para aquellos que prefieran una version en castellano de este documento, consultad la traduccion de Alfredo Sanjuan en -http://slug.ctv.es/~alfredo/Cambios.html. +http://slug.ctv.es/~alfredo/Cambios.html (Spanish translation). Akik magyarul szeretnenek olvasni az uj kernellel kapcsolatos valtozasokrol, az alabbi cimen megtalaljak Nyitrai Tamas forditasat: -http://www.datanet.hu/generations/linux/newkernel.html. +http://www.datanet.hu/generations/linux/newkernel.html (Hungarian +translation). - Tamas also maintains a version of this file in English at -http://www.datanet.hu/generations/linux/Changes.html. + Tamas also maintains a version of this file at +http://www.datanet.hu/generations/linux/Changes.html (English). For people who prefer Japanese (thanks to Mitsuhiro Kojima): Kono bunshou no nihongo ban wa http://jf.gee.kyoto-u.ac.jp/JF/v2.0/Changes-2.0.html ni arimasu. -Last updated: August 18, 1996. +Last updated: August 29, 1996. Current Author: Chris Ricker (gt1355b@prism.gatech.edu). Current Releases @@ -152,7 +153,7 @@ the sig11 FAQ. On the other hand, if you're using a gcc patched for Pentium optimization and are getting these errors, downgrade to a standard GNU -gcc before assuming your hardware (or the kernel) is to blame.. +gcc before assuming your hardware (or the kernel) is to blame. On a related note, if you get random OOPses that don't seem to be related to anything and you have a motherboard with APM support, try @@ -678,11 +679,14 @@ upgrade to install. Almost everything you need is available in ftp://ftp.redhat.com/pub/current/i386/updates/2.0-kernel/ and its mirrors. - For others, especially those of you running Slackware 3.0, David -Bourgin has put together a Slackware-compatible package of everything + For others, David Bourgin has put together a package of everything necessary to quickly and easily upgrade to 2.0.x. See ftp://ftp.wsc.com/pub/freeware/linux/update.linux/ for more information -and the files. +and the files. This package also includes many bug-fixes, including +one for a recently discovered bug in sendmail-8.7.5 (just look at +/pub/freeware/linux/update.linux/updat2-0.addon1/sendmail-8.7.5a.tar.gz +if you only need the bug fix). There's also an alternate lightweight +termcap in the same directory that works well for many people. Please send info about any other packages that 2.0.x "broke" or about any new features of 2.0.x that require extra or new packages for use to diff --git a/Makefile b/Makefile index fabd9663f297..179a9821ffeb 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 0 -SUBLEVEL = 15 +SUBLEVEL = 16 ARCH = i386 diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 39d940b2a4c6..43df14a575ab 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -966,7 +966,7 @@ static int wait_for_completion(int delay, timeout_fn function) return 1; } - if (jiffies - delay < 0){ + if ((signed) (jiffies - delay) < 0){ del_timer(&fd_timer); fd_timer.function = function; fd_timer.expires = delay; @@ -1415,7 +1415,7 @@ static void setup_rw_floppy(void) * again just before spinup completion. Beware that * after scandrives, we must again wait for selection. */ - if (ready_date - jiffies > DP->select_delay){ + if ((signed) (ready_date - jiffies) > DP->select_delay){ ready_date -= DP->select_delay; function = (timeout_fn) floppy_start; } else diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index a28c2a1e0ff1..65723fef99c9 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.28 1996/06/28 17:02:53 fritz Exp $ +/* $Id: icn.c,v 1.29 1996/08/29 20:34:54 fritz Exp $ * * ISDN low-level module for the ICN active ISDN-Card. * @@ -19,6 +19,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.29 1996/08/29 20:34:54 fritz + * Bugfix in send queue management: + * sndcount was not updated correctly. + * Minor Bugfixes. + * * Revision 1.28 1996/06/28 17:02:53 fritz * replaced memcpy_fromfs_toio. * @@ -136,7 +141,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.28 $"; +*revision = "$Revision: 1.29 $"; static int icn_addcard(int, char *, char *); @@ -675,9 +680,7 @@ static void icn_polldchan(unsigned long data) /* Append a packet to the transmit buffer-queue. * Parameters: * channel = Number of B-channel - * buffer = pointer to packet - * len = size of packet (max 4000) - * user = 1 = call from userproc, 0 = call from kernel + * skb = pointer to sk_buff * card = pointer to card-struct * Return: * Number of bytes transferred, -E??? on error @@ -701,19 +704,25 @@ static int icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card) return 0; save_flags(flags); cli(); - card->sndcount[channel] += len; nskb = skb_clone(skb, GFP_ATOMIC); if (nskb) { - skb_queue_tail(&card->spqueue[channel], nskb); - dev_kfree_skb(skb, FREE_WRITE); - } + skb_queue_tail(&card->spqueue[channel], nskb); + dev_kfree_skb(skb, FREE_WRITE); + } else + len = 0; + card->sndcount[channel] += len; restore_flags(flags); - if (!nskb) - return 0; } return len; } +/* + * Check card's status after starting the bootstrap loader. + * On entry, the card's shared memory has already to be mapped. + * Return: + * 0 on success (Boot loader ready) + * -EIO on failure (timeout) + */ static int icn_check_loader(int cardnumber) { int timer = 0; @@ -1162,7 +1171,19 @@ static int icn_command(isdn_ctrl * c, icn_card * card) case ICN_IOCTL_GETDOUBLE: return (int) card->doubleS0; case ICN_IOCTL_DEBUGVAR: - return (ulong) card; + if ((i = verify_area(VERIFY_WRITE, + (void *) a, + sizeof(ulong) * 2))) + return i; + memcpy_tofs((char *)a, + (char *)&card, sizeof(ulong)); + a += sizeof(ulong); + { + ulong l = (ulong)&dev; + memcpy_tofs((char *)a, + (char *)&l, sizeof(ulong)); + } + return 0; case ICN_IOCTL_LOADBOOT: icn_stopcard(card); return (icn_loadboot((u_char *) a, card)); @@ -1630,7 +1651,7 @@ void cleanup_module(void) } card = card->next; } - card = card; + card = cards; while (card) { last = card; card = card->next; diff --git a/drivers/isdn/icn/icn.h b/drivers/isdn/icn/icn.h index 5a8076ee255e..acbc113a260b 100644 --- a/drivers/isdn/icn/icn.h +++ b/drivers/isdn/icn/icn.h @@ -1,4 +1,4 @@ -/* $Id: icn.h,v 1.20 1996/06/24 17:20:37 fritz Exp $ +/* $Id: icn.h,v 1.21 1996/08/29 20:35:57 fritz Exp $ * * ISDN lowlevel-module for the ICN active ISDN-Card. * @@ -19,6 +19,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.h,v $ + * Revision 1.21 1996/08/29 20:35:57 fritz + * Speed up B-Channel polling interval. + * * Revision 1.20 1996/06/24 17:20:37 fritz * Bugfixes in pollbchan_send(): * - Using lock field of skbuff breaks networking. @@ -156,7 +159,7 @@ typedef struct icn_cdef { #define ICN_BOOT_TIMEOUT1 100 /* Delay for Boot-download (jiffies) */ #define ICN_CHANLOCK_DELAY 10 /* Delay for Channel-mapping (jiffies) */ -#define ICN_TIMER_BCREAD 3 /* B-Channel poll-cycle */ +#define ICN_TIMER_BCREAD 1 /* B-Channel poll-cycle */ #define ICN_TIMER_DCREAD 50 /* D-Channel poll-cycle */ #define ICN_CODE_STAGE1 4096 /* Size of bootcode */ diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index d5bc55eca032..0774f53196c1 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.18 1996/07/03 13:48:51 hipp Exp $ +/* $Id: isdn_net.c,v 1.20 1996/08/29 20:06:03 fritz Exp $ * * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.20 1996/08/29 20:06:03 fritz + * Bugfix: Transmission timeout had been much to low. + * + * Revision 1.19 1996/08/12 16:24:32 hipp + * removed some (now) obsolete functions for syncPPP in rebuild_header etc. + * * Revision 1.18 1996/07/03 13:48:51 hipp * bugfix: Call dev_purge_queues() only for master device * @@ -124,7 +130,7 @@ static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *); extern void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */ -char *isdn_net_revision = "$Revision: 1.18 $"; +char *isdn_net_revision = "$Revision: 1.20 $"; /* * Code for raw-networking over ISDN @@ -369,6 +375,10 @@ isdn_net_stat_callback(int idx, int cmd) */ lp->chargetime = jiffies; /* Immediately send first skb to speed up arp */ +#ifdef CONFIG_ISDN_PPP + if(lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + isdn_ppp_wakeup_daemon(lp); +#endif if (lp->first_skb) { if (!(isdn_net_xmit(&p->dev,lp,lp->first_skb))) lp->first_skb = NULL; @@ -658,7 +668,6 @@ isdn_net_log_packet(u_char * buf, isdn_net_local * lp) u_char *p = buf; unsigned short proto = ETH_P_IP; int data_ofs; - int len; ip_ports *ipp; char addinfo[100]; @@ -676,22 +685,6 @@ isdn_net_log_packet(u_char * buf, isdn_net_local * lp) proto = ntohs(*(unsigned short *)&buf[2]); p = &buf[4]; break; - case ISDN_NET_ENCAP_SYNCPPP: - len = 4; -#ifdef CONFIG_ISDN_MPP - if (lp->ppp_minor!=-1) { - if (ippp_table[lp->ppp_minor]->mpppcfg & - SC_MP_PROT) { - if (ippp_table[lp->ppp_minor]->mpppcfg & - SC_OUT_SHORT_SEQ) - len = 7; - else - len = 9; - } - } -#endif - p = &buf[len]; - break; } data_ofs = ((p[0] & 15) * 4); switch (proto) { @@ -851,7 +844,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev) isdn_net_local *lp = (isdn_net_local *) ndev->priv; if (ndev->tbusy) { - if (jiffies - ndev->trans_start < 20) + if (jiffies - ndev->trans_start < (2 * HZ)) return 1; if (!lp->dialstate) lp->stats.tx_errors++; @@ -1248,29 +1241,6 @@ isdn_net_header(struct sk_buff *skb, struct device *dev, unsigned short type, *((ushort*)&skb->data[2]) = htons(type); len = 4; break; -#ifdef CONFIG_ISDN_PPP - case ISDN_NET_ENCAP_SYNCPPP: - /* reserve space to be filled in isdn_ppp_xmit */ - len = 4; -#ifdef CONFIG_ISDN_MPP - if (lp->ppp_minor!=-1) { - if (ippp_table[lp->ppp_minor]->mpppcfg & - SC_MP_PROT) { - if (ippp_table[lp->ppp_minor]->mpppcfg & - SC_OUT_SHORT_SEQ) - len = 7; - else - len = 9; - } - } -#endif - /* Initialize first 4 bytes to a value, which is - * guaranteed to be invalid. Need that to check - * for already compressed packets in isdn_ppp_xmit(). - */ - *((u32 *)skb_push(skb, len)) = 0; - break; -#endif } return len; } @@ -1756,7 +1726,7 @@ isdn_net_find_icall(int di, int ch, int idx, char *num) dev->st_netdev[idx] = lp->netdev; p->local.isdn_device = di; p->local.isdn_channel = ch; - p->local.ppp_minor = -1; + p->local.ppp_slot = -1; p->local.pppbind = -1; p->local.flags |= ISDN_NET_CONNECTED; p->local.dialstate = 7; @@ -1927,7 +1897,7 @@ isdn_net_new(char *name, struct device *master) netdev->local.pre_device = -1; netdev->local.pre_channel = -1; netdev->local.exclusive = -1; - netdev->local.ppp_minor = -1; + netdev->local.ppp_slot = -1; netdev->local.pppbind = -1; netdev->local.l2_proto = ISDN_PROTO_L2_X75I; netdev->local.l3_proto = ISDN_PROTO_L3_TRANS; @@ -2443,8 +2413,7 @@ void dev_purge_queues(struct device *dev) for(i=0;ibuffs[i]))) - if(skb->free) - kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb,FREE_WRITE); } } diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c index bec4f14e13f1..1c31b272e3fd 100644 --- a/drivers/isdn/isdn_ppp.c +++ b/drivers/isdn/isdn_ppp.c @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.13 1996/07/01 19:47:24 hipp Exp $ +/* $Id: isdn_ppp.c,v 1.14 1996/08/12 16:26:47 hipp Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.c,v $ + * Revision 1.14 1996/08/12 16:26:47 hipp + * code cleanup + * changed connection management from minors to slots + * * Revision 1.13 1996/07/01 19:47:24 hipp * Fixed memory leak in VJ handling and more VJ changes * @@ -82,21 +86,21 @@ #endif /* Prototypes */ -static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int minor); -static int isdn_ppp_closewait(int); +static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot); +static int isdn_ppp_closewait(int slot); static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto); -static int isdn_ppp_if_get_unit(char **namebuf); +static int isdn_ppp_if_get_unit(char *namebuf); #ifdef CONFIG_ISDN_MPP -static int isdn_ppp_bundle(int, int); +static int isdn_ppp_bundle(struct ippp_struct *, int unit); static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask); static void isdn_ppp_cleanup_queue(isdn_net_dev * dev, long min); static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb, int BEbyte, int *sqno, int min_sqno); #endif -char *isdn_ppp_revision = "$Revision: 1.13 $"; +char *isdn_ppp_revision = "$Revision: 1.14 $"; struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; extern int isdn_net_force_dial_lp(isdn_net_local *); @@ -109,10 +113,13 @@ int isdn_ppp_free(isdn_net_local *lp) { isdn_net_local *master_lp=lp; unsigned long flags; + struct ippp_struct *is; - if (lp->ppp_minor < 0) + if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) return 0; + is = ippp_table[lp->ppp_slot]; + save_flags(flags); cli(); #ifdef CONFIG_ISDN_MPP @@ -132,13 +139,13 @@ int isdn_ppp_free(isdn_net_local *lp) lp->next = lp->last = lp; /* (re)set own pointers */ #endif - isdn_ppp_closewait(lp->ppp_minor); /* force wakeup on ippp device */ + isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */ - if(ippp_table[lp->ppp_minor]->debug & 0x1) - printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_minor, (long) lp,(long) ippp_table[lp->ppp_minor]->lp); + if(is->debug & 0x1) + printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp,(long) is->lp); - ippp_table[lp->ppp_minor]->lp = NULL; /* link is down .. set lp to NULL */ - lp->ppp_minor = -1; /* is this OK ?? */ + is->lp = NULL; /* link is down .. set lp to NULL */ + lp->ppp_slot = -1; /* is this OK ?? */ restore_flags(flags); return 0; @@ -151,11 +158,11 @@ int isdn_ppp_bind(isdn_net_local * lp) { int i; int unit = 0; - char *name; long flags; + struct ippp_struct *is; if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) - return 0; + return -1; save_flags(flags); cli(); @@ -172,19 +179,18 @@ int isdn_ppp_bind(isdn_net_local * lp) net_dev = net_dev->next; } /* - * search a free device + * search a free device / slot */ for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (ippp_table[i]->state == IPPP_OPEN && !exclusive[i]) { /* OPEN, but not connected! */ + if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */ break; } } } else { - if (ippp_table[lp->pppbind]->state == IPPP_OPEN) /* OPEN, but not connected! */ - i = lp->pppbind; - else - i = ISDN_MAX_CHANNELS; /* trigger error */ + for(i=0;iminor == lp->pppbind && ippp_table[i]->state == IPPP_OPEN) + break; } if (i >= ISDN_MAX_CHANNELS) { @@ -192,24 +198,33 @@ int isdn_ppp_bind(isdn_net_local * lp) printk(KERN_WARNING "isdn_ppp_bind: Can't find usable ippp device.\n"); return -1; } - lp->ppp_minor = i; - ippp_table[lp->ppp_minor]->lp = lp; - name = lp->name; - unit = isdn_ppp_if_get_unit(&name); /* get unit number from interface name .. ugly! */ - ippp_table[lp->ppp_minor]->unit = unit; + unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */ + if(unit < 0) { + printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n",lp->name); + return -1; + } - ippp_table[lp->ppp_minor]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; + lp->ppp_slot = i; + is = ippp_table[i]; + is->lp = lp; + is->unit = unit; + is->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; restore_flags(flags); - /* - * kick the ipppd on the new device - */ - if (ippp_table[lp->ppp_minor]->wq) - wake_up_interruptible(&ippp_table[lp->ppp_minor]->wq); + return lp->ppp_slot; +} - return lp->ppp_minor; +/* + * kick the ipppd on the device + * (wakes up daemon after B-channel connect) + */ + +void isdn_ppp_wakeup_daemon(isdn_net_local *lp) +{ + if (ippp_table[lp->ppp_slot]->wq) + wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq); } /* @@ -217,51 +232,76 @@ int isdn_ppp_bind(isdn_net_local * lp) * force wakeup of the ippp device * go into 'device waits for release' state */ -static int isdn_ppp_closewait(int minor) +static int isdn_ppp_closewait(int slot) { - if (minor < 0 || minor >= ISDN_MAX_CHANNELS) + struct ippp_struct *is; + + if (slot < 0 || slot >= ISDN_MAX_CHANNELS) return 0; + is = ippp_table[slot]; - if (ippp_table[minor]->state && ippp_table[minor]->wq) - wake_up_interruptible(&ippp_table[minor]->wq); + if (is->state && is->wq) + wake_up_interruptible(&is->wq); - ippp_table[minor]->state = IPPP_CLOSEWAIT; + is->state = IPPP_CLOSEWAIT; return 1; } +/* + * isdn_ppp_find_slot / isdn_ppp_free_slot + */ + +static int isdn_ppp_get_slot(void) +{ + int i; + for(i=0;istate) + return i; + } + return -1; +} + /* * isdn_ppp_open */ -int isdn_ppp_open(int minor, struct file *file) +int isdn_ppp_open(int min, struct file *file) { - if(ippp_table[minor]->debug & 0x1) - printk(KERN_DEBUG "ippp, open, minor: %d state: %04x\n", minor,ippp_table[minor]->state); - if (ippp_table[minor]->state) - return -EBUSY; + int slot; + struct ippp_struct *is; - ippp_table[minor]->lp = 0; - ippp_table[minor]->mp_seqno = 0; /* MP sequence number */ - ippp_table[minor]->pppcfg = 0; /* ppp configuration */ - ippp_table[minor]->mpppcfg = 0; /* mppp configuration */ - ippp_table[minor]->range = 0x1000000; /* MP: 24 bit range */ - ippp_table[minor]->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */ - ippp_table[minor]->unit = -1; /* set, when we have our interface */ - ippp_table[minor]->mru = 1524; /* MRU, default 1524 */ - ippp_table[minor]->maxcid = 16; /* VJ: maxcid */ - ippp_table[minor]->tk = current; - ippp_table[minor]->wq = NULL; /* read() wait queue */ - ippp_table[minor]->wq1 = NULL; /* select() wait queue */ - ippp_table[minor]->first = ippp_table[minor]->rq + NUM_RCV_BUFFS - 1; /* receive queue */ - ippp_table[minor]->last = ippp_table[minor]->rq; + slot = isdn_ppp_get_slot(); + if(slot < 0) { + return -EBUSY; + } + is = file->private_data = ippp_table[slot]; + + if(is->debug & 0x1) + printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",slot, min,is->state); + + is->lp = 0; + is->mp_seqno = 0; /* MP sequence number */ + is->pppcfg = 0; /* ppp configuration */ + is->mpppcfg = 0; /* mppp configuration */ + is->range = 0x1000000; /* MP: 24 bit range */ + is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */ + is->unit = -1; /* set, when we have our interface */ + is->mru = 1524; /* MRU, default 1524 */ + is->maxcid = 16; /* VJ: maxcid */ + is->tk = current; + is->wq = NULL; /* read() wait queue */ + is->wq1 = NULL; /* select() wait queue */ + is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ + is->last = is->rq; + is->minor = min; #ifdef CONFIG_ISDN_PPP_VJ /* * VJ header compression init */ - ippp_table[minor]->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ + is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ #endif - ippp_table[minor]->state = IPPP_OPEN; + is->state = IPPP_OPEN; return 0; } @@ -269,38 +309,40 @@ int isdn_ppp_open(int minor, struct file *file) /* * release ippp device */ -void isdn_ppp_release(int minor, struct file *file) +void isdn_ppp_release(int min, struct file *file) { int i; + struct ippp_struct *is; - if (minor < 0 || minor >= ISDN_MAX_CHANNELS) + if (min < 0 || min >= ISDN_MAX_CHANNELS) return; + is = file->private_data; - if(ippp_table[minor]->debug & 0x1) - printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) ippp_table[minor]->lp); + if(is->debug & 0x1) + printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp); - if (ippp_table[minor]->lp) { /* a lp address says: this link is still up */ + if (is->lp) { /* a lp address says: this link is still up */ isdn_net_dev *p = dev->netdev; - p = ippp_table[minor]->lp->netdev; - ippp_table[minor]->lp->ppp_minor = -1; - isdn_net_hangup(&p->dev); /* lp->ppp_minor==-1 => no calling of isdn_ppp_closewait() */ - ippp_table[minor]->lp = NULL; + p = is->lp->netdev; + is->lp->ppp_slot = -1; + isdn_net_hangup(&p->dev); /* lp->ppp_slot==-1 => no calling of isdn_ppp_closewait() */ + is->lp = NULL; } for (i = 0; i < NUM_RCV_BUFFS; i++) { - if (ippp_table[minor]->rq[i].buf) { - kfree(ippp_table[minor]->rq[i].buf); - ippp_table[minor]->rq[i].buf = NULL; + if (is->rq[i].buf) { + kfree(is->rq[i].buf); + is->rq[i].buf = NULL; } } - ippp_table[minor]->first = ippp_table[minor]->rq + NUM_RCV_BUFFS - 1; /* receive queue */ - ippp_table[minor]->last = ippp_table[minor]->rq; + is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ + is->last = is->rq; #ifdef CONFIG_ISDN_PPP_VJ - slhc_free(ippp_table[minor]->slcomp); - ippp_table[minor]->slcomp = NULL; + slhc_free(is->slcomp); + is->slcomp = NULL; #endif - ippp_table[minor]->state = 0; + is->state = 0; } /* @@ -330,62 +372,59 @@ static int set_arg(void *b, unsigned long val) /* * ippp device ioctl */ -int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long arg) +int isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long val; int r; + struct ippp_struct *is; + + is = file->private_data; - if(ippp_table[minor]->debug & 0x1) - printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", - minor,cmd,ippp_table[minor]->state); + if(is->debug & 0x1) + printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n",min,cmd,is->state); - if (!(ippp_table[minor]->state & IPPP_OPEN)) + if (!(is->state & IPPP_OPEN)) return -EINVAL; switch (cmd) { -#if 0 - case PPPIOCSINPSIG: /* obsolete: set input ready signal */ - /* usual: sig = SIGIO *//* we always deliver a SIGIO */ - break; -#endif case PPPIOCBUNDLE: #ifdef CONFIG_ISDN_MPP if ((r = get_arg((void *) arg, &val))) return r; printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", - (int) minor, (int) ippp_table[minor]->unit, (int) val); - return isdn_ppp_bundle(minor, val); + (int) min, (int) is->unit, (int) val); + return isdn_ppp_bundle(is, val); #else return -1; #endif break; case PPPIOCGUNIT: /* get ppp/isdn unit number */ - if ((r = set_arg((void *) arg, ippp_table[minor]->unit))) + if ((r = set_arg((void *) arg, is->unit))) return r; break; case PPPIOCGMPFLAGS: /* get configuration flags */ - if ((r = set_arg((void *) arg, ippp_table[minor]->mpppcfg))) + if ((r = set_arg((void *) arg, is->mpppcfg))) return r; break; case PPPIOCSMPFLAGS: /* set configuration flags */ if ((r = get_arg((void *) arg, &val))) return r; - ippp_table[minor]->mpppcfg = val; + is->mpppcfg = val; break; case PPPIOCGFLAGS: /* get configuration flags */ - if ((r = set_arg((void *) arg, ippp_table[minor]->pppcfg))) + if ((r = set_arg((void *) arg, is->pppcfg))) return r; break; case PPPIOCSFLAGS: /* set configuration flags */ if ((r = get_arg((void *) arg, &val))) { return r; } - if (val & SC_ENABLE_IP && !(ippp_table[minor]->pppcfg & SC_ENABLE_IP)) { - isdn_net_local *lp = ippp_table[minor]->lp; + if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP)) { + isdn_net_local *lp = is->lp; lp->netdev->dev.tbusy = 0; mark_bh(NET_BH); /* OK .. we are ready to send buffers */ } - ippp_table[minor]->pppcfg = val; + is->pppcfg = val; break; #if 0 case PPPIOCGSTAT: /* read PPP statistic information */ @@ -396,7 +435,7 @@ int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long case PPPIOCSMRU: /* set receive unit size for PPP */ if ((r = get_arg((void *) arg, &val))) return r; - ippp_table[minor]->mru = val; + is->mru = val; break; case PPPIOCSMPMRU: break; @@ -406,33 +445,33 @@ int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long if ((r = get_arg((void *) arg, &val))) return r; val++; - if(ippp_table[minor]->maxcid != val) { + if(is->maxcid != val) { #ifdef CONFIG_ISDN_PPP_VJ struct slcompress *sltmp; #endif - if(ippp_table[minor]->debug & 0x1) + if(is->debug & 0x1) printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n",val); - ippp_table[minor]->maxcid = val; + is->maxcid = val; #ifdef CONFIG_ISDN_PPP_VJ sltmp = slhc_init(16,val); if(!sltmp) { printk(KERN_ERR "ippp, can't realloc slhc struct\n"); return -ENOMEM; } - if(ippp_table[minor]->slcomp) - slhc_free(ippp_table[minor]->slcomp); - ippp_table[minor]->slcomp = sltmp; + if(is->slcomp) + slhc_free(is->slcomp); + is->slcomp = sltmp; #endif } break; case PPPIOCGDEBUG: - if ((r = set_arg((void *) arg, ippp_table[minor]->debug))) + if ((r = set_arg((void *) arg, is->debug))) return r; break; case PPPIOCSDEBUG: if ((r = get_arg((void *) arg, &val))) return r; - ippp_table[minor]->debug = val; + is->debug = val; break; default: break; @@ -440,39 +479,42 @@ int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long return 0; } -int isdn_ppp_select(int minor, struct file *file, int type, select_table * st) +int isdn_ppp_select(int min, struct file *file, int type, select_table * st) { struct ippp_buf_queue *bf, *bl; unsigned long flags; + struct ippp_struct *is; + + is = file->private_data; - if(ippp_table[minor]->debug & 0x2) - printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n",minor,type); + if(is->debug & 0x2) + printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n",min,type); - if (!(ippp_table[minor]->state & IPPP_OPEN)) + if (!(is->state & IPPP_OPEN)) return -EINVAL; switch (type) { case SEL_IN: save_flags(flags); cli(); - bl = ippp_table[minor]->last; - bf = ippp_table[minor]->first; + bl = is->last; + bf = is->first; /* * if IPPP_NOBLOCK is set we return even if we have nothing to read */ - if (bf->next == bl && !(ippp_table[minor]->state & IPPP_NOBLOCK)) { - select_wait(&ippp_table[minor]->wq, st); + if (bf->next == bl && !(is->state & IPPP_NOBLOCK)) { + select_wait(&is->wq, st); restore_flags(flags); return 0; } - ippp_table[minor]->state &= ~IPPP_NOBLOCK; + is->state &= ~IPPP_NOBLOCK; restore_flags(flags); return 1; case SEL_OUT: /* we're always ready to send .. */ return 1; case SEL_EX: - select_wait(&ippp_table[minor]->wq1, st); + select_wait(&is->wq1, st); return 0; } return 1; @@ -482,17 +524,20 @@ int isdn_ppp_select(int minor, struct file *file, int type, select_table * st) * fill up isdn_ppp_read() queue .. */ -static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int minor) +static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot) { struct ippp_buf_queue *bf, *bl; unsigned long flags; unsigned char *nbuf; + struct ippp_struct *is; - if (minor < 0 || minor >= ISDN_MAX_CHANNELS) { - printk(KERN_WARNING "ippp: illegal minor.\n"); + if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { + printk(KERN_WARNING "ippp: illegal slot.\n"); return 0; } - if (!(ippp_table[minor]->state & IPPP_CONNECT)) { + is = ippp_table[slot]; + + if (!(is->state & IPPP_CONNECT)) { printk(KERN_DEBUG "ippp: device not activated.\n"); return 0; } @@ -511,23 +556,23 @@ static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int minor) save_flags(flags); cli(); - bf = ippp_table[minor]->first; - bl = ippp_table[minor]->last; + bf = is->first; + bl = is->last; if (bf == bl) { printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n"); bf = bf->next; kfree(bf->buf); - ippp_table[minor]->first = bf; + is->first = bf; } bl->buf = (char *) nbuf; bl->len = len+4; - ippp_table[minor]->last = bl->next; + is->last = bl->next; restore_flags(flags); - if (ippp_table[minor]->wq) - wake_up_interruptible(&ippp_table[minor]->wq); + if (is->wq) + wake_up_interruptible(&is->wq); return len; } @@ -537,14 +582,16 @@ static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int minor) * reports, that there is data */ -int isdn_ppp_read(int minor, struct file *file, char *buf, int count) +int isdn_ppp_read(int min, struct file *file, char *buf, int count) { - struct ippp_struct *c = ippp_table[minor]; + struct ippp_struct *is; struct ippp_buf_queue *b; int r; unsigned long flags; - if (!(ippp_table[minor]->state & IPPP_OPEN)) + is = file->private_data; + + if (!(is->state & IPPP_OPEN)) return 0; if ((r = verify_area(VERIFY_WRITE, (void *) buf, count))) @@ -553,7 +600,7 @@ int isdn_ppp_read(int minor, struct file *file, char *buf, int count) save_flags(flags); cli(); - b = c->first->next; + b = is->first->next; if (!b->buf) { restore_flags(flags); return -EAGAIN; @@ -563,7 +610,7 @@ int isdn_ppp_read(int minor, struct file *file, char *buf, int count) memcpy_tofs(buf, b->buf, count); kfree(b->buf); b->buf = NULL; - c->first = b; + is->first = b; restore_flags(flags); return count; @@ -573,14 +620,17 @@ int isdn_ppp_read(int minor, struct file *file, char *buf, int count) * ipppd wanna write a packet to the card .. non-blocking */ -int isdn_ppp_write(int minor, struct file *file, const char *buf, int count) +int isdn_ppp_write(int min, struct file *file, const char *buf, int count) { isdn_net_local *lp; + struct ippp_struct *is; - if (!(ippp_table[minor]->state & IPPP_CONNECT)) + is = file->private_data; + + if (!(is->state & IPPP_CONNECT)) return 0; - lp = ippp_table[minor]->lp; + lp = is->lp; /* -> push it directly to the lowlevel interface */ @@ -659,7 +709,10 @@ void isdn_ppp_cleanup(void) void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb) { - if(ippp_table[lp->ppp_minor]->debug & 0x4) + struct ippp_struct *is; + is = ippp_table[lp->ppp_slot]; + + if(is->debug & 0x4) printk(KERN_DEBUG "recv skb, len: %ld\n",skb->len); if(net_dev->local.master) { @@ -669,14 +722,14 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf if(skb->data[0] == 0xff && skb->data[1] == 0x03) skb_pull(skb,2); - else if (ippp_table[lp->ppp_minor]->pppcfg & SC_REJ_COMP_AC) { + else if (is->pppcfg & SC_REJ_COMP_AC) { skb->free = 1; dev_kfree_skb(skb,0 /* FREE_READ */ ); return; /* discard it silently */ } #ifdef CONFIG_ISDN_MPP - if (!(ippp_table[lp->ppp_minor]->mpppcfg & SC_REJ_MP_PROT)) { + if (!(is->mpppcfg & SC_REJ_MP_PROT)) { int proto; int sqno_end; if (skb->data[0] & 0x1) { @@ -690,11 +743,11 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf isdn_net_local *lpq; int sqno, min_sqno, tseq; u_char BEbyte = skb->data[0]; - if(ippp_table[lp->ppp_minor]->debug & 0x8) - printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_minor, proto , + if(is->debug & 0x8) + printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto , (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]); - if (!(ippp_table[lp->ppp_minor]->mpppcfg & SC_IN_SHORT_SEQ)) { + if (!(is->mpppcfg & SC_IN_SHORT_SEQ)) { sqno = ((int) skb->data[1] << 16) + ((int) skb->data[2] << 8) + (int) skb->data[3]; skb_pull(skb,4); } else { @@ -702,26 +755,26 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf skb_pull(skb,2); } - if ((tseq = ippp_table[lp->ppp_minor]->last_link_seqno) >= sqno) { - int range = ippp_table[lp->ppp_minor]->range; + if ((tseq = is->last_link_seqno) >= sqno) { + int range = is->range; if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */ printk(KERN_WARNING "isdn_ppp_receive, MP, detected overflow with sqno: %d, last: %d !!!\n", sqno, tseq); else { sqno += range; - ippp_table[lp->ppp_minor]->last_link_seqno = sqno; + is->last_link_seqno = sqno; } } else - ippp_table[lp->ppp_minor]->last_link_seqno = sqno; + is->last_link_seqno = sqno; for (min_sqno = 0, lpq = net_dev->queue;;) { - if (ippp_table[lpq->ppp_minor]->last_link_seqno > min_sqno) - min_sqno = ippp_table[lpq->ppp_minor]->last_link_seqno; + if (ippp_table[lpq->ppp_slot]->last_link_seqno > min_sqno) + min_sqno = ippp_table[lpq->ppp_slot]->last_link_seqno; lpq = lpq->next; if (lpq == net_dev->queue) break; } - if (min_sqno >= ippp_table[lpq->ppp_minor]->range) { /* OK, every link overflowed */ - int mask = ippp_table[lpq->ppp_minor]->range - 1; /* range is a power of 2 */ + if (min_sqno >= ippp_table[lpq->ppp_slot]->range) { /* OK, every link overflowed */ + int mask = ippp_table[lpq->ppp_slot]->range - 1; /* range is a power of 2 */ isdn_ppp_cleanup_queue(net_dev, min_sqno); isdn_ppp_mask_queue(net_dev, mask); net_dev->ib.next_num &= mask; @@ -734,14 +787,14 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf } min_sqno &= mask; for (lpq = net_dev->queue;;) { - ippp_table[lpq->ppp_minor]->last_link_seqno &= mask; + ippp_table[lpq->ppp_slot]->last_link_seqno &= mask; lpq = lpq->next; if (lpq == net_dev->queue) break; } } if ((BEbyte & (MP_BEGIN_FRAG | MP_END_FRAG)) != (MP_BEGIN_FRAG | MP_END_FRAG)) { - printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_minor); + printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_slot); if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb , BEbyte, &sqno, min_sqno)) < 0) return; /* no packet complete */ } else @@ -820,9 +873,14 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf } +/* + * push frame to higher layers + * note: net_dev has to be master net_dev + */ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb,int proto) { struct device *dev = &net_dev->dev; + struct ippp_struct *is = ippp_table[lp->ppp_slot]; if (proto < 0) { /* MP, oder normales Paket bei REJ_MP, MP Pakete gehen bei REJ zum pppd */ if (skb->data[0] & 0x01) { /* is it odd? */ @@ -834,12 +892,12 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru } } - if(ippp_table[lp->ppp_minor]->debug & 0x10) + if(is->debug & 0x10) printk(KERN_DEBUG "push, skb %ld %04x\n",skb->len,proto); switch (proto) { case PPP_IPX: /* untested */ - if(ippp_table[lp->ppp_minor]->debug & 0x20) + if(is->debug & 0x20) printk(KERN_DEBUG "isdn_ppp: _IPX\n"); skb->dev = dev; skb->mac.raw = skb->data; @@ -847,9 +905,9 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru break; #ifdef CONFIG_ISDN_PPP_VJ case PPP_VJC_UNCOMP: - if(ippp_table[lp->ppp_minor]->debug & 0x20) + if(is->debug & 0x20) printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); - if(slhc_remember(ippp_table[net_dev->local.ppp_minor]->slcomp, skb->data, skb->len) <= 0) { + if(slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) { printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); net_dev->local.stats.rx_dropped++; skb->free = 1; @@ -858,14 +916,14 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru } #endif case PPP_IP: - if(ippp_table[lp->ppp_minor]->debug & 0x20) + if(is->debug & 0x20) printk(KERN_DEBUG "isdn_ppp: IP\n"); skb->dev = dev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IP); break; case PPP_VJC_COMP: - if(ippp_table[lp->ppp_minor]->debug & 0x20) + if(is->debug & 0x20) printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n"); #ifdef CONFIG_ISDN_PPP_VJ { @@ -885,7 +943,7 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru skb_put(skb,skb_old->len + 40); memcpy(skb->data, skb_old->data, skb_old->len); skb->mac.raw = skb->data; - pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_minor]->slcomp, + pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb_old->len); dev_kfree_skb(skb_old,0 /* FREE_READ */ ); if(pkt_len < 0) { @@ -906,7 +964,7 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru #endif break; default: - isdn_ppp_fill_rq(skb->data, skb->len,proto, lp->ppp_minor); /* push data to pppd device */ + isdn_ppp_fill_rq(skb->data, skb->len,proto, lp->ppp_slot); /* push data to pppd device */ skb->free = 1; dev_kfree_skb(skb,0 /* FREE_READ */ ); return; @@ -928,6 +986,19 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru * skb isn't allowed!! */ +static void isdn_ppp_skb_destructor(struct sk_buff *skb) +{ + char outstr[80],*outpnt=outstr; + int i; + + *outpnt = 0; + for(i=0;i<24 && ilen;i++) { + sprintf(outpnt,"%02x ",skb->data[i]); + outpnt += 3; + } + printk(KERN_DEBUG "ippp_dstrct: %s\n",outstr); +} + int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) { struct device *mdev = ((isdn_net_local *) (dev->priv) )->master; /* get master (for redundancy) */ @@ -941,13 +1012,18 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) else mlp = (isdn_net_local *) (dev->priv); nd = mlp->netdev; /* get master lp */ - ipts = ippp_table[mlp->ppp_minor]; + ipts = ippp_table[mlp->ppp_slot]; if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ - printk(KERN_INFO "%s: IP frame delayed.\n",dev->name); - return 1; + if(ipts->debug & 0x1) { + printk(KERN_INFO "%s: IP frame delayed.\n",dev->name); + skb->destructor = isdn_ppp_skb_destructor; + } + return 1; } + skb->destructor = NULL; + lp = nd->queue; /* get lp on top of queue */ if(lp->sav_skb) { /* find a non-busy device */ isdn_net_local *nlp = lp->next; @@ -958,35 +1034,21 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) } lp = nlp; } - ipt = ippp_table[lp->ppp_minor]; + ipt = ippp_table[lp->ppp_slot]; lp->huptimer = 0; - - /* If packet is to be resent, it has already been processed and - * therefore its first bytes are already initialized. In this case - * send it immediately ... - */ - if (*((u32 *)skb->data) != 0) { - printk(KERN_ERR "%s: Whoops .. packet resend should no longer happen!\n",dev->name); - return (isdn_net_send_skb(dev , lp , skb)); - } - /* ... else packet needs processing. */ + /* + * after this line .. requeueing in the device queue is no longer allowed!!! + */ - if(ippp_table[lp->ppp_minor]->debug & 0x4) + if(ipt->debug & 0x4) printk(KERN_DEBUG "xmit skb, len %ld\n",skb->len); #ifdef CONFIG_ISDN_PPP_VJ - if (ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes .. but check again */ + if (ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes .. but this check again */ struct sk_buff *new_skb; - int len = 4; -#ifdef CONFIG_ISDN_MPP - if (ipt->mpppcfg & SC_MP_PROT) /* sigh */ /* ipt or ipts ?? */ - if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) - len += 3; - else - len += 5; -#endif + new_skb = dev_alloc_skb(skb->len); if(new_skb) { u_char *buf; @@ -995,8 +1057,6 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) new_skb->dev = skb->dev; new_skb->free = 1; skb_put(new_skb,skb->len); - skb_pull(skb,len); /* pull PPP header */ - skb_pull(new_skb,len); /* pull PPP header */ buf = skb->data; pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data, @@ -1021,12 +1081,11 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) proto = PPP_VJC_UNCOMP; skb->data[0] = (skb->data[0] & 0x0f) | 0x40; } - skb_push(skb,len); } } #endif - if(ippp_table[lp->ppp_minor]->debug & 0x24) + if(ipt->debug & 0x24) printk(KERN_DEBUG "xmit2 skb, len %ld, proto %04x\n",skb->len,proto); #ifdef CONFIG_ISDN_MPP @@ -1036,22 +1095,23 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) ipts->mp_seqno++; nd->queue = nd->queue->next; if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) { - /* skb_push(skb, 3); Done in isdn_net_header() */ + skb_push(skb, 3); mp_seqno &= 0xfff; - skb->data[4] = MP_BEGIN_FRAG | MP_END_FRAG | (mp_seqno >> 8); /* (B)egin & (E)ndbit .. */ - skb->data[5] = mp_seqno & 0xff; - skb->data[6] = proto; /* PID compression */ + skb->data[0] = MP_BEGIN_FRAG | MP_END_FRAG | (mp_seqno >> 8); /* (B)egin & (E)ndbit .. */ + skb->data[1] = mp_seqno & 0xff; + skb->data[2] = proto; /* PID compression */ } else { - /* skb_push(skb, 5); Done in isdn_net_header () */ - skb->data[4] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */ - skb->data[5] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */ - skb->data[6] = (mp_seqno >> 8) & 0xff; - skb->data[7] = (mp_seqno >> 0) & 0xff; - skb->data[8] = proto; /* PID compression */ + skb_push(skb, 5); + skb->data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */ + skb->data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */ + skb->data[2] = (mp_seqno >> 8) & 0xff; + skb->data[3] = (mp_seqno >> 0) & 0xff; + skb->data[4] = proto; /* PID compression */ } proto = PPP_MP; /* MP Protocol, 0x003d */ } #endif + skb_push(skb,4); skb->data[0] = 0xff; /* All Stations */ skb->data[1] = 0x03; /* Unnumbered information */ skb->data[2] = proto >> 8; @@ -1100,7 +1160,7 @@ void isdn_ppp_free_mpqueue(isdn_net_dev * p) #ifdef CONFIG_ISDN_MPP -static int isdn_ppp_bundle(int minor, int unit) +static int isdn_ppp_bundle(struct ippp_struct *is, int unit) { char ifn[IFNAMSIZ + 1]; long flags; @@ -1117,7 +1177,7 @@ static int isdn_ppp_bundle(int minor, int unit) save_flags(flags); cli(); - nlp = ippp_table[minor]->lp; + nlp = is->lp; lp = p->queue; p->ib.bundled = 1; @@ -1127,17 +1187,17 @@ static int isdn_ppp_bundle(int minor, int unit) nlp->next = lp; p->queue = nlp; - ippp_table[nlp->ppp_minor]->unit = ippp_table[lp->ppp_minor]->unit; + ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit; /* maybe also SC_CCP stuff */ - ippp_table[nlp->ppp_minor]->pppcfg |= ippp_table[lp->ppp_minor]->pppcfg & + ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg & (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP); - ippp_table[nlp->ppp_minor]->mpppcfg |= ippp_table[lp->ppp_minor]->mpppcfg & + ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg & (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ); #if 0 - if (ippp_table[nlp->ppp_minor]->mpppcfg != ippp_table[lp->ppp_minor]->mpppcfg) { + if (ippp_table[nlp->ppp_slot]->mpppcfg != ippp_table[lp->ppp_slot]->mpppcfg) { printk(KERN_WARNING "isdn_ppp_bundle: different MP options %04x and %04x\n", - ippp_table[nlp->ppp_minor]->mpppcfg, ippp_table[lp->ppp_minor]->mpppcfg); + ippp_table[nlp->ppp_slot]->mpppcfg, ippp_table[lp->ppp_slot]->mpppcfg); } #endif @@ -1325,7 +1385,7 @@ static void isdn_ppp_cleanup_queue(isdn_net_dev * dev, long min_sqno) #ifdef CONFIG_ISDN_PPP_VJ /* did we free a stale frame ? */ if(toss) - slhc_toss(ippp_table[dev->local.ppp_minor]->slcomp); + slhc_toss(ippp_table[dev->local.ppp_slot]->slcomp); #endif } @@ -1355,7 +1415,7 @@ void isdn_ppp_timer_timeout(void) #ifdef CONFIG_ISDN_PPP_VJ /* did we step over a missing frame ? */ if(q->sqno_start != net_dev->ib.next_num) - slhc_toss(ippp_table[lp->ppp_minor]->slcomp); + slhc_toss(ippp_table[lp->ppp_slot]->slcomp); #endif ql = net_dev->ib.sq; @@ -1381,7 +1441,7 @@ void isdn_ppp_timer_timeout(void) * network device ioctl handlers */ -static int isdn_ppp_dev_ioctl_stats(int minor,struct ifreq *ifr,struct device *dev) +static int isdn_ppp_dev_ioctl_stats(int slot,struct ifreq *ifr,struct device *dev) { struct ppp_stats *res, t; isdn_net_local *lp = (isdn_net_local *) dev->priv; @@ -1402,8 +1462,8 @@ static int isdn_ppp_dev_ioctl_stats(int minor,struct ifreq *ifr,struct device *d t.p.ppp_opackets = lp->stats.tx_packets; t.p.ppp_oerrors = lp->stats.tx_errors; #ifdef CONFIG_ISDN_PPP_VJ - if(minor >= 0 && ippp_table[minor]->slcomp) { - struct slcompress *slcomp = ippp_table[minor]->slcomp; + if(slot >= 0 && ippp_table[slot]->slcomp) { + struct slcompress *slcomp = ippp_table[slot]->slcomp; t.vj.vjs_packets = slcomp->sls_o_compressed+slcomp->sls_o_uncompressed; t.vj.vjs_compressed = slcomp->sls_o_compressed; t.vj.vjs_searches = slcomp->sls_o_searches; @@ -1428,7 +1488,7 @@ int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd) isdn_net_local *lp = (isdn_net_local *) dev->priv; #if 0 - printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n",cmd,lp->ppp_minor); + printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n",cmd,lp->ppp_slot); #endif if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) @@ -1443,7 +1503,7 @@ int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd) memcpy_tofs(r, PPP_VERSION, len); break; case SIOCGPPPSTATS: - error = isdn_ppp_dev_ioctl_stats (lp->ppp_minor, ifr, dev); + error = isdn_ppp_dev_ioctl_stats (lp->ppp_slot, ifr, dev); break; default: error = -EINVAL; @@ -1452,24 +1512,26 @@ int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd) return error; } -static int isdn_ppp_if_get_unit(char **namebuf) +static int isdn_ppp_if_get_unit(char *name) { - char *name = *namebuf; int len, i, unit = 0, deci; len = strlen(name); + + if(strncmp("ippp",name,4) || len > 8) + return -1; + for (i = 0, deci = 1; i < len; i++, deci *= 10) { - if (name[len - 1 - i] >= '0' && name[len - 1 - i] <= '9') - unit += (name[len - 1 - i] - '0') * deci; + char a = name[len-i-1]; + if (a >= '0' && a <= '9') + unit += (a - '0') * deci; else break; } - if (!i) + if (!i || len-i != 4) unit = -1; - *namebuf = name + len - 1 - i; return unit; - } diff --git a/drivers/isdn/isdn_ppp.h b/drivers/isdn/isdn_ppp.h index cb01128c33dd..70de759505c2 100644 --- a/drivers/isdn/isdn_ppp.h +++ b/drivers/isdn/isdn_ppp.h @@ -51,5 +51,6 @@ extern int isdn_ppp_select(int, struct file *, int, select_table *); extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long); extern void isdn_ppp_release(int, struct file *); extern int isdn_ppp_dial_slave(char *); +extern void isdn_ppp_wakeup_daemon(isdn_net_local *); extern struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; diff --git a/drivers/isdn/teles/card.c b/drivers/isdn/teles/card.c index 1bd55e3ebf70..c90bcd00bc5a 100644 --- a/drivers/isdn/teles/card.c +++ b/drivers/isdn/teles/card.c @@ -1,4 +1,4 @@ -/* $Id: card.c,v 1.12 1996/06/24 17:16:52 fritz Exp $ +/* $Id: card.c,v 1.13 1996/07/18 11:21:24 jdenoud Exp $ * * card.c low level stuff for the Teles S0 isdn card * @@ -7,6 +7,9 @@ * Beat Doebeli log all D channel traffic * * $Log: card.c,v $ + * Revision 1.13 1996/07/18 11:21:24 jdenoud + * Use small buffers for incoming audio data + * * Revision 1.12 1996/06/24 17:16:52 fritz * Added check for misconfigured membase. * @@ -424,7 +427,7 @@ hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) { byte r; struct HscxState *hsp = sp->hs + hscx; - int count; + int count, err; if (!hsp->init) return; @@ -471,9 +474,15 @@ hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) } afterRME: if (val & 0x40) { /* RPF */ - if (!hsp->rcvibh) - if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, - GFP_ATOMIC, (void *) 1, 2)) { + if (!hsp->rcvibh) { + if (hsp->mode == 1) + err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool, + GFP_ATOMIC, (void *)1, 2); + else + err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, + GFP_ATOMIC, (void *)1, 2); + + if (err) { printk(KERN_WARNING "HSCX RPF out of buffers at %ld\n", jiffies); @@ -482,7 +491,8 @@ hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) goto afterRPF; } else hsp->rcvptr = 0; - + } + hscx_empty_fifo(hsp, 32); if (hsp->mode == 1) { /* receive audio data */ diff --git a/drivers/scsi/ChangeLog.ncr53c8xx b/drivers/scsi/ChangeLog.ncr53c8xx index fc285043639c..d13f6f5c8207 100644 --- a/drivers/scsi/ChangeLog.ncr53c8xx +++ b/drivers/scsi/ChangeLog.ncr53c8xx @@ -1,3 +1,10 @@ +Fri Aug 30 10:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c - Version 1.12c + Incorporate the changes of FreeBSD/ncr.c revision 1.76. + The changes add support for the 53c860 and 53c875, + but without taking advantage of the new features. + Those chips are used exactly as the old 53c810. + Sun Jul 21 00:00 1996 Gerard Roudier (groudier@club-internet.fr) * ncr53c8xx.c, README.ncr53c8xx Add the ncr53c8xx_select_queue_depths() function. diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 2410cb828af4..4362a6b1fcf9 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -40,7 +40,7 @@ */ /* -** 21 July 1996, version 1.12b +** 30 August 1996, version 1.12c ** ** Supported SCSI-II features: ** Synchronous negotiation @@ -55,6 +55,8 @@ ** 53C815 (~53C810 with on board rom BIOS) ** 53C820 (Wide, NCR BIOS in flash bios required) ** 53C825 (Wide, ~53C820 with on board rom BIOS) +** 53C860 (not yet tested) +** 53C875 (not yet tested) ** ** Other features: ** Memory mapped IO (linux-1.3.X only) @@ -1492,7 +1494,7 @@ static void ncr_alloc_ccb (ncb_p np, u_long t, u_long l); static void ncr_complete (ncb_p np, ccb_p cp); static void ncr_exception (ncb_p np); static void ncr_free_ccb (ncb_p np, ccb_p cp); -static void ncr_getclock (ncb_p np); +static void ncr_getclock (ncb_p np, u_char scntl3); static ccb_p ncr_get_ccb (ncb_p np, u_long t,u_long l); static void ncr_init (ncb_p np, char * msg, u_long code); static int ncr_intr (ncb_p np); @@ -3540,7 +3542,7 @@ retry_chip_init: ** Find the right value for scntl3. */ - ncr_getclock (np); + ncr_getclock (np, INB(nc_scntl3)); /* ** Reset chip. @@ -4816,8 +4818,8 @@ void ncr_init (ncb_p np, char * msg, u_long code) if ((ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion >= 0x10) || ChipDevice == PCI_DEVICE_ID_NCR_53C875) { OUTB(nc_dmode, 0xc0); /* Set 16-transfer burst */ - OUTB(nc_ctest5, 0x04); /* Set DMA FIFO to 88 */ #if 0 + OUTB(nc_ctest5, 0x04); /* Set DMA FIFO to 88 */ OUTB(nc_ctest5, 0x24); /* Set DMA FIFO to 536 */ OUTB(nc_dmode, 0x40); /* Set 64-transfer burst */ OUTB(nc_ctest3, 0x01); /* Set write and invalidate */ @@ -6278,9 +6280,18 @@ void ncr_int_sir (ncb_p np) /* ** Check against controller limits. */ - fak = (4ul * per - 1) / np->ns_sync - 3; - if (ofs && (fak>7)) {chg = 1; ofs = 0;} - if (!ofs) fak=7; + if (ofs != 0) { + fak = (4ul * per - 1) / np->ns_sync - 3; + if (fak>7) { + chg = 1; + ofs = 0; + } + } + if (ofs == 0) { + fak = 7; + per = 0; + tp->minsync = 0; + } if (DEBUG_FLAGS & DEBUG_NEGO) { PRINT_ADDR(cp->cmd); @@ -7311,8 +7322,9 @@ static u_long ncr_lookup(char * id) #endif /* NCR_CLOCK */ -static void ncr_getclock (ncb_p np) +static void ncr_getclock (ncb_p np, u_char scntl3) { +#if 0 u_char tbl[5] = {6,2,3,4,6}; u_char f; u_char ns_clock = (1000/NCR_CLOCK); @@ -7335,6 +7347,25 @@ static void ncr_getclock (ncb_p np) if (DEBUG_FLAGS & DEBUG_TIMING) printf ("%s: sclk=%d async=%d sync=%d (ns) scntl3=0x%x\n", ncr_name (np), ns_clock, np->ns_async, np->ns_sync, np->rv_scntl3); +#else + /* + * For now just preserve the BIOS setting ... + */ + + if ((scntl3 & 7) < 3) { + printf ("%s: assuming 40MHz clock", ncr_name(np)); + scntl3 = 3; /* assume 40MHz if no value supplied by BIOS */ + } + + np->ns_sync = 25; + np->ns_async = 50; + np->rv_scntl3 = ((scntl3 & 0x7) << 4) -0x20 + (scntl3 & 0x7); + + if (bootverbose) { + printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n", + ncr_name(np), scntl3, np->rv_scntl3); + } +#endif } /*===================== LINUX ENTRY POINTS SECTION ==========================*/ diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h index a0e5d7912603..7e40e72a4369 100644 --- a/drivers/scsi/ncr53c8xx.h +++ b/drivers/scsi/ncr53c8xx.h @@ -196,7 +196,7 @@ int ncr53c8xx_release(struct Scsi_Host *); #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) -#define NCR53C8XX {NULL,NULL,NULL,NULL,"ncr53c8xx (rel 1.12b)", ncr53c8xx_detect,\ +#define NCR53C8XX {NULL,NULL,NULL,NULL,"ncr53c8xx (rel 1.12c)", ncr53c8xx_detect,\ ncr53c8xx_release, /* info */ NULL, /* command, deprecated */ NULL, \ ncr53c8xx_queue_command, ncr53c8xx_abort, ncr53c8xx_reset, \ NULL /* slave attach */, scsicam_bios_param, /* can queue */ SCSI_NCR_CAN_QUEUE,\ @@ -207,7 +207,7 @@ int ncr53c8xx_release(struct Scsi_Host *); #else -#define NCR53C8XX {NULL, NULL, "ncr53c8xx (rel 1.12b)", ncr53c8xx_detect,\ +#define NCR53C8XX {NULL, NULL, "ncr53c8xx (rel 1.12c)", ncr53c8xx_detect,\ ncr53c8xx_release, /* info */ NULL, /* command, deprecated */ NULL, \ ncr53c8xx_queue_command, ncr53c8xx_abort, ncr53c8xx_reset, \ NULL /* slave attach */, scsicam_bios_param, /* can queue */ SCSI_NCR_CAN_QUEUE,\ diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 9e5845b4d156..6cb8801864e6 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -275,8 +275,39 @@ static void sg_command_done(Scsi_Cmnd * SCpnt) * See if the command completed normally, or whether something went * wrong. */ - memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer)); - device->header.result = (SCpnt->sense_buffer[0] == 0 ? 0 : EIO); + memcpy(device->header.sense_buffer, SCpnt->sense_buffer, + sizeof(SCpnt->sense_buffer)); + switch (host_byte(SCpnt->result)) { + case DID_OK: + device->header.result = 0; + break; + case DID_NO_CONNECT: + case DID_BUS_BUSY: + case DID_TIME_OUT: + device->header.result = EBUSY; + break; + case DID_BAD_TARGET: + case DID_ABORT: + case DID_PARITY: + case DID_RESET: + case DID_BAD_INTR: + device->header.result = EIO; + break; + case DID_ERROR: + /* + * There really should be DID_UNDERRUN and DID_OVERRUN error values, + * and a means for callers of scsi_do_cmd to indicate whether an + * underrun or overrun should signal an error. Until that can be + * implemented, this kludge allows for returning useful error values + * except in cases that return DID_ERROR that might be due to an + * underrun. + */ + if (SCpnt->sense_buffer[0] == 0 && + status_byte(SCpnt->result) == GOOD) + device->header.result = 0; + else device->header.result = EIO; + break; + } /* * Now wake up the process that is waiting for the diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index 39390416adba..59e1e10028d2 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -98,6 +98,23 @@ * one of the FD boards, it would be nice to come up with a signature * for it. * J.B. Jan 1994. + * + * + * Revision: 08/24/1996. by Miroslav Zagorac + * + * Enhancement for wd7000_detect function has been made, so you don't have + * to enter BIOS ROM adress and IO port in initialisation data (see struct + * Config). We cannot detect IRQ and DMA for now, so we have to enter them + * as arguments while wd_7000 is detected. If someone has IRQ and DMA set + * to some other value, he can enter them in configuration without any + * problem. Also I wrote a function wd7000_setup, so now you can enter + * WD-7000 definition as kernel arguments, as in lilo.conf: + * + * append="wd7000=IRQ,DMA" + * + * PS: If card BIOS ROM is disabled, function wd7000_detect now will recognize + * adapter, unlike the old one. Anyway, BIOS ROM from WD7000 adapter is + * worthless for Linux. :) */ #ifdef MODULE @@ -121,7 +138,7 @@ #include "hosts.h" #include "sd.h" -#define ANY2SCSI_INLINE /* undef this to use old macros */ +#define ANY2SCSI_INLINE /* undef this to use old macros */ #undef DEBUG #include "wd7000.h" @@ -158,7 +175,7 @@ struct proc_dir_entry proc_scsi_wd7000 = { */ typedef volatile struct mailbox{ unchar status; - unchar scbptr[3]; /* SCSI-style - MSB first (big endian) */ + unchar scbptr[3]; /* SCSI-style - MSB first (big endian) */ } Mailbox; /* @@ -167,17 +184,17 @@ typedef volatile struct mailbox{ * */ typedef struct adapter { - struct Scsi_Host *sh; /* Pointer to Scsi_Host structure */ - int iobase; /* This adapter's I/O base address */ - int irq; /* This adapter's IRQ level */ - int dma; /* This adapter's DMA channel */ - struct { /* This adapter's mailboxes */ - Mailbox ogmb[OGMB_CNT]; /* Outgoing mailboxes */ - Mailbox icmb[ICMB_CNT]; /* Incoming mailboxes */ + struct Scsi_Host *sh; /* Pointer to Scsi_Host structure */ + int iobase; /* This adapter's I/O base address */ + int irq; /* This adapter's IRQ level */ + int dma; /* This adapter's DMA channel */ + struct { /* This adapter's mailboxes */ + Mailbox ogmb[OGMB_CNT]; /* Outgoing mailboxes */ + Mailbox icmb[ICMB_CNT]; /* Incoming mailboxes */ } mb; - int next_ogmb; /* to reduce contention at mailboxes */ - unchar control; /* shadows CONTROL port value */ - unchar rev1, rev2; /* filled in by wd7000_revision */ + int next_ogmb; /* to reduce contention at mailboxes */ + unchar control; /* shadows CONTROL port value */ + unchar rev1, rev2; /* filled in by wd7000_revision */ } Adapter; /* @@ -186,22 +203,47 @@ typedef struct adapter { * Note that if SA_INTERRUPT is not used, wd7000_intr_handle must be * changed to pick up the IRQ level correctly. */ -Adapter *irq2host[16] = {NULL}; /* Possible IRQs are 0-15 */ +Adapter *irq2host[16] = {NULL}; /* Possible IRQs are 0-15 */ + +/* + * (linear) base address for ROM BIOS + */ +static const long wd7000_biosaddr[] = { + 0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000, + 0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000 +}; +#define NUM_ADDRS (sizeof(wd7000_biosaddr)/sizeof(long)) + +static const unsigned short wd7000_iobase[] = { + 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338, + 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378, + 0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8, + 0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8 +}; +#define NUM_IOPORTS (sizeof(wd7000_iobase)/sizeof(unsigned short)) + +static const short wd7000_irq[] = { 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 }; +#define NUM_IRQS (sizeof(wd7000_irq)/sizeof(short)) +static const short wd7000_dma[] = { 5, 6, 7 }; +#define NUM_DMAS (sizeof(wd7000_dma)/sizeof(short)) + /* * Standard Adapter Configurations - used by wd7000_detect */ typedef struct { - const void *bios; /* (linear) base address for ROM BIOS */ - int iobase; /* I/O ports base address */ - int irq; /* IRQ level */ - int dma; /* DMA channel */ + int irq; /* IRQ level */ + int dma; /* DMA channel */ } Config; +/* + * Add here your configuration... + */ static const Config configs[] = { - {(void *) 0xce000, 0x350, 15, 6}, /* defaults for single adapter */ - {(void *) 0xc8000, 0x330, 11, 5}, /* defaults for second adapter */ - {(void *) 0xd8000, 0x350, 15, 6}, /* Arghhh.... who added this ? */ + { 15, 6 }, /* defaults for single adapter */ + { 11, 5 }, /* defaults for second adapter */ + { 9, 6 }, /* My configuretion (Zaga) */ + { -1, -1 } /* Empty slot */ }; #define NUM_CONFIGS (sizeof(configs)/sizeof(Config)) @@ -211,13 +253,13 @@ static const Config configs[] = { * added for the Future Domain version. */ typedef struct signature { - const void *sig; /* String to look for */ - unsigned ofs; /* offset from BIOS base address */ - unsigned len; /* length of string */ + const void *sig; /* String to look for */ + unsigned ofs; /* offset from BIOS base address */ + unsigned len; /* length of string */ } Signature; static const Signature signatures[] = { - {"SSTBIOS",0x0000d,7} /* "SSTBIOS" @ offset 0x0000d */ + { "SSTBIOS", 0x0000d, 7 } /* "SSTBIOS" @ offset 0x0000d */ }; #define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature)) @@ -226,19 +268,20 @@ static const Signature signatures[] = { * I/O Port Offsets and Bit Definitions * 4 addresses are used. Those not defined here are reserved. */ -#define ASC_STAT 0 /* Status, Read */ -#define ASC_COMMAND 0 /* Command, Write */ -#define ASC_INTR_STAT 1 /* Interrupt Status, Read */ -#define ASC_INTR_ACK 1 /* Acknowledge, Write */ -#define ASC_CONTROL 2 /* Control, Write */ +#define ASC_STAT 0 /* Status, Read */ +#define ASC_COMMAND 0 /* Command, Write */ +#define ASC_INTR_STAT 1 /* Interrupt Status, Read */ +#define ASC_INTR_ACK 1 /* Acknowledge, Write */ +#define ASC_CONTROL 2 /* Control, Write */ -/* ASC Status Port +/* + * ASC Status Port */ -#define INT_IM 0x80 /* Interrupt Image Flag */ -#define CMD_RDY 0x40 /* Command Port Ready */ -#define CMD_REJ 0x20 /* Command Port Byte Rejected */ -#define ASC_INIT 0x10 /* ASC Initialized Flag */ -#define ASC_STATMASK 0xf0 /* The lower 4 Bytes are reserved */ +#define INT_IM 0x80 /* Interrupt Image Flag */ +#define CMD_RDY 0x40 /* Command Port Ready */ +#define CMD_REJ 0x20 /* Command Port Byte Rejected */ +#define ASC_INIT 0x10 /* ASC Initialized Flag */ +#define ASC_STATMASK 0xf0 /* The lower 4 Bytes are reserved */ /* COMMAND opcodes * @@ -248,31 +291,31 @@ static const Signature signatures[] = { * discernible effect whatsoever. I think they may be related to certain * ICB commands, but again, the OEM manual doesn't make that clear. */ -#define NO_OP 0 /* NO-OP toggles CMD_RDY bit in ASC_STAT */ -#define INITIALIZATION 1 /* initialization (10 bytes) */ -#define DISABLE_UNS_INTR 2 /* disable unsolicited interrupts */ -#define ENABLE_UNS_INTR 3 /* enable unsolicited interrupts */ -#define INTR_ON_FREE_OGMB 4 /* interrupt on free OGMB */ -#define SOFT_RESET 5 /* SCSI bus soft reset */ -#define HARD_RESET_ACK 6 /* SCSI bus hard reset acknowledge */ -#define START_OGMB 0x80 /* start command in OGMB (n) */ -#define SCAN_OGMBS 0xc0 /* start multiple commands, signature (n) */ +#define NO_OP 0 /* NO-OP toggles CMD_RDY bit in ASC_STAT */ +#define INITIALIZATION 1 /* initialization (10 bytes) */ +#define DISABLE_UNS_INTR 2 /* disable unsolicited interrupts */ +#define ENABLE_UNS_INTR 3 /* enable unsolicited interrupts */ +#define INTR_ON_FREE_OGMB 4 /* interrupt on free OGMB */ +#define SOFT_RESET 5 /* SCSI bus soft reset */ +#define HARD_RESET_ACK 6 /* SCSI bus hard reset acknowledge */ +#define START_OGMB 0x80 /* start command in OGMB (n) */ +#define SCAN_OGMBS 0xc0 /* start multiple commands, signature (n) */ /* where (n) = lower 6 bits */ /* For INITIALIZATION: */ typedef struct initCmd { - unchar op; /* command opcode (= 1) */ - unchar ID; /* Adapter's SCSI ID */ - unchar bus_on; /* Bus on time, x 125ns (see below) */ - unchar bus_off; /* Bus off time, "" "" */ - unchar rsvd; /* Reserved */ - unchar mailboxes[3]; /* Address of Mailboxes, MSB first */ - unchar ogmbs; /* Number of outgoing MBs, max 64, 0,1 = 1 */ - unchar icmbs; /* Number of incoming MBs, "" "" */ + unchar op; /* command opcode (= 1) */ + unchar ID; /* Adapter's SCSI ID */ + unchar bus_on; /* Bus on time, x 125ns (see below) */ + unchar bus_off; /* Bus off time, "" "" */ + unchar rsvd; /* Reserved */ + unchar mailboxes[3]; /* Address of Mailboxes, MSB first */ + unchar ogmbs; /* Number of outgoing MBs, max 64, 0,1 = 1 */ + unchar icmbs; /* Number of incoming MBs, "" "" */ } InitCmd; -#define BUS_ON 64 /* x 125ns = 8000ns (BIOS default) */ -#define BUS_OFF 15 /* x 125ns = 1875ns (BIOS default) */ +#define BUS_ON 64 /* x 125ns = 8000ns (BIOS default) */ +#define BUS_OFF 15 /* x 125ns = 1875ns (BIOS default) */ /* Interrupt Status Port - also returns diagnostic codes at ASC reset * @@ -301,29 +344,29 @@ typedef struct initCmd { #define ASC_RES 0x01 /* ASC Reset */ /* - Driver data structures: - - mb and scbs are required for interfacing with the host adapter. - An SCB has extra fields not visible to the adapter; mb's - _cannot_ do this, since the adapter assumes they are contiguous in - memory, 4 bytes each, with ICMBs following OGMBs, and uses this fact - to access them. - - An icb is for host-only (non-SCSI) commands. ICBs are 16 bytes each; - the additional bytes are used only by the driver. - - For now, a pool of SCBs are kept in global storage by this driver, - and are allocated and freed as needed. - - The 7000-FASST2 marks OGMBs empty as soon as it has _started_ a command, - not when it has finished. Since the SCB must be around for completion, - problems arise when SCBs correspond to OGMBs, which may be reallocated - earlier (or delayed unnecessarily until a command completes). - Mailboxes are used as transient data structures, simply for - carrying SCB addresses to/from the 7000-FASST2. - - Note also since SCBs are not "permanently" associated with mailboxes, - there is no need to keep a global list of Scsi_Cmnd pointers indexed - by OGMB. Again, SCBs reference their Scsi_Cmnds directly, so mailbox - indices need not be involved. -*/ + * Driver data structures: + * - mb and scbs are required for interfacing with the host adapter. + * An SCB has extra fields not visible to the adapter; mb's + * _cannot_ do this, since the adapter assumes they are contiguous in + * memory, 4 bytes each, with ICMBs following OGMBs, and uses this fact + * to access them. + * - An icb is for host-only (non-SCSI) commands. ICBs are 16 bytes each; + * the additional bytes are used only by the driver. + * - For now, a pool of SCBs are kept in global storage by this driver, + * and are allocated and freed as needed. + * + * The 7000-FASST2 marks OGMBs empty as soon as it has _started_ a command, + * not when it has finished. Since the SCB must be around for completion, + * problems arise when SCBs correspond to OGMBs, which may be reallocated + * earlier (or delayed unnecessarily until a command completes). + * Mailboxes are used as transient data structures, simply for + * carrying SCB addresses to/from the 7000-FASST2. + * + * Note also since SCBs are not "permanently" associated with mailboxes, + * there is no need to keep a global list of Scsi_Cmnd pointers indexed + * by OGMB. Again, SCBs reference their Scsi_Cmnds directly, so mailbox + * indices need not be involved. + */ /* * WD7000-specific scatter/gather element structure @@ -482,11 +525,88 @@ static Scb scbs[MAX_SCBS]; static Scb *scbfree = NULL; /* free list */ static int freescbs = MAX_SCBS; /* free list counter */ +/* + * + */ +static short wd7000_setupIRQ[NUM_CONFIGS]; +static short wd7000_setupDMA[NUM_CONFIGS]; +static short wd7000_card_num = 0; + /* * END of data/declarations - code follows. */ +/* + * Note: You can now set these options from the kernel's "command line". + * The syntax is: + * + * wd7000=IRQ,DMA + * eg: + * wd7000=15,6 + * + * will configure the driver for a WD-7000 controller + * using IRQ 15 with a DMA channel 6. + */ +void wd7000_setup (char *str, int *ints) { + short i, j; + + if (wd7000_card_num >= NUM_CONFIGS) { + printk ("wd7000_setup: Too many \"wd7000=\" configurations in " + "command line!\n"); + + return; + } + + if (ints[0] != 2) + printk ("wd7000_setup: Error in command line! " + "Usage: wd7000=IRQ,DMA\n"); + else { + for (i = 0; i < NUM_IRQS; i++) + if (ints[1] == wd7000_irq[i]) + break; + + if (i == NUM_IRQS) { + printk ("wd7000_setup: invalid IRQ.\n"); + return; + } + else + wd7000_setupIRQ[wd7000_card_num] = ints[1]; + + for (i = 0; i < NUM_DMAS; i++) + if (ints[2] == wd7000_dma[i]) + break; + + if (i == NUM_IRQS) { + printk ("wd7000_setup: invalid DMA channel.\n"); + return; + } + else + wd7000_setupDMA[wd7000_card_num] = ints[2]; + + if (wd7000_card_num) + for (i = 0; i < (wd7000_card_num - 1); i++) + for (j = i + 1; j < wd7000_card_num; j++) + if (wd7000_setupIRQ[i] == wd7000_setupIRQ[j]) { + printk ("wd7000_setup: duplicated IRQ!\n"); + return; + } + else if (wd7000_setupDMA[i] == wd7000_setupDMA[j]) { + printk ("wd7000_setup: duplicated DMA channel!\n"); + return; + } + +#ifdef DEBUG + printk ("wd7000_setup: IRQ=%d, DMA=%d\n", + wd7000_setupIRQ[wd7000_card_num], + wd7000_setupDMA[wd7000_card_num]); +#endif + + wd7000_card_num++; + } +} + + #ifdef ANY2SCSI_INLINE /* Since they're used a lot, I've redone the following from the macros @@ -627,7 +747,8 @@ static inline Scb *alloc_scbs(int needed) timeout = jiffies + WAITnexttimeout; do { sti(); /* Yes this is really needed here */ - now = jiffies; while (jiffies == now) /* wait a jiffy */; + now = jiffies; + while (jiffies == now); /* wait a jiffy */ cli(); } while (freescbs < needed && jiffies <= timeout); /* @@ -699,7 +820,7 @@ static int mail_out( Adapter *host, Scb *scbptr ) Mailbox *ogmbs = host->mb.ogmb; int *next_ogmb = &(host->next_ogmb); #ifdef DEBUG - printk("wd7000 mail_out: %06x",(unsigned int) scbptr); + printk("wd7000 mail_out: 0x%06lx",(long) scbptr); #endif /* We first look for a free outgoing mailbox */ save_flags(flags); @@ -708,7 +829,7 @@ static int mail_out( Adapter *host, Scb *scbptr ) for (i = 0; i < OGMB_CNT; i++) { if (ogmbs[ogmb].status == 0) { #ifdef DEBUG - printk(" using OGMB %x",ogmb); + printk(" using OGMB 0x%x",ogmb); #endif ogmbs[ogmb].status = 1; any2scsi((unchar *) ogmbs[ogmb].scbptr, (int) scbptr); @@ -720,7 +841,7 @@ static int mail_out( Adapter *host, Scb *scbptr ) } restore_flags(flags); #ifdef DEBUG - printk(", scb is %x",(unsigned int) scbptr); + printk(", scb is 0x%06lx",(long) scbptr); #endif if (i >= OGMB_CNT) { /* @@ -790,7 +911,7 @@ int make_code(unsigned hosterr, unsigned scsierr) } #ifdef DEBUG if (scsierr||hosterr) - printk("\nSCSI command error: SCSI %02x host %04x return %d", + printk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n", scsierr,in_error,hosterr); #endif return scsierr | (hosterr << 16); @@ -800,7 +921,7 @@ int make_code(unsigned hosterr, unsigned scsierr) static void wd7000_scsi_done(Scsi_Cmnd * SCpnt) { #ifdef DEBUG - printk("wd7000_scsi_done: %06x\n",(unsigned int) SCpnt); + printk("wd7000_scsi_done: 0x%06x\n",(long) SCpnt); #endif SCpnt->SCp.phase = 0; } @@ -819,12 +940,12 @@ void wd7000_intr_handle(int irq, void *dev_id, struct pt_regs * regs) Mailbox *icmbs = host->mb.icmb; #ifdef DEBUG - printk("wd7000_intr_handle: irq = %d, host = %06x\n", irq, host); + printk("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host); #endif flag = inb(host->iobase+ASC_INTR_STAT); #ifdef DEBUG - printk("wd7000_intr_handle: intr stat = %02x\n",flag); + printk("wd7000_intr_handle: intr stat = 0x%02x\n",flag); #endif if (!(inb(host->iobase+ASC_STAT) & INT_IM)) { @@ -847,7 +968,7 @@ void wd7000_intr_handle(int irq, void *dev_id, struct pt_regs * regs) /* The interrupt is for a mailbox */ if (!(flag & IMB_INTR)) { #ifdef DEBUG - printk("wd7000_intr_handle: free outgoing mailbox"); + printk("wd7000_intr_handle: free outgoing mailbox\n"); #endif /* * If sleep_on() and the "interrupt on free OGMB" command are @@ -862,7 +983,7 @@ void wd7000_intr_handle(int irq, void *dev_id, struct pt_regs * regs) icmb_status = icmbs[icmb].status; if (icmb_status & 0x80) { /* unsolicited - result in ICMB */ #ifdef DEBUG - printk("wd7000_intr_handle: unsolicited interrupt %02xh\n", + printk("wd7000_intr_handle: unsolicited interrupt 0x%02xh\n", icmb_status); #endif wd7000_intr_ack(host); @@ -983,7 +1104,7 @@ int wd7000_diagnostics( Adapter *host, int code ) return 0; } if (make_code(icb.vue|(icb.status << 8),0)) { - printk("wd7000_diagnostics: failed (%02x,%02x)\n", + printk("wd7000_diagnostics: failed (0x%02x,0x%02x)\n", icb.vue, icb.status); return 0; } @@ -1011,6 +1132,7 @@ int wd7000_init( Adapter *host ) if ((diag = inb(host->iobase+ASC_INTR_STAT)) != 1) { printk("wd7000_init: "); + switch (diag) { case 2: printk("RAM failure.\n"); @@ -1031,8 +1153,7 @@ int wd7000_init( Adapter *host ) printk("ROM checksum error.\n"); break; default: - printk("diagnostic code %02Xh received.\n", diag); - break; + printk("diagnostic code 0x%02Xh received.\n", diag); } return 0; } @@ -1093,8 +1214,7 @@ void wd7000_revision(Adapter *host) } -int wd7000_detect(Scsi_Host_Template * tpnt) -/* +/* * Returns the number of adapters this driver is supporting. * * The source for hosts.c says to wait to call scsi_register until 100% @@ -1104,87 +1224,139 @@ int wd7000_detect(Scsi_Host_Template * tpnt) * calling scsi_unregister. * */ +int wd7000_detect (Scsi_Host_Template *tpnt) { - int i,j, present = 0; - const Config *cfg; - const Signature *sig; + short present = 0, biosaddr_ptr, iobase_ptr, cfg_ptr, sig_ptr, i; + short biosptr[NUM_CONFIGS]; Adapter *host = NULL; struct Scsi_Host *sh; + for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1); + tpnt->proc_dir = &proc_scsi_wd7000; - /* Set up SCB free list, which is shared by all adapters */ - init_scbs(); + /* + * Set up SCB free list, which is shared by all adapters + */ + init_scbs (); + + for (cfg_ptr = 0; cfg_ptr < NUM_CONFIGS; cfg_ptr++) { + for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++) + for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) { + for (i = 0; i < cfg_ptr; i++) + if (biosptr[i] == biosaddr_ptr) + break; + + if ((i == cfg_ptr) && + !memcmp ((void *) (wd7000_biosaddr[biosaddr_ptr] + + signatures[sig_ptr].ofs), signatures[sig_ptr].sig, + signatures[sig_ptr].len)) + goto bios_matched; + } + +bios_matched: - cfg = configs; - for (i = 0; i < NUM_CONFIGS; i++) { - sig = signatures; - for (j = 0; j < NUM_SIGNATURES; j++) { - if (!memcmp(cfg->bios+sig->ofs, sig->sig, sig->len)) { - /* matched this one */ #ifdef DEBUG - printk("WD-7000 SST BIOS detected at %04X: checking...\n", - (int) cfg->bios); + printk ("wd7000_detect: pass %d\n", cfg_ptr + 1); + + if (biosaddr_ptr == NUM_ADDRS) + printk ("WD-7000 SST BIOS not detected...\n"); + else + printk ("WD-7000 SST BIOS detected at 0x%lx: checking...\n", + wd7000_biosaddr[biosaddr_ptr]); #endif - /* - * We won't explicitly test the configuration (in this - * version); instead, we'll just see if it works to - * setup the adapter; if it does, we'll use it. - */ - if (check_region(cfg->iobase, 4)) { /* ports in use */ - printk("IO %xh already in use.\n", host->iobase); - continue; - } - /* - * We register here, to get a pointer to the extra space, - * which we'll use as the Adapter structure (host) for - * this adapter. It is located just after the registered - * Scsi_Host structure (sh), and is located by the empty - * array hostdata. + + for (iobase_ptr = 0; iobase_ptr < NUM_IOPORTS; iobase_ptr++) + if (! check_region (wd7000_iobase[iobase_ptr], 4)) { + /* + * ASC reset... */ - sh = scsi_register(tpnt, sizeof(Adapter) ); - host = (Adapter *) sh->hostdata; + outb (ASC_RES, wd7000_iobase[iobase_ptr] + ASC_CONTROL); + delay (1); + outb (0, wd7000_iobase[iobase_ptr] + ASC_CONTROL); + WAIT (wd7000_iobase[iobase_ptr] + ASC_STAT, ASC_STATMASK, + CMD_RDY, 0); + + if (inb (wd7000_iobase[iobase_ptr] + ASC_INTR_STAT) == 1) { + /* + * We register here, to get a pointer to the extra space, + * which we'll use as the Adapter structure (host) for + * this adapter. It is located just after the registered + * Scsi_Host structure (sh), and is located by the empty + * array hostdata. + */ + sh = scsi_register (tpnt, sizeof (Adapter)); + host = (Adapter *) sh->hostdata; + #ifdef DEBUG - printk("wd7000_detect: adapter allocated at %06x\n", - (int)host); + printk ("wd7000_detect: adapter allocated at 0x%x\n", + (int) host); #endif - memset( host, 0, sizeof(Adapter) ); - host->sh = sh; - host->irq = cfg->irq; - host->iobase = cfg->iobase; - host->dma = cfg->dma; - irq2host[host->irq] = host; - - if (!wd7000_init(host)) { /* Initialization failed */ - scsi_unregister (sh); - continue; - } - /* - * OK from here - we'll use this adapter/configuration. - */ - wd7000_revision(host); /* important for scatter/gather */ + memset (host, 0, sizeof (Adapter)); - printk("Western Digital WD-7000 (%d.%d) ", - host->rev1, host->rev2); - printk("using IO %xh IRQ %d DMA %d.\n", - host->iobase, host->irq, host->dma); + if (wd7000_card_num) { + host->irq = wd7000_setupIRQ[--wd7000_card_num]; + host->dma = wd7000_setupDMA[wd7000_card_num]; + } + else { + host->irq = configs[cfg_ptr].irq; + host->dma = configs[cfg_ptr].dma; + } - request_region(host->iobase, 4,"wd7000"); /* Register our ports */ - /* - * For boards before rev 6.0, scatter/gather isn't supported. - */ - if (host->rev1 < 6) sh->sg_tablesize = SG_NONE; + host->sh = sh; + host->iobase = wd7000_iobase[iobase_ptr]; + irq2host[host->irq] = host; + +#ifdef DEBUG + printk ("wd7000_detect: Trying init WD-7000 card at IO " + "0x%x, IRQ %d, DMA %d...\n", + host->iobase, host->irq, host->dma); +#endif + + if (! wd7000_init (host)) { /* Initialization failed */ + scsi_unregister (sh); + + continue; + } + + /* + * OK from here - we'll use this adapter/configuration. + */ + wd7000_revision (host); /* important for scatter/gather */ - present++; /* count it */ - break; /* don't try any more sigs */ + /* + * Register our ports. + */ + request_region (host->iobase, 4, "wd7000"); + + /* + * For boards before rev 6.0, scatter/gather + * isn't supported. + */ + if (host->rev1 < 6) + sh->sg_tablesize = SG_NONE; + + present++; /* count it */ + + if (biosaddr_ptr != NUM_ADDRS) + biosptr[cfg_ptr] = biosaddr_ptr; + + printk ("Western Digital WD-7000 (rev %d.%d) ", + host->rev1, host->rev2); + printk ("using IO 0x%xh, IRQ %d, DMA %d.\n", + host->iobase, host->irq, host->dma); + + break; + } +fail: } - sig++; /* try next signature with this configuration */ - } - cfg++; /* try next configuration */ } - return present; + if (! present) + printk ("Failed initialization of WD-7000 SCSI card!\n"); + + return (present); } diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index ebeae0079ea4..7f0fcf4aa99d 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -1182,7 +1182,7 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) if (!audio_devs[dev]->go) tmout = 0; else - tmout = 2 * HZ; + tmout = 10 * HZ; { diff --git a/fs/buffer.c b/fs/buffer.c index 4dc96aa51769..cdbd45185294 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -968,11 +968,6 @@ struct buffer_head * breada(kdev_t dev, int block, int bufsize, */ static void put_unused_buffer_head(struct buffer_head * bh) { - struct wait_queue * wait; - - wait = ((volatile struct buffer_head *) bh)->b_wait; - memset(bh,0,sizeof(*bh)); - ((volatile struct buffer_head *) bh)->b_wait = wait; bh->b_next_free = unused_list; unused_list = bh; wake_up(&buffer_wait); @@ -1402,6 +1397,11 @@ static int grow_buffers(int pri, int size) /* =========== Reduce the buffer memory ============= */ +static inline int buffer_waiting(struct buffer_head * bh) +{ + return waitqueue_active(&bh->b_wait); +} + /* * try_to_free_buffer() checks if all the buffers on this particular page * are unused, and free's the page if so. @@ -1421,7 +1421,8 @@ int try_to_free_buffer(struct buffer_head * bh, struct buffer_head ** bhp, if (!tmp) return 0; if (tmp->b_count || buffer_protected(tmp) || - buffer_dirty(tmp) || buffer_locked(tmp) || tmp->b_wait) + buffer_dirty(tmp) || buffer_locked(tmp) || + buffer_waiting(bh)) return 0; if (priority && buffer_touched(tmp)) return 0; diff --git a/fs/locks.c b/fs/locks.c index 91916d9278d1..dd6189c35fa3 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -132,6 +132,15 @@ static struct file_lock *file_lock_table = NULL; /* Free lock not inserted in any queue */ static inline void locks_free_lock(struct file_lock *fl) { + /* + * CAREFUL! We can't free it until everybody waiting for + * this block have removed themselves from the wait queue + */ + if (fl->fl_wait) { + struct wait_queue *head = WAIT_QUEUE_HEAD(&fl->fl_wait); + while (fl->fl_wait != head) + schedule(); + } kfree(fl); return; } @@ -636,10 +645,12 @@ next_task: if (my_task == blocked_task) return (1); for (fl = file_lock_table; fl != NULL; fl = fl->fl_nextlink) { + struct wait_queue *head; if (fl->fl_owner == NULL || fl->fl_wait == NULL) continue; + head = WAIT_QUEUE_HEAD(&fl->fl_wait); dlock_wait = fl->fl_wait; - do { + while (dlock_wait != head) { if (dlock_wait->task == blocked_task) { if (fl->fl_owner == my_task) { return (1); @@ -648,7 +659,7 @@ next_task: goto next_task; } dlock_wait = dlock_wait->next; - } while (dlock_wait != fl->fl_wait); + } } return (0); } @@ -979,7 +990,7 @@ static void locks_delete_lock(struct file_lock **fl_p, unsigned int wait) } wake_up(&fl->fl_wait); - kfree(fl); + locks_free_lock(fl); return; } @@ -1014,10 +1025,11 @@ static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx) (long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink, (long)fl->fl_next, (long)fl->fl_block, id, pfx); if ((wt = fl->fl_wait) != NULL) { - do { + struct wait_queue *head = WAIT_QUEUE_HEAD(&fl->fl_wait); + while (wt != head) { p += sprintf(p, " %d", wt->task->pid); wt = wt->next; - } while (wt != fl->fl_wait); + } } p += sprintf(p, "\n"); return (p); diff --git a/include/linux/isdn.h b/include/linux/isdn.h index bd212e000d45..1408407d9388 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.15 1996/06/15 14:56:57 fritz Exp $ +/* $Id: isdn.h,v 1.16 1996/08/12 16:20:56 hipp Exp $ * * Main header for the Linux ISDN subsystem (linklevel). * @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn.h,v $ + * Revision 1.16 1996/08/12 16:20:56 hipp + * renamed ppp_minor to ppp_slot + * * Revision 1.15 1996/06/15 14:56:57 fritz * Added version signatures for data structures used * by userlevel programs. @@ -319,7 +322,7 @@ typedef struct isdn_net_local_s { struct enet_statistics stats; /* Ethernet Statistics */ int isdn_device; /* Index to isdn-device */ int isdn_channel; /* Index to isdn-channel */ - int ppp_minor; /* PPPD device minor number */ + int ppp_slot; /* PPPD device slot number */ int pre_device; /* Preselected isdn-device */ int pre_channel; /* Preselected isdn-channel */ int exclusive; /* If non-zero idx to reserved chan.*/ @@ -549,6 +552,7 @@ struct ippp_struct { unsigned int maxcid; isdn_net_local *lp; int unit; + int minor; long last_link_seqno; long mp_seqno; long range; diff --git a/include/linux/sched.h b/include/linux/sched.h index ef527d212456..ba1ca20bfc8f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -401,12 +401,10 @@ extern inline struct file *file_from_fd(const unsigned int fd) extern inline void __add_wait_queue(struct wait_queue ** p, struct wait_queue * wait) { struct wait_queue *head = *p; - struct wait_queue *next = wait; + struct wait_queue *next = WAIT_QUEUE_HEAD(p); - if (head) { - next = head->next; - p = &head->next; - } + if (head) + next = head; *p = wait; wait->next = next; } @@ -424,22 +422,15 @@ extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wa extern inline void __remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait) { struct wait_queue * next = wait->next; + struct wait_queue * head = next; - if (wait == next) { - *p = NULL; - } else { - struct wait_queue *head = *p; - if (head == wait) - *p = next; - for (;;) { - struct wait_queue *nextlist = head->next; - if (nextlist == wait) - break; - head = nextlist; - } - head->next = next; + for (;;) { + struct wait_queue * nextlist = head->next; + if (nextlist == wait) + break; + head = nextlist; } - wait->next = NULL; + head->next = next; } extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait) diff --git a/include/linux/soundcard.h b/include/linux/soundcard.h index 17475694c00e..c1753186143c 100644 --- a/include/linux/soundcard.h +++ b/include/linux/soundcard.h @@ -742,15 +742,13 @@ typedef struct copr_msg { /* Note! Number 31 cannot be used since the sign bit is reserved */ -#ifdef NO_LONGER_AVAILABLE /* - * The following unsupported macros will be removed from the API in near - * future. + * The following unsupported macros are no longer functional. + * Use SOUND_MIXER_PRIVATE# macros in future. */ -#define SOUND_MIXER_ENHANCE 29 /* Enhanced stereo (0, 40, 60 or 80) */ -#define SOUND_MIXER_MUTE 28 /* 0 or 1 */ -#define SOUND_MIXER_LOUD 30 /* 0 or 1 */ -#endif +#define SOUND_MIXER_ENHANCE 31 +#define SOUND_MIXER_MUTE 31 +#define SOUND_MIXER_LOUD 31 #define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \ @@ -790,11 +788,10 @@ typedef struct copr_msg { #define SOUND_MASK_LINE2 (1 << SOUND_MIXER_LINE2) #define SOUND_MASK_LINE3 (1 << SOUND_MIXER_LINE3) -#ifdef NO_LONGER_AVAILABLE +/* Obsolete macros */ #define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE) #define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE) #define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD) -#endif #define MIXER_READ(dev) _IOR('M', dev, int) #define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME) @@ -814,11 +811,11 @@ typedef struct copr_msg { #define SOUND_MIXER_READ_LINE1 MIXER_READ(SOUND_MIXER_LINE1) #define SOUND_MIXER_READ_LINE2 MIXER_READ(SOUND_MIXER_LINE2) #define SOUND_MIXER_READ_LINE3 MIXER_READ(SOUND_MIXER_LINE3) -#ifdef NO_LONGER_AVAILABLE + +/* Obsolete macros */ #define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE) #define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE) #define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD) -#endif #define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC) #define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK) @@ -844,11 +841,11 @@ typedef struct copr_msg { #define SOUND_MIXER_WRITE_LINE1 MIXER_WRITE(SOUND_MIXER_LINE1) #define SOUND_MIXER_WRITE_LINE2 MIXER_WRITE(SOUND_MIXER_LINE2) #define SOUND_MIXER_WRITE_LINE3 MIXER_WRITE(SOUND_MIXER_LINE3) -#ifdef NO_LONGER_AVAILABLE + +/* Obsolete macros */ #define SOUND_MIXER_WRITE_MUTE MIXER_WRITE(SOUND_MIXER_MUTE) #define SOUND_MIXER_WRITE_ENHANCE MIXER_WRITE(SOUND_MIXER_ENHANCE) #define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD) -#endif #define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC) diff --git a/include/linux/wait.h b/include/linux/wait.h index 90ffe7b3b71b..9ac815be562a 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -13,6 +13,19 @@ struct wait_queue { struct wait_queue * next; }; +#define WAIT_QUEUE_HEAD(x) ((struct wait_queue *)((x)-1)) + +static inline void init_waitqueue(struct wait_queue **q) +{ + *q = WAIT_QUEUE_HEAD(q); +} + +static inline int waitqueue_active(struct wait_queue **q) +{ + struct wait_queue *head = *q; + return head && head != WAIT_QUEUE_HEAD(q); +} + struct semaphore { int count; struct wait_queue * wait; diff --git a/init/main.c b/init/main.c index c19a0813effc..3ff76edae901 100644 --- a/init/main.c +++ b/init/main.c @@ -94,6 +94,7 @@ extern void BusLogic_Setup(char *str, int *ints); extern void fdomain_setup(char *str, int *ints); extern void in2000_setup(char *str, int *ints); extern void NCR53c406a_setup(char *str, int *ints); +extern void wd7000_setup(char *str, int *ints); extern void ppa_setup(char *str, int *ints); extern void scsi_luns_setup(char *str, int *ints); extern void sound_setup(char *str, int *ints); @@ -330,6 +331,9 @@ struct { #ifdef CONFIG_SCSI_IN2000 { "in2000=", in2000_setup}, #endif +#ifdef CONFIG_SCSI_7000FASST + { "wd7000=", wd7000_setup}, +#endif #ifdef CONFIG_SCSI_PPA { "ppa=", ppa_setup }, #endif diff --git a/ipc/msg.c b/ipc/msg.c index 3df15e005fd1..cce1cce6f170 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -193,8 +193,7 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg msq->msg_lspid = current->pid; msq->msg_stime = CURRENT_TIME; restore_flags(flags); - if (msq->rwait) - wake_up (&msq->rwait); + wake_up (&msq->rwait); return 0; } @@ -350,8 +349,7 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty msghdrs--; msq->msg_cbytes -= nmsg->msg_ts; restore_flags(flags); - if (msq->wwait) - wake_up (&msq->wwait); + wake_up (&msq->wwait); /* * Calls from kernel level (IPC_KERNELD set) * wants the message copied to kernel space! @@ -438,8 +436,7 @@ found: msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL); if (!msq) { msgque[id] = (struct msqid_ds *) IPC_UNUSED; - if (msg_lock) - wake_up (&msg_lock); + wake_up (&msg_lock); return -ENOMEM; } ipcp = &msq->msg_perm; @@ -459,8 +456,7 @@ found: max_msqid = id; msgque[id] = msq; used_queues++; - if (msg_lock) - wake_up (&msg_lock); + wake_up (&msg_lock); return (unsigned int) msq->msg_perm.seq * MSGMNI + id; } @@ -525,11 +521,9 @@ static void freeque (int id) while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED)); msgque[id] = (struct msqid_ds *) IPC_UNUSED; used_queues--; - while (msq->rwait || msq->wwait) { - if (msq->rwait) - wake_up (&msq->rwait); - if (msq->wwait) - wake_up (&msq->wwait); + while (waitqueue_active(&msq->rwait) || waitqueue_active(&msq->wwait)) { + wake_up (&msq->rwait); + wake_up (&msq->wwait); schedule(); } for (msgp = msq->msg_first; msgp; msgp = msgh ) { diff --git a/ipc/sem.c b/ipc/sem.c index d3e1b4014267..916e0a3aa11c 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -103,8 +103,7 @@ found: if (!sma) { semary[id] = (struct semid_ds *) IPC_UNUSED; used_sems -= nsems; - if (sem_lock) - wake_up (&sem_lock); + wake_up (&sem_lock); return -ENOMEM; } memset (sma, 0, size); @@ -124,8 +123,7 @@ found: max_semid = id; used_semids++; semary[id] = sma; - if (sem_lock) - wake_up (&sem_lock); + wake_up (&sem_lock); return (unsigned int) sma->sem_perm.seq * SEMMNI + id; } diff --git a/ipc/shm.c b/ipc/shm.c index d304fbb7cde2..2eac5fda4db3 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -92,16 +92,14 @@ found: shp = (struct shmid_ds *) kmalloc (sizeof (*shp), GFP_KERNEL); if (!shp) { shm_segs[id] = (struct shmid_ds *) IPC_UNUSED; - if (shm_lock) - wake_up (&shm_lock); + wake_up (&shm_lock); return -ENOMEM; } shp->shm_pages = (ulong *) kmalloc (numpages*sizeof(ulong),GFP_KERNEL); if (!shp->shm_pages) { shm_segs[id] = (struct shmid_ds *) IPC_UNUSED; - if (shm_lock) - wake_up (&shm_lock); + wake_up (&shm_lock); kfree(shp); return -ENOMEM; } @@ -125,8 +123,7 @@ found: max_shmid = id; shm_segs[id] = shp; used_segs++; - if (shm_lock) - wake_up (&shm_lock); + wake_up (&shm_lock); return (unsigned int) shp->shm_perm.seq * SHMMNI + id; } diff --git a/kernel/fork.c b/kernel/fork.c index 723e4242cd2b..52e434285f57 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -247,6 +247,7 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) p->prev_run = NULL; p->p_pptr = p->p_opptr = current; p->p_cptr = NULL; + init_waitqueue(&p->wait_chldexit); p->signal = 0; p->it_real_value = p->it_virt_value = p->it_prof_value = 0; p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0; diff --git a/kernel/sched.c b/kernel/sched.c index 9bcb089cc48a..b3e28370d4ec 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -431,51 +431,55 @@ asmlinkage int sys_pause(void) */ void wake_up(struct wait_queue **q) { - struct wait_queue *tmp; - struct task_struct * p; + struct wait_queue *next; + struct wait_queue *head; - if (!q || !(tmp = *q)) + if (!q || !(next = *q)) return; - do { - if ((p = tmp->task) != NULL) { + head = WAIT_QUEUE_HEAD(q); + while (next != head) { + struct task_struct *p = next->task; + next = next->next; + if (p != NULL) { if ((p->state == TASK_UNINTERRUPTIBLE) || (p->state == TASK_INTERRUPTIBLE)) wake_up_process(p); } - if (!tmp->next) { - printk("wait_queue is bad (eip = %p)\n", - __builtin_return_address(0)); - printk(" q = %p\n",q); - printk(" *q = %p\n",*q); - printk(" tmp = %p\n",tmp); - break; - } - tmp = tmp->next; - } while (tmp != *q); + if (!next) + goto bad; + } + return; +bad: + printk("wait_queue is bad (eip = %p)\n", + __builtin_return_address(0)); + printk(" q = %p\n",q); + printk(" *q = %p\n",*q); } void wake_up_interruptible(struct wait_queue **q) { - struct wait_queue *tmp; - struct task_struct * p; + struct wait_queue *next; + struct wait_queue *head; - if (!q || !(tmp = *q)) + if (!q || !(next = *q)) return; - do { - if ((p = tmp->task) != NULL) { + head = WAIT_QUEUE_HEAD(q); + while (next != head) { + struct task_struct *p = next->task; + next = next->next; + if (p != NULL) { if (p->state == TASK_INTERRUPTIBLE) wake_up_process(p); } - if (!tmp->next) { - printk("wait_queue is bad (eip = %p)\n", - __builtin_return_address(0)); - printk(" q = %p\n",q); - printk(" *q = %p\n",*q); - printk(" tmp = %p\n",tmp); - break; - } - tmp = tmp->next; - } while (tmp != *q); + if (!next) + goto bad; + } + return; +bad: + printk("wait_queue is bad (eip = %p)\n", + __builtin_return_address(0)); + printk(" q = %p\n",q); + printk(" *q = %p\n",*q); } void __down(struct semaphore * sem) diff --git a/net/core/net_alias.c b/net/core/net_alias.c index e6f1fe3eb591..03095567f73a 100644 --- a/net/core/net_alias.c +++ b/net/core/net_alias.c @@ -1298,6 +1298,7 @@ void net_alias_init(void) */ #ifndef ALIAS_USER_LAND_DEBUG +#ifdef CONFIG_PROC_FS proc_net_register(&(struct proc_dir_entry) { PROC_NET_ALIAS_TYPES, 11, "alias_types", S_IFREG | S_IRUGO, 1, 0, 0, @@ -1311,6 +1312,7 @@ void net_alias_init(void) net_alias_getinfo }); #endif +#endif } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index ba78c867da6d..4ae481a7c42f 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -966,8 +966,10 @@ void tcp_send_ack(struct sock *sk) sock_wfree(sk, buff); return; } +#if 0 /* why does this result in problems? */ #ifndef CONFIG_NO_PATH_MTU_DISCOVERY buff->ip_hdr->frag_off |= htons(IP_DF); +#endif #endif t1 =(struct tcphdr *)skb_put(buff,sizeof(struct tcphdr)); -- 2.39.5