diff -u --recursive --new-file v1.2.4/linux/Makefile linux/Makefile --- v1.2.4/linux/Makefile Sun Apr 9 11:59:55 1995 +++ linux/Makefile Wed Apr 12 15:25:52 1995 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 2 -SUBLEVEL = 4 +SUBLEVEL = 5 ARCH = i386 diff -u --recursive --new-file v1.2.4/linux/README linux/README --- v1.2.4/linux/README Sun Apr 9 11:59:55 1995 +++ linux/README Wed Apr 12 08:12:14 1995 @@ -124,15 +124,15 @@ floppy. If you boot Linux from the hard drive, chances are you use LILO which - uses the kernel image as specified in the file /etc/lilo/config. The + uses the kernel image as specified in the file /etc/lilo.conf. The kernel image file is usually /vmlinuz, or /zImage, or /etc/zImage. To use the new kernel, copy the new image over the old one (save a backup of the original!). Then, you MUST RERUN LILO to update the loading map!! If you don't, you won't be able to boot the new kernel image. - Reinstalling LILO is usually a matter of running /etc/lilo/install. - You may wish to edit /etc/lilo/config to specify an entry for your + Reinstalling LILO is usually a matter of running /sbin/lilo. + You may wish to edit /etc/lilo.conf to specify an entry for your old kernel image (say, /vmlinux.old) in case the new one does not work. See the LILO docs for more information. diff -u --recursive --new-file v1.2.4/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v1.2.4/linux/drivers/block/ll_rw_blk.c Sun Apr 9 11:59:56 1995 +++ linux/drivers/block/ll_rw_blk.c Mon Apr 10 11:22:45 1995 @@ -169,20 +169,40 @@ /* * wait until a free request in the first N entries is available. - * NOTE: interrupts must be disabled on the way in, and will still - * be disabled on the way out. */ -static inline struct request * get_request_wait(int n, int dev) +static struct request * __get_request_wait(int n, int dev) { register struct request *req; + struct wait_queue wait = { current, NULL }; - while ((req = get_request(n, dev)) == NULL) { + add_wait_queue(&wait_for_request, &wait); + for (;;) { unplug_device(MAJOR(dev)+blk_dev); - sleep_on(&wait_for_request); + current->state = TASK_UNINTERRUPTIBLE; + cli(); + req = get_request(n, dev); + sti(); + if (req) + break; + schedule(); } + remove_wait_queue(&wait_for_request, &wait); + current->state = TASK_RUNNING; return req; } +static inline struct request * get_request_wait(int n, int dev) +{ + register struct request *req; + + cli(); + req = get_request(n, dev); + sti(); + if (req) + return req; + return __get_request_wait(n, dev); +} + /* RO fail safe mechanism */ static long ro_bits[MAX_BLKDEV][8]; @@ -303,9 +323,7 @@ */ max_req = (rw == READ) ? NR_REQUEST : ((NR_REQUEST*2)/3); -/* big loop: look for a free request. */ - -repeat: +/* look for a free request. */ cli(); /* The scsi disk drivers and the IDE driver completely remove the request @@ -363,23 +381,17 @@ /* find an unused request. */ req = get_request(max_req, bh->b_dev); + sti(); -/* if no request available: if rw_ahead, forget it; otherwise try again. */ - if (! req) { +/* if no request available: if rw_ahead, forget it; otherwise try again blocking.. */ + if (!req) { if (rw_ahead) { - sti(); unlock_buffer(bh); return; } - unplug_device(major+blk_dev); - sleep_on(&wait_for_request); - sti(); - goto repeat; + req = __get_request_wait(max_req, bh->b_dev); } -/* we found a request. */ - sti(); - /* fill up the request-info, and add it to the queue */ req->cmd = rw; req->errors = 0; @@ -410,9 +422,7 @@ printk("Can't page to read-only device 0x%X\n",dev); return; } - cli(); req = get_request_wait(NR_REQUEST, dev); - sti(); /* fill up the request-info, and add it to the queue */ req->cmd = rw; req->errors = 0; @@ -533,9 +543,7 @@ for (i=0; icmd = rw; req->errors = 0; req->sector = (b[i] * buffersize) >> 9; diff -u --recursive --new-file v1.2.4/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog --- v1.2.4/linux/drivers/char/ChangeLog Thu Mar 9 20:37:34 1995 +++ linux/drivers/char/ChangeLog Wed Apr 12 21:24:17 1995 @@ -1,3 +1,11 @@ +Wed Apr 12 08:06:16 1995 Theodore Y. Ts'o + + * serial.c (do_serial_hangup, do_softint, check_modem_status, + rs_init): Hangups are now scheduled via a separate tqueue + structure in the async_struct structure, tqueue_hangup. + This task is pushed on to the tq_schedule queue, so that + it is processed syncronously by the scheduler. + Sat Feb 18 12:13:51 1995 Theodore Y. Ts'o (tytso@rt-11) * tty_io.c (disassociate_ctty, tty_open, tty_ioctl): Clear diff -u --recursive --new-file v1.2.4/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v1.2.4/linux/drivers/char/serial.c Thu Feb 23 13:31:40 1995 +++ linux/drivers/char/serial.c Wed Apr 12 21:24:17 1995 @@ -468,7 +468,8 @@ #ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup..."); #endif - rs_sched_event(info, RS_EVENT_HANGUP); + queue_task_irq_off(&info->tqueue_hangup, + &tq_scheduler); } } if (info->flags & ASYNC_CTS_FLOW) { @@ -722,12 +723,6 @@ if (!tty) return; - if (clear_bit(RS_EVENT_HANGUP, &info->event)) { - tty_hangup(tty); - wake_up_interruptible(&info->open_wait); - info->flags &= ~(ASYNC_NORMAL_ACTIVE| - ASYNC_CALLOUT_ACTIVE); - } if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) @@ -737,6 +732,28 @@ } /* + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occured. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_serial_hangup() -> tty->hangup() -> rs_hangup() + * + */ +static void do_serial_hangup(void *private_) +{ + struct async_struct *info = (struct async_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + tty_hangup(tty); +} + + +/* * This subroutine is called when the RS_TIMER goes off. It is used * by the serial driver to handle ports that do not have an interrupt * (irq=0). This doesn't work very well for 16450's, but gives barely @@ -2615,6 +2632,8 @@ info->blocked_open = 0; info->tqueue.routine = do_softint; info->tqueue.data = info; + info->tqueue_hangup.routine = do_serial_hangup; + info->tqueue_hangup.data = info; info->callout_termios =callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; info->open_wait = 0; diff -u --recursive --new-file v1.2.4/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v1.2.4/linux/drivers/net/lance.c Fri Jan 20 11:34:39 1995 +++ linux/drivers/net/lance.c Sun Apr 9 10:38:29 1995 @@ -913,7 +913,7 @@ lp->rx_ring[entry].base &= 0x03ffffff; } else { /* Malloc up new buffer, compatible with net-2e. */ - short pkt_len = lp->rx_ring[entry].msg_length; + short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4; struct sk_buff *skb; skb = alloc_skb(pkt_len, GFP_ATOMIC); diff -u --recursive --new-file v1.2.4/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v1.2.4/linux/drivers/net/ne.c Sun Apr 9 11:59:56 1995 +++ linux/drivers/net/ne.c Wed Apr 12 13:16:11 1995 @@ -1,3 +1,4 @@ +#define rw_bugfix /* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */ /* Written 1992-94 by Donald Becker. @@ -375,6 +376,7 @@ { int retries = 0; int nic_base = NE_BASE; + unsigned long flags; /* Round the count up for word writes. Do we need to do this? What effect will an odd byte count have on the 8390? @@ -415,8 +417,13 @@ race condition will munge the remote byte count values, and then the ne2k will hang the machine by holding I/O CH RDY because it expects more data. Hopefully fixes the lockups. -- Paul Gortmaker. + + Use save_flags/cli/restore_flags rather than cli/sti to avoid risk + of accidentally enabling interrupts which were disabled when we + were entered. Dave Platt */ + save_flags(flags); cli(); outb_p(count & 0xff, nic_base + EN0_RCNTLO); outb_p(count >> 8, nic_base + EN0_RCNTHI); @@ -429,7 +436,7 @@ } else { outsb(NE_BASE + NE_DATAPORT, buf, count); } - sti(); + restore_flags(flags); #ifdef CONFIG_NE_SANITY /* This was for the ALPHA version only, but enough people have diff -u --recursive --new-file v1.2.4/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v1.2.4/linux/drivers/net/wavelan.c Wed Feb 22 16:25:04 1995 +++ linux/drivers/net/wavelan.c Tue Apr 11 07:45:38 1995 @@ -71,7 +71,7 @@ extern int wavelan_probe(device *); /* See Space.c */ -static char *version = "wavelan.c:v6 22/2/95\n"; +static char *version = "wavelan.c:v7 95/4/8\n"; /* * Entry point forward declarations. @@ -508,6 +508,9 @@ ac_cfg_t cfg; ac_ias_t ias; + if (wavelan_debug > 0) + printk("%s: ->wavelan_hardware_reset(dev=0x%x)\n", dev->name, (unsigned int)dev); + ioaddr = dev->base_addr; lp = (net_local *)dev->priv; @@ -565,7 +568,12 @@ } if (i <= 0) + { printk("%s: wavelan_hardware_reset(): iscp_busy timeout.\n", dev->name); + if (wavelan_debug > 0) + printk("%s: <-wavelan_hardware_reset(): -1\n", dev->name); + return -1; + } for (i = 15; i > 0; i--) { @@ -578,7 +586,12 @@ } if (i <= 0) + { printk("%s: wavelan_hardware_reset(): status: expected 0x%02x, got 0x%02x.\n", dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status); + if (wavelan_debug > 0) + printk("%s: <-wavelan_hardware_reset(): -1\n", dev->name); + return -1; + } wavelan_ack(dev); @@ -588,12 +601,18 @@ obram_write(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb)); if (wavelan_synchronous_cmd(dev, "diag()") == -1) + { + if (wavelan_debug > 0) + printk("%s: <-wavelan_hardware_reset(): -1\n", dev->name); return -1; + } obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb)); if (cb.ac_status & AC_SFLD_FAIL) { printk("%s: wavelan_hardware_reset(): i82586 Self Test failed.\n", dev->name); + if (wavelan_debug > 0) + printk("%s: <-wavelan_hardware_reset(): -1\n", dev->name); return -1; } @@ -654,7 +673,12 @@ obram_write(ioaddr, OFFSET_CU, (unsigned char *)&cfg, sizeof(cfg)); if (wavelan_synchronous_cmd(dev, "reset()-configure") == -1) + { + if (wavelan_debug > 0) + printk("%s: <-wavelan_hardware_reset(): -1\n", dev->name); + return -1; + } memset(&ias, 0x00, sizeof(ias)); ias.ias_h.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_ia_setup); @@ -663,19 +687,24 @@ obram_write(ioaddr, OFFSET_CU, (unsigned char *)&ias, sizeof(ias)); if (wavelan_synchronous_cmd(dev, "reset()-address") == -1) + { + if (wavelan_debug > 0) + printk("%s: <-wavelan_hardware_reset(): -1\n", dev->name); + return -1; + } wavelan_ints_on(dev); if (wavelan_debug > 4) - { wavelan_scb_show(ioaddr); - printk("%s: Initialized WaveLAN.\n", dev->name); - } wavelan_ru_start(dev); wavelan_cu_start(dev); + if (wavelan_debug > 0) + printk("%s: <-wavelan_hardware_reset(): 0\n", dev->name); + return 0; } @@ -708,6 +737,7 @@ wavelan_probe(device *dev) { int i; + int r; short base_addr; static unsigned short iobase[] = { @@ -721,10 +751,17 @@ 0x390, }; + if (wavelan_debug > 0) + printk("%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n", dev->name, (unsigned int)dev, (unsigned int)dev->base_addr); + #if STRUCT_CHECK == 1 if (wavelan_struct_check() != (char *)0) { printk("%s: structure/compiler botch: \"%s\"\n", dev->name, wavelan_struct_check()); + + if (wavelan_debug > 0) + printk("%s: <-wavelan_probe(): ENODEV\n", dev->name); + return ENODEV; } #endif /* STRUCT_CHECK == 1 */ @@ -732,16 +769,25 @@ base_addr = dev->base_addr; if (base_addr < 0) + { /* * Don't probe at all. */ + if (wavelan_debug > 0) + printk("%s: <-wavelan_probe(): ENXIO\n", dev->name); return ENXIO; + } if (base_addr > 0x100) + { /* * Check a single specified location. */ - return wavelan_probe1(dev, base_addr); + r = wavelan_probe1(dev, base_addr); + if (wavelan_debug > 0) + printk("%s: <-wavelan_probe(): %d\n", dev->name, r); + return r; + } for (i = 0; i < nels(iobase); i++) { @@ -749,9 +795,16 @@ continue; if (wavelan_probe1(dev, iobase[i]) == 0) + { + if (wavelan_debug > 0) + printk("%s: <-wavelan_probe(): 0\n", dev->name); return 0; + } } + if (wavelan_debug > 0) + printk("%s: <-wavelan_probe(): ENODEV\n", dev->name); + return ENODEV; } @@ -764,6 +817,9 @@ int i; net_local *lp; + if (wavelan_debug > 0) + printk("%s: ->wavelan_probe1(dev=0x%x, ioaddr=0x%x)\n", dev->name, (unsigned int)dev, ioaddr); + wavelan_reset(ioaddr); psa_read(ioaddr, HACR_DEFAULT, 0, (unsigned char *)&psa, sizeof(psa)); @@ -780,13 +836,19 @@ || psa.psa_univ_mac_addr[2] != SA_ADDR2 ) + { + if (wavelan_debug > 0) + printk("%s: <-wavelan_probe1(): ENODEV\n", dev->name); return ENODEV; + } printk("%s: WaveLAN at %#x,", dev->name, ioaddr); if ((irq = wavelan_map_irq(ioaddr, psa.psa_int_req_no)) == -1) { printk(" could not wavelan_map_irq(0x%x, %d).\n", ioaddr, psa.psa_int_req_no); + if (wavelan_debug > 0) + printk("%s: <-wavelan_probe1(): EAGAIN\n", dev->name); return EAGAIN; } @@ -871,7 +933,7 @@ printk("\n"); - if (wavelan_debug) + if (wavelan_debug > 0) printk(version); dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL); @@ -915,6 +977,9 @@ dev->mtu = WAVELAN_MTU; + if (wavelan_debug > 0) + printk("%s: <-wavelan_probe1(): 0\n", dev->name); + return 0; } @@ -1074,12 +1139,21 @@ { unsigned short ioaddr; net_local *lp; + unsigned long x; + int r; + + if (wavelan_debug > 0) + printk("%s: ->wavelan_open(dev=0x%x)\n", dev->name, (unsigned int)dev); ioaddr = dev->base_addr; lp = (net_local *)dev->priv; if (dev->irq == 0) + { + if (wavelan_debug > 0) + printk("%s: <-wavelan_open(): -ENXIO\n", dev->name); return -ENXIO; + } if ( @@ -1092,23 +1166,35 @@ ) { irq2dev_map[dev->irq] = (device *)0; + if (wavelan_debug > 0) + printk("%s: <-wavelan_open(): -EAGAIN\n", dev->name); return -EAGAIN; } - if (wavelan_hardware_reset(dev) == -1) + x = wavelan_splhi(); + if ((r = wavelan_hardware_reset(dev)) != -1) + { + dev->interrupt = 0; + dev->start = 1; + } + wavelan_splx(x); + + if (r == -1) { free_irq(dev->irq); irq2dev_map[dev->irq] = (device *)0; + if (wavelan_debug > 0) + printk("%s: <-wavelan_open(): -EAGAIN(2)\n", dev->name); return -EAGAIN; } - dev->interrupt = 0; - dev->start = 1; - #if defined(MODULE) MOD_INC_USE_COUNT; #endif /* defined(MODULE) */ + if (wavelan_debug > 0) + printk("%s: <-wavelan_open(): 0\n", dev->name); + return 0; } @@ -1438,7 +1524,7 @@ } #endif /* 0 */ - if (wavelan_debug > 0) + if (wavelan_debug > 5) { unsigned char addr[WAVELAN_ADDR_SIZE]; unsigned short ltype; @@ -1723,14 +1809,14 @@ * This will clear it -- ignored for now. */ mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, sizeof(dce_status)); - if (wavelan_debug > 4) + if (wavelan_debug > 0) printk("%s: warning: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", dev->name, dce_status); } if ((hasr & HASR_82586_INTR) == 0) { dev->interrupt = 0; - if (wavelan_debug > 4) + if (wavelan_debug > 0) printk("%s: warning: wavelan_interrupt() but (hasr & HASR_82586_INTR) == 0.\n", dev->name); return; } @@ -1746,7 +1832,7 @@ set_chan_attn(ioaddr, lp->hacr); - if (wavelan_debug > 4) + if (wavelan_debug > 5) printk("%s: interrupt, status 0x%04x.\n", dev->name, status); if ((status & SCB_ST_CX) == SCB_ST_CX) @@ -1804,6 +1890,9 @@ net_local *lp; unsigned short scb_cmd; + if (wavelan_debug > 0) + printk("%s: ->wavelan_close(dev=0x%x)\n", dev->name, (unsigned int)dev); + ioaddr = dev->base_addr; lp = (net_local *)dev->priv; @@ -1831,6 +1920,9 @@ MOD_DEC_USE_COUNT; #endif /* defined(MODULE) */ + if (wavelan_debug > 0) + printk("%s: <-wavelan_close(): 0\n", dev->name); + return 0; } @@ -1856,6 +1948,9 @@ net_local *lp; unsigned long x; + if (wavelan_debug > 0) + printk("%s: ->wavelan_set_multicast_list(dev=0x%x, num_addrs=%d, addrs=0x%x)\n", dev->name, (unsigned int)dev, num_addrs, (unsigned int)addrs); + lp = (net_local *)dev->priv; switch (num_addrs) @@ -1888,6 +1983,9 @@ */ break; } + + if (wavelan_debug > 0) + printk("%s: <-wavelan_set_multicast_list()\n", dev->name); } /* @@ -2330,6 +2428,7 @@ * Matthew Geier (matthew@cs.usyd.edu.au), * Remo di Giovanni (remo@cs.usyd.edu.au), * Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de), + * Vipul Gupta (vgupta@cs.binghamton.edu), * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), * Tim Nicholson (tim@cs.usyd.edu.au), * Ian Parkin (ian@cs.usyd.edu.au), diff -u --recursive --new-file v1.2.4/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v1.2.4/linux/drivers/scsi/Makefile Tue Apr 4 09:05:34 1995 +++ linux/drivers/scsi/Makefile Tue Apr 11 07:56:24 1995 @@ -86,9 +86,11 @@ SCSI_SRCS := $(SCSI_SRCS) buslogic.c endif +SCSI_SRCS := $(SCSI_SRCS) eata_dma.c ifdef CONFIG_SCSI_EATA_DMA SCSI_OBJS := $(SCSI_OBJS) eata_dma.o -SCSI_SRCS := $(SCSI_SRCS) eata_dma.c +else +SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) eata_dma.o endif ifdef CONFIG_SCSI_U14_34F diff -u --recursive --new-file v1.2.4/linux/drivers/scsi/buslogic.c linux/drivers/scsi/buslogic.c --- v1.2.4/linux/drivers/scsi/buslogic.c Mon Jan 23 10:38:29 1995 +++ linux/drivers/scsi/buslogic.c Wed Apr 12 08:12:14 1995 @@ -56,16 +56,18 @@ * BT-747D - 747S + differential termination. * BT-757S - 747S + WIDE SCSI. * BT-757D - 747D + WIDE SCSI. - * BT-445S - VESA bus-master FAST SCSI with active termination and floppy - * support. + * BT-445S - VESA bus-master FAST SCSI with active termination + * and floppy support. * BT-445C - 445S + enhanced BIOS & firmware options. - * BT-946C - PCI bus-master FAST SCSI. (??? Nothing else known.) + * BT-946C - PCI bus-master FAST SCSI. + * BT-956C - PCI bus-master FAST/WIDE SCSI. * * ??? I believe other boards besides the 445 now have a "C" model, but I * have no facts on them. * * This driver SHOULD support all of these boards. It has only been tested - * with a 747S and 445S. + * with a 747S, 445S, 946C, and 956C; there is no PCI-specific support as + * yet. * * Should you require further information on any of these boards, BusLogic * can be reached at (408)492-9090. Their BBS # is (408)492-1984 (maybe BBS @@ -118,7 +120,7 @@ The test is believed to fail on at least some AMI BusLogic clones. */ /* #define BIOS_TRANSLATION_OVERRIDE BIOS_TRANSLATION_BIG */ -#define BUSLOGIC_VERSION "1.14" +#define BUSLOGIC_VERSION "1.15" /* Not a random value - if this is too large, the system hangs for a long time waiting for something to happen if a board is not installed. */ @@ -137,11 +139,13 @@ /* Since the SG list is malloced, we have to limit the length. */ #define BUSLOGIC_MAX_SG (BUSLOGIC_SG_MALLOC / sizeof (struct chain)) -/* ??? Arbitrary. If we can dynamically allocate the mailbox arrays, I may - bump up this number. */ -#define BUSLOGIC_MAILBOXES 16 +/* Since the host adapters have room to buffer 32 commands internally, there + is some virtue in setting BUSLOGIC_MAILBOXES to 32. The maximum value + appears to be 255, since the Count parameter to the Initialize Extended + Mailbox command is limited to one byte. */ +#define BUSLOGIC_MAILBOXES 32 -#define BUSLOGIC_CMDLUN 4 /* ??? Arbitrary */ +#define BUSLOGIC_CMDLUN 4 /* Arbitrary, but seems to work well. */ /* BusLogic boards can be configured for quite a number of port addresses (six to be exact), but I generally do not want the driver poking around at @@ -165,8 +169,8 @@ struct hostdata { unsigned int bus_type; unsigned int bios_translation: 1; /* BIOS mapping (for compatibility) */ - size_t last_mbi_used; - size_t last_mbo_used; + int last_mbi_used; + int last_mbo_used; char model[7]; char firmware_rev[6]; Scsi_Cmnd *sc[BUSLOGIC_MAILBOXES]; @@ -425,174 +429,131 @@ return "BusLogic SCSI driver " BUSLOGIC_VERSION; } -/* A "high" level interrupt handler. */ +/* + This is a major rewrite of the interrupt handler to support the newer + and faster PCI cards. While the previous interrupt handler was supposed + to handle multiple incoming becoming available mailboxes during the same + interrupt, my testing showed that in practice only a single mailbox was + ever made available. With the 946C and 956C, multiple incoming mailboxes + being ready for processing during a single interrupt occurs much more + frequently, and so care must be taken to avoid race conditions managing + the Host Adapter Interrupt Register, which can lead to lost interrupts. + + Leonard N. Zubkoff, 23-Mar-95 +*/ + static void buslogic_interrupt(int irq, struct pt_regs * regs) { - void (*my_done)(Scsi_Cmnd *) = NULL; - int errstatus, mbistatus = MBX_NOT_IN_USE, number_serviced, found; - size_t mbi, mbo = 0; + int mbi, saved_mbo[BUSLOGIC_MAILBOXES]; + int base, interrupt_flags, found, i; struct Scsi_Host *shpnt; Scsi_Cmnd *sctmp; - unsigned long flags; - int base, flag; - int needs_restart; struct mailbox *mb; struct ccb *ccb; shpnt = host[irq - 9]; - if (!shpnt) - panic("buslogic_interrupt: NULL SCSI host entry"); + if (shpnt == NULL) + panic("buslogic_interrupt: NULL SCSI host entry"); mb = HOSTDATA(shpnt)->mb; ccb = HOSTDATA(shpnt)->ccbs; base = shpnt->io_port; -#if (BUSLOGIC_DEBUG & BD_INTERRUPT) - flag = inb(INTERRUPT(base)); + /* + This interrupt handler is now specified to use the SA_INTERRUPT + protocol, so interrupts are inhibited on entry until explicitly + allowed again. Read the Host Adapter Interrupt Register, and + complain if there is no pending interrupt being signaled. + */ + + interrupt_flags = inb(INTERRUPT(base)); + + if (!(interrupt_flags & INTV)) + { + buslogic_printk("interrupt received, but INTV not set\n"); + return; + } + + /* + Reset the Host Adapter Interrupt Register. It appears to be + important that this is only done once per interrupt to avoid + losing interrupts under heavy loads. + */ - buslogic_printk(""); - if (!(flag & INTV)) - printk("no interrupt? "); - if (flag & IMBL) - printk("IMBL "); - if (flag & MBOR) - printk("MBOR "); - if (flag & CMDC) - printk("CMDC "); - if (flag & RSTS) - printk("RSTS "); - printk("status %02X\n", inb(STATUS(base))); -#endif - - number_serviced = 0; - needs_restart = 0; - - for (;;) { - flag = inb(INTERRUPT(base)); - - /* Check for unusual interrupts. If any of these happen, we should - probably do something special, but for now just printing a message - is sufficient. A SCSI reset detected is something that we really - need to deal with in some way. */ - if (flag & (MBOR | CMDC | RSTS)) { - buslogic_printk("unusual flag:"); - if (flag & MBOR) - printk(" MBOR"); - if (flag & CMDC) - printk(" CMDC"); - if (flag & RSTS) { - needs_restart = 1; - printk(" RSTS"); - } - printk("\n"); - } - - INTR_RESET(base); - - save_flags(flags); - cli(); - - mbi = HOSTDATA(shpnt)->last_mbi_used + 1; - if (mbi >= 2 * BUSLOGIC_MAILBOXES) - mbi = BUSLOGIC_MAILBOXES; - - /* I use the "found" variable as I like to keep cli/sti pairs at the - same block level. Debugging dropped sti's is no fun... */ - - found = FALSE; - do { - if (mb[mbi].status != MBX_NOT_IN_USE) { - found = TRUE; - break; - } - mbi++; - if (mbi >= 2 * BUSLOGIC_MAILBOXES) - mbi = BUSLOGIC_MAILBOXES; - } while (mbi != HOSTDATA(shpnt)->last_mbi_used); - - if (found) { - mbo = (struct ccb *)mb[mbi].ccbptr - ccb; - mbistatus = mb[mbi].status; - mb[mbi].status = MBX_NOT_IN_USE; - HOSTDATA(shpnt)->last_mbi_used = mbi; - } - - restore_flags(flags); - - if (!found) { - /* Hmm, no mail. Must have read it the last time around. */ - if (!number_serviced && !needs_restart) - buslogic_printk("interrupt received, but no mail.\n"); - /* We detected a reset. Restart all pending commands for devices - that use the hard reset option. */ - if (needs_restart) - restart(shpnt); - return; - } - -#if (BUSLOGIC_DEBUG & BD_INTERRUPT) - if (ccb[mbo].tarstat || ccb[mbo].hastat) - buslogic_printk("returning %08X (status %d).\n", - ((int)ccb[mbo].hastat << 16) | ccb[mbo].tarstat, - mb[mbi].status); -#endif - - if (mbistatus == MBX_COMPLETION_NOT_FOUND) - continue; - -#if (BUSLOGIC_DEBUG & BD_INTERRUPT) - buslogic_printk("...done %u %u\n", mbo, mbi); -#endif + INTR_RESET(base); + if (interrupt_flags & RSTS) + { + restart(shpnt); + return; + } + + /* + With interrupts still inhibited, scan through the incoming mailboxes + in strict round robin fashion saving the status information and + then freeing the mailbox. A second pass over the completed commands + will be made separately to complete their processing. + */ + + mbi = HOSTDATA(shpnt)->last_mbi_used + 1; + if (mbi >= 2*BUSLOGIC_MAILBOXES) + mbi = BUSLOGIC_MAILBOXES; + + found = 0; + + while (mb[mbi].status != MBX_NOT_IN_USE && found < BUSLOGIC_MAILBOXES) + { + int mbo = (struct ccb *)mb[mbi].ccbptr - ccb; + int result = 0; + + saved_mbo[found++] = mbo; + + if (mb[mbi].status != MBX_COMPLETION_OK) + result = makecode(ccb[mbo].hastat, ccb[mbo].tarstat); + + HOSTDATA(shpnt)->sc[mbo]->result = result; + + mb[mbi].status = MBX_NOT_IN_USE; + + HOSTDATA(shpnt)->last_mbi_used = mbi; + + if (++mbi >= 2*BUSLOGIC_MAILBOXES) + mbi = BUSLOGIC_MAILBOXES; + } + + /* + With interrupts no longer inhibited, iterate over the completed + commands freeing resources and calling the completion routines. + Since we exit upon completion of this loop, there is no need to + inhibit interrupts before exit, as this will be handled by the + fast interrupt assembly code we return to. + */ + + sti(); + + for (i = 0; i < found; i++) + { + int mbo = saved_mbo[i]; sctmp = HOSTDATA(shpnt)->sc[mbo]; - - if (!sctmp || !sctmp->scsi_done) { - buslogic_printk("unexpected interrupt.\n"); - buslogic_printk("tarstat=%02X, hastat=%02X id=%d lun=%d ccb#=%u\n", - ccb[mbo].tarstat, ccb[mbo].hastat, - ccb[mbo].id, ccb[mbo].lun, mbo); - return; - } - - my_done = sctmp->scsi_done; + /* + First, free any storage allocated for a scatter/gather + data segment list. + */ if (sctmp->host_scribble) - scsi_free(sctmp->host_scribble, BUSLOGIC_SG_MALLOC); - - /* ??? more error checking left out here */ - if (mbistatus != MBX_COMPLETION_OK) { - /* ??? This is surely wrong, but I don't know what's right. */ - errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat); - } else - errstatus = 0; - -#if (BUSLOGIC_DEBUG & BD_INTERRUPT) - if (errstatus) - buslogic_printk("error: %04X %04X\n", - ccb[mbo].hastat, ccb[mbo].tarstat); - - if (status_byte(ccb[mbo].tarstat) == CHECK_CONDITION) { - size_t i; - - buslogic_printk("sense:"); - for (i = 0; i < sizeof sctmp->sense_buffer; i++) - printk(" %02X", sctmp->sense_buffer[i]); - printk("\n"); - } - - if (errstatus) - buslogic_printk("returning %08X.\n", errstatus); -#endif - - sctmp->result = errstatus; - HOSTDATA(shpnt)->sc[mbo] = NULL; /* This effectively frees up - the mailbox slot, as far as - queuecommand is - concerned. */ - my_done(sctmp); - number_serviced++; - } + scsi_free(sctmp->host_scribble, BUSLOGIC_SG_MALLOC); + /* + Next, call the SCSI command completion handler. + */ + sctmp->scsi_done(sctmp); + /* + Finally, mark the SCSI Command as completed so it may be reused + for another command by buslogic_queuecommand. + */ + HOSTDATA(shpnt)->sc[mbo] = NULL; + } } + /* ??? Why does queuecommand return a value? scsi.c never looks at it... */ int buslogic_queuecommand(Scsi_Cmnd *scpnt, void (*done)(Scsi_Cmnd *)) { @@ -605,9 +566,10 @@ int bufflen = scpnt->request_bufflen; int mbo; unsigned long flags; - struct mailbox *mb; - struct ccb *ccb; struct Scsi_Host *shpnt = scpnt->host; + struct mailbox *mb = HOSTDATA(shpnt)->mb; + struct ccb *ccb; + #if (BUSLOGIC_DEBUG & BD_COMMAND) if (target > 1) { @@ -651,9 +613,6 @@ } #endif - mb = HOSTDATA(shpnt)->mb; - ccb = HOSTDATA(shpnt)->ccbs; - /* Use the outgoing mailboxes in a round-robin fashion, because this is how the host adapter will scan for them. */ @@ -693,12 +652,14 @@ buslogic_printk("sending command (%d %08X)...", mbo, done); #endif + ccb = &HOSTDATA(shpnt)->ccbs[mbo]; + /* This gets trashed for some reason */ - mb[mbo].ccbptr = &ccb[mbo]; + mb[mbo].ccbptr = ccb; - memset(&ccb[mbo], 0, sizeof (struct ccb)); + memset(ccb, 0, sizeof (struct ccb)); - ccb[mbo].cdblen = scpnt->cmd_len; /* SCSI Command Descriptor + ccb->cdblen = scpnt->cmd_len; /* SCSI Command Descriptor Block Length */ direction = 0; @@ -707,14 +668,14 @@ else if (*cmd == WRITE_10 || *cmd == WRITE_6) direction = 16; - memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen); + memcpy(ccb->cdb, cmd, ccb->cdblen); if (scpnt->use_sg) { struct scatterlist *sgpnt; struct chain *cptr; size_t i; - ccb[mbo].op = CCB_OP_INIT_SG; /* SCSI Initiator Command + ccb->op = CCB_OP_INIT_SG; /* SCSI Initiator Command w/scatter-gather */ scpnt->host_scribble = (unsigned char *)scsi_malloc(BUSLOGIC_SG_MALLOC); @@ -735,8 +696,8 @@ cptr[i].dataptr = sgpnt[i].address; cptr[i].datalen = sgpnt[i].length; } - ccb[mbo].datalen = scpnt->use_sg * sizeof (struct chain); - ccb[mbo].dataptr = cptr; + ccb->datalen = scpnt->use_sg * sizeof (struct chain); + ccb->dataptr = cptr; #if (BUSLOGIC_DEBUG & BD_COMMAND) { unsigned char *ptr; @@ -749,27 +710,26 @@ } #endif } else { - ccb[mbo].op = CCB_OP_INIT; /* SCSI Initiator Command */ + ccb->op = CCB_OP_INIT; /* SCSI Initiator Command */ scpnt->host_scribble = NULL; CHECK_DMA_ADDR(shpnt->unchecked_isa_dma, buff, goto baddma); - ccb[mbo].datalen = bufflen; - ccb[mbo].dataptr = buff; + ccb->datalen = bufflen; + ccb->dataptr = buff; } - ccb[mbo].id = target; - ccb[mbo].lun = lun; - ccb[mbo].dir = direction; - ccb[mbo].rsalen = sizeof scpnt->sense_buffer; - ccb[mbo].senseptr = scpnt->sense_buffer; - ccb[mbo].linkptr = NULL; - ccb[mbo].commlinkid = 0; + ccb->id = target; + ccb->lun = lun; + ccb->dir = direction; + ccb->rsalen = sizeof scpnt->sense_buffer; + ccb->senseptr = scpnt->sense_buffer; + /* ccbcontrol, commlinkid, and linkptr are 0 due to above memset. */ #if (BUSLOGIC_DEBUG & BD_COMMAND) { size_t i; buslogic_printk("sending..."); - for (i = 0; i < sizeof ccb[mbo] - 10; i++) - printk(" %02X", ((unsigned char *)&ccb[mbo])[i]); + for (i = 0; i < sizeof(struct ccb) - 10; i++) + printk(" %02X", ((unsigned char *)ccb)[i]); printk("\n"); } #endif @@ -1255,7 +1215,8 @@ save_flags(flags); cli(); - if (request_irq(irq, buslogic_interrupt, 0, "buslogic")) { + if (request_irq(irq, buslogic_interrupt, + SA_INTERRUPT, "buslogic")) { buslogic_printk("unable to allocate IRQ for " "BusLogic controller.\n"); restore_flags(flags); diff -u --recursive --new-file v1.2.4/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c --- v1.2.4/linux/drivers/scsi/eata_dma.c Tue Feb 14 08:02:58 1995 +++ linux/drivers/scsi/eata_dma.c Wed Apr 12 21:03:23 1995 @@ -44,13 +44,14 @@ * Thanks also to Greg Hosler who did a lot of testing and * * found quite a number of bugs during the development. * ************************************************************ - * last change: 95/02/13 OS: Linux 1.1.91 or higher * + * last change: 95/04/10 OS: Linux 1.2.00 or higher * ************************************************************/ /* Look in eata_dma.h for configuration and revision information */ #ifdef MODULE #include +#include #endif #include @@ -61,6 +62,7 @@ #include #include #include +#include #include #include #include "../block/blk.h" @@ -87,10 +89,13 @@ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static unchar reg_IRQL[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static struct eata_sp status[MAXIRQ]; /* Statuspacket array */ +static struct eata_sp *status = 0; /* Statuspacket array */ +static void *dma_scratch = 0; static uint internal_command_finished = TRUE; static unchar HBA_interpret = FALSE; +static u32 fake_int_base; +static u32 fake_int_result; static struct geom_emul geometry; /* Drive 1 & 2 geometry */ static ulong int_counter = 0; @@ -101,6 +106,14 @@ return; } +void eata_fake_int_handler(s32 irq, struct pt_regs * regs) +{ + fake_int_result = inb(fake_int_base + HA_RSTATUS); + DBG(DBG_INTR3, printk("eata_fake_int_handler called irq%ld base %#lx res %#lx\n", + irq, fake_int_base, fake_int_result)); + return; +} + #if EATA_DMA_PROC #include "eata_dma_proc.c" #endif @@ -109,6 +122,9 @@ { if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq); else reg_IRQ[sh->irq]--; + + scsi_init_free((void *)status, 512); + if (SD(sh)->channel == 0) { if (sh->dma_channel != 0xff) free_dma(sh->dma_channel); if (sh->io_port && sh->n_io_port) @@ -125,7 +141,7 @@ void eata_int_handler(int irq, struct pt_regs * regs) { - uint i, result; + uint i, result = 0; uint hba_stat, scsi_stat, eata_stat; Scsi_Cmnd *cmd; struct eata_ccb *cp; @@ -183,21 +199,25 @@ eata_stat, hba_stat)); switch (hba_stat) { - case 0x00: /* NO Error */ + case HA_NO_ERROR: /* NO Error */ if (scsi_stat == CONDITION_GOOD && cmd->device->type == TYPE_DISK && (HD(cmd)->t_state[cmd->target] == RESET)) result = DID_BUS_BUSY << 16; + else if (scsi_stat == GOOD) + HD(cmd)->t_state[cmd->target] = FALSE; + else if (scsi_stat == CHECK_CONDITION + && cmd->device->type == TYPE_DISK + && (cmd->sense_buffer[2] & 0xf) == RECOVERED_ERROR) + result = DID_BUS_BUSY << 16; else result = DID_OK << 16; - if (scsi_stat == GOOD) - HD(cmd)->t_state[cmd->target] = FALSE; - HD(cmd)->t_timeout[cmd->target] = 0; + HD(cmd)->t_timeout[cmd->target] = FALSE; break; - case 0x01: /* Selection Timeout */ + case HA_ERR_SEL_TO: /* Selection Timeout */ result = DID_BAD_TARGET << 16; break; - case 0x02: /* Command Timeout */ + case HA_ERR_CMD_TO: /* Command Timeout */ if (HD(cmd)->t_timeout[cmd->target] > 1) result = DID_ERROR << 16; else { @@ -205,7 +225,8 @@ HD(cmd)->t_timeout[cmd->target]++; } break; - case 0x03: /* SCSI Bus Reset Received */ + case HA_ERR_RESET: /* SCSI Bus Reset Received */ + case HA_INIT_POWERUP: /* Initial Controller Power-up */ if (cmd->device->type != TYPE_TAPE) result = DID_BUS_BUSY << 16; else @@ -214,23 +235,19 @@ for (i = 0; i < MAXTARGET; i++) HD(cmd)->t_state[i] = RESET; break; - case 0x07: /* Bus Parity Error */ - case 0x0c: /* Controller Ram Parity */ - case 0x04: /* Initial Controller Power-up */ - case 0x05: /* Unexpected Bus Phase */ - case 0x06: /* Unexpected Bus Free */ - case 0x08: /* SCSI Hung */ - case 0x09: /* Unexpected Message Reject */ - case 0x0a: /* SCSI Bus Reset Stuck */ - case 0x0b: /* Auto Request-Sense Failed */ + case HA_UNX_BUSPHASE: /* Unexpected Bus Phase */ + case HA_UNX_BUS_FREE: /* Unexpected Bus Free */ + case HA_BUS_PARITY: /* Bus Parity Error */ + case HA_SCSI_HUNG: /* SCSI Hung */ + case HA_UNX_MSGRJCT: /* Unexpected Message Reject */ + case HA_RESET_STUCK: /* SCSI Bus Reset Stuck */ + case HA_RSENSE_FAIL: /* Auto Request-Sense Failed */ + case HA_PARITY_ERR: /* Controller Ram Parity */ default: result = DID_ERROR << 16; break; } - cmd->result = result | scsi_stat; - if (in_scan_scsis && scsi_stat == CHECK_CONDITION && - (cmd->sense_buffer[2] & 0xf) == UNIT_ATTENTION) - cmd->result |= (DRIVER_SENSE << 24); + cmd->result = result | (scsi_stat << 1); #if DBG_INTR2 if (scsi_stat || result || hba_stat || eata_stat != 0x50) @@ -262,14 +279,14 @@ while (inb(base + HA_RAUXSTAT) & HA_ABUSY) if (--loop == 0) - return(TRUE); + return(FALSE); outb(addr & 0x000000ff, base + HA_WDMAADDR); outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1); outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2); outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3); outb(command, base + HA_WCOMMAND); - return(FALSE); + return(TRUE); } int eata_queue(Scsi_Cmnd * cmd, void *(done) (Scsi_Cmnd *)) @@ -337,10 +354,10 @@ case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE: case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: case WRITE_6: case WRITE_10: case WRITE_VERIFY: - case 0x3f: case 0x41: case 0xb1: - case 0xb0: case 0xb2: case 0xaa: - case 0xae: case 0x24: case 0x38: - case 0x3d: case 0xb6: + case UPDATE_BLOCK: case WRITE_LONG: case WRITE_SAME: + case SEARCH_HIGH_12: case SEARCH_EQUAL_12: case SEARCH_LOW_12: + case WRITE_12: case WRITE_VERIFY_12: case SET_WINDOW: + case MEDIUM_SCAN: case SEND_VOLUME_TAG: case 0xea: /* alternate number for WRITE LONG */ cp->DataOut = TRUE; /* Output mode */ break; @@ -376,7 +393,7 @@ cp->cp_lun = cmd->lun; cp->cp_dispri = TRUE; cp->cp_identify = TRUE; - memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd)); + memcpy(cp->cp_cdb, cmd->cmnd, cmd->cmd_len); cp->cp_statDMA = htonl((ulong) &(hd->sp)); @@ -384,7 +401,7 @@ cp->cmd = cmd; cmd->host_scribble = (char *)&hd->ccb[y]; - if(eata_send_command((ulong) cp, (uint) sh->base, EATA_CMD_DMA_SEND_CP)) { + if(eata_send_command((ulong) cp, (uint) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) { cmd->result = DID_ERROR << 16; printk("eata_queue target %d, pid %ld, HBA busy, returning DID_ERROR, done.\n", cmd->target, cmd->pid); @@ -494,8 +511,10 @@ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); return (SCSI_RESET_ERROR); } - for (z = 0; z < MAXTARGET; z++) + for (z = 0; z < MAXTARGET; z++) { HD(cmd)->t_state[z] = RESET; + HD(cmd)->t_timeout[z] = FALSE; + } for (x = 0; x < cmd->host->can_queue; x++) { @@ -577,16 +596,21 @@ { struct eata_ccb cp; struct eata_sp sp; - static char buff[256]; + static char *buff; + u32 i; + + buff = dma_scratch; memset(&cp, 0, sizeof(struct eata_ccb)); - memset(buff, 0, sizeof(buff)); + memset(&sp, 0, sizeof(struct eata_sp)); + memset(buff, 0, 256); cp.DataIn = TRUE; cp.Interpret = TRUE; /* Interpret command */ cp.cp_datalen = htonl(255); - cp.cp_dataDMA = htonl((long)buff); + cp.cp_dataDMA = htonl((s32)buff); + cp.cp_viraddr = &cp; cp.cp_id = id; cp.cp_lun = 0; @@ -600,9 +624,21 @@ cp.cp_statDMA = htonl((ulong) &sp); - eata_send_command((ulong) &cp, (uint) base, EATA_CMD_DMA_SEND_CP); - while (!(inb(base + HA_RAUXSTAT) & HA_AIRQ)); - if(inb((uint) base + HA_RSTATUS) & 1) + fake_int_base = base; + fake_int_result = 0; + + eata_send_command((u32) &cp, (u32) base, EATA_CMD_DMA_SEND_CP); + + i = jiffies + 300; + while (!fake_int_result && jiffies <= i) + /* nothing */; + + DBG(DBG_INTR3, printk("fake_int_result: %#lx hbastat %#lx scsistat %#lx," + " buff %p sp %p\n", + fake_int_result, (u32) (sp.hba_stat & 0x7f), + (u32) sp.scsi_stat, buff, &sp)); + + if (jiffies > i || (fake_int_result & 1)) return (NULL); else return (buff); @@ -610,7 +646,6 @@ int check_blink_state(long base) { - uint ret = 0; uint loops = 10; ulong blinkindicator = 0x42445054; ulong state = 0x12345678; @@ -621,10 +656,13 @@ state = inl((uint) base + 1); } + DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n", + (state == oldstate) && (state == blinkindicator))); + if ((state == oldstate) && (state == blinkindicator)) - ret = 1; - DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n", ret)); - return (ret); + return(TRUE); + else + return (FALSE); } int get_conf_PIO(struct eata_register *base, struct get_conf *buf) @@ -632,8 +670,14 @@ ulong loop = R_LIMIT; ushort *p; - if(check_region((uint)base, 9)) + u8 warning = FALSE; + + if(check_region((int) base, 9)) { + if ((int)base == 0x1f0 || (int)base == 0x170) { + warning = 1; + } else return (FALSE); + } memset(buf, 0, sizeof(struct get_conf)); @@ -665,11 +709,15 @@ while (inb((uint) base + HA_RSTATUS) & HA_SDRQ) inw((uint) base + HA_RDATA); + if (warning == TRUE) + printk("Warning: HBA with IO on 0x%p dectected,\n" + " this IO space is already allocated, probably by the IDE driver.\n" + " This might lead to problems.", base); return (TRUE); } } else { - printk("eata_dma: get_conf_PIO, error during transfer for HBA at %lx", - (long)base); + DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during transfer " + "for HBA at %lx\n", (long)base)); } return (FALSE); } @@ -701,42 +749,14 @@ DBG(DBG_REGISTER, print_config(gc)); - if (!gc->DMA_support) { - printk("HBA at %#.8lx doesn't support DMA. Sorry\n",base); - return (FALSE); - } - - if ((buff = get_board_data((uint)base, gc->IRQ, gc->scsi_id[3])) == NULL){ - printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", (ulong) base); - return (FALSE); - } - - if(gc->HAA_valid == FALSE || ntohl(gc->len) <= 0x1e) - gc->MAX_CHAN = 0; - - if(strncmp("PM2322", &buff[16], 6) && strncmp("PM3021", &buff[16], 6) - && strncmp("PM3222", &buff[16], 6) && strncmp("PM3224", &buff[16], 6)) + if(gc->HAA_valid == FALSE || ntohl(gc->len) < 0x22) gc->MAX_CHAN = 0; - /* if gc->DMA_valid it must be a PM2011 and we have to register it */ - dma_channel = 0xff; - if (gc->DMA_valid) { - if (request_dma(dma_channel = (8 - gc->DMA_channel) & 7, "DPT_PM2011")) { - printk("Unable to allocate DMA channel %d for HBA PM2011.\n", - dma_channel); - return (FALSE); - } - } - if (!reg_IRQ[gc->IRQ]) { /* Interrupt already registered ? */ - if (!request_irq(gc->IRQ, eata_int_handler, SA_INTERRUPT, "EATA-DMA")){ + if (!request_irq(gc->IRQ, (void *) eata_fake_int_handler, SA_INTERRUPT, "eata_dma")){ reg_IRQ[gc->IRQ] += (gc->MAX_CHAN+1); if (!gc->IRQ_TR) reg_IRQL[gc->IRQ] = TRUE; /* IRQ is edge triggered */ - - /* We free it again so we can do a get_conf_dma and - * allocate the interrupt again later */ - free_irq(gc->IRQ); } else { printk("Couldn't allocate IRQ %d, Sorry.", gc->IRQ); return (FALSE); @@ -750,7 +770,47 @@ reg_IRQ[gc->IRQ] += (gc->MAX_CHAN+1); } - request_region(base, 9, "eata_dma"); + /* if gc->DMA_valid it must be an ISA HBA and we have to register it */ + dma_channel = 0xff; + if (gc->DMA_valid) { + if (request_dma(dma_channel = (8 - gc->DMA_channel) & 7, "eata_dma")) { + printk("Unable to allocate DMA channel %d for ISA HBA at %#.4lx.\n", + dma_channel, base); + reg_IRQ[gc->IRQ] -= (gc->MAX_CHAN+1); + if (reg_IRQ[gc->IRQ] == 0) + free_irq(gc->IRQ); + if (!gc->IRQ_TR) + reg_IRQL[gc->IRQ] = FALSE; + return (FALSE); + } + } + + buff = get_board_data(base, gc->IRQ, gc->scsi_id[3]); + + if (buff == NULL) { + if (gc->DMA_support == FALSE) + printk("HBA at %#.4lx doesn't support DMA. Sorry\n", base); + else + printk("HBA at %#.4lx didn't react on INQUIRY. Sorry.\n", base); + if (gc->DMA_valid) + free_dma(dma_channel); + reg_IRQ[gc->IRQ] -= (gc->MAX_CHAN+1); + if (reg_IRQ[gc->IRQ] == 0) + free_irq(gc->IRQ); + if (!gc->IRQ_TR) + reg_IRQL[gc->IRQ] = FALSE; + return (FALSE); + } + + if (gc->DMA_support == FALSE && buff != NULL) + printk("HBA %.12sat %#.4lx doesn't set the DMA_support flag correctly.\n", + &buff[16], base); + + request_region(base, 9, "eata_dma"); /* We already checked the + * availability, so this could + * only fail if we're on + * 0x1f0 or 0x170. + */ if(ntohs(gc->queuesiz) == 0) { gc->queuesiz = ntohs(64); @@ -769,6 +829,18 @@ for (i = 0; i <= gc->MAX_CHAN; i++) { sh = scsi_register(tpnt, size); + + if(sh == NULL) { + if (gc->DMA_valid) + free_dma(dma_channel); + reg_IRQ[gc->IRQ] -= 1; + if (reg_IRQ[gc->IRQ] == 0) + free_irq(gc->IRQ); + if (!gc->IRQ_TR) + reg_IRQL[gc->IRQ] = FALSE; + return (FALSE); + } + hd = SD(sh); memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)) / @@ -808,8 +880,10 @@ if (gc->OCS_enabled == TRUE) { sh->cmd_per_lun = sh->can_queue/C_P_L_DIV; +#if 0 /* The memory management seems to be more stable now */ if (sh->cmd_per_lun > C_P_L_CURRENT_MAX) sh->cmd_per_lun = C_P_L_CURRENT_MAX; +#endif } else { sh->cmd_per_lun = 1; } @@ -940,7 +1014,7 @@ { #ifndef CONFIG_PCI - printk("Kernel PCI support not enabled. Skipping.\n"); + printk("Kernel PCI support not enabled. Skipping scan for PCI HBAs.\n"); #else unchar pci_bus, pci_device_fn; @@ -1041,14 +1115,12 @@ geometry.drv[0].trans = geometry.drv[1].trans = 0; - printk("EATA (Extended Attachment) driver version: %d.%d%s\n" - "developed in co-operation with DPT\n" - "(c) 1993-95 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de\n", - VER_MAJOR, VER_MINOR, VER_SUB); - DBG((DBG_PROBE && DBG_DELAY)|| DPT_DEBUG, printk("Using lots of delays to let you read the debugging output\n")); + status = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA); + dma_scratch = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA); + find_PCI(&gc, tpnt); for (i = 0; i < MAXEISA; i++) { @@ -1064,23 +1136,40 @@ } for (i = 0; i <= MAXIRQ; i++) - if (reg_IRQ[i]) + if (reg_IRQ[i]){ + free_irq(i); request_irq(i, eata_int_handler, SA_INTERRUPT, "EATA-DMA"); + } HBA_ptr = first_HBA; + if (registered_HBAs != 0) { + printk("EATA (Extended Attachment) driver version: %d.%d%s\n" + "developed in co-operation with DPT\n" + "(c) 1993-95 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de\n", + VER_MAJOR, VER_MINOR, VER_SUB); printk("Registered HBAs:\n"); printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: DMA: Ch: ID: Pr: QS: SG: CPL:\n"); for (i = 1; i <= registered_HBAs; i++) { - printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4x %2d %2x %d %d %d %2d %2d %2d\n", + printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4lx %2d", HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision, SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')? "PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ", - (uint) HBA_ptr->base, HBA_ptr->irq, HBA_ptr->dma_channel, - SD(HBA_ptr)->channel, HBA_ptr->this_id, SD(HBA_ptr)->primary, + (u32) HBA_ptr->base, HBA_ptr->irq); + if(HBA_ptr->dma_channel != 0xff) + printk(" %2x ", HBA_ptr->dma_channel); + else + printk(" %s", "BMST"); + printk(" %d %d %c %2d %2d %2d\n", SD(HBA_ptr)->channel, + HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N', HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun); HBA_ptr = SD(HBA_ptr)->next; } + } else + scsi_init_free((void *)status, 512); + + scsi_init_free((void *)dma_scratch, 512); + DBG(DPT_DEBUG,DELAY(1200)); return (registered_HBAs); diff -u --recursive --new-file v1.2.4/linux/drivers/scsi/eata_dma.h linux/drivers/scsi/eata_dma.h --- v1.2.4/linux/drivers/scsi/eata_dma.h Tue Feb 14 08:02:58 1995 +++ linux/drivers/scsi/eata_dma.h Tue Apr 11 07:56:25 1995 @@ -2,7 +2,7 @@ * Header file for eata_dma.c Linux EATA-DMA SCSI driver * * (c) 1993,94,95 Michael Neuffer * ********************************************************* -* last change: 95/02/13 * +* last change: 95/04/10 * ********************************************************/ @@ -11,7 +11,7 @@ #define VER_MAJOR 2 #define VER_MINOR 3 -#define VER_SUB "1a" +#define VER_SUB "5r" /************************************************************************ * Here you can configure your drives that are using a non-standard * @@ -61,6 +61,7 @@ #define DBG_QUEUE 0 /* Trace command queueing. */ #define DBG_INTR 0 /* Trace interrupt service routine. */ #define DBG_INTR2 0 /* Trace interrupt service routine. */ +#define DBG_INTR3 0 /* Trace interrupt service routine. */ #define DBG_PROC 0 /* Debug proc-fs related statistics */ #define DBG_REGISTER 0 /* */ #define DBG_ABNORM 1 /* Debug abnormal actions (reset, abort)*/ @@ -125,13 +126,15 @@ #define SG_SIZE 64 -#define C_P_L_CURRENT_MAX 10 /* Until this limit in the mm is removed +#define C_P_L_CURRENT_MAX 16 /* Until this limit in the mm is removed * Kernels < 1.1.86 died horrible deaths * if you used values >2. The memory management * since pl1.1.86 seems to cope with up to 10 * queued commands per device. + * Since 1.2.0 the memory management seems to + * have no more problems...... */ -#define C_P_L_DIV 4 /* 1 <= C_P_L_DIV <= 8 +#define C_P_L_DIV 3 /* 1 <= C_P_L_DIV <= 8 * You can use this parameter to fine-tune * the driver. Depending on the number of * devices and their speed and ability to queue @@ -200,6 +203,24 @@ #define HA_SREADY 0x40 /* drive ready */ #define HA_SBUSY 0x80 /* drive busy */ #define HA_SDRDY HA_SSC+HA_SREADY+HA_SDRQ + +#define HA_NO_ERROR 0x00 +#define HA_ERR_SEL_TO 0x01 +#define HA_ERR_CMD_TO 0x02 +#define HA_ERR_RESET 0x03 +#define HA_INIT_POWERUP 0x04 +#define HA_UNX_BUSPHASE 0x05 +#define HA_UNX_BUS_FREE 0x06 +#define HA_BUS_PARITY 0x07 +#define HA_SCSI_HUNG 0x08 +#define HA_UNX_MSGRJCT 0x09 +#define HA_RESET_STUCK 0x0a +#define HA_RSENSE_FAIL 0x0b +#define HA_PARITY_ERR 0x0c +#define HA_CP_ABORT_NA 0x0d +#define HA_CP_ABORTED 0x0e +#define HA_CP_RESET_NA 0x0f +#define HA_CP_RESET 0x10 /********************************************** * Message definitions * diff -u --recursive --new-file v1.2.4/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v1.2.4/linux/drivers/scsi/scsi.c Wed Mar 29 06:52:58 1995 +++ linux/drivers/scsi/scsi.c Wed Apr 12 21:03:23 1995 @@ -387,7 +387,8 @@ if(SCpnt->result) { - if ((driver_byte(SCpnt->result) & DRIVER_SENSE) && + if (((driver_byte(SCpnt->result) & DRIVER_SENSE) || + (status_byte(SCpnt->result) & CHECK_CONDITION)) && ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) { if (SCpnt->sense_buffer[2] &0xe0) continue; /* No devices here... */ diff -u --recursive --new-file v1.2.4/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v1.2.4/linux/drivers/scsi/scsi.h Wed Mar 29 06:52:59 1995 +++ linux/drivers/scsi/scsi.h Tue Apr 11 07:56:25 1995 @@ -50,6 +50,7 @@ #define SEND_DIAGNOSTIC 0x1d #define ALLOW_MEDIUM_REMOVAL 0x1e +#define SET_WINDOW 0x24 #define READ_CAPACITY 0x25 #define READ_10 0x28 #define WRITE_10 0x2a @@ -65,16 +66,26 @@ #define SYNCHRONIZE_CACHE 0x35 #define LOCK_UNLOCK_CACHE 0x36 #define READ_DEFECT_DATA 0x37 +#define MEDIUM_SCAN 0x38 #define COMPARE 0x39 #define COPY_VERIFY 0x3a #define WRITE_BUFFER 0x3b #define READ_BUFFER 0x3c +#define UPDATE_BLOCK 0x3d #define READ_LONG 0x3e +#define WRITE_LONG 0x3f #define CHANGE_DEFINITION 0x40 +#define WRITE_SAME 0x41 #define LOG_SELECT 0x4c #define LOG_SENSE 0x4d #define MODE_SELECT_10 0x55 #define MODE_SENSE_10 0x5a +#define WRITE_12 0xaa +#define WRITE_VERIFY_12 0xae +#define SEARCH_HIGH_12 0xb0 +#define SEARCH_EQUAL_12 0xb1 +#define SEARCH_LOW_12 0xb2 +#define SEND_VOLUME_TAG 0xb6 extern void scsi_make_blocked_list(void); extern volatile int in_scan_scsis; diff -u --recursive --new-file v1.2.4/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v1.2.4/linux/drivers/scsi/sd.c Sun Feb 19 11:33:13 1995 +++ linux/drivers/scsi/sd.c Mon Apr 10 08:31:51 1995 @@ -358,8 +358,8 @@ unsigned long flags; int flag = 0; + save_flags(flags); while (1==1){ - save_flags(flags); cli(); if (CURRENT != NULL && CURRENT->dev == -1) { restore_flags(flags); @@ -387,12 +387,10 @@ /* * The following restore_flags leads to latency problems. FIXME. + * Using a "sti()" gets rid of the latency problems but causes + * race conditions and crashes. */ -#if 0 restore_flags(flags); -#else - sti(); -#endif /* This is a performance enhancement. We dig down into the request list and try and find a queueable request (i.e. device not busy, and host able to @@ -404,7 +402,6 @@ if (!SCpnt && sd_template.nr_dev > 1){ struct request *req1; req1 = NULL; - save_flags(flags); cli(); req = CURRENT; while(req){ diff -u --recursive --new-file v1.2.4/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v1.2.4/linux/drivers/scsi/st.c Sun Apr 9 11:59:57 1995 +++ linux/drivers/scsi/st.c Sun Apr 9 12:50:58 1995 @@ -1063,8 +1063,7 @@ SCpnt->request.dev = dev; scsi_do_cmd (SCpnt, (void *) cmd, (STp->buffer)->b_data, - (STp->buffer)->buffer_size, - st_sleep_done, ST_TIMEOUT, MAX_RETRIES); + bytes, st_sleep_done, ST_TIMEOUT, MAX_RETRIES); /* this must be done with interrupts off */ diff -u --recursive --new-file v1.2.4/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v1.2.4/linux/fs/isofs/inode.c Wed Feb 22 08:15:14 1995 +++ linux/fs/isofs/inode.c Sun Apr 9 10:04:42 1995 @@ -79,7 +79,7 @@ popt->rock = 'y'; popt->cruft = 'n'; popt->unhide = 'n'; - popt->conversion = 'a'; + popt->conversion = 'b'; /* default: no conversion */ popt->blocksize = 1024; popt->mode = S_IRUGO; popt->gid = 0; diff -u --recursive --new-file v1.2.4/linux/include/linux/major.h linux/include/linux/major.h --- v1.2.4/linux/include/linux/major.h Thu Feb 23 13:31:40 1995 +++ linux/include/linux/major.h Tue Apr 11 08:03:29 1995 @@ -7,8 +7,8 @@ /* limits */ -#define MAX_CHRDEV 32 -#define MAX_BLKDEV 32 +#define MAX_CHRDEV 64 +#define MAX_BLKDEV 64 /* * assignments diff -u --recursive --new-file v1.2.4/linux/include/linux/serial.h linux/include/linux/serial.h --- v1.2.4/linux/include/linux/serial.h Mon Feb 20 21:29:53 1995 +++ linux/include/linux/serial.h Wed Apr 12 21:24:17 1995 @@ -140,6 +140,7 @@ int xmit_tail; int xmit_cnt; struct tq_struct tqueue; + struct tq_struct tqueue_hangup; struct termios normal_termios; struct termios callout_termios; struct wait_queue *open_wait; @@ -160,7 +161,6 @@ * time, instead of at rs interrupt time. */ #define RS_EVENT_WRITE_WAKEUP 0 -#define RS_EVENT_HANGUP 1 /* * Multiport serial configuration structure --- internal structure diff -u --recursive --new-file v1.2.4/linux/include/linux/tqueue.h linux/include/linux/tqueue.h --- v1.2.4/linux/include/linux/tqueue.h Wed Dec 28 16:38:30 1994 +++ linux/include/linux/tqueue.h Wed Apr 12 21:24:17 1995 @@ -57,7 +57,7 @@ #define DECLARE_TASK_QUEUE(q) task_queue q = &tq_last extern struct tq_struct tq_last; -extern task_queue tq_timer, tq_immediate; +extern task_queue tq_timer, tq_immediate, tq_scheduler; #ifdef INCLUDE_INLINE_FUNCS struct tq_struct tq_last = { diff -u --recursive --new-file v1.2.4/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v1.2.4/linux/kernel/ksyms.c Sun Apr 9 11:59:57 1995 +++ linux/kernel/ksyms.c Wed Apr 12 21:24:17 1995 @@ -41,8 +41,10 @@ #include #include "../net/inet/protocol.h" #include "../net/inet/arp.h" +#if defined(CONFIG_PPP) || defined(CONFIG_SLIP) #include "../drivers/net/slhc.h" #endif +#endif #ifdef CONFIG_PCI #include #endif @@ -209,6 +211,7 @@ X(del_timer), X(tq_timer), X(tq_immediate), + X(tq_scheduler), X(tq_last), X(timer_active), X(timer_table), @@ -273,12 +276,14 @@ #ifdef CONFIG_INET X(inet_add_protocol), X(inet_del_protocol), +#if defined(CONFIG_PPP) || defined(CONFIG_SLIP) X(slhc_init), X(slhc_free), X(slhc_remember), X(slhc_compress), X(slhc_uncompress), #endif +#endif /* Device callback registration */ X(register_netdevice_notifier), X(unregister_netdevice_notifier), @@ -323,6 +328,8 @@ X(scsi_register), X(scsi_unregister), X(scsicam_bios_param), + X(scsi_init_malloc), + X(scsi_init_free), X(print_command), #endif /* Added to make file system as module */ diff -u --recursive --new-file v1.2.4/linux/kernel/sched.c linux/kernel/sched.c --- v1.2.4/linux/kernel/sched.c Sun Apr 9 11:59:57 1995 +++ linux/kernel/sched.c Wed Apr 12 21:24:17 1995 @@ -45,6 +45,7 @@ DECLARE_TASK_QUEUE(tq_timer); DECLARE_TASK_QUEUE(tq_immediate); +DECLARE_TASK_QUEUE(tq_scheduler); /* * phase-lock loop variables @@ -119,6 +120,7 @@ printk("Aiee: scheduling in interrupt\n"); intr_count = 0; } + run_task_queue(&tq_scheduler); cli(); ticks = itimer_ticks; itimer_ticks = 0;