From 0c3217f200aeba1ce3934861ca7ef04fafb00845 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:20:27 -0500 Subject: [PATCH] Linux 2.2.14pre13 o Cure SMP deadlock on non DMA ide disk (Alan Cox) o Change argument copying for mount (needed for Davem's sparc64) (Alan Cox) o Fix missing tlb flushes on vmscan (Dave Miller) o Account always defragment off as well as on (Julian Anastasov) o Fix APIC handling with short form table (Eirik Fuller) o GDTH driver update (ICP Vortex) o Finish fixing the AX.25 socket bug (Tomi Manninen) o QlogicFC driver update (Chris Loveland) o New Tlan maintainer (Torben Mathiasen) o Hopefully fix the NFS submount bug (Trond Myklebust) o Fix mem= on Alpha (Jay Estabrook) o Allow hiding interfaces from global arp (Alexey Kuznetsov & o IPV6 autoconfig for non ethernet Julian Anastasov) o event is now global_event, the export defined made a horrible mess of local variable/structs when debugging with source (Alan Cox) --- Documentation/networking/ip-sysctl.txt | 8 + Documentation/proc.txt | 8 + Documentation/sound/NM256 | 101 +++- MAINTAINERS | 4 +- Makefile | 2 +- arch/alpha/mm/init.c | 12 +- arch/i386/kernel/smp.c | 3 +- drivers/block/ide-disk.c | 3 + drivers/block/loop.c | 2 +- drivers/net/tlan.c | 2 + drivers/net/tlan.h | 2 + drivers/scsi/gdth.c | 437 +++++++++++---- drivers/scsi/gdth.h | 42 +- drivers/scsi/gdth_ioctl.h | 18 +- drivers/scsi/gdth_proc.c | 185 ++++--- drivers/scsi/gdth_proc.h | 5 +- drivers/scsi/qlogicfc.c | 5 +- drivers/sound/ac97.c | 86 ++- drivers/sound/ac97.h | 19 +- drivers/sound/nm256.h | 126 +++-- drivers/sound/nm256_audio.c | 729 ++++++++++++++++++------- drivers/sound/nm256_coeff.h | 14 +- fs/adfs/inode.c | 2 +- fs/affs/inode.c | 4 +- fs/affs/namei.c | 16 +- fs/dcache.c | 37 ++ fs/ext2/file.c | 2 +- fs/ext2/inode.c | 2 +- fs/ext2/namei.c | 22 +- fs/fat/inode.c | 4 +- fs/file_table.c | 2 +- fs/hfs/dir.c | 4 +- fs/minix/namei.c | 10 +- fs/msdos/namei.c | 6 +- fs/nfs/dir.c | 5 +- fs/nfs/inode.c | 2 +- fs/read_write.c | 2 +- fs/super.c | 8 +- fs/ufs/file.c | 2 +- fs/ufs/inode.c | 2 +- fs/ufs/namei.c | 22 +- fs/vfat/namei.c | 14 +- include/linux/dcache.h | 3 + include/linux/errqueue.h | 2 + include/linux/if.h | 25 - include/linux/inetdevice.h | 2 + include/linux/ip.h | 3 +- include/linux/netdevice.h | 2 + include/linux/rtnetlink.h | 2 + include/linux/sched.h | 2 +- include/linux/socket.h | 2 +- include/linux/sysctl.h | 3 +- kernel/ksyms.c | 3 +- kernel/sched.c | 2 +- mm/vmscan.c | 2 + net/ax25/af_ax25.c | 1 - net/bridge/br.c | 2 +- net/ipv4/arp.c | 31 +- net/ipv4/devinet.c | 11 +- net/ipv4/ip_masq.c | 1 + net/ipv6/addrconf.c | 20 +- 61 files changed, 1493 insertions(+), 607 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 8def0e7fc2b7..208b7a0f1621 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -156,6 +156,14 @@ mc_forwarding - BOOLEAN proxy_arp - BOOLEAN Do proxy arp. +hidden - BOOLEAN + Hide addresses attached to this device from another devices. + Such addresses will never be selected by source address autoselection + mechanism, host does not answer broadcast ARP requests for them, + does not announce it as source address of ARP requests, but they + are still reachable via IP. This flag is activated only if it is + enabled both in specific device section and in "all" section. + shared_media - BOOLEAN undocumented. diff --git a/Documentation/proc.txt b/Documentation/proc.txt index 5f5c20f2fc9c..bc5e55f37db2 100644 --- a/Documentation/proc.txt +++ b/Documentation/proc.txt @@ -1192,6 +1192,14 @@ secure_redirects Accept ICMP redirect messages only for gateways, listed in default gateway list. Enabled by default. +hidden + Hide addresses attached to this device from another devices. + Such addresses will never be selected by source address autoselection + mechanism, host does not answer broadcast ARP requests for them, + does not announce it as source address of ARP requests, but they + are still reachable via IP. This flag is activated only if it is + enabled both in specific device section and in "all" section. + shared_media If it is not set the kernel does not assume that different subnets on this device can communicate directly. Default setting is 'yes'. diff --git a/Documentation/sound/NM256 b/Documentation/sound/NM256 index edff4c1b4838..e9610c23e95c 100644 --- a/Documentation/sound/NM256 +++ b/Documentation/sound/NM256 @@ -2,10 +2,10 @@ Documentation for the NeoMagic 256AV/256ZX sound driver ======================================================= -You're looking at version 1.0 of the driver. (Woohoo!) It has been +You're looking at version 1.11 of the driver. (Woohoo!) It has been successfully tested against the following laptop models: - Sony Z505S/Z505SX/Z505DX + Sony Z505S/Z505SX/Z505DX/Z505RX Sony F150, F160, F180, F250, F270, F280, PCG-F26 Dell Latitude CPi, CPt (various submodels) @@ -16,9 +16,13 @@ This driver was developed without any support or assistance from NeoMagic. There is no warranty, expressed, implied, or otherwise. It is free software in the public domain; feel free to use it, sell it, give it to your best friends, even claim that you wrote it (but why?!) -but don't come whining to me, NeoMagic, Sony, Dell, or anyone else +but don't go whining to me, NeoMagic, Sony, Dell, or anyone else when it blows up your computer. +Version 1.11 fixes a bug uncovered by Timidity--the sound would start clicking +after the first MIDI file was finished playing. There are no other changes +over 1.1. + ============ Installation ============ @@ -42,16 +46,19 @@ hurting themselves. It works correctly if it shares an IRQ with another device (it normally shares IRQ 9 with the builtin eepro100 ethernet on the Sony Z505 laptops). -It does not run the card in any sort of compatibility mode. Thus it -almost certainly will not work on laptops that have the -SB16-compatible codec/mixer; you will want to use the standard SB16 -OSS driver with these chipsets. I cannot provide any assistance with -machines using the SB-16 compatible version. +It does not run the card in any sort of compatibility mode. It will +not work on laptops that have the SB16-compatible, AD1848-compatible +or CS4232-compatible codec/mixer; you will want to use the appropriate +compatible OSS driver with these chipsets. I cannot provide any +assistance with machines using the SB16, AD1848 or CS4232 compatible +versions. (The driver now attempts to detect the mixer version, and +will refuse to load if it believes the hardware is not not +AC97-compatible.) The sound support is very basic, but it does include simultaneous playback and record capability. The mixer support is also quite simple, although this is in keeping with the rather limited -functionality of the chipset. +functionality of the chipset. There is no hardware synthesizer available, as the Losedows OPL-3 and MIDI support is done via hardware emulation. @@ -63,8 +70,6 @@ models of laptops.) The Z505 series does not have a builtin CD-ROM, so of course the CD-ROM input doesn't work. It does work on laptops with a builtin CD-ROM drive. -Recording is mono 8-bit only. - The mixer device does not appear to have any tone controls, at least on the Z505 series. The mixer module checks for tone controls in the AC97 mixer, and will enable them if they are available. @@ -93,10 +98,11 @@ Known problems limitation. It may be possible to support other speeds in the future. * There is no support for the telephone mixer/codec. There is support - for a phonein/phoneout device if your mixer program supports it; - whether or not it does anything is anyone's guess. (Reports on this - would be appreciated.) - + for a phonein/phoneout device in the mixer driver; whether or not + it does anything is anyone's guess. (Reports on this would be + appreciated. You'll have to figure out how to get the phone to + go off-hook before it'll work, tho.) + * This driver was not written with any cooperation or support from NeoMagic. If you have any questions about this, see their website for their official stance on supporting open source drivers. @@ -118,8 +124,8 @@ This implies a few things: * Sometimes the NM256 driver has to guess at where the buffer should be placed, especially if the module is loaded after the - X server is started. It's usually correct, but it will fail on - the Sony F250. + X server is started. It's usually correct, but it will consistently + fail on the Sony F250. * Virtual screens greater than 1024x768x16 under XFree86 are problematic on laptops with only 2.5MB of screen RAM. This @@ -139,10 +145,16 @@ screen), the best fix is to On the F250, it is possible to force the driver to load properly even after the XFree86 server is started by doing: - insmod nm256.o buffertop=0x25a800 + insmod nm256 buffertop=0x25a800 This forces the audio buffers to the correct offset in screen RAM. +One user has reported a similar problem on the Sony F270, although +others apparently aren't seeing any problems. His suggested command +is + + insmod nm256 buffertop=0x272800 + ================= Official WWW site ================= @@ -154,6 +166,17 @@ The official site for the NM256 driver is: You should always be able to get the latest version of the driver there, and the driver will be supported for the foreseeable future. +============== +Z505RX and IDE +============== + +There appears to be a problem with the IDE chipset on the Z505RX; one +of the symptoms is that sound playback periodically hangs (when the +disk is accessed). The user reporting the problem also reported that +enabling all of the IDE chipset workarounds in the kernel solved the +problem, tho obviously only one of them should be needed--if someone +can give me more details I would appreciate it. + ============================== Z505S/Z505SX on-board Ethernet ============================== @@ -176,11 +199,30 @@ PCMCIA and the Z505S/Z505SX/Z505DX ================================== There is also a known problem with the Sony Z505S and Z505SX hanging -if a PCMCIA card is inserted while the ethernet driver is loaded. -This is caused by tons of spurious IRQ 9s, probably generated from the -PCMCIA or ACPI bridges. There is currently no fix for the problem, -and the only known workaround is to disable the ethernet interface -before inserting or removing a PCMCIA card. +if a PCMCIA card is inserted while the ethernet driver is loaded, or +in some cases if the laptop is suspended. This is caused by tons of +spurious IRQ 9s, probably generated from the PCMCIA or ACPI bridges. + +There is currently no fix for the problem that works in every case. +The only known workarounds are to disable the ethernet interface +before inserting or removing a PCMCIA card, or with some cards +disabling the PCMCIA card before ejecting it will also help the +problem with the laptop hanging when the card is ejected. + +One user has reported that setting the tcic's cs_irq to some value +other than 9 (like 11) fixed the problem. This doesn't work on my +Z505S, however--changing the value causes the cardmgr to stop seeing +card insertions and removals, cards don't seem to work correctly, and +I still get hangs if a card is inserted when the kernel is booted. + +Using the latest ethernet driver and pcmcia package allows me to +insert an Adaptec 1480A SlimScsi card without the laptop hanging, +although I still have to shut down the card before ejecting or +powering down the laptop. However, similar experiments with a DE-660 +ethernet card still result in hangs when the card is inserted. I am +beginning to think that the interrupts are CardBus-related, since the +Adaptec card is a CardBus card, and the DE-660 is not; however, I +don't have any other CardBus cards to test with. ====== Thanks @@ -208,6 +250,11 @@ I will be rather unfair and single out a few people, however: Jeff Garzik, for various helpful suggestions on the AC97 interface + "Mr. Bumpy" for feedback on the Z505RX + + Bill Nottingham, for generous assistance in getting the mixer ID + code working + ================= Previous versions ================= @@ -227,3 +274,11 @@ mixer module. Version 0.75 renamed all the functions and files with slightly more generic names. + +Version 1.1 contains a change to try and detect non-AC97 versions of +the hardware, and not install itself appropriately. It should also +reinitialize the hardware on an APM resume event, assuming that APM +was configured into your kernel. + +Note that previous versions of this document claimed that recording was +8-bit only; it actually has been working for 16-bits all along. diff --git a/MAINTAINERS b/MAINTAINERS index 1b617feacffa..13c39ff6fd1a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -811,8 +811,10 @@ M: kgb@manjak.knm.org.pl S: Maintained TLAN NETWORK DRIVER +P: Torben Mathiasen +M: torben.mathiasen@compaq.com L: tlan@vuser.vu.union.edu -S: Orphan +S: Maintained TOKEN-RING NETWORK DRIVER P: Paul Norton diff --git a/Makefile b/Makefile index 5528f2421ffe..605340612d0a 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 14 -EXTRAVERSION = pre12 +EXTRAVERSION = pre13 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c index 334dbfb56cfc..606fe1e5a920 100644 --- a/arch/alpha/mm/init.c +++ b/arch/alpha/mm/init.c @@ -211,7 +211,11 @@ paging_init(unsigned long start_mem, unsigned long end_mem) if (cluster->usage & 3) continue; pfn = cluster->start_pfn; + if (pfn >= MAP_NR(end_mem)) /* if we overrode mem size */ + continue; nr = cluster->numpages; + if ((pfn + nr) > MAP_NR(end_mem)) /* if override in cluster */ + nr = MAP_NR(end_mem) - pfn; while (nr--) clear_bit(PG_reserved, &mem_map[pfn++].flags); @@ -221,7 +225,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem) the last slot of the L1 page table. */ memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE); memset(swapper_pg_dir, 0, PAGE_SIZE); - newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT; + newptbr = MAP_NR(swapper_pg_dir); pgd_val(swapper_pg_dir[1023]) = (newptbr << 32) | pgprot_val(PAGE_KERNEL); @@ -328,8 +332,8 @@ mem_init(unsigned long start_mem, unsigned long end_mem) kill_page(tmp); free_page(tmp); } - tmp = nr_free_pages << PAGE_SHIFT; - printk("Memory: %luk available\n", tmp >> 10); + tmp = nr_free_pages << (PAGE_SHIFT - 10); + printk("Memory: %luk available\n", tmp); return; } @@ -358,7 +362,7 @@ si_meminfo(struct sysinfo *val) i = max_mapnr; val->totalram = 0; val->sharedram = 0; - val->freeram = nr_free_pages << PAGE_SHIFT; + val->freeram = ((unsigned long)nr_free_pages) << PAGE_SHIFT; val->bufferram = buffermem; while (i-- > 0) { if (PageReserved(mem_map+i)) diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 3a52d51138a7..4526add03068 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -114,7 +114,6 @@ volatile unsigned long smp_invalidate_needed; /* Used for the invalidate map th volatile unsigned long kstack_ptr; /* Stack vector for booting CPUs */ struct cpuinfo_x86 cpu_data[NR_CPUS]; /* Per CPU bogomips and other parameters */ static unsigned int num_processors = 1; /* Internal processor count */ -unsigned long mp_ioapic_addr = 0xFEC00000; /* Address of the I/O apic (not yet used) */ unsigned char boot_cpu_id = 0; /* Processor that is doing the boot up */ static int smp_activated = 0; /* Tripped once we need to start cross invalidating */ int apic_version[NR_CPUS]; /* APIC version number */ @@ -493,6 +492,8 @@ static int __init smp_scan_config(unsigned long base, unsigned long length) cpu_present_map=3; num_processors=2; printk("I/O APIC at 0xFEC00000.\n"); + mp_apics[0].mpc_apicaddr = 0xFEC00000; + mp_apic_entries = 1; /* * Save the default type number, we diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c index 34b6fe51ab7e..6a4309f86270 100644 --- a/drivers/block/ide-disk.c +++ b/drivers/block/ide-disk.c @@ -227,7 +227,10 @@ int ide_multwrite (ide_drive_t *drive, unsigned int mcount) #endif spin_lock_irqsave(&io_request_lock, flags); /* Is this really necessary? */ if ((rq->nr_sectors -= nsect) <= 0) + { + spin_unlock_irqrestore(&io_request_lock, flags); break; + } if ((rq->current_nr_sectors -= nsect) == 0) { if ((rq->bh = rq->bh->b_reqnext) != NULL) { rq->current_nr_sectors = rq->bh->b_size>>9; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index c94c9b3c6e76..a404fcab33b7 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -315,7 +315,7 @@ static int create_missing_block(struct loop_device *lo, int block, int blksize) /* Do what the default llseek() code would have done */ file->f_pos = new_offset; file->f_reada = 0; - file->f_version = ++event; + file->f_version = ++global_event; } if (file->f_op->write == NULL) { diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 4b2281efa30f..d76947188c9c 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -32,6 +32,8 @@ * Alan Cox : Fixed the out of memory * handling. * + * Torben Mathiasen New Maintainer! + * ********************************************************************/ diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index fa1f91bbee14..3c135e7471c2 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -14,6 +14,8 @@ * ** This file is best viewed/edited with tabstop=4, colums>=132 * + * Dec 10, 1999 Torben Mathiasen + * New Maintainer ********************************************************************/ diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 63468443a963..c710f4cc600d 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -20,9 +20,32 @@ * along with this kernel; if not, write to the Free Software * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * - * Tested with Linux 1.2.13, ..., 2.2.4 * + * Tested with Linux 1.2.13, ..., 2.2.12 * * * * $Log: gdth.c,v $ + * Revision 1.30 1999/11/02 13:42:39 achim + * ARRAY_DRV_LIST2 implemented + * Now 255 log. and 100 host drives supported + * + * Revision 1.29 1999/10/05 13:28:47 achim + * GDT_CLUST_RESET added + * + * Revision 1.28 1999/08/12 13:44:54 achim + * MOUNTALL removed + * Cluster drives -> removeable drives + * + * Revision 1.27 1999/06/22 07:22:38 achim + * Small changes + * + * Revision 1.26 1999/06/10 16:09:12 achim + * Cluster Host Drive support: Bugfixes + * + * Revision 1.25 1999/06/01 16:03:56 achim + * gdth_init_pci(): Manipulate config. space to start RP controller + * + * Revision 1.24 1999/05/26 11:53:06 achim + * Cluster Host Drive support added + * * Revision 1.23 1999/03/26 09:12:31 achim * Default value for hdr_channel set to 0 * @@ -120,7 +143,7 @@ * Initial revision * ************************************************************************/ -#ident "$Id: gdth.c,v 1.23 1999/03/26 09:12:31 achim Exp $" +#ident "$Id: gdth.c,v 1.30 1999/11/02 13:42:39 achim Exp $" /* All GDT Disk Array Controllers are fully supported by this driver. * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the @@ -581,18 +604,18 @@ static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs) { *cyls = size /HEADS/SECS; if (*cyls <= MAXCYLS) { - *heads = HEADS; - *secs = SECS; - } else { /* too high for 64*32 */ - *cyls = size /MEDHEADS/MEDSECS; - if (*cyls <= MAXCYLS) { - *heads = MEDHEADS; - *secs = MEDSECS; - } else { /* too high for 127*63 */ - *cyls = size /BIGHEADS/BIGSECS; - *heads = BIGHEADS; - *secs = BIGSECS; - } + *heads = HEADS; + *secs = SECS; + } else { /* too high for 64*32 */ + *cyls = size /MEDHEADS/MEDSECS; + if (*cyls <= MAXCYLS) { + *heads = MEDHEADS; + *secs = MEDSECS; + } else { /* too high for 127*63 */ + *cyls = size /BIGHEADS/BIGSECS; + *heads = BIGHEADS; + *secs = BIGSECS; + } } } @@ -686,7 +709,7 @@ __initfunc (static int gdth_search_pci(gdth_pci_str *pcistr)) } TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%x\n", pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), - pcistr[cnt].irq, pcistr[cnt].dpmem)); + pcistr[cnt].irq, (int)pcistr[cnt].dpmem)); cnt++; } #else @@ -981,7 +1004,11 @@ __initfunc (static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) register gdt6m_dpram_str *dp6m_ptr; ulong32 retries; unchar prot_ver; + ushort command; int i, found = FALSE; +#if LINUX_VERSION_CODE < 0x2015C + int rom_addr; +#endif TRACE(("gdth_init_pci()\n")); @@ -1137,6 +1164,36 @@ __initfunc (static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)) return 0; } + /* manipulate config. space to enable DPMEM, start RP controller */ +#if LINUX_VERSION_CODE >= 0x2015C + pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command); + command |= 6; + pci_write_config_word(pcistr->pdev, PCI_COMMAND, command); + if (pcistr->pdev->rom_address == 1UL) + pcistr->pdev->rom_address = 0UL; + i = 0xFEFF0001UL; + pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, i); + gdth_delay(1); + pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, + pcistr->pdev->rom_address); +#else + pcibios_read_config_word(pcistr->bus, pcistr->device_fn, + PCI_COMMAND, &command); + command |= 6; + pcibios_write_config_word(pcistr->bus, pcistr->device_fn, + PCI_COMMAND, command); + pcibios_read_config_dword(pcistr->bus, pcistr->device_fn, + PCI_ROM_ADDRESS, &rom_addr); + if (rom_addr == 1UL) + rom_addr = 0UL; + i = 0xFEFF0001UL; + pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, + PCI_ROM_ADDRESS, i); + gdth_delay(1); + pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, + PCI_ROM_ADDRESS, rom_addr); +#endif + /* check and reset interface area */ dp6m_ptr = (gdt6m_dpram_str *)ha->brd; gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u); @@ -1585,7 +1642,8 @@ __initfunc (static int gdth_search_drives(int hanum)) gdth_drlist_str *drl; gdth_iochan_str *ioc; gdth_raw_iochan_str *iocr; - gdth_arraylist_str *alst; + gdth_arcdl_str *alst; + gdth_alist_str *alst2; TRACE(("gdth_search_drives() hanum %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); @@ -1607,19 +1665,6 @@ __initfunc (static int gdth_search_drives(int hanum)) TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n")); cdev_cnt = (ushort)ha->info; - /* mount all cache devices */ - gdth_internal_cmd(hanum,CACHESERVICE,GDT_MOUNT,0xffff,1,0); - TRACE2(("gdth_search_drives(): mountall CACHESERVICE OK\n")); - - /* initialize cache service after mountall */ - if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) { - printk("GDT: Initialization error cache service (code %d)\n", - ha->status); - return 0; - } - TRACE2(("gdth_search_drives() CACHES. init. after mountall\n")); - cdev_cnt = (ushort)ha->info; - /* detect number of buses - try new IOCTL */ iocr = (gdth_raw_iochan_str *)ha->pscratch; iocr->hdr.version = 0xffffffff; @@ -1747,22 +1792,37 @@ __initfunc (static int gdth_search_drives(int hanum)) INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) { for (j = 0; j < drv_cnt; ++j) { drv_no = ((ulong32 *)ha->pscratch)[j]; - if (drv_no < MAX_HDRIVES) { + if (drv_no < MAX_LDRIVES) { ha->hdr[drv_no].is_logdrv = TRUE; TRACE2(("Drive %d is log. drive\n",drv_no)); } } } + alst = (gdth_arcdl_str *)ha->pscratch; + alst->entries_avail = MAX_LDRIVES; + alst->first_entry = 0; + alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]); if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, - ARRAY_DRV_LIST | LA_CTRL_PATTERN, - 0, 35 * sizeof(gdth_arraylist_str))) { + ARRAY_DRV_LIST2 | LA_CTRL_PATTERN, + INVALID_CHANNEL, sizeof(gdth_arcdl_str) + + (alst->entries_avail-1) * sizeof(gdth_alist_str))) { + for (j = 0; j < alst->entries_init; ++j) { + ha->hdr[j].is_arraydrv = alst->list[j].is_arrayd; + ha->hdr[j].is_master = alst->list[j].is_master; + ha->hdr[j].is_parity = alst->list[j].is_parity; + ha->hdr[j].is_hotfix = alst->list[j].is_hotfix; + ha->hdr[j].master_no = alst->list[j].cd_handle; + } + } else if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, + ARRAY_DRV_LIST | LA_CTRL_PATTERN, + 0, 35 * sizeof(gdth_alist_str))) { for (j = 0; j < 35; ++j) { - alst = &((gdth_arraylist_str *)ha->pscratch)[j]; - ha->hdr[j].is_arraydrv = alst->is_arrayd; - ha->hdr[j].is_master = alst->is_master; - ha->hdr[j].is_parity = alst->is_parity; - ha->hdr[j].is_hotfix = alst->is_hotfix; - ha->hdr[j].master_no = alst->cd_handle; + alst2 = &((gdth_alist_str *)ha->pscratch)[j]; + ha->hdr[j].is_arraydrv = alst2->is_arrayd; + ha->hdr[j].is_master = alst2->is_master; + ha->hdr[j].is_parity = alst2->is_parity; + ha->hdr[j].is_hotfix = alst2->is_hotfix; + ha->hdr[j].master_no = alst2->cd_handle; } } } @@ -1825,17 +1885,13 @@ __initfunc (static int gdth_search_drives(int hanum)) for (i=0; ibus_cnt,i)); - ha->hdr[i].present = TRUE; ha->hdr[i].size = ha->info; /* evaluate mapping (sectors per head, heads per cylinder) */ ha->hdr[i].size &= ~SECS32; if (ha->info2 == 0) { - gdth_eval_mapping(ha->hdr[i].size,&drv_cyls,&drv_hds,&drv_secs); + gdth_eval_mapping(ha->hdr[i].size,&drv_cyls,&drv_hds,&drv_secs); } else { drv_hds = ha->info2 & 0xff; drv_secs = (ha->info2 >> 8) & 0xff; @@ -1851,10 +1907,30 @@ __initfunc (static int gdth_search_drives(int hanum)) /* get informations about device */ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,i, 0,0)) { - TRACE(("gdth_search_dr() cache drive %d devtype %d\n", + TRACE2(("gdth_search_dr() cache drive %d devtype %d\n", i,ha->info)); ha->hdr[i].devtype = (ushort)ha->info; } + + /* cluster info */ + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_CLUST_INFO,i, + 0,0)) { + TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n", + i,ha->info)); + ha->hdr[i].cluster_type = (unchar)ha->info; + } else { + ha->hdr[i].cluster_type = 0; + } + + /* R/W attributes */ + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,i, + 0,0)) { + TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n", + i,ha->info)); + ha->hdr[i].rw_attribs = (unchar)ha->info; + } else { + ha->hdr[i].rw_attribs = 0; + } } } @@ -1969,11 +2045,11 @@ static void gdth_next(int hanum) } #if LINUX_VERSION_CODE >= 0x010300 - if (nscp->done != gdth_scsi_done) + if (nscp->done != gdth_scsi_done || nscp->cmnd[0] != 0xff) #endif { if (nscp->SCp.phase == -1) { - nscp->SCp.phase = SCSIRAWSERVICE; /* default: raw svc. */ + nscp->SCp.phase = CACHESERVICE; /* default: cache svc. */ if (nscp->cmnd[0] == TEST_UNIT_READY) { TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", b, t, nscp->lun)); @@ -1987,7 +2063,8 @@ static void gdth_next(int hanum) if (b == 0 && ((t == 0 && nscp->lun == 1) || (t == 1 && nscp->lun == 0))) { nscp->SCp.Status = GDT_SCAN_START; - nscp->SCp.phase |= ((ha->scan_mode & 0x10 ? 1:0) << 8); + nscp->SCp.phase = ((ha->scan_mode & 0x10 ? 1:0) << 8) + | SCSIRAWSERVICE; ha->scan_mode = 0x12; TRACE2(("Scan mode: 0x%x (SCAN_START)\n", ha->scan_mode)); @@ -1997,6 +2074,7 @@ static void gdth_next(int hanum) } } else if (ha->scan_mode == 0x12) { if (b == ha->bus_cnt && t == ha->tid_cnt-1) { + nscp->SCp.phase = SCSIRAWSERVICE; nscp->SCp.Status = GDT_SCAN_END; ha->scan_mode &= 0x10; TRACE2(("Scan mode: 0x%x (SCAN_END)\n", @@ -2004,19 +2082,55 @@ static void gdth_next(int hanum) } } } + if (b == ha->virt_bus && nscp->cmnd[0] != INQUIRY && + nscp->cmnd[0] != READ_CAPACITY && nscp->cmnd[0] != MODE_SENSE && + (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) { + if (!(ha->hdr[t].cluster_type & CLUSTER_MOUNTED)) { + /* cluster drive NOT MOUNTED */ + if (!(ha->hdr[t].cluster_type & CLUSTER_RESERVED)) { + /* cluster drive NOT RESERVED */ + nscp->SCp.Status = GDT_MOUNT; + } else { + /* cluster drive RESERVED (on the other node) */ + nscp->SCp.Status = GDT_CLUST_INFO; + } + } else { + if (!(ha->hdr[t].cluster_type & CLUSTER_RESERVED)) { + /* cluster drive MOUNTED and not RESERVED */ + nscp->SCp.Status = GDT_CLUST_INFO; + } + } + } } } if (nscp->SCp.Status != -1) { - if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) { + if ((nscp->SCp.phase & 0xff) == CACHESERVICE) { + if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t))) + this_cmd = FALSE; + next_cmd = FALSE; + } else if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) { if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b)))) this_cmd = FALSE; next_cmd = FALSE; + } else { + memset((char*)nscp->sense_buffer,0,16); + nscp->sense_buffer[0] = 0x70; + nscp->sense_buffer[2] = NOT_READY; + nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); + if (!nscp->SCp.have_data_in) + nscp->SCp.have_data_in++; + else { + GDTH_UNLOCK_HA(ha,flags); + /* io_request_lock already active ! */ + nscp->scsi_done(nscp); + GDTH_LOCK_HA(ha,flags); + } } } else #if LINUX_VERSION_CODE >= 0x010300 - if (nscp->done == gdth_scsi_done) { + if (nscp->done == gdth_scsi_done && nscp->cmnd[0] == 0xff) { if (!(cmd_index=gdth_special_cmd(hanum,nscp))) this_cmd = FALSE; next_cmd = FALSE; @@ -2080,6 +2194,14 @@ static void gdth_next(int hanum) } break; + case RESERVE: + case RELEASE: + TRACE2(("cache cmd %s\n",nscp->cmnd[0] == RESERVE ? + "RESERVE" : "RELEASE")); + if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t))) + this_cmd = FALSE; + break; + case READ_6: case WRITE_6: case READ_10: @@ -2184,7 +2306,10 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp) inq.type_qual = (ha->hdr[t].devtype&4) ? TYPE_ROM:TYPE_DISK; /* you can here set all disks to removable, if you want to do a flush using the ALLOW_MEDIUM_REMOVAL command */ - inq.modif_rmb = ha->hdr[t].devtype&1 ? 0x80:0x00; + inq.modif_rmb = 0x00; + if ((ha->hdr[t].devtype & 1) || + (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) + inq.modif_rmb = 0x80; inq.version = 2; inq.resp_aenc = 2; inq.add_length= 32; @@ -2243,7 +2368,7 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive) register gdth_cmd_str *cmdp; struct scatterlist *sl; ushort i; - int cmd_index; + int cmd_index, read_write; ha = HADATA(gdth_ctr_tab[hanum]); cmdp = ha->pccb; @@ -2265,31 +2390,38 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive) gdth_set_sema0(hanum); /* fill command */ - if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) { + read_write = FALSE; + if (scp->SCp.Status != -1) + cmdp->OpCode = scp->SCp.Status; /* special cache cmd. */ + else if (scp->cmnd[0] == RESERVE) + cmdp->OpCode = GDT_RESERVE_DRV; + else if (scp->cmnd[0] == RELEASE) + cmdp->OpCode = GDT_RELEASE_DRV; + else if (scp->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { if (scp->cmnd[4] & 1) /* prevent ? */ - cmdp->OpCode = GDT_MOUNT; + cmdp->OpCode = GDT_MOUNT; else if (scp->cmnd[3] & 1) /* removable drive ? */ - cmdp->OpCode = GDT_UNMOUNT; + cmdp->OpCode = GDT_UNMOUNT; + else + cmdp->OpCode = GDT_FLUSH; + } else if (scp->cmnd[0] == WRITE_6 || scp->cmnd[0] == WRITE_10) { + read_write = TRUE; + if (gdth_write_through || ((ha->hdr[hdrive].rw_attribs & 1) && + (ha->cache_feat & GDT_WR_THROUGH))) + cmdp->OpCode = GDT_WRITE_THR; else - cmdp->OpCode = GDT_FLUSH; + cmdp->OpCode = GDT_WRITE; } else { - if (scp->cmnd[0]==WRITE_6 || scp->cmnd[0]==WRITE_10) { - if (gdth_write_through) - cmdp->OpCode = GDT_WRITE_THR; - else - cmdp->OpCode = GDT_WRITE; - } else { - cmdp->OpCode = GDT_READ; - } + read_write = TRUE; + cmdp->OpCode = GDT_READ; } + + cmdp->BoardNode = LOCALBOARD; + cmdp->u.cache.DeviceNo = hdrive; + cmdp->u.cache.BlockNo = 1; + cmdp->u.cache.sg_canz = 0; - cmdp->BoardNode = LOCALBOARD; - cmdp->u.cache.DeviceNo = hdrive; - - if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) { - cmdp->u.cache.BlockNo = 1; - cmdp->u.cache.sg_canz = 0; - } else { + if (read_write) { if (scp->cmd_len != 6) { cmdp->u.cache.BlockNo = ntohl(*(ulong32*)&scp->cmnd[2]); cmdp->u.cache.BlockCnt= (ulong32)ntohs(*(ushort*)&scp->cmnd[7]); @@ -2942,37 +3074,92 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp) } /* cache or raw service */ if (ha->status == S_OK) { - scp->SCp.Message = S_OK; + scp->SCp.Message = (int)(ha->info<<16|S_OK); if (scp->SCp.Status != -1) { TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n", scp->SCp.Status)); - scp->SCp.Status = -1; - scp->SCp.this_residual = HIGH_PRI; - return 2; + /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */ + if (scp->SCp.Status == GDT_CLUST_INFO) { + ha->hdr[scp->target].cluster_type = (unchar)ha->info; + if (!(ha->hdr[scp->target].cluster_type & + CLUSTER_MOUNTED)) { + /* NOT MOUNTED -> MOUNT */ + if (!(ha->hdr[scp->target].cluster_type & + CLUSTER_RESERVED)) { + /* cluster drive NOT RESERVED */ + scp->SCp.Status = GDT_MOUNT; + } else { + /* cluster drive RESERVED (on the other node) */ + scp->SCp.Status = GDT_MOUNT; + scp->SCp.phase = -2; /* reservation conflict */ + } + } else { + scp->SCp.Status = -1; + } + /* retry */ + scp->SCp.this_residual = HIGH_PRI; + return 2; + } else if (scp->SCp.Status == GDT_MOUNT) { + ha->hdr[scp->target].cluster_type |= CLUSTER_MOUNTED; + scp->SCp.Status = -1; + /* return UNIT_ATTENTION */ + memset((char*)scp->sense_buffer,0,16); + scp->sense_buffer[0] = 0x70; + scp->sense_buffer[2] = UNIT_ATTENTION; + scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); + } else { + scp->SCp.Status = -1; + /* retry */ + scp->SCp.this_residual = HIGH_PRI; + return 2; + } + } else { + /* RESERVE/RELEASE ? */ + if (scp->cmnd[0] == RESERVE) { + ha->hdr[scp->target].cluster_type |= CLUSTER_RESERVED; + } else if (scp->cmnd[0] == RELEASE) { + ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED; + } + scp->result = DID_OK << 16; } - scp->result = DID_OK << 16; } else if (ha->status == S_BSY) { TRACE2(("Controller busy -> retry !\n")); - scp->SCp.Message = S_BSY; + scp->SCp.Message = (int)(ha->info<<16|S_BSY); + if (scp->SCp.Status == GDT_MOUNT) + scp->SCp.Status = GDT_CLUST_INFO; + /* retry */ return 2; } else { scp->SCp.Message = (int)((ha->info<<16)|ha->status); + memset((char*)scp->sense_buffer,0,16); + scp->sense_buffer[0] = 0x70; + scp->sense_buffer[2] = NOT_READY; + if (scp->SCp.Status != -1) { TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n", scp->SCp.Status, ha->status)); - scp->SCp.Status = -1; - scp->SCp.this_residual = HIGH_PRI; - return 2; - } - if (service == CACHESERVICE) { - memset((char*)scp->sense_buffer,0,16); - scp->sense_buffer[0] = 0x70; - scp->sense_buffer[2] = NOT_READY; + if (scp->SCp.Status == GDT_SCAN_START || + scp->SCp.Status == GDT_SCAN_END) { + scp->SCp.Status = -1; + /* retry */ + scp->SCp.this_residual = HIGH_PRI; + return 2; + } + scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); + } else if (scp->cmnd[0] == RESERVE || + scp->cmnd[0] == RELEASE) { + scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); + } else if (service == CACHESERVICE) { + if (ha->status == S_CACHE_UNKNOWN && + (ha->hdr[scp->target].cluster_type & + CLUSTER_RESERVE_STATE) == CLUSTER_RESERVE_STATE) { + /* bus reset -> force GDT_CLUST_INFO */ + ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED; + } scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - #if LINUX_VERSION_CODE >= 0x010300 if (scp->done != gdth_scsi_done) -#endif +#endif { dvr.size = sizeof(dvr.eu.sync); dvr.eu.sync.ionode = hanum; @@ -3754,24 +3941,46 @@ int gdth_eh_bus_reset(Scsi_Cmnd *scp) TRACE2(("gdth_eh_bus_reset()\n")); hanum = NUMDATA(scp->host)->hanum; ha = HADATA(gdth_ctr_tab[hanum]); - if (scp->channel == ha->virt_bus) - return FAILED; + /* clear command tab */ GDTH_LOCK_HA(ha, flags); - for (i = 0; i < MAXID; ++i) - ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[i] = 0; for (i = 0; i < GDTH_MAXCMDS; ++i) { cmnd = ha->cmd_tab[i].cmnd; if (!SPECIAL_SCP(cmnd) && cmnd->channel == scp->channel) ha->cmd_tab[i].cmnd = UNUSED_CMND; } - gdth_polling = TRUE; - while (gdth_test_busy(hanum)) - gdth_delay(0); - gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS, - BUS_L2P(ha,scp->channel), 0, 0); - gdth_polling = FALSE; GDTH_UNLOCK_HA(ha, flags); + + if (scp->channel == ha->virt_bus) { + /* host drives */ + for (i = 0; i < MAX_HDRIVES; ++i) { + if (ha->hdr[i].present && + (ha->hdr[i].cluster_type & CLUSTER_RESERVED) + == CLUSTER_RESERVED) { + GDTH_LOCK_HA(ha, flags); + gdth_polling = TRUE; + while (gdth_test_busy(hanum)) + gdth_delay(0); + if (gdth_internal_cmd(hanum, CACHESERVICE, + GDT_CLUST_RESET, i, 0, 0)) + ha->hdr[i].cluster_type &= ~CLUSTER_RESERVED; + gdth_polling = FALSE; + GDTH_UNLOCK_HA(ha, flags); + } + } + } else { + /* raw devices */ + GDTH_LOCK_HA(ha, flags); + for (i = 0; i < MAXID; ++i) + ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[i] = 0; + gdth_polling = TRUE; + while (gdth_test_busy(hanum)) + gdth_delay(0); + gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS, + BUS_L2P(ha,scp->channel), 0, 0); + gdth_polling = FALSE; + GDTH_UNLOCK_HA(ha, flags); + } return SUCCESS; } @@ -3800,12 +4009,12 @@ int gdth_bios_param(Disk *disk,int dev,int *ip) if (disk->device->channel != ha->virt_bus || ha->hdr[t].heads == 0) { /* raw device or host drive without mapping information */ - TRACE2(("Evaluate mapping\n")); - gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]); + TRACE2(("Evaluate mapping\n")); + gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]); } else { - ip[0] = ha->hdr[t].heads; - ip[1] = ha->hdr[t].secs; - ip[2] = disk->capacity / ip[0] / ip[1]; + ip[0] = ha->hdr[t].heads; + ip[1] = ha->hdr[t].secs; + ip[2] = disk->capacity / ip[0] / ip[1]; } TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n", @@ -3869,18 +4078,16 @@ static void gdth_flush(int hanum) Scsi_Cmnd scp; Scsi_Device sdev; gdth_cmd_str gdtcmd; + char cmnd[12]; TRACE2(("gdth_flush() hanum %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); memset(&sdev,0,sizeof(Scsi_Device)); memset(&scp, 0,sizeof(Scsi_Cmnd)); - sdev.host = gdth_ctr_tab[hanum]; - sdev.id = sdev.host->this_id; - scp.cmd_len = 12; - scp.host = gdth_ctr_tab[hanum]; - scp.target = sdev.host->this_id; + memset(cmnd, 0xff, 12); + sdev.host = scp.host = gdth_ctr_tab[hanum]; + sdev.id = scp.target = sdev.host->this_id; scp.device = &sdev; - scp.use_sg = 0; for (i = 0; i < MAX_HDRIVES; ++i) { if (ha->hdr[i].present) { @@ -3891,7 +4098,7 @@ static void gdth_flush(int hanum) gdtcmd.u.cache.BlockNo = 1; gdtcmd.u.cache.sg_canz = 0; TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i)); - gdth_do_cmd(&scp, &gdtcmd, 30); + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); } } } @@ -3908,10 +4115,11 @@ void gdth_halt(void) Scsi_Cmnd scp; Scsi_Device sdev; gdth_cmd_str gdtcmd; + char cmnd[12]; #endif #if LINUX_VERSION_CODE >= 0x020100 - TRACE2(("gdth_halt() event %d\n",event)); + TRACE2(("gdth_halt() event %d\n",(int)event)); if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) return NOTIFY_DONE; #else @@ -3930,19 +4138,16 @@ void gdth_halt(void) /* controller reset */ memset(&sdev,0,sizeof(Scsi_Device)); memset(&scp, 0,sizeof(Scsi_Cmnd)); - sdev.host = gdth_ctr_tab[hanum]; - sdev.id = sdev.host->this_id; - scp.cmd_len = 12; - scp.host = gdth_ctr_tab[hanum]; - scp.target = sdev.host->this_id; + memset(cmnd, 0xff, 12); + sdev.host = scp.host = gdth_ctr_tab[hanum]; + sdev.id = scp.target = sdev.host->this_id; scp.device = &sdev; - scp.use_sg = 0; gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_RESET; TRACE2(("gdth_halt(): reset controller %d\n", hanum)); - gdth_do_cmd(&scp, &gdtcmd, 10); + gdth_do_cmd(&scp, &gdtcmd, cmnd, 10); #endif } printk("Done.\n"); diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h index 6d77ef1ae9c7..02aae111348c 100644 --- a/drivers/scsi/gdth.h +++ b/drivers/scsi/gdth.h @@ -10,7 +10,7 @@ * * * - * $Id: gdth.h,v 1.21 1999/03/26 09:12:24 achim Exp $ + * $Id: gdth.h,v 1.24 1999/11/02 13:43:49 achim Exp $ */ #include @@ -29,9 +29,9 @@ /* defines, macros */ /* driver version */ -#define GDTH_VERSION_STR "1.14" +#define GDTH_VERSION_STR "1.17" #define GDTH_VERSION 1 -#define GDTH_SUBVERSION 14 +#define GDTH_SUBVERSION 17 /* protocol version */ #define PROTOCOL_VERSION 1 @@ -135,7 +135,8 @@ #define MAXID 127 #define MAXLUN 8 #define MAXBUS 6 -#define MAX_HDRIVES 35 /* max. host drive count */ +#define MAX_HDRIVES 100 /* max. host drive count */ +#define MAX_LDRIVES 255 /* max. log. drive count */ #define MAX_EVENTS 100 /* event buffer count */ #define MAX_RES_ARGS 40 /* device reservation, must be a multiple of 4 */ @@ -173,6 +174,12 @@ #define IC_QUEUE_BYTES 4 #define DPMEM_COMMAND_OFFSET IC_HEADER_BYTES+IC_QUEUE_BYTES*MAXOFFSETS +/* cluster_type constants */ +#define CLUSTER_DRIVE 1 +#define CLUSTER_MOUNTED 2 +#define CLUSTER_RESERVED 4 +#define CLUSTER_RESERVE_STATE (CLUSTER_DRIVE|CLUSTER_MOUNTED|CLUSTER_RESERVED) + /* cache/raw service commands */ #define GDT_INIT 0 /* service initialization */ #define GDT_READ 1 /* read command */ @@ -189,6 +196,11 @@ #define GDT_READ_THR 17 /* read through */ #define GDT_EXT_INFO 18 /* extended info */ #define GDT_RESET 19 /* controller reset */ +#define GDT_RESERVE_DRV 20 /* reserve host drive */ +#define GDT_RELEASE_DRV 21 /* release host drive */ +#define GDT_CLUST_INFO 22 /* cluster info */ +#define GDT_RW_ATTRIBS 23 /* R/W attribs (write thru,..)*/ +#define GDT_CLUST_RESET 24 /* releases the cluster drives*/ /* additional raw service commands */ #define GDT_RESERVE 14 /* reserve dev. to raw serv. */ @@ -206,10 +218,11 @@ #define SCSI_DEF_CNT 0x15 /* grown/primary defects */ #define DSK_STATISTICS 0x4b /* SCSI disk statistics */ #define IOCHAN_DESC 0x5d /* description of IO channel */ -#define IOCHAN_RAW_DESC 0x5e /* description of raw IO channel */ +#define IOCHAN_RAW_DESC 0x5e /* description of raw IO chn. */ #define L_CTRL_PATTERN 0x20000000L /* SCSI IOCTL mask */ #define ARRAY_INFO 0x12 /* array drive info */ #define ARRAY_DRV_LIST 0x0f /* array drive list */ +#define ARRAY_DRV_LIST2 0x34 /* array drive list (new) */ #define LA_CTRL_PATTERN 0x10000000L /* array IOCTL mask */ #define CACHE_DRV_CNT 0x01 /* cache drive count */ #define CACHE_DRV_LIST 0x02 /* cache drive list */ @@ -235,6 +248,7 @@ /* service errors */ #define S_OK 1 /* no error */ #define S_BSY 7 /* controller busy */ +#define S_CACHE_UNKNOWN 12 /* cache serv.: drive unknown */ #define S_RAW_SCSI 12 /* raw serv.: target error */ #define S_RAW_ILL 0xff /* raw serv.: illegal */ @@ -300,7 +314,7 @@ typedef struct { unchar revision[4]; /* revision */ ulong32 sy_rate; /* current rate for sync. tr. */ ulong32 sy_max_rate; /* max. rate for sync. tr. */ - ulong32 no_ldrive; /* belongs to this logical drv.*/ + ulong32 no_ldrive; /* belongs to this log. drv.*/ ulong32 blkcnt; /* number of blocks */ ushort blksize; /* size of block in bytes */ unchar available; /* flag: access is available */ @@ -455,7 +469,15 @@ typedef struct { unchar is_parity; /* Flag: is parity drive? */ unchar is_hotfix; /* Flag: is hotfix drive? */ unchar res[3]; -} PACKED gdth_arraylist_str; +} PACKED gdth_alist_str; + +typedef struct { + ulong32 entries_avail; /* allocated entries */ + ulong32 entries_init; /* returned entries */ + ulong32 first_entry; /* first entry number */ + ulong32 list_offset; /* offset of following list */ + gdth_alist_str list[1]; /* list */ +} PACKED gdth_arcdl_str; /* cache info/config IOCTL */ typedef struct { @@ -864,13 +886,15 @@ typedef struct { ulong32 size; /* capacity */ unchar ldr_no; /* log. drive no. */ unchar rw_attribs; /* r/w attributes */ + unchar cluster_type; /* cluster properties */ + unchar reserved; ulong32 start_sec; /* start sector */ - } hdr[MAX_HDRIVES]; /* host drives */ + } hdr[MAX_LDRIVES]; /* host drives */ struct { unchar lock; /* channel locked? (hot plug) */ unchar pdev_cnt; /* physical device count */ unchar local_no; /* local channel number */ - unchar io_cnt[MAXID]; /* current IO count */ + unchar io_cnt[MAXID]; /* current IO count */ ulong32 address; /* channel address */ ulong32 id_list[MAXID]; /* IDs of the phys. devices */ } raw[MAXBUS]; /* SCSI channels */ diff --git a/drivers/scsi/gdth_ioctl.h b/drivers/scsi/gdth_ioctl.h index 68395616009d..64a00c5900ff 100644 --- a/drivers/scsi/gdth_ioctl.h +++ b/drivers/scsi/gdth_ioctl.h @@ -2,7 +2,7 @@ #define _GDTH_IOCTL_H /* gdth_ioctl.h - * $Id: gdth_ioctl.h,v 1.2 1998/12/17 15:42:49 achim Exp $ + * $Id: gdth_ioctl.h,v 1.3 1999/05/26 11:49:57 achim Exp $ */ /* IOCTLs */ @@ -11,10 +11,13 @@ #define GDTIOCTL_DRVERS (GDTIOCTL_MASK | 1) /* get driver version */ #define GDTIOCTL_CTRTYPE (GDTIOCTL_MASK | 2) /* get controller type */ #define GDTIOCTL_OSVERS (GDTIOCTL_MASK | 3) /* get OS version */ +#define GDTIOCTL_HDRLIST (GDTIOCTL_MASK | 4) /* get host drive list */ #define GDTIOCTL_CTRCNT (GDTIOCTL_MASK | 5) /* get controller count */ #define GDTIOCTL_LOCKDRV (GDTIOCTL_MASK | 6) /* lock host drive */ #define GDTIOCTL_LOCKCHN (GDTIOCTL_MASK | 7) /* lock channel */ #define GDTIOCTL_EVENT (GDTIOCTL_MASK | 8) /* read controller events */ +#define GDTIOCTL_SCSI (GDTIOCTL_MASK | 9) /* SCSI command */ +#define GDTIOCTL_RESET_BUS (GDTIOCTL_MASK |10) /* reset SCSI bus */ #define GDTIOCTL_MAGIC 0xaffe0001UL @@ -45,6 +48,13 @@ typedef struct { int handle; unchar evt[34]; /* event structure */ } event; + struct { + unchar bus; /* SCSI bus */ + unchar target; /* target ID */ + unchar lun; /* LUN */ + unchar cmd_len; /* command length */ + unchar cmd[12]; /* SCSI command */ + } scsi; } iu; } gdth_iowr_str; @@ -79,6 +89,12 @@ typedef struct { int handle; unchar evt[34]; /* event structure */ } event; + struct { + unchar bus; /* SCSI bus, 0xff: invalid */ + unchar target; /* target ID */ + unchar lun; /* LUN */ + unchar cluster_type; /* cluster properties */ + } hdr_list[35]; /* index is host drive number */ } iu; } gdth_iord_str; diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c index a6c79e7df3d6..aa10802c48c3 100644 --- a/drivers/scsi/gdth_proc.c +++ b/drivers/scsi/gdth_proc.c @@ -1,9 +1,8 @@ /* gdth_proc.c - * $Id: gdth_proc.c,v 1.13 1999/03/22 16:12:53 achim Exp $ + * $Id: gdth_proc.c,v 1.16 1999/11/02 13:44:11 achim Exp $ */ #include "gdth_ioctl.h" -#include int gdth_proc_info(char *buffer,char **start,off_t offset,int length, int hostno,int inout) @@ -41,13 +40,9 @@ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum) memset(&sdev,0,sizeof(Scsi_Device)); memset(&scp, 0,sizeof(Scsi_Cmnd)); - sdev.host = gdth_ctr_vtab[vh]; - sdev.id = sdev.host->this_id; - scp.cmd_len = 12; - scp.host = gdth_ctr_vtab[vh]; - scp.target = sdev.host->this_id; + sdev.host = scp.host = gdth_ctr_vtab[vh]; + sdev.id = scp.target = sdev.host->this_id; scp.device = &sdev; - scp.use_sg = 0; if (length >= 4) { if (strncmp(buffer,"gdth",4) == 0) { @@ -73,6 +68,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) gdth_ha_str *ha; gdth_cmd_str gdtcmd; gdth_cpar_str *pcpar; + char cmnd[12]; TRACE2(("gdth_set_asc_info() ha %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); @@ -80,6 +76,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) drive = -1; wb_mode = 0; found = FALSE; + memset(cmnd, 0xff, 12); if (length >= 5 && strncmp(buffer,"flush",5)==0) { buffer += 6; @@ -106,7 +103,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) gdtcmd.u.cache.DeviceNo = i; gdtcmd.u.cache.BlockNo = 1; gdtcmd.u.cache.sg_canz = 0; - gdth_do_cmd(&scp, &gdtcmd, 30); + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); } } if (!found) @@ -159,7 +156,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) gdtcmd.u.ioctl.subfunc = CACHE_CONFIG; gdtcmd.u.ioctl.channel = INVALID_CHANNEL; pcpar->write_back = wb_mode==1 ? 0:1; - gdth_do_cmd(&scp, &gdtcmd, 30); + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); gdth_ioctl_free(hanum); printk("Done.\n"); return(orig_length); @@ -180,6 +177,8 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) ulong32 *ppadd, add_size; ulong32 *ppadd2, add_size2; ulong flags; + char cmnd[12]; + gdth_cmd_str gdtcmd; TRACE2(("gdth_set_bin_info() ha %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); @@ -188,6 +187,7 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) pcmd = NULL; ppadd = ppadd2 = NULL; add_size = add_size2 = 0; + memset(cmnd, 0xff, 12); if (length < GDTOFFSOF(gdth_iowr_str,iu)) return(-EINVAL); @@ -242,7 +242,7 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) *ppadd2 = virt_to_bus(piord->iu.general.data+add_size); } /* do IOCTL */ - gdth_do_cmd(&scp, pcmd, piowr->timeout); + gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout); piord->status = (ulong32)scp.SCp.Message; break; @@ -363,10 +363,10 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) pevt->event_data.size = sizeof(pevt->event_data.eu.async); gdth_log_event(&pevt->event_data, NULL); } - GDTH_LOCK_HA(ha, flags); + GDTH_LOCK_HA(ha, flags); gdth_store_event(ha, pevt->event_source, pevt->event_idx, &pevt->event_data); - GDTH_UNLOCK_HA(ha, flags); + GDTH_UNLOCK_HA(ha, flags); } else if (piowr->iu.event.erase == 0xfe) { gdth_clear_events(); } else if (piowr->iu.event.erase == 0) { @@ -382,6 +382,58 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) piord->status = S_OK; break; + case GDTIOCTL_SCSI: + if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) )) + return(-EBUSY); + piord = (gdth_iord_str *)ha->pscratch; + piord->size = sizeof(gdth_iord_str); + scp.target = scp.device->id = piowr->iu.scsi.target; + scp.channel = scp.device->channel = piowr->iu.scsi.bus; + memcpy(cmnd, piowr->iu.scsi.cmd, 12); + scp.cmd_len = piowr->iu.scsi.cmd_len; + gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout); + piord->status = (ulong32)scp.result; + break; + + case GDTIOCTL_RESET_BUS: + if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) )) + return(-EBUSY); + piord = (gdth_iord_str *)ha->pscratch; + piord->size = sizeof(gdth_iord_str); + scp.channel = scp.device->channel = piowr->iu.scsi.bus; + piord->status = (ulong32)gdth_eh_bus_reset( &scp ); + break; + + case GDTIOCTL_HDRLIST: + if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) )) + return(-EBUSY); + piord = (gdth_iord_str *)ha->pscratch; + piord->size = sizeof(gdth_iord_str); + piord->status = S_OK; + for (i = 0; i < MAX_HDRIVES; ++i) { + if (ha->hdr[i].present) { + piord->iu.hdr_list[i].bus = ha->virt_bus; + piord->iu.hdr_list[i].target = i; + piord->iu.hdr_list[i].lun = 0; + piord->iu.hdr_list[i].cluster_type = ha->hdr[i].cluster_type; + if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) { + gdtcmd.BoardNode = LOCALBOARD; + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_CLUST_INFO; + gdtcmd.u.cache.DeviceNo = i; + gdtcmd.u.cache.BlockNo = 0; + gdtcmd.u.cache.sg_canz = 0; + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if ((scp.SCp.Message & 0xffff) == S_OK) + piord->iu.hdr_list[i].cluster_type = + (unchar)(scp.SCp.Message>>16); + } + } else { + piord->iu.hdr_list[i].bus = 0xff; + } + } + break; + default: return(-EINVAL); } @@ -404,6 +456,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, gdth_evt_str estr; Scsi_Cmnd scp; Scsi_Device sdev; + char cmnd[12]; char hrec[161]; struct timeval tv; @@ -420,13 +473,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, memset(&sdev,0,sizeof(Scsi_Device)); memset(&scp, 0,sizeof(Scsi_Cmnd)); - sdev.host = gdth_ctr_vtab[vh]; - sdev.id = sdev.host->this_id; - scp.cmd_len = 12; - scp.host = gdth_ctr_vtab[vh]; - scp.target = sdev.host->this_id; + memset(cmnd, 0xff, 12); + sdev.host = scp.host = gdth_ctr_vtab[vh]; + sdev.id = scp.target = sdev.host->this_id; scp.device = &sdev; - scp.use_sg = 0; /* look for buffer ID in length */ if (id > 1) { @@ -514,7 +564,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, /* 2. about physical devices */ size = sprintf(buffer+len,"\nPhysical Devices:"); len += size; pos = begin + len; - flag = FALSE; + flag = FALSE; if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH)) goto stop_output; @@ -536,8 +586,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, sizeof(pds->list[0]); if (pds->entries > cnt) pds->entries = cnt; - gdth_do_cmd(&scp, &gdtcmd, 30); - if (scp.SCp.Message != S_OK) + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if ((scp.SCp.Message & 0xffff) != S_OK) pds->count = 0; TRACE2(("pdr_statistics() entries %d status %d\n", pds->count, scp.SCp.Message)); @@ -556,8 +606,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN; gdtcmd.u.ioctl.channel = ha->raw[i].address | ha->raw[i].id_list[j]; - gdth_do_cmd(&scp, &gdtcmd, 30); - if (scp.SCp.Message == S_OK) { + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if ((scp.SCp.Message & 0xffff) == S_OK) { strncpy(hrec,pdi->vendor,8); strncpy(hrec+8,pdi->product,16); strncpy(hrec+24,pdi->revision,4); @@ -566,7 +616,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, "\n Chn/ID/LUN: \t%c/%02d/%d \tName: \t%s\n", 'A'+i,pdi->target_id,pdi->lun,hrec); len += size; pos = begin + len; - flag = TRUE; + flag = TRUE; pdi->no_ldrive &= 0xffff; if (pdi->no_ldrive == 0xffff) strcpy(hrec,"--"); @@ -607,8 +657,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, gdtcmd.u.ioctl.channel = ha->raw[i].address | ha->raw[i].id_list[j]; pdef->sddc_type = 0x08; - gdth_do_cmd(&scp, &gdtcmd, 30); - if (scp.SCp.Message == S_OK) { + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if ((scp.SCp.Message & 0xffff) == S_OK) { size = sprintf(buffer+len, " Grown Defects:\t%d\n", pdef->sddc_cnt); @@ -619,10 +669,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, } gdth_ioctl_free(hanum); - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; + } if (pos < offset) { len = 0; begin = pos; @@ -633,11 +683,11 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, /* 3. about logical drives */ size = sprintf(buffer+len,"\nLogical Drives:"); len += size; pos = begin + len; - flag = FALSE; + flag = FALSE; if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH)) goto stop_output; - for (i = 0; i < MAX_HDRIVES; ++i) { + for (i = 0; i < MAX_LDRIVES; ++i) { if (!ha->hdr[i].is_logdrv) continue; drv_no = i; @@ -654,8 +704,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str); gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO; gdtcmd.u.ioctl.channel = drv_no; - gdth_do_cmd(&scp, &gdtcmd, 30); - if (scp.SCp.Message != S_OK) + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if ((scp.SCp.Message & 0xffff) != S_OK) break; pcdi->ld_dtype >>= 16; j++; @@ -675,7 +725,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, "\n Number: \t%-2d \tStatus: \t%s\n", drv_no, hrec); len += size; pos = begin + len; - flag = TRUE; + flag = TRUE; no_mdrv = pcdi->cd_ldcnt; if (no_mdrv > 1 || pcdi->ld_slave != -1) { is_mirr = TRUE; @@ -720,10 +770,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, } gdth_ioctl_free(hanum); - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; + } if (pos < offset) { len = 0; begin = pos; @@ -734,11 +784,11 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, /* 4. about array drives */ size = sprintf(buffer+len,"\nArray Drives:"); len += size; pos = begin + len; - flag = FALSE; + flag = FALSE; if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH)) goto stop_output; - for (i = 0; i < MAX_HDRIVES; ++i) { + for (i = 0; i < MAX_LDRIVES; ++i) { if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master)) continue; /* 4.a array drive info */ @@ -751,8 +801,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str); gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN; gdtcmd.u.ioctl.channel = i; - gdth_do_cmd(&scp, &gdtcmd, 30); - if (scp.SCp.Message == S_OK) { + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if ((scp.SCp.Message & 0xffff) == S_OK) { if (pai->ai_state == 0) strcpy(hrec, "idle"); else if (pai->ai_state == 2) @@ -792,10 +842,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, } gdth_ioctl_free(hanum); - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; + } if (pos < offset) { len = 0; begin = pos; @@ -806,11 +856,11 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, /* 5. about host drives */ size = sprintf(buffer+len,"\nHost Drives:"); len += size; pos = begin + len; - flag = FALSE; + flag = FALSE; if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH)) goto stop_output; - for (i = 0; i < MAX_HDRIVES; ++i) { + for (i = 0; i < MAX_LDRIVES; ++i) { if (!ha->hdr[i].is_logdrv || (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master)) continue; @@ -826,15 +876,15 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, gdtcmd.u.ioctl.channel = i; phg->entries = MAX_HDRIVES; phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); - gdth_do_cmd(&scp, &gdtcmd, 30); - if (scp.SCp.Message != S_OK) { + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + if ((scp.SCp.Message & 0xffff) != S_OK) { ha->hdr[i].ldr_no = i; ha->hdr[i].rw_attribs = 0; ha->hdr[i].start_sec = 0; } else { for (j = 0; j < phg->entries; ++j) { k = phg->entry[j].host_drive; - if (k >= MAX_HDRIVES) + if (k >= MAX_LDRIVES) continue; ha->hdr[k].ldr_no = phg->entry[j].log_drive; ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs; @@ -854,7 +904,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, "\n Number: \t%-2d \tArr/Log. Drive:\t%d\n", i, ha->hdr[i].ldr_no); len += size; pos = begin + len; - flag = TRUE; + flag = TRUE; size = sprintf(buffer+len, " Capacity [MB]:\t%-6d \tStart Sector: \t%d\n", @@ -862,10 +912,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, len += size; pos = begin + len; } - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; + } if (pos < offset) { len = 0; begin = pos; @@ -887,7 +937,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, gdth_log_event(&estr.event_data, hrec); do_gettimeofday(&tv); sec = (int)(tv.tv_sec - estr.first_stamp); - if (sec < 0) sec = 0; + if (sec < 0) sec = 0; size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n", sec/3600, sec%3600/60, sec%60, hrec); len += size; pos = begin + len; @@ -929,19 +979,24 @@ stop_output: return(len); } -static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *gdtcmd,int timeout) +static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *gdtcmd, + char *cmnd, int timeout) { - char cmnd[12]; struct semaphore sem = MUTEX_LOCKED; + unsigned bufflen; TRACE2(("gdth_do_cmd()\n")); - memset(cmnd, 0, 12); + if (gdtcmd != NULL) { + scp->SCp.this_residual = IOCTL_PRI; + bufflen = sizeof(gdth_cmd_str); + } else { + scp->SCp.this_residual = DEFAULT_PRI; + bufflen = 0; + } scp->request.rq_status = RQ_SCSI_BUSY; scp->request.sem = &sem; - scp->SCp.this_residual = IOCTL_PRI; GDTH_LOCK_SCSI_DOCMD(); - scsi_do_cmd(scp, cmnd, gdtcmd, sizeof(gdth_cmd_str), - gdth_scsi_done, timeout*HZ, 1); + scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1); GDTH_UNLOCK_SCSI_DOCMD(); down(&sem); } diff --git a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h index 1a6f2d164b78..d559389b7427 100644 --- a/drivers/scsi/gdth_proc.h +++ b/drivers/scsi/gdth_proc.h @@ -2,7 +2,7 @@ #define _GDTH_PROC_H /* gdth_proc.h - * $Id: gdth_proc.h,v 1.6 1999/03/05 14:32:36 achim Exp $ + * $Id: gdth_proc.h,v 1.7 1999/05/26 11:49:32 achim Exp $ */ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum); @@ -18,7 +18,8 @@ static void gdth_stop_timeout(int hanum, int busnum, int id); static void gdth_start_timeout(int hanum, int busnum, int id); static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout); -static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *cmd,int timeout); +static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, + char *cmnd, int timeout); void gdth_scsi_done(Scsi_Cmnd *scp); #endif diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c index 7f91fa4bd8fb..631fac415050 100644 --- a/drivers/scsi/qlogicfc.c +++ b/drivers/scsi/qlogicfc.c @@ -758,7 +758,7 @@ int isp2x00_detect(Scsi_Host_Template * tmpt) hostdata->control_block.firm_opts = 0x0108; hostdata->control_block.max_frame_len = 2048; hostdata->control_block.max_iocb = 256; - hostdata->control_block.exec_throttle = 8; + hostdata->control_block.exec_throttle = QLOGICFC_CMD_PER_LUN; hostdata->control_block.retry_delay = 5; hostdata->control_block.retry_cnt = 1; hostdata->control_block.node_name[0] = 0x0020; @@ -1287,8 +1287,9 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) /* scsi.c expects sense info in a different buffer */ cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->sense_buffer); #if BITS_PER_LONG > 32 - cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer); + cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->sense_buffer); #endif + cmd->dataseg[0].d_count = sizeof(Cmnd->sense_buffer); cmd->segment_cnt = 1; cmd->control_flags = CFLAG_READ; break; diff --git a/drivers/sound/ac97.c b/drivers/sound/ac97.c index bc313134fcad..b54e62f76954 100644 --- a/drivers/sound/ac97.c +++ b/drivers/sound/ac97.c @@ -5,6 +5,10 @@ /* And for stereo. */ #define ST 1 +/* Whether or not the bits in the channel are inverted. */ +#define INV 1 +#define NINV 0 + static struct ac97_chn_desc { int ac97_regnum; int oss_channel; @@ -13,21 +17,22 @@ static struct ac97_chn_desc { int oss_mask; int recordNum; u16 regmask; + int is_inverted; } mixerRegs[] = { - { AC97_MASTER_VOL_STEREO, SOUND_MIXER_VOLUME, 0x3f, ST, SOUND_MASK_VOLUME, 5, 0x0000 }, - { AC97_MASTER_VOL_MONO, SOUND_MIXER_PHONEOUT, 0x3f, MO, SOUND_MASK_PHONEOUT, 6, 0x0000 }, - { AC97_MASTER_TONE, SOUND_MIXER_TREBLE, 0x0f, MO, SOUND_MASK_TREBLE, -1, 0x00ff }, - { AC97_MASTER_TONE, SOUND_MIXER_BASS, 0x0f, MO, SOUND_MASK_BASS, -1, 0xff00 }, - { AC97_PCBEEP_VOL, SOUND_MIXER_SPEAKER, 0x0f, MO, SOUND_MASK_SPEAKER, -1, 0x001e }, - { AC97_PHONE_VOL, SOUND_MIXER_PHONEIN, 0x1f, MO, SOUND_MASK_PHONEIN, 7, 0x0000 }, - { AC97_MIC_VOL, SOUND_MIXER_MIC, 0x1f, MO, SOUND_MASK_MIC, 0, 0x0000 }, - { AC97_LINEIN_VOL, SOUND_MIXER_LINE, 0x1f, ST, SOUND_MASK_LINE, 4, 0x0000 }, - { AC97_CD_VOL, SOUND_MIXER_CD, 0x1f, ST, SOUND_MASK_CD, 1, 0x0000 }, - { AC97_VIDEO_VOL, SOUND_MIXER_VIDEO, 0x1f, ST, SOUND_MASK_VIDEO, 2, 0x0000 }, - { AC97_AUX_VOL, SOUND_MIXER_LINE1, 0x1f, ST, SOUND_MASK_LINE1, 3, 0x0000 }, - { AC97_PCMOUT_VOL, SOUND_MIXER_PCM, 0x1f, ST, SOUND_MASK_PCM, -1, 0x0000 }, - { AC97_RECORD_GAIN, SOUND_MIXER_IGAIN, 0x0f, ST, SOUND_MASK_IGAIN, -1, 0x0000 }, - { -1, -1, 0xff, 0, 0, -1, 0x0000 }, + { AC97_MASTER_VOL_STEREO, SOUND_MIXER_VOLUME, 0x3f, ST, SOUND_MASK_VOLUME, 5, 0x0000, INV }, + { AC97_MASTER_VOL_MONO, SOUND_MIXER_PHONEOUT, 0x3f, MO, SOUND_MASK_PHONEOUT, 6, 0x0000, INV }, + { AC97_MASTER_TONE, SOUND_MIXER_TREBLE, 0x0f, MO, SOUND_MASK_TREBLE, -1, 0x00ff, INV }, + { AC97_MASTER_TONE, SOUND_MIXER_BASS, 0x0f, MO, SOUND_MASK_BASS, -1, 0xff00, INV }, + { AC97_PCBEEP_VOL, SOUND_MIXER_SPEAKER, 0x0f, MO, SOUND_MASK_SPEAKER, -1, 0x001e, INV }, + { AC97_PHONE_VOL, SOUND_MIXER_PHONEIN, 0x1f, MO, SOUND_MASK_PHONEIN, 7, 0x0000, INV }, + { AC97_MIC_VOL, SOUND_MIXER_MIC, 0x1f, MO, SOUND_MASK_MIC, 0, 0x0000, INV }, + { AC97_LINEIN_VOL, SOUND_MIXER_LINE, 0x1f, ST, SOUND_MASK_LINE, 4, 0x0000, INV }, + { AC97_CD_VOL, SOUND_MIXER_CD, 0x1f, ST, SOUND_MASK_CD, 1, 0x0000, INV }, + { AC97_VIDEO_VOL, SOUND_MIXER_VIDEO, 0x1f, ST, SOUND_MASK_VIDEO, 2, 0x0000, INV }, + { AC97_AUX_VOL, SOUND_MIXER_LINE1, 0x1f, ST, SOUND_MASK_LINE1, 3, 0x0000, INV }, + { AC97_PCMOUT_VOL, SOUND_MIXER_PCM, 0x1f, ST, SOUND_MASK_PCM, -1, 0x0000, INV }, + { AC97_RECORD_GAIN, SOUND_MIXER_IGAIN, 0x0f, ST, SOUND_MASK_IGAIN, -1, 0x0000, NINV }, + { -1, -1, 0xff, 0, 0, -1, 0x0000, 0 }, }; static struct ac97_chn_desc * @@ -104,6 +109,25 @@ ac97_init (struct ac97_hwint *dev) return 0; } +/* Reset the mixer to the currently saved settings. */ +int +ac97_reset (struct ac97_hwint *dev) +{ + int x; + + if (dev->reset_device (dev)) + return -1; + + /* Now set the registers back to their last-written values. */ + for (x = 0; mixerRegs[x].ac97_regnum != -1; x++) { + int regnum = mixerRegs[x].ac97_regnum; + int value = dev->last_written_mixer_values [regnum / 2]; + if (value >= 0) + ac97_put_register (dev, regnum, value); + } + return 0; +} + /* Return the contents of register REG; use the cache if the value in it is valid. Returns a negative error code on failure. */ int @@ -156,38 +180,45 @@ ac97_put_register (struct ac97_hwint *dev, u8 reg, u16 value) scaled value on success. */ static int -ac97_scale_to_oss_val (int value, int maxval, int is_stereo) +ac97_scale_to_oss_val (int value, int maxval, int is_stereo, int inv) { /* Muted? */ if (value & AC97_MUTE) return 0; if (is_stereo) - return (ac97_scale_to_oss_val (value & 255, maxval, 0) << 8) - | (ac97_scale_to_oss_val ((value >> 8) & 255, maxval, 0) << 0); + return (ac97_scale_to_oss_val (value & 255, maxval, 0, inv) << 8) + | (ac97_scale_to_oss_val ((value >> 8) & 255, maxval, 0, inv) << 0); else { int i; /* Inverted. */ - value = maxval - value; + if (inv) + value = maxval - value; i = (value * 100 + (maxval / 2)) / maxval; if (i > 100) i = 100; + if (i < 0) + i = 0; return i; } } static int -ac97_scale_from_oss_val (int value, int maxval, int is_stereo) +ac97_scale_from_oss_val (int value, int maxval, int is_stereo, int inv) { if (is_stereo) - return (ac97_scale_from_oss_val (value & 255, maxval, 0) << 8) - | (ac97_scale_from_oss_val ((value >> 8) & 255, maxval, 0) << 0); + return (ac97_scale_from_oss_val (value & 255, maxval, 0, inv) << 8) + | (ac97_scale_from_oss_val ((value >> 8) & 255, maxval, 0, inv) << 0); else { - int i = maxval - ((value & 255) * maxval + 50) / 100; + int i = ((value & 255) * maxval + 50) / 100; + if (inv) + i = maxval - i; if (i < 0) i = 0; + if (i > maxval) + i = maxval; return i; } } @@ -204,7 +235,8 @@ ac97_set_mixer (struct ac97_hwint *dev, int oss_channel, u16 oss_value) if (! ac97_is_valid_channel (dev, channel)) return -ENODEV; scaled_value = ac97_scale_from_oss_val (oss_value, channel->maxval, - channel->is_stereo); + channel->is_stereo, + channel->is_inverted); if (scaled_value < 0) return scaled_value; @@ -253,7 +285,8 @@ ac97_get_mixer_scaled (struct ac97_hwint *dev, int oss_channel) regval >>= 1; } return ac97_scale_to_oss_val (regval, channel->maxval, - channel->is_stereo); + channel->is_stereo, + channel->is_inverted); } int @@ -383,8 +416,9 @@ ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd, caddr_t arg) else ret = -EFAULT; } - if (ret >= 0) { - if (dev->last_written_OSS_values[channel] == AC97_REGVAL_UNKNOWN) + if (ret >= 0 && (dir & _IOC_READ)) { + if (dev->last_written_OSS_values[channel] + == AC97_REGVAL_UNKNOWN) dev->last_written_OSS_values[channel] = ac97_get_mixer_scaled (dev, channel); ret = dev->last_written_OSS_values[channel]; diff --git a/drivers/sound/ac97.h b/drivers/sound/ac97.h index 490d69f88073..e1898584a234 100644 --- a/drivers/sound/ac97.h +++ b/drivers/sound/ac97.h @@ -10,7 +10,7 @@ #include "sound_config.h" #include "sound_calls.h" -#define AC97_RESET 0x0000 // */ +#define AC97_RESET 0x0000 // #define AC97_MASTER_VOL_STEREO 0x0002 // Line Out #define AC97_HEADPHONE_VOL 0x0004 // #define AC97_MASTER_VOL_MONO 0x0006 // TAD Output @@ -46,6 +46,19 @@ #define AC97_RESERVED_3A 0x003A /* Reserved */ /* range 0x3c-0x58 - MODEM */ +/* AC'97 2.0 */ +#define AC97_EXTENDED_ID 0x0028 /* Extended Audio ID */ +#define AC97_EXTENDED_STATUS 0x002A /* Extended Audio Status */ +#define AC97_PCM_FRONT_DAC_RATE 0x002C /* PCM Front DAC Rate */ +#define AC97_PCM_SURR_DAC_RATE 0x002E /* PCM Surround DAC Rate */ +#define AC97_PCM_LFE_DAC_RATE 0x0030 /* PCM LFE DAC Rate */ +#define AC97_PCM_LR_DAC_RATE 0x0032 /* PCM LR DAC Rate */ +#define AC97_PCM_MIC_ADC_RATE 0x0034 /* PCM MIC ADC Rate */ +#define AC97_CENTER_LFE_MASTER 0x0036 /* Center + LFE Master Volume */ +#define AC97_SURROUND_MASTER 0x0038 /* Surround (Rear) Master Volume */ +#define AC97_RESERVED_3A 0x003A /* Reserved */ +/* range 0x3c-0x58 - MODEM */ + /* registers 0x005a - 0x007a are vendor reserved */ #define AC97_VENDOR_ID1 0x007c @@ -207,6 +220,10 @@ extern int ac97_get_mixer_scaled (struct ac97_hwint *dev, int oss_channel); /* Default ioctl. */ extern int ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd, caddr_t arg); + +/* Do a complete reset on the AC97 mixer, restoring all mixer registers to + the current values. Normally used after an APM resume event. */ +extern int ac97_reset (struct ac97_hwint *dev); #endif /* diff --git a/drivers/sound/nm256.h b/drivers/sound/nm256.h index 4cc720ab94f8..e506ab2d7d00 100644 --- a/drivers/sound/nm256.h +++ b/drivers/sound/nm256.h @@ -3,10 +3,12 @@ #include "ac97.h" +/* The revisions that we currently handle. */ enum nm256rev { REV_NM256AV, REV_NM256ZX }; +/* Per-card structure. */ struct nm256_info { /* Magic number used to verify that this struct is valid. */ @@ -34,10 +36,12 @@ struct nm256_info /* The mixer device. */ int mixer_oss_dev; - /* Can only be opened once for each operation. These aren't set - until an actual I/O operation is performed; this allows one - device to be open for read/write without inhibiting I/O to - the other device. */ + /* + * Can only be opened once for each operation. These aren't set + * until an actual I/O operation is performed; this allows one + * device to be open for read/write without inhibiting I/O to + * the other device. + */ int is_open_play; int is_open_record; @@ -46,25 +50,42 @@ struct nm256_info /* Ditto for recording a sample. */ int recording; - /* The two memory ports. */ - char *ports[2]; - - /* Starting offset of the port1 area mapped into memory. */ - u32 port1_start; - /* Ending offset. */ - u32 port1_end; - /* The offset of the end of the actual buffer area. */ - u32 bufend; + /* The two memory ports. */ + struct nm256_ports { + /* Physical address of the port. */ + u32 physaddr; + /* Our mapped-in pointer. */ + char *ptr; + /* PTR's offset within the physical port. */ + u32 start_offset; + /* And the offset of the end of the buffer. */ + u32 end_offset; + } port[2]; /* The following are offsets within memory port 1. */ u32 coeffBuf; u32 allCoeffBuf; + /* Record and playback buffers. */ u32 abuf1, abuf2; /* Offset of the AC97 mixer in memory port 2. */ u32 mixer; + /* Offset of the mixer status register in memory port 2. */ + u32 mixer_status_offset; + + /* Non-zero if we have written initial values to the mixer. */ + u8 mixer_values_init; + + u16 playRingsize; + + /* + * Status mask bit; (*mixer_status_loc & mixer_status_mask) == 0 means + * it's ready. + */ + u16 mixer_status_mask; + /* The sizes of the playback and record ring buffers. */ u32 playbackBufferSize; u32 recordBufferSize; @@ -77,7 +98,7 @@ struct nm256_info /* The start of the block currently playing. */ u32 curPlayPos; - /* The amount of data we requested to record. */ + /* The amount of data we were requested to record. */ u32 requestedRecAmt; /* The offset of the currently-recording block. */ u32 curRecPos; @@ -107,10 +128,17 @@ struct nm256_info /* Debug flag--bigger numbers mean more output. */ extern int nm256_debug; -/* Size of the second memory port. */ +/* The BIOS signature. */ +#define NM_SIGNATURE 0x4e4d0000 +/* Signature mask. */ +#define NM_SIG_MASK 0xffff0000 + +/* Size of the second memory area. */ #define NM_PORT2_SIZE 4096 -/* The location of the mixer. */ -#define NM_MIXER_BASE 0x600 + +/* The base offset of the mixer in the second memory area. */ +#define NM_MIXER_OFFSET 0x600 + /* The maximum size of a coefficient entry. */ #define NM_MAX_COEFFICIENT 0x5000 @@ -123,21 +151,33 @@ extern int nm256_debug; #define NM_MISC_INT_2 0x1 #define NM_ACK_INT(CARD, X) nm256_writePort16((CARD), 2, NM_INT_REG, (X) << 1) -/* For the second revision. It uses the same interrupt register, but it - holds 32 bits instead of 16. */ +/* The AV's "mixer ready" status bit and location. */ +#define NM_MIXER_STATUS_OFFSET 0xa04 +#define NM_MIXER_READY_MASK 0x0800 +#define NM_MIXER_PRESENCE 0xa06 +#define NM_PRESENCE_MASK 0x0050 +#define NM_PRESENCE_VALUE 0x0040 + +/* + * For the ZX. It uses the same interrupt register, but it holds 32 + * bits instead of 16. + */ #define NM2_PLAYBACK_INT 0x10000 #define NM2_RECORD_INT 0x80000 #define NM2_MISC_INT_1 0x8 #define NM2_MISC_INT_2 0x2 #define NM2_ACK_INT(CARD, X) nm256_writePort32((CARD), 2, NM_INT_REG, (X)) +/* The ZX's "mixer ready" status bit and location. */ +#define NM2_MIXER_STATUS_OFFSET 0xa06 +#define NM2_MIXER_READY_MASK 0x0800 + /* The playback registers start from here. */ #define NM_PLAYBACK_REG_OFFSET 0x0 /* The record registers start from here. */ #define NM_RECORD_REG_OFFSET 0x200 -/* The rate register is located 2 bytes from the start of the register - area. */ +/* The rate register is located 2 bytes from the start of the register area. */ #define NM_RATE_REG_OFFSET 2 /* Mono/stereo flag, number of bits on playback, and rate mask. */ @@ -156,7 +196,7 @@ extern int nm256_debug; #define NM_AUDIO_MUTE_LEFT 0x8000 #define NM_AUDIO_MUTE_RIGHT 0x0080 -/* Recording enable register */ +/* Recording enable register. */ #define NM_RECORD_ENABLE_REG (NM_RECORD_REG_OFFSET + 0) #define NM_RECORD_ENABLE_FLAG 1 #define NM_RECORD_FREERUN 2 @@ -179,26 +219,25 @@ extern int nm256_debug; if (port < 1 || port > 2 || card == NULL) \ return -1; \ \ - if (port == 1) { \ - if (offset < card->port1_start || offset >= card->port1_end) { \ - printk (KERN_ERR "Bad port request port 1:0x%x\n", offset); \ - return -1; \ - } \ - offset -= card->port1_start; \ - } else if (offset < 0 || offset > 4096) { \ - printk (KERN_ERR "Bad port request port 2: 0x%x\n", offset); \ - return -1; \ - } + if (offset < card->port[port - 1].start_offset \ + || offset >= card->port[port - 1].end_offset) { \ + printk (KERN_ERR "Bad access: port %d, offset 0x%x\n", port, offset); \ + return -1; \ + } \ + offset -= card->port[port - 1].start_offset; #define DEFwritePortX(X, func) \ static inline int nm256_writePort##X (struct nm256_info *card,\ - int port, int offset, int value)\ + int port, int offset, int value)\ {\ u##X *addr;\ +\ + if (nm256_debug > 1)\ + printk (KERN_DEBUG "Writing 0x%x to %d:0x%x\n", value, port, offset);\ \ NM_FIX_PORT;\ \ - addr = (u##X *)(card->ports[port - 1] + offset);\ + addr = (u##X *)(card->port[port - 1].ptr + offset);\ func (value, addr);\ return 0;\ } @@ -207,29 +246,28 @@ DEFwritePortX (8, writeb) DEFwritePortX (16, writew) DEFwritePortX (32, writel) -#define DEFreadPortX(X) \ +#define DEFreadPortX(X, func) \ static inline u##X nm256_readPort##X (struct nm256_info *card,\ int port, int offset)\ {\ - u##X *addr, res;\ + u##X *addr;\ \ NM_FIX_PORT\ \ - addr = (u##X *)(card->ports[port - 1] + offset);\ - memcpy_fromio (&res, addr, sizeof (res));\ - return res;\ + addr = (u##X *)(card->port[port - 1].ptr + offset);\ + return func(addr);\ } -DEFreadPortX (8) -DEFreadPortX (16) -DEFreadPortX (32) +DEFreadPortX (8, readb) +DEFreadPortX (16, readw) +DEFreadPortX (32, readl) static inline int nm256_writeBuffer8 (struct nm256_info *card, u8 *src, int port, int offset, int amt) { NM_FIX_PORT; - memcpy_toio (card->ports[port - 1] + offset, src, amt); + memcpy_toio (card->port[port - 1].ptr + offset, src, amt); return 0; } @@ -238,7 +276,7 @@ nm256_readBuffer8 (struct nm256_info *card, u8 *dst, int port, int offset, int amt) { NM_FIX_PORT; - memcpy_fromio (dst, card->ports[port - 1] + offset, amt); + memcpy_fromio (dst, card->port[port - 1].ptr + offset, amt); return 0; } diff --git a/drivers/sound/nm256_audio.c b/drivers/sound/nm256_audio.c index 387c44416da9..2c2e76f1d03c 100644 --- a/drivers/sound/nm256_audio.c +++ b/drivers/sound/nm256_audio.c @@ -1,20 +1,23 @@ -/* Audio driver for the NeoMagic 256AV and 256ZX chipsets in native - mode, with AC97 mixer support. - - Overall design and parts of this code stolen from vidc_*.c and - skeleton.c. - - Yeah, there are a lot of magic constants in here. You tell ME what - they are. I just get this stuff psychically, remember? - - This driver was written by someone who wishes to remain anonymous. - It is in the public domain, so share and enjoy. Try to make a profit - off of it; go on, I dare you. */ - +/* + * Audio driver for the NeoMagic 256AV and 256ZX chipsets in native + * mode, with AC97 mixer support. + * + * Overall design and parts of this code stolen from vidc_*.c and + * skeleton.c. + * + * Yeah, there are a lot of magic constants in here. You tell ME what + * they are. I just get this stuff psychically, remember? + * + * This driver was written by someone who wishes to remain anonymous. + * It is in the public domain, so share and enjoy. Try to make a profit + * off of it; go on, I dare you. + */ + #include #include #include #include +#include #include "sound_config.h" #include "soundmodule.h" @@ -22,8 +25,13 @@ #include "nm256_coeff.h" int nm256_debug = 0; +static int force_load = 0; -/* The size of the playback reserve. */ +/* + * The size of the playback reserve. When the playback buffer has less + * than NM256_PLAY_WMARK_SIZE bytes to output, we request a new + * buffer. + */ #define NM256_PLAY_WMARK_SIZE 512 static struct audio_driver nm256_audio_driver; @@ -31,16 +39,74 @@ static struct audio_driver nm256_audio_driver; static int nm256_grabInterrupt (struct nm256_info *card); static int nm256_releaseInterrupt (struct nm256_info *card); static void nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy); -static void nm256_interrupt_zx (int irq, void *dev_id, - struct pt_regs *dummy); +static void nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy); /* These belong in linux/pci.h. */ #define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005 #define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006 +/* eeeew. */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) +#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) +#else +#define RSRCADDRESS(dev,num) ((dev)->base_address[(num)] \ + & PCI_BASE_ADDRESS_MEM_MASK) + +#endif + /* List of cards. */ static struct nm256_info *nmcard_list; +/* Release the mapped-in memory for CARD. */ +static void +nm256_release_ports (struct nm256_info *card) +{ + int x; + + for (x = 0; x < 2; x++) { + if (card->port[x].ptr != NULL) { + u32 size = + card->port[x].end_offset - card->port[x].start_offset; + release_region ((unsigned long) card->port[x].ptr, size); + card->port[x].ptr = NULL; + } + } +} + +/* + * Map in the memory ports for CARD, if they aren't already mapped in + * and have been configured. If successful, a zero value is returned; + * otherwise any previously mapped-in areas are released and a non-zero + * value is returned. + * + * This is invoked twice, once for each port. Ideally it would only be + * called once, but we now need to map in the second port in order to + * check how much memory the card has on the 256ZX. + */ +static int +nm256_remap_ports (struct nm256_info *card) +{ + int x; + + for (x = 0; x < 2; x++) { + if (card->port[x].ptr == NULL && card->port[x].end_offset > 0) { + u32 physaddr + = card->port[x].physaddr + card->port[x].start_offset; + u32 size + = card->port[x].end_offset - card->port[x].start_offset; + + card->port[x].ptr = ioremap_nocache (physaddr, size); + + if (card->port[x].ptr == NULL) { + printk (KERN_ERR "NM256: Unable to remap port %d\n", x + 1); + nm256_release_ports (card); + return -1; + } + } + } + return 0; +} + /* Locate the card in our list. */ static struct nm256_info * nm256_find_card (int dev) @@ -54,8 +120,10 @@ nm256_find_card (int dev) return NULL; } -/* Ditto, but find the card struct corresponding to the mixer device DEV - instead. */ +/* + * Ditto, but find the card struct corresponding to the mixer device DEV + * instead. + */ static struct nm256_info * nm256_find_card_for_mixer (int dev) { @@ -83,11 +151,13 @@ static int samplerates[9] = { 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 }; -/* Set the card samplerate, word size and stereo mode to correspond to - the settings in the CARD struct for the specified device in DEV. - We keep two separate sets of information, one for each device; the - hardware is not actually configured until a read or write is - attempted. */ +/* + * Set the card samplerate, word size and stereo mode to correspond to + * the settings in the CARD struct for the specified device in DEV. + * We keep two separate sets of information, one for each device; the + * hardware is not actually configured until a read or write is + * attempted. + */ int nm256_setInfo (int dev, struct nm256_info *card) @@ -115,24 +185,33 @@ nm256_setInfo (int dev, struct nm256_info *card) break; if (x < 8) { - u8 speedbits = ((x << 4) & NM_RATE_MASK) - | (card->sinfo[w].bits == 16 ? NM_RATE_BITS_16: 0) - | (card->sinfo[w].stereo ? NM_RATE_STEREO : 0); + u8 ratebits = ((x << 4) & NM_RATE_MASK); + if (card->sinfo[w].bits == 16) + ratebits |= NM_RATE_BITS_16; + if (card->sinfo[w].stereo) + ratebits |= NM_RATE_STEREO; card->sinfo[w].samplerate = samplerates[x]; + if (card->dev_for_play == dev && card->playing) { + if (nm256_debug) + printk (KERN_DEBUG "Setting play ratebits to 0x%x\n", + ratebits); nm256_loadCoefficient (card, 0, x); nm256_writePort8 (card, 2, - NM_PLAYBACK_REG_OFFSET + NM_RATE_REG_OFFSET, - speedbits); + NM_PLAYBACK_REG_OFFSET + NM_RATE_REG_OFFSET, + ratebits); } if (card->dev_for_record == dev && card->recording) { + if (nm256_debug) + printk (KERN_DEBUG "Setting record ratebits to 0x%x\n", + ratebits); nm256_loadCoefficient (card, 1, x); - nm256_writePort8 (card, 2, - NM_RECORD_REG_OFFSET + NM_RATE_REG_OFFSET, - speedbits); + nm256_writePort8 (card, 2, + NM_RECORD_REG_OFFSET + NM_RATE_REG_OFFSET, + ratebits); } return 0; } @@ -151,7 +230,7 @@ startPlay (struct nm256_info *card) /* Enable playback engine and interrupts. */ nm256_writePort8 (card, 2, NM_PLAYBACK_ENABLE_REG, - NM_PLAYBACK_ENABLE_FLAG | NM_PLAYBACK_FREERUN); + NM_PLAYBACK_ENABLE_FLAG | NM_PLAYBACK_FREERUN); /* Enable both channels. */ nm256_writePort16 (card, 2, NM_AUDIO_MUTE_REG, 0x0); @@ -159,9 +238,11 @@ startPlay (struct nm256_info *card) } } -/* Request one chunk of AMT bytes from the recording device. When the - operation is complete, the data will be copied into BUFFER and the - function DMAbuf_inputintr will be invoked. */ +/* + * Request one chunk of AMT bytes from the recording device. When the + * operation is complete, the data will be copied into BUFFER and the + * function DMAbuf_inputintr will be invoked. + */ static void nm256_startRecording (struct nm256_info *card, char *buffer, u32 amt) @@ -169,11 +250,14 @@ nm256_startRecording (struct nm256_info *card, char *buffer, u32 amt) u32 endpos; int enableEngine = 0; u32 ringsize = card->recordBufferSize; + unsigned long flags; if (amt > (ringsize / 2)) { - /* Of course this won't actually work right, because the - caller is going to assume we will give what we got asked - for. */ + /* + * Of course this won't actually work right, because the + * caller is going to assume we will give what we got asked + * for. + */ printk (KERN_ERR "NM256: Read request too large: %d\n", amt); amt = ringsize / 2; } @@ -183,8 +267,12 @@ nm256_startRecording (struct nm256_info *card, char *buffer, u32 amt) return; } - /* If we're not currently recording, set up the start and end registers - for the recording engine. */ + save_flags (flags); + cli (); + /* + * If we're not currently recording, set up the start and end registers + * for the recording engine. + */ if (! card->recording) { card->recording = 1; if (nm256_grabInterrupt (card) == 0) { @@ -200,10 +288,16 @@ nm256_startRecording (struct nm256_info *card, char *buffer, u32 amt) } else { /* Not sure what else to do here. */ + restore_flags (flags); return; } } + /* + * If we happen to go past the end of the buffer a bit (due to a + * delayed interrupt) it's OK. So might as well set the watermark + * right at the end of the data we want. + */ endpos = card->abuf2 + ((card->curRecPos + amt) % ringsize); card->recBuf = buffer; @@ -213,6 +307,8 @@ nm256_startRecording (struct nm256_info *card, char *buffer, u32 amt) if (enableEngine) nm256_writePort8 (card, 2, NM_RECORD_ENABLE_REG, NM_RECORD_ENABLE_FLAG | NM_RECORD_FREERUN); + + restore_flags (flags); } /* Stop the play engine. */ @@ -221,7 +317,7 @@ stopPlay (struct nm256_info *card) { /* Shut off sound from both channels. */ nm256_writePort16 (card, 2, NM_AUDIO_MUTE_REG, - NM_AUDIO_MUTE_LEFT | NM_AUDIO_MUTE_RIGHT); + NM_AUDIO_MUTE_LEFT | NM_AUDIO_MUTE_RIGHT); /* Disable play engine. */ nm256_writePort8 (card, 2, NM_PLAYBACK_ENABLE_REG, 0); if (card->playing) { @@ -248,18 +344,22 @@ stopRecord (struct nm256_info *card) } } -/* Ring buffers, man. That's where the hip-hop, wild-n-wooly action's at. - 1972? - - Write AMT bytes of BUFFER to the playback ring buffer, and start the - playback engine running. It will only accept up to 1/2 of the total - size of the ring buffer. */ +/* + * Ring buffers, man. That's where the hip-hop, wild-n-wooly action's at. + * 1972? (Well, I suppose it was cheep-n-easy to implement.) + * + * Write AMT bytes of BUFFER to the playback ring buffer, and start the + * playback engine running. It will only accept up to 1/2 of the total + * size of the ring buffer. No check is made that we're about to overwrite + * the currently-playing sample. + */ static void nm256_write_block (struct nm256_info *card, char *buffer, u32 amt) { u32 ringsize = card->playbackBufferSize; u32 endstop; + unsigned long flags; if (amt > (ringsize / 2)) { printk (KERN_ERR "NM256: Write request too large: %d\n", amt); @@ -275,48 +375,58 @@ nm256_write_block (struct nm256_info *card, char *buffer, u32 amt) card->requested_amt = amt; + save_flags (flags); + cli (); + if ((card->curPlayPos + amt) >= ringsize) { u32 rem = ringsize - card->curPlayPos; nm256_writeBuffer8 (card, buffer, 1, - card->abuf1 + card->curPlayPos, - rem); + card->abuf1 + card->curPlayPos, + rem); if (amt > rem) - nm256_writeBuffer8 (card, buffer, 1, card->abuf1, - amt - rem); + nm256_writeBuffer8 (card, buffer + rem, 1, card->abuf1, + amt - rem); } else nm256_writeBuffer8 (card, buffer, 1, card->abuf1 + card->curPlayPos, amt); - /* Setup the start-n-stop-n-limit registers, and start that engine - goin'. - - Normally we just let it wrap around to avoid the click-click - action scene. */ + /* + * Setup the start-n-stop-n-limit registers, and start that engine + * goin'. + * + * Normally we just let it wrap around to avoid the click-click + * action scene. + */ if (! card->playing) { - /* The PBUFFER_END register in this case points to one "word" + /* The PBUFFER_END register in this case points to one sample before the end of the buffer. */ int w = (card->dev_for_play == card->dev[0] ? 0 : 1); - int wordsize = (card->sinfo[w].bits == 16 ? 2 : 1) - * (card->sinfo[w].stereo ? 2 : 1); + int sampsize = (card->sinfo[w].bits == 16 ? 2 : 1); + + if (card->sinfo[w].stereo) + sampsize *= 2; /* Need to set the not-normally-changing-registers up. */ nm256_writePort32 (card, 2, NM_PBUFFER_START, card->abuf1 + card->curPlayPos); nm256_writePort32 (card, 2, NM_PBUFFER_END, - card->abuf1 + ringsize - wordsize); + card->abuf1 + ringsize - sampsize); nm256_writePort32 (card, 2, NM_PBUFFER_CURRP, card->abuf1 + card->curPlayPos); } endstop = (card->curPlayPos + amt - NM256_PLAY_WMARK_SIZE) % ringsize; nm256_writePort32 (card, 2, NM_PBUFFER_WMARK, card->abuf1 + endstop); + if (! card->playing) startPlay (card); + + restore_flags (flags); } -/* We just got a card playback interrupt; process it. */ +/* We just got a card playback interrupt; process it. */ static void nm256_get_new_block (struct nm256_info *card) { @@ -334,13 +444,14 @@ nm256_get_new_block (struct nm256_info *card) amt -= card->curPlayPos; if (card->requested_amt > (amt + NM256_PLAY_WMARK_SIZE)) { - u32 endstop = + u32 endstop = card->curPlayPos + card->requested_amt - NM256_PLAY_WMARK_SIZE; nm256_writePort32 (card, 2, NM_PBUFFER_WMARK, card->abuf1 + endstop); - } else { + } + else { card->curPlayPos += card->requested_amt; /* Get a new block to write. This will eventually invoke - nm256_write_block (). */ + nm256_write_block () or stopPlay (). */ DMAbuf_outputintr (card->dev_for_play, 1); } } @@ -348,9 +459,11 @@ nm256_get_new_block (struct nm256_info *card) /* Ultra cheez-whiz. But I'm too lazy to grep headers. */ #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) -/* Read the last-recorded block from the ring buffer, copy it into the - saved buffer pointer, and invoke DMAuf_inputintr() with the recording - device. */ +/* + * Read the last-recorded block from the ring buffer, copy it into the + * saved buffer pointer, and invoke DMAuf_inputintr() with the recording + * device. + */ static void nm256_read_block (struct nm256_info *card) @@ -365,8 +478,10 @@ nm256_read_block (struct nm256_info *card) currptr = 0; } - /* This test is probably redundant; we shouldn't be here unless - it's true. */ + /* + * This test is probably redundant; we shouldn't be here unless + * it's true. + */ if (card->recording) { /* If we wrapped around, copy everything from the start of our recording buffer to the end of the buffer. */ @@ -396,52 +511,28 @@ nm256_read_block (struct nm256_info *card) } #undef MIN -/* Initialize the hardware and various other card data we'll need - later. */ +/* + * Initialize the hardware. + */ static void nm256_initHw (struct nm256_info *card) { - int x; - - card->playbackBufferSize = 16384; - card->recordBufferSize = 16384; - - card->coeffBuf = card->bufend - NM_MAX_COEFFICIENT; - card->abuf2 = card->coeffBuf - card->recordBufferSize; - card->abuf1 = card->abuf2 - card->playbackBufferSize; - card->allCoeffBuf = card->abuf2 - (NM_TOTAL_COEFF_COUNT * 4); - - /* Fixed setting. */ - card->mixer = NM_MIXER_BASE; - - card->playing = 0; - card->is_open_play = 0; - card->curPlayPos = 0; - - card->recording = 0; - card->is_open_record = 0; - card->curRecPos = 0; - - card->coeffsCurrent = 0; - - card->opencnt[0] = 0; card->opencnt[1] = 0; - /* Reset everything. */ - nm256_writePort8 (card, 2, 0, 0x11); - - /* Disable recording. */ - nm256_writePort8 (card, 2, NM_RECORD_ENABLE_REG, 0); + nm256_writePort8 (card, 2, 0x0, 0x11); nm256_writePort16 (card, 2, 0x214, 0); - /* Reasonable default settings, but largely unnecessary. */ - for (x = 0; x < 2; x++) { - card->sinfo[x].bits = 8; - card->sinfo[x].stereo = 0; - card->sinfo[x].samplerate = 8000; - } + stopRecord (card); + stopPlay (card); } -/* Handle a potential interrupt for the device referred to by DEV_ID. */ +/* + * Handle a potential interrupt for the device referred to by DEV_ID. + * + * I don't like the cut-n-paste job here either between the two routines, + * but there are sufficient differences between the two interrupt handlers + * that parameterizing it isn't all that great either. (Could use a macro, + * I suppose...yucky bleah.) + */ static void nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy) @@ -460,14 +551,32 @@ nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy) /* Not ours. */ if (status == 0) { if (badintrcount++ > 1000) { - printk (KERN_ERR "NM256: Releasing interrupt, over 1000 invalid interrupts\n"); - nm256_releaseInterrupt (card); + /* + * I'm not sure if the best thing is to stop the card from + * playing or just release the interrupt (after all, we're in + * a bad situation, so doing fancy stuff may not be such a good + * idea). + * + * I worry about the card engine continuing to play noise + * over and over, however--that could become a very + * obnoxious problem. And we know that when this usually + * happens things are fairly safe, it just means the user's + * inserted a PCMCIA card and someone's spamming us with IRQ 9s. + */ + + if (card->playing) + stopPlay (card); + if (card->recording) + stopRecord (card); + badintrcount = 0; } return; } badintrcount = 0; + /* Rather boring; check for individual interrupts and process them. */ + if (status & NM_PLAYBACK_INT) { status &= ~NM_PLAYBACK_INT; NM_ACK_INT (card, NM_PLAYBACK_INT); @@ -505,6 +614,7 @@ nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy) nm256_writePort8 (card, 2, 0x400, cbyte & ~2); } + /* Unknown interrupt. */ if (status) { printk (KERN_ERR "NM256: Fire in the hole! Unknown status 0x%x\n", status); @@ -513,8 +623,11 @@ nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy) } } -/* Handle a potential interrupt for the device referred to by DEV_ID. - This handler is for the 256ZX. */ +/* + * Handle a potential interrupt for the device referred to by DEV_ID. + * This handler is for the 256ZX, and is very similar to the non-ZX + * routine. + */ static void nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy) @@ -534,13 +647,33 @@ nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy) if (status == 0) { if (badintrcount++ > 1000) { printk (KERN_ERR "NM256: Releasing interrupt, over 1000 invalid interrupts\n"); - nm256_releaseInterrupt (card); + /* + * I'm not sure if the best thing is to stop the card from + * playing or just release the interrupt (after all, we're in + * a bad situation, so doing fancy stuff may not be such a good + * idea). + * + * I worry about the card engine continuing to play noise + * over and over, however--that could become a very + * obnoxious problem. And we know that when this usually + * happens things are fairly safe, it just means the user's + * inserted a PCMCIA card and someone's spamming us with + * IRQ 9s. + */ + + if (card->playing) + stopPlay (card); + if (card->recording) + stopRecord (card); + badintrcount = 0; } return; } badintrcount = 0; + /* Rather boring; check for individual interrupts and process them. */ + if (status & NM2_PLAYBACK_INT) { status &= ~NM2_PLAYBACK_INT; NM2_ACK_INT (card, NM2_PLAYBACK_INT); @@ -577,6 +710,7 @@ nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy) nm256_writePort8 (card, 2, 0x400, cbyte & ~2); } + /* Unknown interrupt. */ if (status) { printk (KERN_ERR "NM256: Fire in the hole! Unknown status 0x%x\n", status); @@ -585,7 +719,9 @@ nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy) } } -/* Request our interrupt. */ +/* + * Request our interrupt. + */ static int nm256_grabInterrupt (struct nm256_info *card) { @@ -599,7 +735,9 @@ nm256_grabInterrupt (struct nm256_info *card) return 0; } -/* Release our interrupt. */ +/* + * Release our interrupt. + */ static int nm256_releaseInterrupt (struct nm256_info *card) { @@ -614,6 +752,11 @@ nm256_releaseInterrupt (struct nm256_info *card) return 0; } +/* + * Waits for the mixer to become ready to be written; returns a zero value + * if it timed out. + */ + static int nm256_isReady (struct ac97_hwint *dev) { @@ -628,26 +771,25 @@ nm256_isReady (struct ac97_hwint *dev) return 0; } - if (card->rev == REV_NM256AV) { - testaddr = 0xa06; - testb = 0x0100; - } else if (card->rev == REV_NM256ZX) { - testaddr = 0xa08; - testb = 0x0800; - } else { - return -1; - } + testaddr = card->mixer_status_offset; + testb = card->mixer_status_mask; - while (t2-- > 0) { - if ((nm256_readPort16 (card, 2, testaddr) & testb) == 0) { + /* + * Loop around waiting for the mixer to become ready. + */ + while (! done && t2-- > 0) { + if ((nm256_readPort16 (card, 2, testaddr) & testb) == 0) done = 1; - break; - } - udelay (100); + else + udelay (100); } return done; } +/* + * Return the contents of the AC97 mixer register REG. Returns a positive + * value if successful, or a negative error code. + */ static int nm256_readAC97Reg (struct ac97_hwint *dev, u8 reg) { @@ -663,6 +805,7 @@ nm256_readAC97Reg (struct ac97_hwint *dev, u8 reg) nm256_isReady (dev); res = nm256_readPort16 (card, 2, card->mixer + reg); + /* Magic delay. Bleah yucky. */ udelay (1000); return res; } @@ -670,6 +813,10 @@ nm256_readAC97Reg (struct ac97_hwint *dev, u8 reg) return -EINVAL; } +/* + * Writes VALUE to AC97 mixer register REG. Returns 0 if successful, or + * a negative error code. + */ static int nm256_writeAC97Reg (struct ac97_hwint *dev, u8 reg, u16 value) { @@ -708,6 +855,13 @@ nm256_writeAC97Reg (struct ac97_hwint *dev, u8 reg, u16 value) return ! done; } +/* + * Initial register values to be written to the AC97 mixer. + * While most of these are identical to the reset values, we do this + * so that we have most of the register contents cached--this avoids + * reading from the mixer directly (which seems to be problematic, + * probably due to ignorance). + */ struct initialValues { unsigned short port; @@ -716,23 +870,24 @@ struct initialValues static struct initialValues nm256_ac97_initial_values[] = { - { 0x0002, 0x8000 }, - { 0x0004, 0x0000 }, - { 0x0006, 0x0000 }, - { 0x000A, 0x0000 }, - { 0x000C, 0x0008 }, - { 0x000E, 0x8008 }, - { 0x0010, 0x8808 }, - { 0x0012, 0x8808 }, - { 0x0014, 0x8808 }, - { 0x0016, 0x8808 }, - { 0x0018, 0x0808 }, - { 0x001A, 0x0000 }, - { 0x001C, 0x0B0B }, - { 0x0020, 0x0000 }, + { AC97_MASTER_VOL_STEREO, 0x8000 }, + { AC97_HEADPHONE_VOL, 0x8000 }, + { AC97_MASTER_VOL_MONO, 0x0000 }, + { AC97_PCBEEP_VOL, 0x0000 }, + { AC97_PHONE_VOL, 0x0008 }, + { AC97_MIC_VOL, 0x8000 }, + { AC97_LINEIN_VOL, 0x8808 }, + { AC97_CD_VOL, 0x8808 }, + { AC97_VIDEO_VOL, 0x8808 }, + { AC97_AUX_VOL, 0x8808 }, + { AC97_PCMOUT_VOL, 0x0808 }, + { AC97_RECORD_SELECT, 0x0000 }, + { AC97_RECORD_GAIN, 0x0B0B }, + { AC97_GENERAL_PURPOSE, 0x0000 }, { 0xffff, 0xffff } }; +/* Initialize the AC97 into a known state. */ static int nm256_resetAC97 (struct ac97_hwint *dev) { @@ -744,22 +899,28 @@ nm256_resetAC97 (struct ac97_hwint *dev) return -EINVAL; } - /* Reset the card. 'Tis magic! */ + /* Reset the mixer. 'Tis magic! */ nm256_writePort8 (card, 2, 0x6c0, 1); nm256_writePort8 (card, 2, 0x6cc, 0x87); nm256_writePort8 (card, 2, 0x6cc, 0x80); nm256_writePort8 (card, 2, 0x6cc, 0x0); - for (x = 0; nm256_ac97_initial_values[x].port != 0xffff; x++) { - ac97_put_register (dev, - nm256_ac97_initial_values[x].port, - nm256_ac97_initial_values[x].value); + if (! card->mixer_values_init) { + for (x = 0; nm256_ac97_initial_values[x].port != 0xffff; x++) { + ac97_put_register (dev, + nm256_ac97_initial_values[x].port, + nm256_ac97_initial_values[x].value); + card->mixer_values_init = 1; + } } return 0; } -/* We don't do anything special here. */ +/* + * We don't do anything particularly special here; it just passes the + * mixer ioctl to the AC97 driver. + */ static int nm256_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) { @@ -776,7 +937,12 @@ static struct mixer_operations nm256_mixer_operations = { nm256_default_mixer_ioctl }; -/* I "love" C sometimes. Got braces? */ +/* + * Default settings for the OSS mixer. These are set last, after the + * mixer is initialized. + * + * I "love" C sometimes. Got braces? + */ static struct ac97_mixer_value_list mixer_defaults[] = { { SOUND_MIXER_VOLUME, { { 85, 85 } } }, { SOUND_MIXER_SPEAKER, { { 100 } } }, @@ -785,6 +951,8 @@ static struct ac97_mixer_value_list mixer_defaults[] = { { -1, { { 0, 0 } } } }; + +/* Installs the AC97 mixer into CARD. */ static int nm256_install_mixer (struct nm256_info *card) { @@ -814,36 +982,67 @@ nm256_install_mixer (struct nm256_info *card) return 0; } -/* See if the signature left by the NM256 BIOS is intact; if so, we use - the associated address as the end of our buffer. */ +/* Perform a full reset on the hardware; this is invoked when an APM + resume event occurs. */ static void -nm256_peek_for_sig (struct nm256_info *card, u32 port1addr) +nm256_full_reset (struct nm256_info *card) { - char *temp = ioremap_nocache (port1addr + card->port1_end - 0x0400, 16); + nm256_initHw (card); + ac97_reset (&(card->mdev)); +} + +/* + * See if the signature left by the NM256 BIOS is intact; if so, we use + * the associated address as the end of our audio buffer in the video + * RAM. + */ + +static void +nm256_peek_for_sig (struct nm256_info *card) +{ + u32 port1offset + = card->port[0].physaddr + card->port[0].end_offset - 0x0400; + /* The signature is located 1K below the end of video RAM. */ + char *temp = ioremap_nocache (port1offset, 16); + /* Default buffer end is 5120 bytes below the top of RAM. */ + u32 default_value = card->port[0].end_offset - 0x1400; u32 sig; + /* Install the default value first, so we don't have to repeatedly + do it if there is a problem. */ + card->port[0].end_offset = default_value; + if (temp == NULL) { printk (KERN_ERR "NM256: Unable to scan for card signature in video RAM\n"); return; } - memcpy_fromio (&sig, temp, sizeof (u32)); - if ((sig & 0xffff0000) == 0x4e4d0000) { - memcpy_fromio (&(card->bufend), temp + 4, sizeof (u32)); + sig = readl (temp); + if ((sig & NM_SIG_MASK) == NM_SIGNATURE) { + u32 pointer = readl (temp + 4); + + /* + * If it's obviously invalid, don't use it (the port already has a + * suitable default value set). + */ + if (pointer != 0xffffffff) + card->port[0].end_offset = pointer; + printk (KERN_INFO "NM256: Found card signature in video RAM: 0x%x\n", - card->bufend); + pointer); } release_region ((unsigned long) temp, 16); } -/* Install a driver for the soundcard referenced by PCIDEV. */ +/* + * Install a driver for the PCI device referenced by PCIDEV. + * VERSTR is a human-readable version string. + */ static int nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr) { struct nm256_info *card; - u32 port1addr = (pcidev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK); - u32 port2addr = (pcidev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK); int x; card = kmalloc (sizeof (struct nm256_info), GFP_KERNEL); @@ -857,52 +1056,85 @@ nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr) card->recording = 0; card->rev = rev; - /* The NM256 has two memory ports. The first port is nothing - more than a chunk of video RAM, which is used as the I/O ring - buffer. The second port has the actual juicy stuff (like the - mixer and the playback engine control registers). */ + /* Init the memory port info. */ + for (x = 0; x < 2; x++) { + card->port[x].physaddr = RSRCADDRESS (pcidev, x); + card->port[x].ptr = NULL; + card->port[x].start_offset = 0; + card->port[x].end_offset = 0; + } - card->ports[1] = ioremap_nocache (port2addr, NM_PORT2_SIZE); + /* Port 2 is easy. */ + card->port[1].start_offset = 0; + card->port[1].end_offset = NM_PORT2_SIZE; - if (card->ports[1] == NULL) { - printk (KERN_ERR "NM256: Unable to remap port 2\n"); + /* Yuck. But we have to map in port 2 so we can check how much RAM the + card has. */ + if (nm256_remap_ports (card)) { kfree_s (card, sizeof (struct nm256_info)); return 0; } + /* + * The NM256 has two memory ports. The first port is nothing + * more than a chunk of video RAM, which is used as the I/O ring + * buffer. The second port has the actual juicy stuff (like the + * mixer and the playback engine control registers). + */ + if (card->rev == REV_NM256AV) { - card->port1_end = 2560 * 1024; + /* Ok, try to see if this is a non-AC97 version of the hardware. */ + int pval = nm256_readPort16 (card, 2, NM_MIXER_PRESENCE); + if ((pval & NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) { + if (! force_load) { + printk (KERN_ERR "NM256: This doesn't look to me like the AC97-compatible version.\n"); + printk (KERN_ERR " You can force the driver to load by passing in the module\n"); + printk (KERN_ERR " parameter:\n"); + printk (KERN_ERR " force_ac97 = 1\n"); + printk (KERN_ERR "\n"); + printk (KERN_ERR " More likely, you should be using the appropriate SB-16 or\n"); + printk (KERN_ERR " CS4232 driver instead. (If your BIOS has settings for\n"); + printk (KERN_ERR " IRQ and/or DMA for the sound card, this is *not* the correct\n"); + printk (KERN_ERR " driver to use.)\n"); + nm256_release_ports (card); + kfree_s (card, sizeof (struct nm256_info)); + return 0; + } + else { + printk (KERN_INFO "NM256: Forcing driver load as per user request.\n"); + } + } + else { + printk (KERN_INFO "NM256: Congratulations. You're not running Eunice.\n"); + } + card->port[0].end_offset = 2560 * 1024; card->introutine = nm256_interrupt; + card->mixer_status_offset = NM_MIXER_STATUS_OFFSET; + card->mixer_status_mask = NM_MIXER_READY_MASK; } else { + /* Not sure if there is any relevant detect for the ZX or not. */ if (nm256_readPort8 (card, 2, 0xa0b) != 0) - card->port1_end = 6144 * 1024; + card->port[0].end_offset = 6144 * 1024; else - card->port1_end = 4096 * 1024; + card->port[0].end_offset = 4096 * 1024; card->introutine = nm256_interrupt_zx; + card->mixer_status_offset = NM2_MIXER_STATUS_OFFSET; + card->mixer_status_mask = NM2_MIXER_READY_MASK; } - /* Default value. */ - card->bufend = card->port1_end - 0x1400; - - if (buffertop >= 98304 && buffertop < card->port1_end) - card->bufend = buffertop; + if (buffertop >= 98304 && buffertop < card->port[0].end_offset) + card->port[0].end_offset = buffertop; else - nm256_peek_for_sig (card, port1addr); + nm256_peek_for_sig (card); - card->port1_start = card->bufend - 98304; + card->port[0].start_offset = card->port[0].end_offset - 98304; printk (KERN_INFO "NM256: Mapping port 1 from 0x%x - 0x%x\n", - card->port1_start, card->port1_end); - - card->ports[0] = - ioremap_nocache (port1addr + card->port1_start, - card->port1_end - card->port1_start); + card->port[0].start_offset, card->port[0].end_offset); - if (card->ports[0] == NULL) { - printk (KERN_ERR "NM256: Unable to remap port 1\n"); - release_region ((unsigned long) card->ports[1], NM_PORT2_SIZE); + if (nm256_remap_ports (card)) { kfree_s (card, sizeof (struct nm256_info)); return 0; } @@ -913,9 +1145,7 @@ nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr) card->has_irq = 0; if (nm256_grabInterrupt (card) != 0) { - release_region ((unsigned long) card->ports[0], - card->port1_end - card->port1_start); - release_region ((unsigned long) card->ports[1], NM_PORT2_SIZE); + nm256_release_ports (card); kfree_s (card, sizeof (struct nm256_info)); return 0; } @@ -926,10 +1156,36 @@ nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr) * Init the board. */ + card->playbackBufferSize = 16384; + card->recordBufferSize = 16384; + + card->coeffBuf = card->port[0].end_offset - NM_MAX_COEFFICIENT; + card->abuf2 = card->coeffBuf - card->recordBufferSize; + card->abuf1 = card->abuf2 - card->playbackBufferSize; + card->allCoeffBuf = card->abuf2 - (NM_TOTAL_COEFF_COUNT * 4); + + /* Fixed setting. */ + card->mixer = NM_MIXER_OFFSET; + card->mixer_values_init = 0; + + card->is_open_play = 0; + card->is_open_record = 0; + + card->coeffsCurrent = 0; + + card->opencnt[0] = 0; card->opencnt[1] = 0; + + /* Reasonable default settings, but largely unnecessary. */ + for (x = 0; x < 2; x++) { + card->sinfo[x].bits = 8; + card->sinfo[x].stereo = 0; + card->sinfo[x].samplerate = 8000; + } + nm256_initHw (card); for (x = 0; x < 2; x++) { - if ((card->dev[x] = + if ((card->dev[x] = sound_install_audiodrv(AUDIO_DRIVER_VERSION, "NM256", &nm256_audio_driver, sizeof(struct audio_driver), @@ -942,9 +1198,7 @@ nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr) } else { printk(KERN_ERR "NM256: Too many PCM devices available\n"); - release_region ((unsigned long) card->ports[0], - card->port1_end - card->port1_start); - release_region ((unsigned long) card->ports[1], NM_PORT2_SIZE); + nm256_release_ports (card); kfree_s (card, sizeof (struct nm256_info)); return 0; } @@ -966,6 +1220,48 @@ nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr) return 1; } + +#ifdef CONFIG_APM +/* + * APM event handler, so the card is properly reinitialized after a power + * event. + */ +static int +handle_apm_event (apm_event_t event) +{ + static int down = 0; + + switch (event) + { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + down++; + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + if (down) + { + struct nm256_info *crd; + + down = 0; + for (crd = nmcard_list; crd != NULL; crd = crd->next_card) + { + int playing = crd->playing; + nm256_full_reset (crd); + /* + * A little ugly, but that's ok; pretend the + * block we were playing is done. + */ + if (playing) + DMAbuf_outputintr (crd->dev_for_play, 1); + } + } + break; + } + return 0; +} +#endif + /* * This loop walks the PCI configuration database and finds where * the sound cards are. @@ -995,6 +1291,10 @@ init_nm256(void) if (count == 0) return -ENODEV; +#ifdef CONFIG_APM + apm_register_callback (&handle_apm_event); +#endif + printk (KERN_INFO "Done installing NM256 audio driver.\n"); return 0; } @@ -1030,10 +1330,13 @@ nm256_audio_open(int dev, int mode) if (! ((mode & OPEN_READ) || (mode & OPEN_WRITE))) return -EIO; - /* If it's open for both read and write, and the card's currently - being read or written to, then do the opposite of what has - already been done. Otherwise, don't specify any mode until the - user actually tries to do I/O. */ + /* + * If it's open for both read and write, and the card's currently + * being read or written to, then do the opposite of what has + * already been done. Otherwise, don't specify any mode until the + * user actually tries to do I/O. (Some programs open the device + * for both read and write, but only actually do reading or writing.) + */ if ((mode & OPEN_WRITE) && (mode & OPEN_READ)) { if (card->is_open_play) @@ -1107,6 +1410,7 @@ nm256_audio_close(int dev) } } +/* Standard ioctl handler. */ static int nm256_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) { @@ -1124,6 +1428,11 @@ nm256_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) else w = 1; + /* + * The code here is messy. There are probably better ways to do + * it. (It should be possible to handle it the same way the AC97 mixer + * is done.) + */ switch (cmd) { case SOUND_PCM_WRITE_RATE: @@ -1195,8 +1504,12 @@ nm256_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) return put_user(ret, (int *) arg); } -/* Given the dev DEV and an associated physical buffer PHYSBUF, return - a pointer to the actual buffer in kernel space. */ +/* + * Given the sound device DEV and an associated physical buffer PHYSBUF, + * return a pointer to the actual buffer in kernel space. + * + * This routine should exist as part of the soundcore routines. + */ static char * nm256_getDMAbuffer (int dev, unsigned long physbuf) @@ -1240,9 +1553,10 @@ nm256_audio_output_block(int dev, unsigned long physbuf, } } +/* Ditto, but do recording instead. */ static void nm256_audio_start_input(int dev, unsigned long physbuf, int count, - int intrflag) + int intrflag) { struct nm256_info *card = nm256_find_card (dev); @@ -1254,6 +1568,12 @@ nm256_audio_start_input(int dev, unsigned long physbuf, int count, } } +/* + * Prepare for inputting samples to DEV. + * Each requested buffer will be BSIZE byes long, with a total of + * BCOUNT buffers. + */ + static int nm256_audio_prepare_for_input(int dev, int bsize, int bcount) { @@ -1280,6 +1600,7 @@ nm256_audio_prepare_for_input(int dev, int bsize, int bcount) * 2. We get a write buffer without dma_mode setup (dmabuf.c:1152) * 3. We restart a transfer (dmabuf.c:1324) */ + static int nm256_audio_prepare_for_output(int dev, int bsize, int bcount) { @@ -1344,12 +1665,13 @@ static int loaded = 0; MODULE_PARM (usecache, "i"); MODULE_PARM (buffertop, "i"); MODULE_PARM (nm256_debug, "i"); +MODULE_PARM (force_load, "i"); int init_module (void) { nmcard_list = NULL; - printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.0\n"); + printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1\n"); if (init_nm256 () == 0) { SOUND_LOCK; @@ -1374,9 +1696,7 @@ cleanup_module (void) stopRecord (card); if (card->has_irq) free_irq (card->irq, card); - release_region ((unsigned long) card->ports[0], - card->port1_end - card->port1_start); - release_region ((unsigned long) card->ports[1], NM_PORT2_SIZE); + nm256_release_ports (card); sound_unload_mixerdev (card->mixer_oss_dev); sound_unload_audiodev (card->dev[0]); sound_unload_audiodev (card->dev[1]); @@ -1385,6 +1705,9 @@ cleanup_module (void) } nmcard_list = NULL; } +#ifdef CONFIG_APM + apm_unregister_callback (&handle_apm_event); +#endif } #endif diff --git a/drivers/sound/nm256_coeff.h b/drivers/sound/nm256_coeff.h index c8fc7ecbe6c8..0ceecc20077b 100644 --- a/drivers/sound/nm256_coeff.h +++ b/drivers/sound/nm256_coeff.h @@ -4622,7 +4622,8 @@ nm256_getStartOffset (u8 which) } static void -nm256_loadOneCoefficient (struct nm256_info *card, u32 port, u16 which) +nm256_loadOneCoefficient (struct nm256_info *card, int devnum, u32 port, + u16 which) { u32 coeffBuf = (which < 8) ? card->coeffBuf : card->allCoeffBuf; u16 offset = nm256_getStartOffset (which); @@ -4631,11 +4632,14 @@ nm256_loadOneCoefficient (struct nm256_info *card, u32 port, u16 which) card->coeffsCurrent = 0; if (nm256_debug) - printk (KERN_INFO "NM256: Loading coefficient buffer 0x%x-0x%x with coefficient %d\n", - coeffBuf, coeffBuf + size - 1, which); + printk (KERN_INFO "NM256: Loading coefficient buffer 0x%x-0x%x with coefficient %d, size %d, port 0x%x\n", + coeffBuf, coeffBuf + size - 1, which, size, port); nm256_writeBuffer8 (card, coefficients + offset, 1, coeffBuf, size); nm256_writePort32 (card, 2, port + 0, coeffBuf); - nm256_writePort32 (card, 2, port + 4, coeffBuf + size - 1); + /* ??? Record seems to behave differently than playback. */ + if (devnum == 0) + size--; + nm256_writePort32 (card, 2, port + 4, coeffBuf + size); } static void @@ -4663,7 +4667,7 @@ nm256_loadCoefficient (struct nm256_info *card, int which, int number) number += 8; if (! nm256_cachedCoefficients (card)) - nm256_loadOneCoefficient (card, addrs[which], number); + nm256_loadOneCoefficient (card, which, addrs[which], number); else { u32 base = card->allCoeffBuf; u32 offset = nm256_getStartOffset (number); diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index 6c8814567ab2..92270e3c9683 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c @@ -166,7 +166,7 @@ void adfs_read_inode (struct inode *inode) sb = inode->i_sb; inode->i_uid = sb->u.adfs_sb.s_uid; inode->i_gid = sb->u.adfs_sb.s_gid; - inode->i_version = ++event; + inode->i_version = ++global_event; if (adfs_inode_validate_no (sb, inode->i_ino & 0xffffff00)) { adfs_error (sb, "adfs_read_inode", diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 9b05ec062ae1..39fe0e6f0960 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -379,13 +379,13 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode, FILE_END(link_bh->b_data,link)->link_chain; FILE_END(link_bh->b_data,link)->link_chain = cpu_to_be32(inode->i_ino); affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5); - link->i_version = ++event; + link->i_version = ++global_event; mark_inode_dirty(link); mark_buffer_dirty(link_bh,1); } affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5); affs_fix_checksum(AFFS_I2BSIZE(dir),dir_bh->b_data,5); - dir->i_version = ++event; + dir->i_version = ++global_event; dir->i_mtime = dir->i_atime = dir->i_ctime = CURRENT_TIME; unlock_super(inode->i_sb); diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 48e95180000f..e823f2eb50aa 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -247,7 +247,7 @@ affs_unlink(struct inode *dir, struct dentry *dentry) inode->i_nlink = retval; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; - dir->i_version = ++event; + dir->i_version = ++global_event; mark_inode_dirty(inode); d_delete(dentry); mark_inode_dirty(dir); @@ -285,7 +285,7 @@ affs_create(struct inode *dir, struct dentry *dentry, int mode) inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); d_instantiate(dentry,inode); mark_inode_dirty(inode); - dir->i_version = ++event; + dir->i_version = ++global_event; mark_inode_dirty(dir); out: return error; @@ -319,7 +319,7 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode) inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); d_instantiate(dentry,inode); mark_inode_dirty(inode); - dir->i_version = ++event; + dir->i_version = ++global_event; mark_inode_dirty(dir); out: return error; @@ -372,7 +372,7 @@ affs_rmdir(struct inode *dir, struct dentry *dentry) inode->i_nlink = retval; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; retval = 0; - dir->i_version = ++event; + dir->i_version = ++global_event; mark_inode_dirty(dir); mark_inode_dirty(inode); d_delete(dentry); @@ -450,7 +450,7 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) if (error) goto out_release; d_instantiate(dentry,inode); - dir->i_version = ++event; + dir->i_version = ++global_event; mark_inode_dirty(dir); out: @@ -504,7 +504,7 @@ affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) if (error) inode->i_nlink = 0; else { - dir->i_version = ++event; + dir->i_version = ++global_event; mark_inode_dirty(dir); mark_inode_dirty(oldinode); oldinode->i_count++; @@ -579,8 +579,8 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry, new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; - new_dir->i_version = ++event; - old_dir->i_version = ++event; + new_dir->i_version = ++global_event; + old_dir->i_version = ++global_event; retval = 0; mark_inode_dirty(new_dir); mark_inode_dirty(old_dir); diff --git a/fs/dcache.c b/fs/dcache.c index e8d2c543f11d..1f057529704f 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -361,6 +361,43 @@ resume: return (count > 1); /* remaining users? */ } +/* + * Search for at least 1 mount point in the dentry's subdirs. + * We descend to the next level whenever the d_subdirs + * list is non-empty and continue searching. + */ +int have_submounts(struct dentry *parent) +{ + struct dentry *this_parent = parent; + struct list_head *next; + + if (parent->d_mounts != parent) + return 1; +repeat: + next = this_parent->d_subdirs.next; +resume: + while (next != &this_parent->d_subdirs) { + struct list_head *tmp = next; + struct dentry *dentry = list_entry(tmp, struct dentry, d_child); next = tmp->next; + /* Have we found a mount point ? */ + if (dentry->d_mounts != dentry) + return 1; + if (!list_empty(&dentry->d_subdirs)) { + this_parent = dentry; + goto repeat; + } + } + /* + * All done at this level ... ascend and resume the search. + */ + if (this_parent != parent) { + next = this_parent->d_child.next; + this_parent = this_parent->d_parent; + goto resume; + } + return 0; /* No mount points found in tree */ +} + /* * Search the dentry child list for the specified parent, * and move any unused dentries to the end of the unused diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 9ce7a231176e..f13984544d18 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -131,7 +131,7 @@ static long long ext2_file_lseek( if (offset != file->f_pos) { file->f_pos = offset; file->f_reada = 0; - file->f_version = ++event; + file->f_version = ++global_event; } return offset; } diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index c50737d675b8..f9a924b40b5e 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -521,7 +521,7 @@ void ext2_read_inode (struct inode * inode) inode->u.ext2_i.i_dtime = le32_to_cpu(raw_inode->i_dtime); inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */ inode->i_blocks = le32_to_cpu(raw_inode->i_blocks); - inode->i_version = ++event; + inode->i_version = ++global_event; inode->u.ext2_i.i_new_inode = 0; inode->u.ext2_i.i_flags = le32_to_cpu(raw_inode->i_flags); inode->u.ext2_i.i_faddr = le32_to_cpu(raw_inode->i_faddr); diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index ecef4a91b9db..24cb4557258c 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -301,7 +301,7 @@ static struct buffer_head * ext2_add_entry (struct inode * dir, dir->i_mtime = dir->i_ctime = CURRENT_TIME; dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL; mark_inode_dirty(dir); - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); *res_dir = de; *err = 0; @@ -383,7 +383,7 @@ int ext2_create (struct inode * dir, struct dentry * dentry, int mode) if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb, EXT2_FEATURE_INCOMPAT_FILETYPE)) de->file_type = EXT2_FT_REG_FILE; - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -412,7 +412,7 @@ int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev) if (!bh) goto out_no_entry; de->inode = cpu_to_le32(inode->i_ino); - dir->i_version = ++event; + dir->i_version = ++global_event; if (S_ISREG(inode->i_mode)) { inode->i_op = &ext2_file_inode_operations; if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb, @@ -511,7 +511,7 @@ int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode) if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb, EXT2_FEATURE_INCOMPAT_FILETYPE)) de->file_type = EXT2_FT_DIR; - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -619,7 +619,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry) goto end_rmdir; retval = ext2_delete_entry (de, bh); - dir->i_version = ++event; + dir->i_version = ++global_event; if (retval) goto end_rmdir; mark_buffer_dirty(bh, 1); @@ -631,7 +631,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry) ext2_warning (inode->i_sb, "ext2_rmdir", "empty directory has nlink!=2 (%d)", inode->i_nlink); - inode->i_version = ++event; + inode->i_version = ++global_event; inode->i_nlink = 0; inode->i_size = 0; mark_inode_dirty(inode); @@ -674,7 +674,7 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry) retval = ext2_delete_entry (de, bh); if (retval) goto end_unlink; - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -747,7 +747,7 @@ int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symnam if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb, EXT2_FEATURE_INCOMPAT_FILETYPE)) de->file_type = EXT2_FT_SYMLINK; - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -800,7 +800,7 @@ int ext2_link (struct dentry * old_dentry, else if (S_ISFIFO(inode->i_mode)) de->file_type = EXT2_FT_FIFO; } - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -880,7 +880,7 @@ int ext2_rename (struct inode * old_dir, struct dentry *old_dentry, if (!new_bh) goto end_rename; } - new_dir->i_version = ++event; + new_dir->i_version = ++global_event; /* * Like most other Unix systems, set the ctime for inodes on a @@ -899,7 +899,7 @@ int ext2_rename (struct inode * old_dir, struct dentry *old_dentry, ext2_delete_entry (old_de, old_bh); - old_dir->i_version = ++event; + old_dir->i_version = ++global_event; if (new_inode) { new_inode->i_nlink--; new_inode->i_ctime = CURRENT_TIME; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 9bdbc37fc83f..f75582d32fbd 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -370,7 +370,7 @@ static void fat_read_root(struct inode *inode) MSDOS_I(inode)->i_fat_inode = inode; inode->i_uid = MSDOS_SB(sb)->options.fs_uid; inode->i_gid = MSDOS_SB(sb)->options.fs_gid; - inode->i_version = ++event; + inode->i_version = ++global_event; MSDOS_I(inode)->i_last_pos = 0; inode->i_mode = (S_IRWXUGO & ~MSDOS_SB(sb)->options.fs_umask) | S_IFDIR; inode->i_op = MSDOS_SB(sb)->dir_ops; @@ -759,7 +759,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) MSDOS_I(inode)->i_fat_inode = inode; inode->i_uid = MSDOS_SB(sb)->options.fs_uid; inode->i_gid = MSDOS_SB(sb)->options.fs_gid; - inode->i_version = ++event; + inode->i_version = ++global_event; if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) { MSDOS_I(inode)->i_last_pos = 0; inode->i_mode = MSDOS_MKMODE(de->attr,S_IRWXUGO & diff --git a/fs/file_table.c b/fs/file_table.c index f7679dba374d..ca1ed4cc1de4 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -80,7 +80,7 @@ struct file * get_empty_filp(void) new_one: memset(f, 0, sizeof(*f)); f->f_count = 1; - f->f_version = ++event; + f->f_version = ++global_event; f->f_uid = current->fsuid; f->f_gid = current->fsgid; put_inuse(f); diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index b355408c9275..17172314a2e2 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -88,7 +88,7 @@ static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir) ++(tmp->i_nlink); } tmp->i_size += HFS_I(tmp)->dir_size; - tmp->i_version = ++event; + tmp->i_version = ++global_event; } tmp->i_ctime = tmp->i_mtime = CURRENT_TIME; mark_inode_dirty(tmp); @@ -118,7 +118,7 @@ static inline void update_dirs_minus(struct hfs_cat_entry *dir, int is_dir) --(tmp->i_nlink); } tmp->i_size -= HFS_I(tmp)->dir_size; - tmp->i_version = ++event; + tmp->i_version = ++global_event; } tmp->i_ctime = tmp->i_mtime = CURRENT_TIME; mark_inode_dirty(tmp); diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 8a855438d264..c67ee85780b5 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -194,7 +194,7 @@ static int minix_add_entry(struct inode * dir, mark_inode_dirty(dir); for (i = 0; i < info->s_namelen ; i++) de->name[i] = (i < namelen) ? name[i] : 0; - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); *res_dir = de; break; @@ -415,7 +415,7 @@ int minix_rmdir(struct inode * dir, struct dentry *dentry) if (inode->i_nlink != 2) printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink); de->inode = 0; - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); inode->i_nlink=0; mark_inode_dirty(inode); @@ -449,7 +449,7 @@ int minix_unlink(struct inode * dir, struct dentry *dentry) inode->i_nlink=1; } de->inode = 0; - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); @@ -601,10 +601,10 @@ int minix_rename(struct inode * old_dir, struct dentry *old_dentry, new_de->inode = old_inode->i_ino; old_de->inode = 0; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; - old_dir->i_version = ++event; + old_dir->i_version = ++global_event; mark_inode_dirty(old_dir); new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME; - new_dir->i_version = ++event; + new_dir->i_version = ++global_event; mark_inode_dirty(new_dir); if (new_inode) { new_inode->i_nlink--; diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index be1c34dac8bb..0f32a50e015a 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -517,7 +517,7 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name, if (error) goto out; } - new_dir->i_version = ++event; + new_dir->i_version = ++global_event; /* There we go */ @@ -532,7 +532,7 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name, else MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN; mark_inode_dirty(old_inode); - old_dir->i_version = ++event; + old_dir->i_version = ++global_event; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; mark_inode_dirty(old_dir); if (new_inode) { @@ -569,7 +569,7 @@ degenerate_case: else MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN; mark_inode_dirty(old_inode); - old_dir->i_version = ++event; + old_dir->i_version = ++global_event; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; mark_inode_dirty(old_dir); return 0; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 6bfa519dd835..8e07295b5757 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -473,9 +473,12 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) out_valid: return 1; out_bad: - d_drop(dentry); if (!list_empty(&dentry->d_subdirs)) shrink_dcache_parent(dentry); + /* If we have submounts, don't unhash ! */ + if (have_submounts(dentry)) + goto out_valid; + d_drop(dentry); if (dentry->d_parent->d_inode) nfs_invalidate_dircache(dentry->d_parent->d_inode); if (inode && S_ISDIR(inode->i_mode)) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index af612843fdfd..12191ee9d0cf 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -772,7 +772,7 @@ _nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry) fh = (u32 *) &fhandle; dfprintk(PAGECACHE, " %08x%08x%08x%08x%08x%08x%08x%08x\n", fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]); - if (!IS_ROOT(dentry)) + if (!IS_ROOT(dentry) && !have_submounts(dentry)) d_drop(dentry); goto out; } diff --git a/fs/read_write.c b/fs/read_write.c index 7b9bf0bf7593..a970a9e661f8 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -29,7 +29,7 @@ static loff_t default_llseek(struct file *file, loff_t offset, int origin) if (offset != file->f_pos) { file->f_pos = offset; file->f_reada = 0; - file->f_version = ++event; + file->f_version = ++global_event; } retval = offset; } diff --git a/fs/super.c b/fs/super.c index 7bec94a6edd6..ef716e21a8be 100644 --- a/fs/super.c +++ b/fs/super.c @@ -983,6 +983,7 @@ static int copy_mount_options (const void * data, unsigned long *where) if (!data) return 0; +#if 0 vma = find_vma(current->mm, (unsigned long) data); if (!vma || (unsigned long) data < vma->vm_start) return -EFAULT; @@ -991,10 +992,13 @@ static int copy_mount_options (const void * data, unsigned long *where) i = vma->vm_end - (unsigned long) data; if (PAGE_SIZE <= (unsigned long) i) i = PAGE_SIZE-1; - if (!(page = __get_free_page(GFP_KERNEL))) { +#else + i = PAGE_SIZE; +#endif + if (!(page = get_free_page(GFP_KERNEL))) { return -ENOMEM; } - if (copy_from_user((void *) page,data,i)) { + if (copy_from_user((void *) page,data,i) == i) { free_page(page); return -EFAULT; } diff --git a/fs/ufs/file.c b/fs/ufs/file.c index 7e94bfd1c8ac..ccbb17dce079 100644 --- a/fs/ufs/file.c +++ b/fs/ufs/file.c @@ -111,7 +111,7 @@ static long long ufs_file_lseek( if (offset != file->f_pos) { file->f_pos = offset; file->f_reada = 0; - file->f_version = ++event; + file->f_version = ++global_event; } retval = offset; } diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 84e003d2d294..c22297f6507a 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -509,7 +509,7 @@ void ufs_read_inode (struct inode * inode) inode->i_mtime = SWAB32(ufs_inode->ui_mtime.tv_sec); inode->i_blocks = SWAB32(ufs_inode->ui_blocks); inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat) */ - inode->i_version = ++event; + inode->i_version = ++global_event; inode->u.ufs_i.i_flags = SWAB32(ufs_inode->ui_flags); inode->u.ufs_i.i_gen = SWAB32(ufs_inode->ui_gen); diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 3daf77c57042..8bce6f8e8c62 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -330,7 +330,7 @@ static struct buffer_head * ufs_add_entry (struct inode * dir, */ dir->i_mtime = dir->i_ctime = CURRENT_TIME; mark_inode_dirty(dir); - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); *res_dir = de; *err = 0; @@ -435,7 +435,7 @@ int ufs_create (struct inode * dir, struct dentry * dentry, int mode) } de->d_ino = SWAB32(inode->i_ino); ufs_set_de_type (de, inode->i_mode); - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -485,7 +485,7 @@ int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev) goto out_no_entry; de->d_ino = SWAB32(inode->i_ino); ufs_set_de_type (de, inode->i_mode); - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -559,7 +559,7 @@ int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode) goto out_no_entry; de->d_ino = SWAB32(inode->i_ino); ufs_set_de_type (de, inode->i_mode); - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -672,7 +672,7 @@ int ufs_rmdir (struct inode * dir, struct dentry *dentry) goto end_rmdir; retval = ufs_delete_entry (dir, de, bh); - dir->i_version = ++event; + dir->i_version = ++global_event; if (retval) goto end_rmdir; mark_buffer_dirty(bh, 1); @@ -684,7 +684,7 @@ int ufs_rmdir (struct inode * dir, struct dentry *dentry) ufs_warning (inode->i_sb, "ufs_rmdir", "empty directory has nlink!=2 (%d)", inode->i_nlink); - inode->i_version = ++event; + inode->i_version = ++global_event; inode->i_nlink = 0; inode->i_size = 0; mark_inode_dirty(inode); @@ -736,7 +736,7 @@ int ufs_unlink(struct inode * dir, struct dentry *dentry) retval = ufs_delete_entry (dir, de, bh); if (retval) goto end_unlink; - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -817,7 +817,7 @@ int ufs_symlink (struct inode * dir, struct dentry * dentry, if (!bh) goto out_no_entry; de->d_ino = SWAB32(inode->i_ino); - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -861,7 +861,7 @@ int ufs_link (struct dentry * old_dentry, struct inode * dir, return err; de->d_ino = SWAB32(inode->i_ino); - dir->i_version = ++event; + dir->i_version = ++global_event; mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -949,7 +949,7 @@ int ufs_rename (struct inode * old_dir, struct dentry * old_dentry, &retval); if (!new_bh) goto end_rename; - new_dir->i_version = ++event; + new_dir->i_version = ++global_event; /* * ok, that's it @@ -957,7 +957,7 @@ int ufs_rename (struct inode * old_dir, struct dentry * old_dentry, new_de->d_ino = SWAB32(old_inode->i_ino); ufs_delete_entry (old_dir, old_de, old_bh); - old_dir->i_version = ++event; + old_dir->i_version = ++global_event; if (new_inode) { new_inode->i_nlink--; new_inode->i_ctime = CURRENT_TIME; diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 392aa8ad3061..64467ba08366 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -975,8 +975,8 @@ int vfat_create(struct inode *dir,struct dentry* dentry,int mode) return res; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); - inode->i_version = ++event; - dir->i_version = event; + inode->i_version = ++global_event; + dir->i_version = global_event; MSDOS_I(dir)->i_last_pos = 0; dentry->d_time = dentry->d_parent->d_inode->i_version; d_instantiate(dentry,inode); @@ -1022,7 +1022,7 @@ static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo, /* remove the shortname */ dir->i_mtime = CURRENT_TIME; dir->i_atime = CURRENT_TIME; - dir->i_version = ++event; + dir->i_version = ++global_event; MSDOS_I(dir)->i_last_pos = 0; mark_inode_dirty(dir); de->name[0] = DELETED_FLAG; @@ -1108,8 +1108,8 @@ int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode) goto out; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); - inode->i_version = ++event; - dir->i_version = event; + inode->i_version = ++global_event; + dir->i_version = global_event; MSDOS_I(dir)->i_last_pos = 0; dir->i_nlink++; inode->i_nlink = 2; /* no need to mark them dirty */ @@ -1181,7 +1181,7 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, if (res < 0) goto rename_done; } - new_dir->i_version = ++event; + new_dir->i_version = ++global_event; MSDOS_I(new_dir)->i_last_pos = 0; /* releases old_bh */ @@ -1191,7 +1191,7 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, fat_attach(old_inode, sinfo.ino); mark_inode_dirty(old_inode); - old_dir->i_version = ++event; + old_dir->i_version = ++global_event; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; mark_inode_dirty(old_dir); if (new_inode) { diff --git a/include/linux/dcache.h b/include/linux/dcache.h index c44917b8023c..9c1f8b5f1169 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -151,6 +151,9 @@ extern struct dentry * d_alloc_root(struct inode * root_inode, struct dentry * o /* test whether root is busy without destroying dcache */ extern int is_root_busy(struct dentry *); +/* test whether we have any submounts in a subdir tree */ +extern int have_submounts(struct dentry *); + /* * This adds the entry to the hash queues. */ diff --git a/include/linux/errqueue.h b/include/linux/errqueue.h index 4a16756d9623..48d79561f879 100644 --- a/include/linux/errqueue.h +++ b/include/linux/errqueue.h @@ -1,7 +1,9 @@ #ifndef _LINUX_ERRQUEUE_H #define _LINUX_ERRQUEUE_H 1 +#ifdef __KERNEL__ #include +#endif struct sock_extended_err { diff --git a/include/linux/if.h b/include/linux/if.h index cd5f3139164e..c95f372c4ab6 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -45,31 +45,6 @@ #define IFF_AUTOMEDIA 0x4000 /* auto media select active */ #define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses*/ -#ifdef __KERNEL__ -/* - * The ifaddr structure contains information about one address - * of an interface. They are maintained by the different address - * families, are allocated and attached when an address is set, - * and are linked together so all addresses for an interface can - * be located. - */ - -struct ifaddr -{ - struct sockaddr ifa_addr; /* address of interface */ - union { - struct sockaddr ifu_broadaddr; - struct sockaddr ifu_dstaddr; - } ifa_ifu; - struct iface *ifa_ifp; /* back-pointer to interface */ - struct ifaddr *ifa_next; /* next address for interface */ -}; - -#define ifa_broadaddr ifa_ifu.ifu_broadaddr /* broadcast address */ -#define ifa_dstaddr ifa_ifu.ifu_dstaddr /* other end of link */ - -#endif /* __KERNEL__ */ - /* * Device mapping structure. I'd just gone off and designed a * beautiful scheme using only loadable modules with arguments diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 25c4495980f8..323a305c46ab 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -16,6 +16,7 @@ struct ipv4_devconf int log_martians; int forwarding; int mc_forwarding; + int hidden; void *sysctl; }; @@ -40,6 +41,7 @@ struct in_device #define IN_DEV_LOG_MARTIANS(in_dev) (ipv4_devconf.log_martians || (in_dev)->cnf.log_martians) #define IN_DEV_PROXY_ARP(in_dev) (ipv4_devconf.proxy_arp || (in_dev)->cnf.proxy_arp) +#define IN_DEV_HIDDEN(in_dev) ((in_dev)->cnf.hidden && ipv4_devconf.hidden) #define IN_DEV_SHARED_MEDIA(in_dev) (ipv4_devconf.shared_media || (in_dev)->cnf.shared_media) #define IN_DEV_TX_REDIRECTS(in_dev) (ipv4_devconf.send_redirects || (in_dev)->cnf.send_redirects) #define IN_DEV_SEC_REDIRECTS(in_dev) (ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects) diff --git a/include/linux/ip.h b/include/linux/ip.h index 6675cee9582e..7b642728ae9e 100644 --- a/include/linux/ip.h +++ b/include/linux/ip.h @@ -88,6 +88,8 @@ #define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ #define IPOPT_TS_PRESPEC 3 /* specified modules only */ +#ifdef __KERNEL__ + struct ip_options { __u32 faddr; /* Saved first hop address */ unsigned char optlen; @@ -108,7 +110,6 @@ struct ip_options { unsigned char __data[0]; }; -#ifdef __KERNEL__ #define optlength(opt) (sizeof(struct ip_options) + opt->optlen) #endif diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2acec5295f43..86f84a90a91c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -24,7 +24,9 @@ #ifndef _LINUX_NETDEVICE_H #define _LINUX_NETDEVICE_H +#ifdef __KERNEL__ #include +#endif #include #include #include diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index b339f6528d83..39802a5f8c20 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -1,7 +1,9 @@ #ifndef __LINUX_RTNETLINK_H #define __LINUX_RTNETLINK_H +#ifdef __KERNEL__ #include +#endif #include #define RTNL_DEBUG 1 diff --git a/include/linux/sched.h b/include/linux/sched.h index 446866db150e..d983c17ebf1d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -3,7 +3,7 @@ #include /* for HZ */ -extern unsigned long event; +extern unsigned long global_event; #include #include diff --git a/include/linux/socket.h b/include/linux/socket.h index d681aa5ba9ba..837a3e4659ea 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -106,7 +106,7 @@ __KINLINE struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size, __ptr = (struct cmsghdr*)(((unsigned char *) __cmsg) + CMSG_ALIGN(__cmsg->cmsg_len)); if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size) - return NULL; + return (struct cmsghdr*)0; return __ptr; } diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index e675d9b2aa24..00bebabefd75 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -268,7 +268,8 @@ enum NET_IPV4_CONF_RP_FILTER=8, NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9, NET_IPV4_CONF_BOOTP_RELAY=10, - NET_IPV4_CONF_LOG_MARTIANS=11 + NET_IPV4_CONF_LOG_MARTIANS=11, + NET_IPV4_CONF_HIDDEN=12 }; /* /proc/sys/net/ipv6 */ diff --git a/kernel/ksyms.c b/kernel/ksyms.c index c8a87b6ff640..e0838cd20bd3 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -140,6 +140,7 @@ EXPORT_SYMBOL(d_instantiate); EXPORT_SYMBOL(d_alloc); EXPORT_SYMBOL(d_lookup); EXPORT_SYMBOL(d_path); +EXPORT_SYMBOL(have_submounts); EXPORT_SYMBOL(__mark_inode_dirty); EXPORT_SYMBOL(get_empty_filp); EXPORT_SYMBOL(init_private_file); @@ -385,7 +386,7 @@ EXPORT_SYMBOL(insert_inode_hash); EXPORT_SYMBOL(remove_inode_hash); EXPORT_SYMBOL(make_bad_inode); EXPORT_SYMBOL(is_bad_inode); -EXPORT_SYMBOL(event); +EXPORT_SYMBOL(global_event); EXPORT_SYMBOL(__down); EXPORT_SYMBOL(__down_interruptible); EXPORT_SYMBOL(__down_trylock); diff --git a/kernel/sched.c b/kernel/sched.c index ecd36cd27dcd..4c2f4a9ef696 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -78,7 +78,7 @@ long time_reftime = 0; /* time at last adjustment (s) */ long time_adjust = 0; long time_adjust_step = 0; -unsigned long event = 0; +unsigned long global_event = 0; extern int do_setitimer(int, struct itimerval *, struct itimerval *); unsigned int * prof_buffer = NULL; diff --git a/mm/vmscan.c b/mm/vmscan.c index f150a052cac7..338baba87664 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -53,6 +53,7 @@ static int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma, * tables to the global page map. */ set_pte(page_table, pte_mkold(pte)); + flush_tlb_page(vma, address); set_bit(PG_referenced, &page_map->flags); return 0; } @@ -95,6 +96,7 @@ drop_pte: * some real work in the future in "shrink_mmap()". */ if (!pte_dirty(pte)) { + flush_cache_page(vma, address); pte_clear(page_table); goto drop_pte; } diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 18dc9c766c8a..9e04da2d4fe9 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1266,7 +1266,6 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) newsk->sleep = &newsock->wait; /* Now attach up the new socket */ - skb->destructor = NULL; kfree_skb(skb); sk->ack_backlog--; newsock->sk = newsk; diff --git a/net/bridge/br.c b/net/bridge/br.c index 6a2fd6358801..aac8a9260d24 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -2655,7 +2655,7 @@ static int brg_rx(struct sk_buff *skb, int port) */ if(clone) { struct sk_buff *skb2 = skb; - skb = skb_clone(skb2, GFP_KERNEL); + skb = skb_clone(skb2, GFP_ATOMIC); if (skb == NULL) { return(0); } diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 79e738126407..d81c1beeb939 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -65,6 +65,8 @@ * clean up the APFDDI & gen. FDDI bits. * Alexey Kuznetsov: new arp state machine; * now it is in net/core/neighbour.c. + * Julian Anastasov: "hidden" flag: hide the + * interface and don't reply for it */ /* RFC1122 Status: @@ -308,10 +310,15 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) u32 saddr; u8 *dst_ha = NULL; struct device *dev = neigh->dev; + struct device *dev2; + struct in_device *in_dev2; u32 target = *(u32*)neigh->primary_key; int probes = neigh->probes; - if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL) + if (skb && + (dev2 = ip_dev_find(skb->nh.iph->saddr)) != NULL && + (in_dev2 = dev2->ip_ptr) != NULL && + !IN_DEV_HIDDEN(in_dev2)) saddr = skb->nh.iph->saddr; else saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); @@ -653,8 +660,14 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) /* Special case: IPv4 duplicate address detection packet (RFC2131) */ if (sip == 0) { + struct device *dev2; + struct in_device *in_dev2; + if (arp->ar_op == __constant_htons(ARPOP_REQUEST) && - inet_addr_type(tip) == RTN_LOCAL) + (dev2 = ip_dev_find(tip)) != NULL && + (dev2 == dev || + ((in_dev2 = dev2->ip_ptr) != NULL && + !IN_DEV_HIDDEN(in_dev2)))) arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr); goto out; } @@ -668,6 +681,20 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) if (addr_type == RTN_LOCAL) { n = neigh_event_ns(&arp_tbl, sha, &sip, dev); if (n) { + if (ipv4_devconf.hidden && + skb->pkt_type != PACKET_HOST) { + struct device *dev2; + struct in_device *in_dev2; + + if ((dev2 = ip_dev_find(tip)) != NULL && + dev2 != dev && + (in_dev2 = dev2->ip_ptr) != NULL && + IN_DEV_HIDDEN(in_dev2)) { + neigh_release(n); + goto out; + } + } + arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); neigh_release(n); } diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index a50ee3bd573d..41b42a52f0b9 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -658,7 +658,7 @@ u32 inet_select_addr(struct device *dev, u32 dst, int scope) addr = ifa->ifa_local; } endfor_ifa(in_dev); - if (addr || scope >= RT_SCOPE_LINK) + if (addr) return addr; /* Not loopback addresses on loopback should be preferred @@ -670,7 +670,9 @@ u32 inet_select_addr(struct device *dev, u32 dst, int scope) continue; for_primary_ifa(in_dev) { - if (ifa->ifa_scope <= scope) + if (!IN_DEV_HIDDEN(in_dev) && + ifa->ifa_scope <= scope && + ifa->ifa_scope != RT_SCOPE_LINK) return ifa->ifa_local; } endfor_ifa(in_dev); } @@ -923,7 +925,7 @@ int devinet_sysctl_forward(ctl_table *ctl, int write, struct file * filp, static struct devinet_sysctl_table { struct ctl_table_header *sysctl_header; - ctl_table devinet_vars[12]; + ctl_table devinet_vars[13]; ctl_table devinet_dev[2]; ctl_table devinet_conf_dir[2]; ctl_table devinet_proto_dir[2]; @@ -963,6 +965,9 @@ static struct devinet_sysctl_table {NET_IPV4_CONF_LOG_MARTIANS, "log_martians", &ipv4_devconf.log_martians, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_CONF_HIDDEN, "hidden", + &ipv4_devconf.hidden, sizeof(int), 0644, NULL, + &proc_dointvec}, {0}}, {{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, devinet_sysctl.devinet_vars},{0}}, diff --git a/net/ipv4/ip_masq.c b/net/ipv4/ip_masq.c index a52e7ed7a5d3..f7d5db426daf 100644 --- a/net/ipv4/ip_masq.c +++ b/net/ipv4/ip_masq.c @@ -842,6 +842,7 @@ static void masq_expire(unsigned long data) */ if (atomic_read(&ms->refcnt) == 1) { kfree_s(ms,sizeof(*ms)); + sysctl_ip_always_defrag--; MOD_DEC_USE_COUNT; goto masq_expire_out; } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 7fa0f0b2121a..65f1129c61a5 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -570,6 +570,21 @@ static int ipv6_generate_eui64(u8 *eui, struct device *dev) } return -1; } + +static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) +{ + int err = -1; + struct inet6_ifaddr *ifp; + + for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { + if (ifp->scope == IFA_LINK && !(ifp->flags&(ADDR_STATUS|DAD_STATUS))) { + memcpy(eui, ifp->addr.s6_addr+8, 8); + err = 0; + break; + } + } + return err; +} #endif /* @@ -742,7 +757,8 @@ void addrconf_prefix_rcv(struct device *dev, u8 *opt, int len) #ifdef CONFIG_IPV6_EUI64 if (pinfo->prefix_len == 64) { memcpy(&addr, &pinfo->prefix, 8); - if (ipv6_generate_eui64(addr.s6_addr + 8, dev)) + if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && + ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) return; goto ok; } @@ -1374,7 +1390,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) */ if (ifp->idev->cnf.forwarding == 0 && - (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) == 0 && + (dev->flags&IFF_LOOPBACK) == 0 && (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { struct in6_addr all_routers; -- 2.39.5