## Automatically generated incremental diff ## From: linux-2.5.3-pre1 ## To: linux-2.5.3-pre2 ## Robot: $Id: make-incremental-diff,v 1.9 2001/12/10 00:06:56 hpa Exp $ diff -urN linux-2.5.3-pre1/Documentation/DocBook/kernel-hacking.tmpl linux/Documentation/DocBook/kernel-hacking.tmpl --- linux-2.5.3-pre1/Documentation/DocBook/kernel-hacking.tmpl Thu Dec 20 08:54:23 2001 +++ linux/Documentation/DocBook/kernel-hacking.tmpl Sat Jan 19 16:58:39 2002 @@ -371,8 +371,7 @@ -if (current->need_resched) - schedule(); /* Will sleep */ +cond_resched(); /* Will sleep */ diff -urN linux-2.5.3-pre1/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- linux-2.5.3-pre1/Documentation/ioctl-number.txt Wed Jul 11 16:35:37 2001 +++ linux/Documentation/ioctl-number.txt Sat Jan 19 16:58:39 2002 @@ -101,7 +101,8 @@ 'S' 82-FF scsi/scsi.h conflict! 'T' all linux/soundcard.h conflict! 'T' all asm-i386/ioctls.h conflict! -'U' all linux/drivers/usb/usb.h +'U' 00-EF linux/drivers/usb/usb.h +'U' F0-FF drivers/usb/auerswald.c 'V' all linux/vt.h 'W' 00-1F linux/watchdog.h conflict! 'W' 00-1F linux/wanrouter.h conflict! diff -urN linux-2.5.3-pre1/Makefile linux/Makefile --- linux-2.5.3-pre1/Makefile Sat Jan 19 16:58:37 2002 +++ linux/Makefile Sat Jan 19 16:58:39 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 3 -EXTRAVERSION =-pre1 +EXTRAVERSION =-pre2 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -urN linux-2.5.3-pre1/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c --- linux-2.5.3-pre1/arch/arm/kernel/process.c Sat Jan 5 13:04:30 2002 +++ linux/arch/arm/kernel/process.c Sat Jan 19 16:58:39 2002 @@ -91,7 +91,7 @@ if (!idle) idle = arch_idle; leds_event(led_idle_start); - while (!current->need_resched) + while (!need_resched()) idle(); leds_event(led_idle_end); schedule(); diff -urN linux-2.5.3-pre1/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- linux-2.5.3-pre1/arch/i386/kernel/apm.c Fri Nov 30 08:38:44 2001 +++ linux/arch/i386/kernel/apm.c Sat Jan 19 16:58:39 2002 @@ -766,14 +766,14 @@ start_idle = jiffies; while (1) { - if (!current->need_resched) { + if (!need_resched()) { if (jiffies - start_idle < HARD_IDLE_TIMEOUT) { if (!current_cpu_data.hlt_works_ok) continue; if (hlt_counter) continue; __cli(); - if (!current->need_resched) + if (!need_resched()) safe_halt(); else __sti(); diff -urN linux-2.5.3-pre1/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- linux-2.5.3-pre1/arch/i386/kernel/process.c Mon Jan 7 12:55:17 2002 +++ linux/arch/i386/kernel/process.c Sat Jan 19 16:58:39 2002 @@ -42,7 +42,6 @@ #include #include #include -#include #ifdef CONFIG_MATH_EMULATION #include #endif @@ -81,7 +80,7 @@ { if (current_cpu_data.hlt_works_ok && !hlt_counter) { __cli(); - if (!current->need_resched) + if (!need_resched()) safe_halt(); else __sti(); @@ -127,7 +126,7 @@ void (*idle)(void) = pm_idle; if (!idle) idle = default_idle; - while (!current->need_resched) + while (!need_resched()) idle(); schedule(); check_pgt_cache(); diff -urN linux-2.5.3-pre1/arch/i386/math-emu/fpu_entry.c linux/arch/i386/math-emu/fpu_entry.c --- linux-2.5.3-pre1/arch/i386/math-emu/fpu_entry.c Fri Apr 6 10:42:47 2001 +++ linux/arch/i386/math-emu/fpu_entry.c Sat Jan 19 16:58:39 2002 @@ -559,7 +559,7 @@ RE_ENTRANT_CHECK_ON; #endif /* DEBUG */ - if (FPU_lookahead && !current->need_resched) + if (FPU_lookahead && !need_resched()) { FPU_ORIG_EIP = FPU_EIP - code_base; if ( valid_prefix(&byte1, (u_char **)&FPU_EIP, diff -urN linux-2.5.3-pre1/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c --- linux-2.5.3-pre1/arch/ia64/kernel/process.c Thu Dec 27 08:21:28 2001 +++ linux/arch/ia64/kernel/process.c Sat Jan 19 16:58:39 2002 @@ -117,10 +117,10 @@ while (1) { #ifdef CONFIG_SMP - if (!current->need_resched) + if (!need_resched()) min_xtp(); #endif - while (!current->need_resched) + while (!need_resched()) continue; #ifdef CONFIG_SMP normal_xtp(); diff -urN linux-2.5.3-pre1/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c --- linux-2.5.3-pre1/arch/m68k/kernel/process.c Thu Dec 27 08:21:28 2001 +++ linux/arch/m68k/kernel/process.c Sat Jan 19 16:58:39 2002 @@ -56,7 +56,7 @@ static void default_idle(void) { while(1) { - if (!current->need_resched) + if (!need_resched()) #if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES) /* block out HSYNC on the atari (falcon) */ __asm__("stop #0x2200" : : : "cc"); diff -urN linux-2.5.3-pre1/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c --- linux-2.5.3-pre1/arch/mips/kernel/process.c Thu Dec 27 08:21:28 2001 +++ linux/arch/mips/kernel/process.c Sat Jan 19 16:58:39 2002 @@ -39,7 +39,7 @@ init_idle(); while (1) { - while (!current->need_resched) + while (!need_resched()) if (cpu_wait) (*cpu_wait)(); schedule(); diff -urN linux-2.5.3-pre1/arch/mips/math-emu/cp1emu.c linux/arch/mips/math-emu/cp1emu.c --- linux-2.5.3-pre1/arch/mips/math-emu/cp1emu.c Sun Sep 9 10:43:01 2001 +++ linux/arch/mips/math-emu/cp1emu.c Sat Jan 19 16:58:39 2002 @@ -1674,8 +1674,7 @@ oldepc = xcp->cp0_epc; do { - if (current->need_resched) - schedule(); + cond_resched(); prevepc = xcp->cp0_epc; insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err); diff -urN linux-2.5.3-pre1/arch/mips64/kernel/process.c linux/arch/mips64/kernel/process.c --- linux-2.5.3-pre1/arch/mips64/kernel/process.c Thu Dec 27 08:21:28 2001 +++ linux/arch/mips64/kernel/process.c Sat Jan 19 16:58:39 2002 @@ -35,7 +35,7 @@ init_idle(); current->nice = 20; while (1) { - while (!current->need_resched) + while (!need_resched()) if (wait_available) __asm__("wait"); schedule(); diff -urN linux-2.5.3-pre1/arch/mips64/math-emu/cp1emu.c linux/arch/mips64/math-emu/cp1emu.c --- linux-2.5.3-pre1/arch/mips64/math-emu/cp1emu.c Sun Sep 9 10:43:02 2001 +++ linux/arch/mips64/math-emu/cp1emu.c Sat Jan 19 16:58:39 2002 @@ -1707,8 +1707,7 @@ oldepc = xcp->cp0_epc; do { - if (current->need_resched) - schedule(); + cond_resched(); prevepc = xcp->cp0_epc; insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err); diff -urN linux-2.5.3-pre1/arch/parisc/kernel/process.c linux/arch/parisc/kernel/process.c --- linux-2.5.3-pre1/arch/parisc/kernel/process.c Thu Dec 27 08:21:28 2001 +++ linux/arch/parisc/kernel/process.c Sat Jan 19 16:58:39 2002 @@ -73,8 +73,8 @@ current->nice = 20; while (1) { - while (!current->need_resched) { - } + while (!need_resched()) + barrier(); schedule(); check_pgt_cache(); } diff -urN linux-2.5.3-pre1/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c --- linux-2.5.3-pre1/arch/ppc/kernel/idle.c Thu Dec 27 08:21:28 2001 +++ linux/arch/ppc/kernel/idle.c Sat Jan 19 16:58:39 2002 @@ -66,15 +66,15 @@ int oldval = xchg(¤t->need_resched, -1); if (!oldval) { - while(current->need_resched == -1) - ; /* Do Nothing */ + while (need_resched()) + barrier(); /* Do Nothing */ } } #endif - if (do_power_save && !current->need_resched) + if (do_power_save && !need_resched()) power_save(); - if (current->need_resched) { + if (need_resched()) { schedule(); check_pgt_cache(); } @@ -150,7 +150,7 @@ if ( atomic_read(&zero_cache_sz) >= zero_cache_water[0] ) return; - while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && (!current->need_resched) ) + while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && !need_resched() ) { /* * Mark a page as reserved so we can mess with it @@ -161,8 +161,7 @@ if ( !pageptr ) return; - if ( current->need_resched ) - schedule(); + cond_resched(); /* * Make the page no cache so we don't blow our cache with 0's @@ -181,8 +180,7 @@ */ for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 ) { - if ( current->need_resched ) - schedule(); + cond_resched(); *(unsigned long *)(bytecount + pageptr) = 0; } @@ -243,7 +241,7 @@ * -- Cort */ _nmask_and_or_msr(MSR_EE, 0); - if (!current->need_resched) + if (!need_resched()) { asm("mfspr %0,1008" : "=r" (hid0) :); hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE); diff -urN linux-2.5.3-pre1/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c --- linux-2.5.3-pre1/arch/s390/kernel/process.c Thu Dec 27 08:21:28 2001 +++ linux/arch/s390/kernel/process.c Sat Jan 19 16:58:39 2002 @@ -60,7 +60,7 @@ wait_psw.mask = _WAIT_PSW_MASK; wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L; while(1) { - if (current->need_resched) { + if (need_resched()) { schedule(); check_pgt_cache(); continue; diff -urN linux-2.5.3-pre1/arch/s390x/kernel/process.c linux/arch/s390x/kernel/process.c --- linux-2.5.3-pre1/arch/s390x/kernel/process.c Thu Dec 27 08:21:28 2001 +++ linux/arch/s390x/kernel/process.c Sat Jan 19 16:58:39 2002 @@ -60,7 +60,7 @@ wait_psw.mask = _WAIT_PSW_MASK; wait_psw.addr = (unsigned long) &&idle_wakeup; while(1) { - if (current->need_resched) { + if (need_resched()) { schedule(); check_pgt_cache(); continue; diff -urN linux-2.5.3-pre1/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c --- linux-2.5.3-pre1/arch/sh/kernel/process.c Thu Dec 27 08:21:28 2001 +++ linux/arch/sh/kernel/process.c Sat Jan 19 16:58:39 2002 @@ -44,11 +44,11 @@ while (1) { if (hlt_counter) { - if (current->need_resched) + if (need_resched()) break; } else { __cli(); - while (!current->need_resched) { + while (!need_resched()) { __sti(); asm volatile("sleep" : : : "memory"); __cli(); diff -urN linux-2.5.3-pre1/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c --- linux-2.5.3-pre1/arch/sparc/kernel/process.c Mon Jan 14 10:10:43 2002 +++ linux/arch/sparc/kernel/process.c Sat Jan 19 16:58:39 2002 @@ -106,7 +106,7 @@ { /* endless idle loop with no priority at all */ while(1) { - if(current->need_resched) { + if(need_resched()) { schedule(); check_pgt_cache(); } diff -urN linux-2.5.3-pre1/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c --- linux-2.5.3-pre1/arch/sparc64/kernel/process.c Mon Jan 14 10:10:44 2002 +++ linux/arch/sparc64/kernel/process.c Sat Jan 19 16:58:39 2002 @@ -61,7 +61,7 @@ * But this requires writing back the contents of the * L2 cache etc. so implement this later. -DaveM */ - while (!current->need_resched) + while (!need_resched()) barrier(); schedule(); @@ -80,7 +80,7 @@ int cpu_idle(void) { while(1) { - if (current->need_resched != 0) { + if (need_resched()) { unidle_me(); schedule(); check_pgt_cache(); diff -urN linux-2.5.3-pre1/drivers/block/cciss.c linux/drivers/block/cciss.c --- linux-2.5.3-pre1/drivers/block/cciss.c Thu Jan 10 10:15:38 2002 +++ linux/drivers/block/cciss.c Sat Jan 19 16:58:39 2002 @@ -64,6 +64,8 @@ 0x0E11, 0x4080, 0, 0, 0}, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4082, 0, 0, 0}, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, + 0x0E11, 0x4083, 0, 0, 0}, {0,} }; MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); @@ -78,6 +80,7 @@ { 0x40700E11, "Smart Array 5300", &SA5_access }, { 0x40800E11, "Smart Array 5i", &SA5B_access}, { 0x40820E11, "Smart Array 532", &SA5B_access}, + { 0x40830E11, "Smart Array 5312", &SA5B_access}, }; /* How long to wait (in millesconds) for board to go into simple mode */ @@ -102,6 +105,8 @@ static int revalidate_allvol(kdev_t dev); static int revalidate_logvol(kdev_t dev, int maxusage); static int frevalidate_logvol(kdev_t dev); +static int deregister_disk(int ctlr, int logvol); +static int register_new_disk(kdev_t dev, int cltr); static void cciss_getgeometry(int cntl_num); @@ -148,6 +153,7 @@ " Memory Address: 0x%08lx\n" " IRQ: %d\n" " Logical drives: %d\n" + " Highest Logical Volume ID: %d\n" " Current Q depth: %d\n" " Max Q depth since init: %d\n" " Max # commands on controller since init: %d\n" @@ -159,12 +165,15 @@ (unsigned long)h->vaddr, (unsigned int)h->intr, h->num_luns, + h->highest_lun, h->Qdepth, h->maxQsinceinit, h->max_outstanding, h->maxSG); pos += size; len += size; cciss_proc_tape_report(ctlr, buffer, &pos, &len); - for(i=0; inum_luns; i++) { + for(i=0; ihighest_lun; i++) { drv = &h->drv[i]; + if (drv->block_size == 0) + continue; size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n", ctlr, i, drv->block_size, drv->nr_blocks); pos += size; len += size; @@ -344,9 +353,10 @@ for(j=0; jblocksizes[(i<gendisk.nr_real++; + //hba[ctlr]->gendisk.nr_real++; (BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr))->hardsect_size = drv->block_size; } + hba[ctlr]->gendisk.nr_real = hba[ctlr]->highest_lun+1; } /* * Open. Make sure the device is really there. @@ -416,24 +426,42 @@ switch(cmd) { case HDIO_GETGEO: { - struct hd_geometry *geo = (struct hd_geometry *)arg; - int diskinfo[4]; - - if (hba[ctlr]->drv[dsk].cylinders) { - diskinfo[0] = hba[ctlr]->drv[dsk].heads; - diskinfo[1] = hba[ctlr]->drv[dsk].sectors; - diskinfo[2] = hba[ctlr]->drv[dsk].cylinders; - } else { - diskinfo[0] = 0xff; - diskinfo[1] = 0x3f; - diskinfo[2] = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f); - } - put_user(diskinfo[0], &geo->heads); - put_user(diskinfo[1], &geo->sectors); - put_user(diskinfo[2], &geo->cylinders); - put_user(get_start_sect(inode->i_rdev), &geo->start); - return 0; + struct hd_geometry driver_geo; + if (hba[ctlr]->drv[dsk].cylinders) { + driver_geo.heads = hba[ctlr]->drv[dsk].heads; + driver_geo.sectors = hba[ctlr]->drv[dsk].sectors; + driver_geo.cylinders = hba[ctlr]->drv[dsk].cylinders; + } else { + driver_geo.heads = 0xff; + driver_geo.sectors = 0x3f; + driver_geo.cylinders = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f); + } + driver_geo.start= + hba[ctlr]->hd[minor(inode->i_rdev)].start_sect; + if (copy_to_user((void *) arg, &driver_geo, + sizeof( struct hd_geometry))) + return -EFAULT; + return(0); } + case HDIO_GETGEO_BIG: + { + struct hd_big_geometry driver_geo; + if (hba[ctlr]->drv[dsk].cylinders) { + driver_geo.heads = hba[ctlr]->drv[dsk].heads; + driver_geo.sectors = hba[ctlr]->drv[dsk].sectors; + driver_geo.cylinders = hba[ctlr]->drv[dsk].cylinders; + } else { + driver_geo.heads = 0xff; + driver_geo.sectors = 0x3f; + driver_geo.cylinders = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f); + } + driver_geo.start= + hba[ctlr]->hd[minor(inode->i_rdev)].start_sect; + if (copy_to_user((void *) arg, &driver_geo, + sizeof( struct hd_big_geometry))) + return -EFAULT; + return(0); + } case BLKRRPART: return revalidate_logvol(inode->i_rdev, 1); case BLKGETSIZE: @@ -603,7 +631,14 @@ case CCISS_REVALIDVOLS: return( revalidate_allvol(inode->i_rdev)); - + + case CCISS_DEREGDISK: + return( deregister_disk(ctlr,dsk)); + + case CCISS_REGNEWD: + { + return(register_new_disk(inode->i_rdev, ctlr)); + } case CCISS_PASSTHRU: { IOCTL_Command_struct iocommand; @@ -827,8 +862,503 @@ return 0; } +static int deregister_disk(int ctlr, int logvol) +{ + unsigned long flags; + struct gendisk *gdev = &(hba[ctlr]->gendisk); + ctlr_info_t *h = hba[ctlr]; + int start, max_p, i; + + + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + spin_lock_irqsave(CCISS_LOCK(ctlr), flags); + /* make sure logical volume is NOT is use */ + if( h->drv[logvol].usage_count > 1) + { + spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); + return -EBUSY; + } + h->drv[logvol].usage_count++; + spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); + + /* invalidate the devices and deregister the disk */ + max_p = 1 << gdev->minor_shift; + start = logvol << gdev->minor_shift; + for (i=max_p-1; i>=0; i--) + { + int minor = start+i; + kdev_t kdev = mk_kdev(MAJOR_NR+ctlr, minor); + // printk("invalidating( %d %d)\n", ctlr, minor); + invalidate_device(kdev, 1); + /* so open will now fail */ + h->sizes[minor] = 0; + /* so it will no longer appear in /proc/partitions */ + gdev->part[minor].start_sect = 0; + gdev->part[minor].nr_sects = 0; + } + /* check to see if it was the last disk */ + if (logvol == h->highest_lun) + { + /* if so, find the new hightest lun */ + int i, newhighest =-1; + for(i=0; ihighest_lun; i++) + { + /* if the disk has size > 0, it is available */ + if (h->sizes[i << gdev->minor_shift] != 0) + newhighest = i; + } + h->highest_lun = newhighest; + + } + --h->num_luns; + gdev->nr_real = h->highest_lun+1; + /* zero out the disk size info */ + h->drv[logvol].nr_blocks = 0; + h->drv[logvol].block_size = 0; + h->drv[logvol].LunID = 0; + return(0); +} +static int sendcmd_withirq(__u8 cmd, + int ctlr, + void *buff, + size_t size, + unsigned int use_unit_num, + unsigned int log_unit, + __u8 page_code ) +{ + ctlr_info_t *h = hba[ctlr]; + CommandList_struct *c; + u64bit buff_dma_handle; + unsigned long flags; + int return_status = IO_OK; + + if ((c = cmd_alloc(h , 0)) == NULL) + { + return -ENOMEM; + } + // Fill in the command type + c->cmd_type = CMD_IOCTL_PEND; + // Fill in Command Header + c->Header.ReplyQueue = 0; // unused in simple mode + if( buff != NULL) // buffer to fill + { + c->Header.SGList = 1; + c->Header.SGTotal= 1; + } else // no buffers to fill + { + c->Header.SGList = 0; + c->Header.SGTotal= 0; + } + c->Header.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag + // Fill in Request block + switch(cmd) + { + case CISS_INQUIRY: + /* If the logical unit number is 0 then, this is going + to controller so It's a physical command + mode = 0 target = 0. + So we have nothing to write. + Otherwise + mode = 1 target = LUNID + */ + if(use_unit_num != 0) + { + c->Header.LUN.LogDev.VolId= + hba[ctlr]->drv[log_unit].LunID; + c->Header.LUN.LogDev.Mode = 1; + } + if(page_code != 0) + { + c->Request.CDB[1] = 0x01; + c->Request.CDB[2] = page_code; + } + c->Request.CDBLen = 6; + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_READ; // Read + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = CISS_INQUIRY; + c->Request.CDB[4] = size & 0xFF; + break; + case CISS_REPORT_LOG: + /* Talking to controller so It's a physical command + mode = 00 target = 0. + So we have nothing to write. + */ + c->Request.CDBLen = 12; + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_READ; // Read + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = CISS_REPORT_LOG; + c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB + c->Request.CDB[7] = (size >> 16) & 0xFF; + c->Request.CDB[8] = (size >> 8) & 0xFF; + c->Request.CDB[9] = size & 0xFF; + break; + case CCISS_READ_CAPACITY: + c->Header.LUN.LogDev.VolId= + hba[ctlr]->drv[log_unit].LunID; + c->Header.LUN.LogDev.Mode = 1; + c->Request.CDBLen = 10; + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_READ; // Read + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = CCISS_READ_CAPACITY; + break; + default: + printk(KERN_WARNING + "cciss: Unknown Command 0x%c sent attempted\n", cmd); + cmd_free(h, c, 1); + return(IO_ERROR); + }; + + // Fill in the scatter gather information + if (size > 0 ) + { + buff_dma_handle.val = (__u64) pci_map_single( h->pdev, + buff, size, PCI_DMA_BIDIRECTIONAL); + c->SG[0].Addr.lower = buff_dma_handle.val32.lower; + c->SG[0].Addr.upper = buff_dma_handle.val32.upper; + c->SG[0].Len = size; + c->SG[0].Ext = 0; // we are not chaining + } + + /* Put the request on the tail of the queue and send it */ + spin_lock_irqsave(CCISS_LOCK(ctlr), flags); + addQ(&h->reqQ, c); + h->Qdepth++; + start_io(h); + spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); + + /* wait for completion */ + while(c->cmd_type != CMD_IOCTL_DONE) + schedule_timeout(1); + /* unlock the buffers from DMA */ + pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val, + size, PCI_DMA_BIDIRECTIONAL); + + if(c->err_info->CommandStatus != 0) + { /* an error has occurred */ + switch(c->err_info->CommandStatus) + { + case CMD_TARGET_STATUS: + printk(KERN_WARNING "cciss: cmd %p has " + " completed with errors\n", c); + if( c->err_info->ScsiStatus) + { + printk(KERN_WARNING "cciss: cmd %p " + "has SCSI Status = %x\n", + c, + c->err_info->ScsiStatus); + } + + break; + case CMD_DATA_UNDERRUN: + case CMD_DATA_OVERRUN: + /* expected for inquire and report lun commands */ + break; + case CMD_INVALID: + printk(KERN_WARNING "cciss: Cmd %p is " + "reported invalid\n", c); + return_status = IO_ERROR; + break; + case CMD_PROTOCOL_ERR: + printk(KERN_WARNING "cciss: cmd %p has " + "protocol error \n", c); + return_status = IO_ERROR; + break; +case CMD_HARDWARE_ERR: + printk(KERN_WARNING "cciss: cmd %p had " + " hardware error\n", c); + return_status = IO_ERROR; + break; + case CMD_CONNECTION_LOST: + printk(KERN_WARNING "cciss: cmd %p had " + "connection lost\n", c); + return_status = IO_ERROR; + break; + case CMD_ABORTED: + printk(KERN_WARNING "cciss: cmd %p was " + "aborted\n", c); + return_status = IO_ERROR; + break; + case CMD_ABORT_FAILED: + printk(KERN_WARNING "cciss: cmd %p reports " + "abort failed\n", c); + return_status = IO_ERROR; + break; + case CMD_UNSOLICITED_ABORT: + printk(KERN_WARNING "cciss: cmd %p aborted " + "do to an unsolicited abort\n", c); + return_status = IO_ERROR; + + break; + default: + printk(KERN_WARNING "cciss: cmd %p returned " + "unknown status %x\n", c, + c->err_info->CommandStatus); + return_status = IO_ERROR; + } + } + cmd_free(h, c, 0); + return(return_status); +} +static int register_new_disk(kdev_t dev, int ctlr) +{ + struct gendisk *gdev = &(hba[ctlr]->gendisk); + ctlr_info_t *h = hba[ctlr]; + int start, max_p, i; + int num_luns; + int logvol; + int new_lun_found = 0; + int new_lun_index = 0; + int free_index_found = 0; + int free_index = 0; + ReportLunData_struct *ld_buff; + ReadCapdata_struct *size_buff; + InquiryData_struct *inq_buff; + int return_code; + int listlength = 0; + __u32 lunid = 0; + unsigned int block_size; + unsigned int total_size; + + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + /* if we have no space in our disk array left to add anything */ + if( h->num_luns >= CISS_MAX_LUN) + return -EINVAL; + + ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL); + if (ld_buff == NULL) + { + printk(KERN_ERR "cciss: out of memory\n"); + return -1; + } + memset(ld_buff, 0, sizeof(ReportLunData_struct)); + size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL); + if (size_buff == NULL) + { + printk(KERN_ERR "cciss: out of memory\n"); + kfree(ld_buff); + return -1; + } + inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); + if (inq_buff == NULL) + { + printk(KERN_ERR "cciss: out of memory\n"); + kfree(ld_buff); + kfree(size_buff); + return -1; + } + + return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, + sizeof(ReportLunData_struct), 0, 0, 0 ); + + if( return_code == IO_OK) + { + + // printk("LUN Data\n--------------------------\n"); + + listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24; + listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16; + listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8; + listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]); + } else /* reading number of logical volumes failed */ + { + printk(KERN_WARNING "cciss: report logical volume" + " command failed\n"); + listlength = 0; + return -1; + } + num_luns = listlength / 8; // 8 bytes pre entry + if (num_luns > CISS_MAX_LUN) + { + num_luns = CISS_MAX_LUN; + } +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0], + ld_buff->LUNListLength[1], ld_buff->LUNListLength[2], + ld_buff->LUNListLength[3], num_luns); +#endif + for(i=0; i< num_luns; i++) + { + int j; + int lunID_found = 0; + + lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24; + lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16; + lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8; + lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); + + /* check to see if this is a new lun */ + for(j=0; j <= h->highest_lun; j++) + { +#ifdef CCISS_DEBUG + printk("Checking %d %x against %x\n", j,h->drv[j].LunID, + lunid); +#endif /* CCISS_DEBUG */ + if (h->drv[j].LunID == lunid) + { + lunID_found = 1; + break; + } + + } + if( lunID_found == 1) + continue; + else + { /* It is the new lun we have been looking for */ +#ifdef CCISS_DEBUG + printk("new lun found at %d\n", i); +#endif /* CCISS_DEBUG */ + new_lun_index = i; + new_lun_found = 1; + break; + } + } + if (!new_lun_found) + { + printk(KERN_WARNING "cciss: New Logical Volume not found\n"); + return -1; + } + /* Now find the free index */ + for(i=0; i drv[i].LunID == 0) + { +#ifdef CCISS_DEBUG + printk("free index found at %d\n", i); +#endif /* CCISS_DEBUG */ + free_index_found = 1; + free_index = i; + break; + } + } + if (!free_index_found) + { + printk(KERN_WARNING "cciss: unable to find free slot for disk\n"); + return -1; + } + + logvol = free_index; + hba[ctlr]->drv[logvol].LunID = lunid; + /* there could be gaps in lun numbers, track hightest */ + if(hba[ctlr]->highest_lun < lunid) + hba[ctlr]->highest_lun = logvol; + + memset(size_buff, 0, sizeof(ReadCapdata_struct)); + return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, size_buff, + sizeof( ReadCapdata_struct), 1, logvol, 0 ); + if (return_code == IO_OK) + { + total_size = (0xff & + (unsigned int)(size_buff->total_size[0])) << 24; + total_size |= (0xff & + (unsigned int)(size_buff->total_size[1])) << 16; + total_size |= (0xff & + (unsigned int)(size_buff->total_size[2])) << 8; + total_size |= (0xff & (unsigned int) + (size_buff->total_size[3])); + total_size++; // command returns highest block address + + block_size = (0xff & + (unsigned int)(size_buff->block_size[0])) << 24; + block_size |= (0xff & + (unsigned int)(size_buff->block_size[1])) << 16; + block_size |= (0xff & + (unsigned int)(size_buff->block_size[2])) << 8; + block_size |= (0xff & + (unsigned int)(size_buff->block_size[3])); + } else /* read capacity command failed */ + { + printk(KERN_WARNING "cciss: read capacity failed\n"); + total_size = 0; + block_size = BLOCK_SIZE; + } + printk(KERN_INFO " blocks= %d block_size= %d\n", + total_size, block_size); + /* Execute the command to read the disk geometry */ + memset(inq_buff, 0, sizeof(InquiryData_struct)); + return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff, + sizeof(InquiryData_struct), 1, logvol ,0xC1 ); + if (return_code == IO_OK) + { + if(inq_buff->data_byte[8] == 0xFF) + { + printk(KERN_WARNING "cciss: reading geometry failed, " + "volume does not support reading geometry\n"); + + hba[ctlr]->drv[logvol].block_size = block_size; + hba[ctlr]->drv[logvol].nr_blocks = total_size; + hba[ctlr]->drv[logvol].heads = 255; + hba[ctlr]->drv[logvol].sectors = 32; // Sectors per track + hba[ctlr]->drv[logvol].cylinders = total_size / 255 / 32; + } else + { + + hba[ctlr]->drv[logvol].block_size = block_size; + hba[ctlr]->drv[logvol].nr_blocks = total_size; + hba[ctlr]->drv[logvol].heads = + inq_buff->data_byte[6]; + hba[ctlr]->drv[logvol].sectors = + inq_buff->data_byte[7]; + hba[ctlr]->drv[logvol].cylinders = + (inq_buff->data_byte[4] & 0xff) << 8; + hba[ctlr]->drv[logvol].cylinders += + inq_buff->data_byte[5]; + } + } + else /* Get geometry failed */ + { + + printk(KERN_WARNING "cciss: reading geometry failed, " + "continuing with default geometry\n"); + + hba[ctlr]->drv[logvol].block_size = block_size; + hba[ctlr]->drv[logvol].nr_blocks = total_size; + hba[ctlr]->drv[logvol].heads = 255; + hba[ctlr]->drv[logvol].sectors = 32; // Sectors per track + hba[ctlr]->drv[logvol].cylinders = total_size / 255 / 32; + } + printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n", + hba[ctlr]->drv[logvol].heads, + hba[ctlr]->drv[logvol].sectors, + hba[ctlr]->drv[logvol].cylinders); + hba[ctlr]->drv[logvol].usage_count = 0; + max_p = 1 << gdev->minor_shift; + start = logvol<< gdev->minor_shift; + + for(i=max_p-1; i>=0; i--) { + int minor = start+i; + kdev_t kdev = mk_kdev(MAJOR_NR + ctlr, minor); + invalidate_device(kdev, 1); + gdev->part[minor].start_sect = 0; + gdev->part[minor].nr_sects = 0; + + /* reset the blocksize so we can read the partition table */ + blksize_size[MAJOR_NR+ctlr][minor] = 1024; + } + + ++hba[ctlr]->num_luns; + gdev->nr_real = hba[ctlr]->highest_lun + 1; + /* setup partitions per disk */ + grok_partitions(dev, hba[ctlr]->drv[logvol].nr_blocks); + + kfree(ld_buff); + kfree(size_buff); + kfree(inq_buff); + return (logvol); +} /* * Wait polling for a command to complete. * The memory mapped FIFO is polled for the completion. @@ -959,6 +1489,15 @@ c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = CCISS_READ_CAPACITY; break; + case CCISS_CACHE_FLUSH: + c->Request.CDBLen = 12; + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_WRITE; // No data + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = BMIC_WRITE; // BMIC Passthru + c->Request.CDB[6] = BMIC_CACHE_FLUSH; + break; default: printk(KERN_WARNING "cciss: Unknown Command 0x%c sent attempted\n", @@ -1169,17 +1708,32 @@ { /* an error has occurred */ switch(cmd->err_info->CommandStatus) { + unsigned char sense_key; case CMD_TARGET_STATUS: - printk(KERN_WARNING "cciss: cmd %p has " - " completed with errors\n", cmd); - if( cmd->err_info->ScsiStatus) - { - printk(KERN_WARNING "cciss: cmd %p " - "has SCSI Status = %x\n", - cmd, - cmd->err_info->ScsiStatus); - } - + status = 0; + + if( cmd->err_info->ScsiStatus == 0x02) + { + printk(KERN_WARNING "cciss: cmd %p " + "has CHECK CONDITION " + " byte 2 = 0x%x\n", cmd, + cmd->err_info->SenseInfo[2] + ); + /* check the sense key */ + sense_key = 0xf & + cmd->err_info->SenseInfo[2]; + /* no status or recovered error */ + if((sense_key == 0x0) || + (sense_key == 0x1)) + { + status = 1; + } + } else + { + printk(KERN_WARNING "cciss: cmd %p " + "has SCSI Status 0x%x\n", + cmd, cmd->err_info->ScsiStatus); + } break; case CMD_DATA_UNDERRUN: printk(KERN_WARNING "cciss: cmd %p has" @@ -1460,6 +2014,15 @@ } #endif /* CCISS_DEBUG */ +static void release_io_mem(ctlr_info_t *c) +{ + /* if IO mem was not protected do nothing */ + if( c->io_mem_addr == 0) + return; + release_region(c->io_mem_addr, c->io_mem_length); + c->io_mem_addr = 0; + c->io_mem_length = 0; +} static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) { ushort vendor_id, device_id, command; @@ -1489,17 +2052,49 @@ printk(KERN_ERR "cciss: Unable to set DMA mask\n"); return(-1); } - + (void) pci_read_config_word(pdev, PCI_COMMAND,&command); (void) pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); (void) pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size); (void) pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer); - (void) pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID, &board_id); + /* check to see if controller has been disabled */ + if(!(command & 0x02)) + { + printk(KERN_WARNING "cciss: controller appears to be disabled\n"); + return(-1); + } + + /* search for our IO range so we can protect it */ + for(i=0; i<6; i++) + { + /* is this an IO range */ + if( pdev->resource[i].flags & 0x01 ) + { + c->io_mem_addr = pdev->resource[i].start; + c->io_mem_length = pdev->resource[i].end - + pdev->resource[i].start +1; +#ifdef CCISS_DEBUG + printk("IO value found base_addr[%d] %lx %lx\n", i, + c->io_mem_addr, c->io_mem_length); +#endif /* CCISS_DEBUG */ + /* register the IO range */ + if(!request_region( c->io_mem_addr, + c->io_mem_length, "cciss")) + { + printk(KERN_WARNING "cciss I/O memory range already in use addr=%lx length=%ld\n", + c->io_mem_addr, c->io_mem_length); + c->io_mem_addr= 0; + c->io_mem_length = 0; + } + break; + } + } + #ifdef CCISS_DEBUG printk("vendor_id = %x\n", vendor_id); printk("device_id = %x\n", device_id); @@ -1520,7 +2115,7 @@ * table */ - c->paddr = addr[0] & 0xfffffff0; /* remove the addressing mode bits */ + c->paddr = addr[0] ; /* addressing mode bits already removed */ #ifdef CCISS_DEBUG printk("address 0 = %x\n", c->paddr); #endif /* CCISS_DEBUG */ @@ -1617,7 +2212,7 @@ int return_code; int i; int listlength = 0; - int lunid = 0; + __u32 lunid = 0; int block_size; int total_size; @@ -1689,14 +2284,19 @@ ld_buff->LUNListLength[1], ld_buff->LUNListLength[2], ld_buff->LUNListLength[3], hba[cntl_num]->num_luns); #endif /* CCISS_DEBUG */ - for(i=0; i< hba[cntl_num]->num_luns ; i++) + + hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1; + for(i=0; i< hba[cntl_num]->num_luns; i++) { + lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24; lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16; lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8; lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); + hba[cntl_num]->drv[i].LunID = lunid; + #ifdef CCISS_DEBUG printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i, ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2], @@ -1729,7 +2329,8 @@ } else /* read capacity command failed */ { printk(KERN_WARNING "cciss: read capacity failed\n"); - total_size = block_size = 0; + total_size = 0; + block_size = BLOCK_SIZE; } printk(KERN_INFO " blocks= %d block_size= %d\n", total_size, block_size); @@ -1781,6 +2382,7 @@ } kfree(ld_buff); kfree(size_buff); + kfree(inq_buff); } /* Function to find the first free pointer into our hba[] array */ @@ -1834,6 +2436,7 @@ memset(hba[i], 0, sizeof(ctlr_info_t)); if (cciss_pci_init(hba[i], pdev) != 0) { + release_io_mem(hba[i]); free_hba(i); return (-1); } @@ -1856,6 +2459,7 @@ { printk(KERN_ERR "cciss: Unable to get major number " "%d for %s\n", MAJOR_NR+i, hba[i]->devname); + release_io_mem(hba[i]); free_hba(i); return(-1); } @@ -1867,6 +2471,7 @@ printk(KERN_ERR "ciss: Unable to get irq %d for %s\n", hba[i]->intr, hba[i]->devname); unregister_blkdev( MAJOR_NR+i, hba[i]->devname); + release_io_mem(hba[i]); free_hba(i); return(-1); } @@ -1895,6 +2500,7 @@ hba[i]->errinfo_pool_dhandle); free_irq(hba[i]->intr, hba[i]); unregister_blkdev(MAJOR_NR+i, hba[i]->devname); + release_io_mem(hba[i]); free_hba(i); printk( KERN_ERR "cciss: out of memory"); return(-1); @@ -1944,7 +2550,7 @@ hba[i]->gendisk.minor_shift = NWD_SHIFT; hba[i]->gendisk.part = hba[i]->hd; hba[i]->gendisk.sizes = hba[i]->sizes; - hba[i]->gendisk.nr_real = hba[i]->num_luns; + hba[i]->gendisk.nr_real = hba[i]->highest_lun+1; /* Get on the disk list */ add_gendisk(&(hba[i]->gendisk)); @@ -1965,6 +2571,8 @@ { ctlr_info_t *tmp_ptr; int i; + char flush_buf[4]; + int return_code; if (pci_get_drvdata(pdev) == NULL) { @@ -1979,8 +2587,16 @@ "already be removed \n"); return; } - /* Turn board interrupts off */ - hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); + /* Turn board interrupts off and send the flush cache command */ + /* sendcmd will turn off interrupt, and send the flush... + * To write all data in the battery backed cache to disks */ + memset(flush_buf, 0, 4); + return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL); + if(return_code != IO_OK) + { + printk(KERN_WARNING "Error Flushing cache on controller %d\n", + i); + } free_irq(hba[i]->intr, hba[i]); pci_set_drvdata(pdev, NULL); iounmap((void*)hba[i]->vaddr); @@ -1996,6 +2612,7 @@ pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle); kfree(hba[i]->cmd_pool_bits); + release_io_mem(hba[i]); free_hba(i); } diff -urN linux-2.5.3-pre1/drivers/block/cciss.h linux/drivers/block/cciss.h --- linux-2.5.3-pre1/drivers/block/cciss.h Thu Jan 10 10:15:38 2002 +++ linux/drivers/block/cciss.h Sat Jan 19 16:58:39 2002 @@ -46,6 +46,8 @@ __u32 board_id; ulong vaddr; __u32 paddr; + unsigned long io_mem_addr; + unsigned long io_mem_length; CfgTable_struct *cfgtable; int intr; @@ -53,6 +55,7 @@ int commands_outstanding; int max_outstanding; /* Debug */ int num_luns; + int highest_lun; int usage_count; /* number of opens all all minor devices */ // information about each logical volume diff -urN linux-2.5.3-pre1/drivers/block/cciss_cmd.h linux/drivers/block/cciss_cmd.h --- linux-2.5.3-pre1/drivers/block/cciss_cmd.h Thu Jan 10 10:15:38 2002 +++ linux/drivers/block/cciss_cmd.h Sat Jan 19 16:58:39 2002 @@ -124,6 +124,12 @@ #define CCISS_READ 0x28 // Read(10) #define CCISS_WRITE 0x2a // Write(10) +// BMIC commands +#define BMIC_READ 0x26 +#define BMIC_WRITE 0x27 +#define BMIC_CACHE_FLUSH 0xc2 +#define CCISS_CACHE_FLUSH 0x01 //C2 was already being used by CCISS + //Command List Structure typedef union _SCSI3Addr_struct { struct { diff -urN linux-2.5.3-pre1/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- linux-2.5.3-pre1/drivers/block/ll_rw_blk.c Thu Jan 10 10:15:38 2002 +++ linux/drivers/block/ll_rw_blk.c Sat Jan 19 16:58:39 2002 @@ -186,7 +186,8 @@ * full 4GB zone, so we have to resort to low memory for any bounces. * ISA has its own < 16MB zone. */ - if (dma_addr == BLK_BOUNCE_ISA) { + if (bounce_pfn < blk_max_low_pfn) { + BUG_ON(dma_addr < BLK_BOUNCE_ISA); init_emergency_isa_pool(); q->bounce_gfp = GFP_NOIO | GFP_DMA; } else @@ -302,8 +303,8 @@ static char *rq_flags[] = { "REQ_RW", "REQ_RW_AHEAD", "REQ_BARRIER", "REQ_CMD", "REQ_NOMERGE", "REQ_STARTED", "REQ_DONTPREP", "REQ_DRIVE_CMD", "REQ_DRIVE_TASK", - "REQ_PC", "REQ_BLOCK_PC", "REQ_SENSE", - "REQ_SPECIAL" }; + "REQ_DRIVE_ACB", "REQ_PC", "REQ_BLOCK_PC", + "REQ_SENSE", "REQ_SPECIAL" }; void blk_dump_rq_flags(struct request *rq, char *msg) { diff -urN linux-2.5.3-pre1/drivers/char/lp.c linux/drivers/char/lp.c --- linux-2.5.3-pre1/drivers/char/lp.c Fri Jan 4 21:19:50 2002 +++ linux/drivers/char/lp.c Sat Jan 19 16:58:39 2002 @@ -367,7 +367,7 @@ = lp_negotiate (port, lp_table[minor].best_mode); - } else if (current->need_resched) + } else if (need_resched()) schedule (); if (count) { diff -urN linux-2.5.3-pre1/drivers/char/mem.c linux/drivers/char/mem.c --- linux-2.5.3-pre1/drivers/char/mem.c Sat Jan 19 16:58:37 2002 +++ linux/drivers/char/mem.c Sat Jan 19 16:58:39 2002 @@ -381,8 +381,7 @@ unsigned long unwritten = clear_user(buf, PAGE_SIZE); if (unwritten) return size + unwritten - PAGE_SIZE; - if (current->need_resched) - schedule(); + cond_resched(); buf += PAGE_SIZE; size -= PAGE_SIZE; } while (size); diff -urN linux-2.5.3-pre1/drivers/char/mwave/3780i.c linux/drivers/char/mwave/3780i.c --- linux-2.5.3-pre1/drivers/char/mwave/3780i.c Sun Sep 30 12:26:05 2001 +++ linux/drivers/char/mwave/3780i.c Sat Jan 19 16:58:39 2002 @@ -68,11 +68,9 @@ static void PaceMsaAccess(unsigned short usDspBaseIO) { - if(current->need_resched) - schedule(); + cond_resched(); udelay(100); - if(current->need_resched) - schedule(); + cond_resched(); } unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO, diff -urN linux-2.5.3-pre1/drivers/char/ppdev.c linux/drivers/char/ppdev.c --- linux-2.5.3-pre1/drivers/char/ppdev.c Tue Jan 1 18:55:31 2002 +++ linux/drivers/char/ppdev.c Sat Jan 19 16:58:39 2002 @@ -170,9 +170,7 @@ break; } - if (current->need_resched) { - schedule (); - } + cond_resched(); } kfree (kbuffer); @@ -242,9 +240,7 @@ break; } - if (current->need_resched) { - schedule (); - } + cond_resched(); } kfree (kbuffer); diff -urN linux-2.5.3-pre1/drivers/char/random.c linux/drivers/char/random.c --- linux-2.5.3-pre1/drivers/char/random.c Fri Nov 9 14:01:21 2001 +++ linux/drivers/char/random.c Sat Jan 19 16:58:39 2002 @@ -1313,7 +1313,7 @@ /* * Check if we need to break out or reschedule.... */ - if ((flags & EXTRACT_ENTROPY_USER) && current->need_resched) { + if ((flags & EXTRACT_ENTROPY_USER) && need_resched()) { if (signal_pending(current)) { if (ret == 0) ret = -ERESTARTSYS; diff -urN linux-2.5.3-pre1/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- linux-2.5.3-pre1/drivers/char/tty_io.c Thu Jan 3 13:22:21 2002 +++ linux/drivers/char/tty_io.c Sat Jan 19 16:58:39 2002 @@ -712,8 +712,7 @@ ret = -ERESTARTSYS; if (signal_pending(current)) break; - if (current->need_resched) - schedule(); + cond_resched(); } } if (written) { diff -urN linux-2.5.3-pre1/drivers/hotplug/cpqphp_core.c linux/drivers/hotplug/cpqphp_core.c --- linux-2.5.3-pre1/drivers/hotplug/cpqphp_core.c Fri Nov 9 14:01:21 2001 +++ linux/drivers/hotplug/cpqphp_core.c Sat Jan 19 16:58:39 2002 @@ -404,6 +404,10 @@ result = pci_hp_register (new_slot->hotplug_slot); if (result) { err ("pci_hp_register failed with error %d\n", result); + kfree (new_slot->hotplug_slot->info); + kfree (new_slot->hotplug_slot->name); + kfree (new_slot->hotplug_slot); + kfree (new_slot); return result; } @@ -429,6 +433,8 @@ while (old_slot) { next_slot = old_slot->next; pci_hp_deregister (old_slot->hotplug_slot); + kfree(old_slot->hotplug_slot->info); + kfree(old_slot->hotplug_slot->name); kfree(old_slot->hotplug_slot); kfree(old_slot); old_slot = next_slot; diff -urN linux-2.5.3-pre1/drivers/i2c/i2c-algo-bit.c linux/drivers/i2c/i2c-algo-bit.c --- linux-2.5.3-pre1/drivers/i2c/i2c-algo-bit.c Thu Oct 11 08:05:47 2001 +++ linux/drivers/i2c/i2c-algo-bit.c Sat Jan 19 16:58:39 2002 @@ -50,7 +50,7 @@ /* might not like this, as they have an internal timeout of some mils */ /* #define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ - if (need_resched) schedule(); + cond_resched(); */ @@ -120,8 +120,7 @@ if (start+adap->timeout <= jiffies) { return -ETIMEDOUT; } - if (current->need_resched) - schedule(); + cond_resched(); } DEBSTAT(printk("needed %ld jiffies\n", jiffies-start)); #ifdef SLO_IO diff -urN linux-2.5.3-pre1/drivers/i2c/i2c-algo-ite.c linux/drivers/i2c/i2c-algo-ite.c --- linux-2.5.3-pre1/drivers/i2c/i2c-algo-ite.c Thu Oct 11 08:05:47 2001 +++ linux/drivers/i2c/i2c-algo-ite.c Sat Jan 19 16:58:39 2002 @@ -67,7 +67,7 @@ /* might not like this, as they have an internal timeout of some mils */ /* #define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ - if (need_resched) schedule(); + cond_resched(); */ diff -urN linux-2.5.3-pre1/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c --- linux-2.5.3-pre1/drivers/ide/ide-disk.c Sat Jan 19 16:58:37 2002 +++ linux/drivers/ide/ide-disk.c Sat Jan 19 16:58:39 2002 @@ -123,12 +123,10 @@ */ static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) { - if (rq_data_dir(rq) == READ) - goto good_command; - if (rq_data_dir(rq) == WRITE) + if (rq->flags & REQ_CMD) goto good_command; - printk(KERN_ERR "%s: bad command: %lx\n", drive->name, rq->flags); + blk_dump_rq_flags(rq, "do_rw_disk, bad command"); ide_end_request(0, HWGROUP(drive)); return ide_stopped; @@ -179,8 +177,10 @@ struct hd_drive_task_hdr taskfile; struct hd_drive_hob_hdr hobfile; ide_task_t args; + int sectors; task_ioreg_t command = get_command(drive, rq_data_dir(rq)); + unsigned int track = (block / drive->sect); unsigned int sect = (block % drive->sect) + 1; unsigned int head = (track % drive->head); @@ -189,7 +189,16 @@ memset(&taskfile, 0, sizeof(task_struct_t)); memset(&hobfile, 0, sizeof(hob_struct_t)); - taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors; + sectors = rq->nr_sectors; + if (sectors == 256) + sectors = 0; + if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) { + sectors = drive->mult_count; + if (sectors > rq->current_nr_sectors) + sectors = rq->current_nr_sectors; + } + + taskfile.sector_count = sectors; taskfile.sector_number = sect; taskfile.low_cylinder = cyl; taskfile.high_cylinder = (cyl>>8); @@ -225,13 +234,23 @@ struct hd_drive_task_hdr taskfile; struct hd_drive_hob_hdr hobfile; ide_task_t args; + int sectors; task_ioreg_t command = get_command(drive, rq_data_dir(rq)); + sectors = rq->nr_sectors; + if (sectors == 256) + sectors = 0; + if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) { + sectors = drive->mult_count; + if (sectors > rq->current_nr_sectors) + sectors = rq->current_nr_sectors; + } + memset(&taskfile, 0, sizeof(task_struct_t)); memset(&hobfile, 0, sizeof(hob_struct_t)); - taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors; + taskfile.sector_count = sectors; taskfile.sector_number = block; taskfile.low_cylinder = (block>>=8); taskfile.high_cylinder = (block>>=8); @@ -273,14 +292,24 @@ struct hd_drive_task_hdr taskfile; struct hd_drive_hob_hdr hobfile; ide_task_t args; + int sectors; task_ioreg_t command = get_command(drive, rq_data_dir(rq)); memset(&taskfile, 0, sizeof(task_struct_t)); memset(&hobfile, 0, sizeof(hob_struct_t)); - taskfile.sector_count = rq->nr_sectors; - hobfile.sector_count = (rq->nr_sectors>>8); + sectors = rq->nr_sectors; + if (sectors == 256) + sectors = 0; + if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) { + sectors = drive->mult_count; + if (sectors > rq->current_nr_sectors) + sectors = rq->current_nr_sectors; + } + + taskfile.sector_count = sectors; + hobfile.sector_count = sectors >> 8; if (rq->nr_sectors == 65536) { taskfile.sector_count = 0x00; @@ -652,7 +681,7 @@ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); taskfile.sector_count = drive->mult_req; taskfile.command = WIN_SETMULT; - do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile)); + do_taskfile(drive, &taskfile, &hobfile, &set_multmode_intr); } } else if (s->all) { int special = s->all; @@ -789,23 +818,12 @@ #endif /* CONFIG_PROC_FS */ +/* + * This is tightly woven into the driver->do_special can not touch. + * DON'T do it again until a total personality rewrite is committed. + */ static int set_multcount(ide_drive_t *drive, int arg) { -#if 1 - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - - if (drive->special.b.set_multmode) - return -EBUSY; - - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - taskfile.sector_count = drive->mult_req; - taskfile.command = WIN_SETMULT; - drive->mult_req = arg; - drive->special.b.set_multmode = 1; - ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); -#else struct request rq; if (drive->special.b.set_multmode) @@ -814,7 +832,6 @@ drive->mult_req = arg; drive->special.b.set_multmode = 1; (void) ide_do_drive_cmd (drive, &rq, ide_wait); -#endif return (drive->mult_count == arg) ? 0 : -EIO; } diff -urN linux-2.5.3-pre1/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c --- linux-2.5.3-pre1/drivers/ide/ide-floppy.c Sat Jan 19 16:58:37 2002 +++ linux/drivers/ide/ide-floppy.c Sat Jan 19 16:58:39 2002 @@ -688,7 +688,7 @@ /* Why does this happen? */ if (!rq) return; - if (rq->flags & IDEFLOPPY_RQ) { + if (!(rq->flags & IDEFLOPPY_RQ)) { ide_end_request (uptodate, hwgroup); return; } diff -urN linux-2.5.3-pre1/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c --- linux-2.5.3-pre1/drivers/ide/ide-tape.c Sat Jan 19 16:58:37 2002 +++ linux/drivers/ide/ide-tape.c Sat Jan 19 16:58:39 2002 @@ -721,7 +721,7 @@ int request_transfer; /* Bytes to transfer */ int actually_transferred; /* Bytes actually transferred */ int buffer_size; /* Size of our data buffer */ - struct buffer_head *bh; + struct bio *bio; char *b_data; int b_count; byte *buffer; /* Data buffer */ @@ -805,7 +805,7 @@ */ typedef struct idetape_stage_s { struct request rq; /* The corresponding request */ - struct buffer_head *bh; /* The data buffers */ + struct bio *bio; /* The data buffers */ struct idetape_stage_s *next; /* Pointer to the next stage */ os_aux_t *aux; /* OnStream aux ptr */ } idetape_stage_t; @@ -929,7 +929,7 @@ int stage_size; /* Data buffer size (chosen based on the tape's recommendation */ idetape_stage_t *merge_stage; int merge_stage_size; - struct buffer_head *bh; + struct bio *bio; char *b_data; int b_count; @@ -1013,7 +1013,7 @@ * Measures number of frames: * * 1. written/read to/from the driver pipeline (pipeline_head). - * 2. written/read to/from the tape buffers (buffer_head). + * 2. written/read to/from the tape buffers (bio). * 3. written/read by the tape to/from the media (tape_head). */ int pipeline_head; @@ -1493,52 +1493,52 @@ static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount) { - struct buffer_head *bh = pc->bh; + struct bio *bio = pc->bio; int count; while (bcount) { #if IDETAPE_DEBUG_BUGS - if (bh == NULL) { - printk (KERN_ERR "ide-tape: bh == NULL in idetape_input_buffers\n"); + if (bio == NULL) { + printk (KERN_ERR "ide-tape: bio == NULL in idetape_input_buffers\n"); idetape_discard_data (drive, bcount); return; } #endif /* IDETAPE_DEBUG_BUGS */ - count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount); - atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count); + count = IDE_MIN (bio->bi_size - pc->b_count, bcount); + atapi_input_bytes (drive, bio_data(bio) + pc->b_count, count); bcount -= count; - atomic_add(count, &bh->b_count); - if (atomic_read(&bh->b_count) == bh->b_size) { - bh = bh->b_reqnext; - if (bh) - atomic_set(&bh->b_count, 0); + pc->b_count += bio->bi_size; + if (pc->b_count == bio->bi_size) { + bio = bio->bi_next; + if (bio) + pc->b_count = 0; } } - pc->bh = bh; + pc->bio = bio; } static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount) { - struct buffer_head *bh = pc->bh; + struct bio *bio = pc->bio; int count; while (bcount) { #if IDETAPE_DEBUG_BUGS - if (bh == NULL) { - printk (KERN_ERR "ide-tape: bh == NULL in idetape_output_buffers\n"); + if (bio == NULL) { + printk (KERN_ERR "ide-tape: bio == NULL in idetape_output_buffers\n"); return; } #endif /* IDETAPE_DEBUG_BUGS */ count = IDE_MIN (pc->b_count, bcount); - atapi_output_bytes (drive, pc->b_data, count); + atapi_output_bytes (drive, bio_data(bio), count); bcount -= count; pc->b_data += count; pc->b_count -= count; if (!pc->b_count) { - pc->bh = bh = bh->b_reqnext; - if (bh) { - pc->b_data = bh->b_data; - pc->b_count = atomic_read(&bh->b_count); + pc->bio = bio = bio->bi_next; + if (bio) { + pc->b_data = bio_data(bio); + pc->b_count = bio->bi_size; } } } @@ -1547,25 +1547,25 @@ #ifdef CONFIG_BLK_DEV_IDEDMA static void idetape_update_buffers (idetape_pc_t *pc) { - struct buffer_head *bh = pc->bh; + struct bio *bio = pc->bio; int count, bcount = pc->actually_transferred; if (test_bit (PC_WRITING, &pc->flags)) return; while (bcount) { #if IDETAPE_DEBUG_BUGS - if (bh == NULL) { - printk (KERN_ERR "ide-tape: bh == NULL in idetape_update_buffers\n"); + if (bio == NULL) { + printk (KERN_ERR "ide-tape: bio == NULL in idetape_update_buffers\n"); return; } #endif /* IDETAPE_DEBUG_BUGS */ - count = IDE_MIN (bh->b_size, bcount); - atomic_set(&bh->b_count, count); - if (atomic_read(&bh->b_count) == bh->b_size) - bh = bh->b_reqnext; + count = IDE_MIN (bio->bi_size, bcount); + pc->b_count = count; + if (pc->b_count == bio->bi_size) + bio = bio->bi_next; bcount -= count; } - pc->bh = bh; + pc->bio = bio; } #endif /* CONFIG_BLK_DEV_IDEDMA */ @@ -1625,7 +1625,7 @@ pc->request_transfer = 0; pc->buffer = pc->pc_buffer; pc->buffer_size = IDETAPE_PC_BUFFER_SIZE; - pc->bh = NULL; + pc->bio = NULL; pc->b_data = NULL; } @@ -1706,10 +1706,10 @@ printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name); #endif while (stage) { - if (stage->rq.cmd == IDETAPE_WRITE_RQ) - stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ; - else if (stage->rq.cmd == IDETAPE_READ_RQ) - stage->rq.cmd = IDETAPE_ABORTED_READ_RQ; + if (stage->rq.flags == IDETAPE_WRITE_RQ) + stage->rq.flags = IDETAPE_ABORTED_WRITE_RQ; + else if (stage->rq.flags == IDETAPE_READ_RQ) + stage->rq.flags = IDETAPE_ABORTED_READ_RQ; stage = stage->next; } } @@ -1735,7 +1735,7 @@ #endif /* IDETAPE_DEBUG_BUGS */ rq->buffer = NULL; - rq->bh = stage->bh; + rq->bio = stage->bio; tape->active_data_request = rq; tape->active_stage = stage; tape->next_stage = stage->next; @@ -1769,21 +1769,21 @@ */ static void __idetape_kfree_stage (idetape_stage_t *stage) { - struct buffer_head *prev_bh, *bh = stage->bh; + struct bio *prev_bio, *bio = stage->bio; int size; - while (bh != NULL) { - if (bh->b_data != NULL) { - size = (int) bh->b_size; + while (bio != NULL) { + if (bio_data(bio) != NULL) { + size = (int) bio->bi_size; while (size > 0) { - free_page ((unsigned long) bh->b_data); + free_page ((unsigned long) bio_data(bio)); size -= PAGE_SIZE; - bh->b_data += PAGE_SIZE; + bio->bi_size += PAGE_SIZE; } } - prev_bh = bh; - bh = bh->b_reqnext; - kfree (prev_bh); + prev_bio = bio; + bio = bio->bi_next; + kfree (prev_bio); } kfree (stage); } @@ -1868,13 +1868,13 @@ tape->active_stage = NULL; tape->active_data_request = NULL; tape->nr_pending_stages--; - if (rq->cmd == IDETAPE_WRITE_RQ) { + if (rq->flags == IDETAPE_WRITE_RQ) { #if ONSTREAM_DEBUG if (tape->debug_level >= 2) { if (tape->onstream) { stage = tape->first_stage; aux = stage->aux; - p = stage->bh->b_data; + p = bio_data(stage->bio); if (ntohl(aux->logical_blk_num) < 11300 && ntohl(aux->logical_blk_num) > 11100) printk(KERN_INFO "ide-tape: finished writing logical blk %u (data %x %x %x %x)\n", ntohl(aux->logical_blk_num), *p++, *p++, *p++, *p++); } @@ -1908,7 +1908,7 @@ complete(tape->waiting); } } - } else if (rq->cmd == IDETAPE_READ_RQ) { + } else if (rq->flags == IDETAPE_READ_RQ) { if (error == IDETAPE_ERROR_EOD) { set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags); idetape_abort_pipeline(drive); @@ -1984,7 +1984,7 @@ { ide_init_drive_cmd (rq); rq->buffer = (char *) pc; - rq->cmd = IDETAPE_PC_RQ1; + rq->flags = IDETAPE_PC_RQ1; (void) ide_do_drive_cmd (drive, rq, ide_preempt); } @@ -2164,12 +2164,12 @@ } } if (test_bit (PC_WRITING, &pc->flags)) { - if (pc->bh != NULL) + if (pc->bio != NULL) idetape_output_buffers (drive, pc, bcount.all); else atapi_output_bytes (drive,pc->current_position,bcount.all); /* Write the current buffer */ } else { - if (pc->bh != NULL) + if (pc->bio != NULL) idetape_input_buffers (drive, pc, bcount.all); else atapi_input_bytes (drive,pc->current_position,bcount.all); /* Read the current buffer */ @@ -2523,21 +2523,22 @@ return ide_stopped; } -static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh) +static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio) { - struct buffer_head *p = bh; + struct bio *p = bio; + struct bio_vec *bv = bio_iovec(p); idetape_init_pc (pc); pc->c[0] = IDETAPE_READ_CMD; put_unaligned (htonl (length), (unsigned int *) &pc->c[1]); pc->c[1] = 1; pc->callback = &idetape_rw_callback; - pc->bh = bh; - atomic_set(&bh->b_count, 0); + pc->bio = bio; + bv->bv_len = 0; pc->buffer = NULL; if (tape->onstream) { while (p) { - atomic_set(&p->b_count, 0); - p = p->b_reqnext; + bv->bv_len = 0; + p = p->bi_next; } } if (!tape->onstream) { @@ -2553,30 +2554,31 @@ } } -static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh) +static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio) { int size = 32768; - struct buffer_head *p = bh; + struct bio *p = bio; idetape_init_pc (pc); pc->c[0] = IDETAPE_READ_BUFFER_CMD; pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK; pc->c[7] = size >> 8; pc->c[8] = size & 0xff; pc->callback = &idetape_pc_callback; - pc->bh = bh; - atomic_set(&bh->b_count, 0); + pc->bio = bio; + atomic_set(&bio->bi_cnt, 0); pc->buffer = NULL; while (p) { - atomic_set(&p->b_count, 0); - p = p->b_reqnext; + p->bi_size = 0; + p = p->bi_next; } pc->request_transfer = pc->buffer_size = size; } -static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh) +static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio) { - struct buffer_head *p = bh; + struct bio *p = bio; + struct bio_vec *bv= bio_iovec(p); idetape_init_pc (pc); pc->c[0] = IDETAPE_WRITE_CMD; put_unaligned (htonl (length), (unsigned int *) &pc->c[1]); @@ -2585,13 +2587,13 @@ set_bit (PC_WRITING, &pc->flags); if (tape->onstream) { while (p) { - atomic_set(&p->b_count, p->b_size); - p = p->b_reqnext; + bv->bv_len = p->bi_size; + p = p->bi_next; } } - pc->bh = bh; - pc->b_data = bh->b_data; - pc->b_count = atomic_read(&bh->b_count); + pc->bio = bio; + pc->b_data = bio_data(bio); + pc->b_count = bio->bi_size; pc->buffer = NULL; if (!tape->onstream) { pc->request_transfer = pc->buffer_size = length * tape->tape_block_size; @@ -2618,16 +2620,16 @@ #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 5) - printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors); +/* printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %ld, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->flags,rq->errors); */ if (tape->debug_level >= 2) - printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors); + printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors); #endif /* IDETAPE_DEBUG_LOG */ - if (!IDETAPE_RQ_CMD (rq->cmd)) { + if (!IDETAPE_RQ_CMD (rq->flags)) { /* * We do not support buffer cache originated requests. */ - printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd); + printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%ld)\n", drive->name, rq->flags); ide_end_request (0, HWGROUP (drive)); /* Let the common code handle it */ return ide_stopped; } @@ -2661,7 +2663,7 @@ */ if (tape->onstream) status.b.dsc = 1; - if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2) + if (!drive->dsc_overlap && rq->flags != IDETAPE_PC_RQ2) set_bit (IDETAPE_IGNORE_DSC, &tape->flags); /* @@ -2674,7 +2676,7 @@ */ if (tape->tape_still_time > 100 && tape->tape_still_time < 200) tape->measure_insert_time = 1; - if (tape->req_buffer_fill && (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) { + if (tape->req_buffer_fill && (rq->flags == IDETAPE_WRITE_RQ || rq->flags == IDETAPE_READ_RQ)) { tape->req_buffer_fill = 0; tape->writes_since_buffer_fill = 0; tape->reads_since_buffer_fill = 0; @@ -2688,19 +2690,19 @@ tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); calculate_speeds(drive); if (tape->onstream && tape->max_frames && - ((rq->cmd == IDETAPE_WRITE_RQ && + ((rq->flags == IDETAPE_WRITE_RQ && ( tape->cur_frames == tape->max_frames || ( tape->speed_control && tape->cur_frames > 5 && (tape->insert_speed > tape->max_insert_speed || (0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */) ) ) ) ) || - (rq->cmd == IDETAPE_READ_RQ && + (rq->flags == IDETAPE_READ_RQ && ( tape->cur_frames == 0 || ( tape->speed_control && (tape->cur_frames < tape->max_frames - 5) && tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) { #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n", - rq->cmd, tape->cur_frames, tape->max_frames); + printk(KERN_INFO "ide-tape: postponing request, cmd %ld, cur %d, max %d\n", + rq->flags, tape->cur_frames, tape->max_frames); #endif if (tape->postpone_cnt++ < 500) { status.b.dsc = 0; @@ -2718,7 +2720,7 @@ tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT; } else if ((signed long) (jiffies - tape->dsc_timeout) > 0) { printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name); - if (rq->cmd == IDETAPE_PC_RQ2) { + if (rq->flags == IDETAPE_PC_RQ2) { idetape_media_access_finished (drive); return ide_stopped; } else { @@ -2729,7 +2731,7 @@ idetape_postpone_request (drive); return ide_stopped; } - switch (rq->cmd) { + switch (rq->flags) { case IDETAPE_READ_RQ: tape->buffer_head++; #if USE_IOTRACE @@ -2744,7 +2746,7 @@ tape->req_buffer_fill = 1; } pc = idetape_next_pc_storage (drive); - idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh); + idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bio); break; case IDETAPE_WRITE_RQ: tape->buffer_head++; @@ -2761,15 +2763,15 @@ calculate_speeds(drive); } pc = idetape_next_pc_storage (drive); - idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh); + idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bio); break; case IDETAPE_READ_BUFFER_RQ: tape->postpone_cnt = 0; pc = idetape_next_pc_storage (drive); - idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bh); + idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bio); break; case IDETAPE_ABORTED_WRITE_RQ: - rq->cmd = IDETAPE_WRITE_RQ; + rq->flags = IDETAPE_WRITE_RQ; idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive)); return ide_stopped; case IDETAPE_ABORTED_READ_RQ: @@ -2777,12 +2779,12 @@ if (tape->debug_level >= 2) printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name); #endif - rq->cmd = IDETAPE_READ_RQ; + rq->flags = IDETAPE_READ_RQ; idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive)); return ide_stopped; case IDETAPE_PC_RQ1: pc = (idetape_pc_t *) rq->buffer; - rq->cmd = IDETAPE_PC_RQ2; + rq->flags = IDETAPE_PC_RQ2; break; case IDETAPE_PC_RQ2: idetape_media_access_finished (drive); @@ -2822,61 +2824,65 @@ static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, int clear) { idetape_stage_t *stage; - struct buffer_head *prev_bh, *bh; + struct bio *prev_bio, *bio; int pages = tape->pages_per_stage; - char *b_data; + char *b_data = NULL; + struct bio_vec *bv; if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL) return NULL; stage->next = NULL; - bh = stage->bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL); - if (bh == NULL) + bio = stage->bio = bio_alloc(GFP_KERNEL,1); + bv = bio_iovec(bio); + bv->bv_len = 0; + if (bio == NULL) goto abort; - bh->b_reqnext = NULL; - if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL) + bio->bi_next = NULL; + if ((bio->bi_io_vec[0].bv_page = alloc_page(GFP_KERNEL)) == NULL) goto abort; if (clear) - memset(bh->b_data, 0, PAGE_SIZE); - bh->b_size = PAGE_SIZE; - atomic_set(&bh->b_count, full ? bh->b_size : 0); - set_bit (BH_Lock, &bh->b_state); + memset(bio_data(bio), 0, PAGE_SIZE); + bio->bi_size = PAGE_SIZE; + if(bv->bv_len == full) bv->bv_len = bio->bi_size; + set_bit (BH_Lock, &bio->bi_flags); while (--pages) { - if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL) + if ((bio->bi_io_vec[pages].bv_page = alloc_page(GFP_KERNEL)) == NULL) goto abort; if (clear) - memset(b_data, 0, PAGE_SIZE); - if (bh->b_data == b_data + PAGE_SIZE) { - bh->b_size += PAGE_SIZE; - bh->b_data -= PAGE_SIZE; + memset(bio_data(bio), 0, PAGE_SIZE); + if (bio->bi_size == bv->bv_len + PAGE_SIZE) { + bio->bi_size += PAGE_SIZE; + bv->bv_len += PAGE_SIZE; + bv->bv_offset -= PAGE_SIZE; if (full) - atomic_add(PAGE_SIZE, &bh->b_count); + bio->bi_size += PAGE_SIZE; continue; } - if (b_data == bh->b_data + bh->b_size) { - bh->b_size += PAGE_SIZE; + if (b_data == bio_data(bio) + bio->bi_size) { + bio->bi_size += PAGE_SIZE; if (full) - atomic_add(PAGE_SIZE, &bh->b_count); + bio->bi_size += PAGE_SIZE; continue; } - prev_bh = bh; - if ((bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL)) == NULL) { - free_page ((unsigned long) b_data); + prev_bio = bio; + if ((bio = bio_alloc(GFP_KERNEL,1)) == NULL) { + free_page ((unsigned long) bio_data(bio)); goto abort; } - bh->b_reqnext = NULL; - bh->b_data = b_data; - bh->b_size = PAGE_SIZE; - atomic_set(&bh->b_count, full ? bh->b_size : 0); - set_bit (BH_Lock, &bh->b_state); - prev_bh->b_reqnext = bh; + bio->bi_next = NULL; + //bio->bi_io_vec[0].bv_offset = b_data; + bio->bi_size = PAGE_SIZE; + atomic_set(&bio->bi_cnt, full ? bio->bi_size : 0); + set_bit (BH_Lock, &bio->bi_flags); + prev_bio->bi_next = bio; } - bh->b_size -= tape->excess_bh_size; + bio->bi_size -= tape->excess_bh_size; if (full) - atomic_sub(tape->excess_bh_size, &bh->b_count); + atomic_sub(tape->excess_bh_size, &bio->bi_cnt); if (tape->onstream) - stage->aux = (os_aux_t *) (bh->b_data + bh->b_size - OS_AUX_SIZE); + stage->aux = (os_aux_t *) (bio_data(bio) + bio->bi_size - OS_AUX_SIZE); return stage; abort: __idetape_kfree_stage (stage); @@ -2903,39 +2909,39 @@ static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n) { - struct buffer_head *bh = tape->bh; + struct bio *bio = tape->bio; int count; while (n) { #if IDETAPE_DEBUG_BUGS - if (bh == NULL) { - printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_from_user\n"); + if (bio == NULL) { + printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_from_user\n"); return; } #endif /* IDETAPE_DEBUG_BUGS */ - count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n); - copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count); + count = IDE_MIN (bio->bi_size - tape->b_count, n); + copy_from_user (bio_data(bio) + tape->b_count, buf, count); n -= count; - atomic_add(count, &bh->b_count); + bio->bi_size += count; buf += count; - if (atomic_read(&bh->b_count) == bh->b_size) { - bh = bh->b_reqnext; - if (bh) - atomic_set(&bh->b_count, 0); + if (tape->b_count == bio->bi_size) { + bio = bio->bi_next; + if (bio) + tape->b_count = 0; } } - tape->bh = bh; + tape->bio = bio; } static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape_stage_t *stage, int n) { - struct buffer_head *bh = tape->bh; + struct bio *bio = tape->bio; int count; while (n) { #if IDETAPE_DEBUG_BUGS - if (bh == NULL) { - printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_to_user\n"); + if (bio == NULL) { + printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_to_user\n"); return; } #endif /* IDETAPE_DEBUG_BUGS */ @@ -2946,10 +2952,10 @@ tape->b_count -= count; buf += count; if (!tape->b_count) { - tape->bh = bh = bh->b_reqnext; - if (bh) { - tape->b_data = bh->b_data; - tape->b_count = atomic_read(&bh->b_count); + tape->bio = bio = bio->bi_next; + if (bio) { + tape->b_data = bio_data(bio); + tape->b_count = bio->bi_size; } } } @@ -2957,25 +2963,25 @@ static void idetape_init_merge_stage (idetape_tape_t *tape) { - struct buffer_head *bh = tape->merge_stage->bh; + struct bio *bio = tape->merge_stage->bio; - tape->bh = bh; + tape->bio = bio; if (tape->chrdev_direction == idetape_direction_write) - atomic_set(&bh->b_count, 0); + atomic_set(&bio->bi_cnt, 0); else { - tape->b_data = bh->b_data; - tape->b_count = atomic_read(&bh->b_count); + tape->b_data = bio_data(bio); + tape->b_count = atomic_read(&bio->bi_cnt); } } static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage) { - struct buffer_head *tmp; + struct bio *tmp; os_aux_t *tmp_aux; - tmp = stage->bh; tmp_aux = stage->aux; - stage->bh = tape->merge_stage->bh; stage->aux = tape->merge_stage->aux; - tape->merge_stage->bh = tmp; tape->merge_stage->aux = tmp_aux; + tmp = stage->bio; tmp_aux = stage->aux; + stage->bio = tape->merge_stage->bio; stage->aux = tape->merge_stage->aux; + tape->merge_stage->bio = tmp; tape->merge_stage->aux = tmp_aux; idetape_init_merge_stage (tape); } @@ -3077,7 +3083,7 @@ idetape_tape_t *tape = drive->driver_data; #if IDETAPE_DEBUG_BUGS - if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) { + if (rq == NULL || !IDETAPE_RQ_CMD (rq->flags)) { printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n"); return; } @@ -3185,7 +3191,7 @@ ide_init_drive_cmd (&rq); rq.buffer = (char *) pc; - rq.cmd = IDETAPE_PC_RQ1; + rq.flags = IDETAPE_PC_RQ1; return ide_do_drive_cmd (drive, &rq, ide_wait); } @@ -3430,7 +3436,7 @@ * idetape_queue_rw_tail generates a read/write request for the block * device interface and wait for it to be serviced. */ -static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct buffer_head *bh) +static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct bio *bio) { idetape_tape_t *tape = drive->driver_data; struct request rq; @@ -3447,8 +3453,8 @@ #endif /* IDETAPE_DEBUG_BUGS */ ide_init_drive_cmd (&rq); - rq.bh = bh; - rq.cmd = cmd; + rq.bio = bio; + rq.flags = cmd; rq.sector = tape->first_frame_position; rq.nr_sectors = rq.current_nr_sectors = blocks; if (tape->onstream) @@ -3489,15 +3495,15 @@ if (!first) first = stage; aux = stage->aux; - p = stage->bh->b_data; - idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bh); + p = bio_data(stage->bio); + idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bio); #if ONSTREAM_DEBUG if (tape->debug_level >= 2) printk(KERN_INFO "ide-tape: %s: read back logical block %d, data %x %x %x %x\n", tape->name, logical_blk_num, *p++, *p++, *p++, *p++); #endif rq = &stage->rq; ide_init_drive_cmd (rq); - rq->cmd = IDETAPE_WRITE_RQ; + rq->flags = IDETAPE_WRITE_RQ; rq->sector = tape->first_frame_position; rq->nr_sectors = rq->current_nr_sectors = tape->capabilities.ctl; idetape_init_stage(drive, stage, OS_FRAME_TYPE_DATA, logical_blk_num++); @@ -3646,18 +3652,18 @@ os_aux_t *aux = stage->aux; os_partition_t *par = &aux->partition; struct request *rq = &stage->rq; - struct buffer_head *bh; + struct bio *bio; if (!tape->onstream) return 1; if (tape->raw) { if (rq->errors) { - bh = stage->bh; - while (bh) { - memset(bh->b_data, 0, bh->b_size); - bh = bh->b_reqnext; + bio = stage->bio; + while (bio) { + memset(bio_data(bio), 0, bio->bi_size); + bio = bio->bi_next; } - strcpy(stage->bh->b_data, "READ ERROR ON FRAME"); + strcpy(bio_data(stage->bio), "READ ERROR ON FRAME"); } return 1; } @@ -3767,12 +3773,12 @@ * Linux is short on memory. Fallback to * non-pipelined operation mode for this request. */ - return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh); + return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio); } } rq = &new_stage->rq; ide_init_drive_cmd (rq); - rq->cmd = IDETAPE_WRITE_RQ; + rq->flags = IDETAPE_WRITE_RQ; rq->sector = tape->first_frame_position; /* Doesn't actually matter - We always assume sequential access */ rq->nr_sectors = rq->current_nr_sectors = blocks; @@ -3843,7 +3849,7 @@ { idetape_tape_t *tape = drive->driver_data; int blocks, i, min; - struct buffer_head *bh; + struct bio *bio; #if IDETAPE_DEBUG_BUGS if (tape->chrdev_direction != idetape_direction_write) { @@ -3860,22 +3866,22 @@ if (tape->merge_stage_size % tape->tape_block_size) { blocks++; i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size; - bh = tape->bh->b_reqnext; - while (bh) { - atomic_set(&bh->b_count, 0); - bh = bh->b_reqnext; + bio = tape->bio->bi_next; + while (bio) { + atomic_set(&bio->bi_cnt, 0); + bio = bio->bi_next; } - bh = tape->bh; + bio = tape->bio; while (i) { - if (bh == NULL) { - printk(KERN_INFO "ide-tape: bug, bh NULL\n"); + if (bio == NULL) { + printk(KERN_INFO "ide-tape: bug, bio NULL\n"); break; } - min = IDE_MIN(i, bh->b_size - atomic_read(&bh->b_count)); - memset(bh->b_data + atomic_read(&bh->b_count), 0, min); - atomic_add(min, &bh->b_count); + min = IDE_MIN(i, bio->bi_size - atomic_read(&bio->bi_cnt)); + memset(bio_data(bio) + bio->bi_size, 0, min); + atomic_add(min, &bio->bi_cnt); i -= min; - bh = bh->b_reqnext; + bio = bio->bi_next; } } (void) idetape_add_chrdev_write_request (drive, blocks); @@ -3949,7 +3955,7 @@ * is switched from completion mode to buffer available * mode. */ - bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh); + bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bio); if (bytes_read < 0) { kfree (tape->merge_stage); tape->merge_stage = NULL; @@ -3960,7 +3966,7 @@ if (tape->restart_speed_control_req) idetape_restart_speed_control(drive); ide_init_drive_cmd (&rq); - rq.cmd = IDETAPE_READ_RQ; + rq.flags = IDETAPE_READ_RQ; rq.sector = tape->first_frame_position; rq.nr_sectors = rq.current_nr_sectors = blocks; if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) { @@ -4083,7 +4089,7 @@ } if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags)) return 0; - return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh); + return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bio); } rq_ptr = &tape->first_stage->rq; bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors); @@ -4137,21 +4143,21 @@ static void idetape_pad_zeros (ide_drive_t *drive, int bcount) { idetape_tape_t *tape = drive->driver_data; - struct buffer_head *bh; + struct bio *bio; int count, blocks; while (bcount) { - bh = tape->merge_stage->bh; + bio = tape->merge_stage->bio; count = IDE_MIN (tape->stage_size, bcount); bcount -= count; blocks = count / tape->tape_block_size; while (count) { - atomic_set(&bh->b_count, IDE_MIN (count, bh->b_size)); - memset (bh->b_data, 0, atomic_read(&bh->b_count)); - count -= atomic_read(&bh->b_count); - bh = bh->b_reqnext; + atomic_set(&bio->bi_cnt, IDE_MIN (count, bio->bi_size)); + memset (bio_data(bio), 0, bio->bi_size); + count -= atomic_read(&bio->bi_cnt); + bio = bio->bi_next; } - idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh); + idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio); } } @@ -4276,7 +4282,7 @@ */ static ide_drive_t *get_drive_ptr (kdev_t i_rdev) { - unsigned int i = MINOR(i_rdev) & ~0xc0; + unsigned int i = minor(i_rdev) & ~0xc0; if (i >= MAX_HWIFS * MAX_DRIVES) return NULL; @@ -4654,7 +4660,7 @@ printk(KERN_INFO "ide-tape: current position (2) tape block %d\n", tape->last_frame_position); #endif idetape_position_tape(drive, last_mark_addr, 0, 0); - if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) { + if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) { printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n", tape->name); __idetape_kfree_stage (stage); idetape_position_tape(drive, position, 0, 0); @@ -4673,7 +4679,7 @@ #endif aux->next_mark_addr = htonl(next_mark_addr); idetape_position_tape(drive, last_mark_addr, 0, 0); - if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) { + if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) { printk(KERN_INFO "ide-tape: %s: couldn't write back marker frame at %d\n", tape->name, last_mark_addr); __idetape_kfree_stage (stage); idetape_position_tape(drive, position, 0, 0); @@ -4705,9 +4711,9 @@ if (rc != 0) return; /* don't write fillers if we cannot position the tape. */ - strcpy(stage->bh->b_data, "Filler"); + strcpy(bio_data(stage->bio), "Filler"); while (cnt--) { - if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) { + if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) { printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header frame\n", tape->name); __idetape_kfree_stage (stage); return; @@ -4739,9 +4745,9 @@ header.partition.last_frame_addr = htonl(tape->capacity); header.partition.wrt_pass_cntr = htons(tape->wrt_pass_cntr); header.partition.eod_frame_addr = htonl(tape->eod_frame_addr); - memcpy(stage->bh->b_data, &header, sizeof(header)); + memcpy(bio_data(stage->bio), &header, sizeof(header)); while (cnt--) { - if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) { + if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) { printk(KERN_INFO "ide-tape: %s: couldn't write header frame\n", tape->name); __idetape_kfree_stage (stage); return; @@ -4860,7 +4866,7 @@ * is switched from completion mode to buffer available * mode. */ - retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh); + retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bio); if (retval < 0) { kfree (tape->merge_stage); tape->merge_stage = NULL; @@ -5326,12 +5332,12 @@ printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name); #endif idetape_position_tape(drive, block, 0, 0); - if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) { + if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) { printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n", tape->name); __idetape_kfree_stage (stage); return 0; } - header = (os_header_t *) stage->bh->b_data; + header = (os_header_t *) bio_data(stage->bio); aux = stage->aux; if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0) { printk(KERN_INFO "ide-tape: %s: invalid header identification string\n", tape->name); @@ -5403,7 +5409,7 @@ ide_drive_t *drive; idetape_tape_t *tape; idetape_pc_t pc; - unsigned int minor=MINOR (inode->i_rdev); + unsigned int minor=minor(inode->i_rdev); #if IDETAPE_DEBUG_LOG printk (KERN_INFO "ide-tape: Reached idetape_chrdev_open\n"); @@ -5460,7 +5466,7 @@ { ide_drive_t *drive = get_drive_ptr (inode->i_rdev); idetape_tape_t *tape = drive->driver_data; - unsigned int minor=MINOR (inode->i_rdev); + unsigned int minor=minor(inode->i_rdev); idetape_empty_write_pipeline (drive); tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0); @@ -5486,7 +5492,7 @@ ide_drive_t *drive = get_drive_ptr (inode->i_rdev); idetape_tape_t *tape; idetape_pc_t pc; - unsigned int minor=MINOR (inode->i_rdev); + unsigned int minor=minor(inode->i_rdev); tape = drive->driver_data; #if IDETAPE_DEBUG_LOG diff -urN linux-2.5.3-pre1/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c --- linux-2.5.3-pre1/drivers/ide/ide-taskfile.c Sat Jan 19 16:58:37 2002 +++ linux/drivers/ide/ide-taskfile.c Sat Jan 19 16:58:39 2002 @@ -706,8 +706,8 @@ ide__sti(); /* local CPU only */ if (!OK_STAT(stat, READY_STAT, BAD_STAT)) - return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */ - + return ide_error(drive, "task_no_data_intr", stat); + /* calls ide_end_drive_cmd */ if (args) ide_end_drive_cmd (drive, stat, GET_ERR()); @@ -723,6 +723,7 @@ byte io_32bit = drive->io_32bit; struct request *rq = HWGROUP(drive)->rq; char *pBuf = NULL; + unsigned long flags; if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) { @@ -735,17 +736,21 @@ } } DTF("stat: %02x\n", stat); - pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + pBuf = ide_map_rq(rq, &flags); DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors); drive->io_32bit = 0; taskfile_input_data(drive, pBuf, SECTOR_WORDS); + ide_unmap_rq(rq, pBuf, &flags); drive->io_32bit = io_32bit; if (--rq->current_nr_sectors <= 0) { /* (hs): swapped next 2 lines */ DTF("Request Ended stat: %02x\n", GET_STAT()); - ide_end_request(1, HWGROUP(drive)); + if (ide_end_request(1, HWGROUP(drive))) { + ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL); + return ide_started; + } } else { ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL); return ide_started; @@ -809,13 +814,14 @@ byte io_32bit = drive->io_32bit; struct request *rq = HWGROUP(drive)->rq; char *pBuf = NULL; + unsigned long flags; if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) { return ide_error(drive, "task_mulin_intr", stat); } /* no data yet, so wait for another interrupt */ - ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL); + ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL); return ide_started; } @@ -834,10 +840,11 @@ */ nsect = 1; while (rq->current_nr_sectors) { - pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + pBuf = ide_map_rq(rq, &flags); DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors); drive->io_32bit = 0; taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS); + ide_unmap_rq(rq, pBuf, &flags); drive->io_32bit = io_32bit; rq->errors = 0; rq->current_nr_sectors -= nsect; @@ -848,22 +855,34 @@ } #endif /* ALTSTAT_SCREW_UP */ - nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors; - pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + do { + nsect = rq->current_nr_sectors; + if (nsect > msect) + nsect = msect; - DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n", - pBuf, nsect, rq->current_nr_sectors); - drive->io_32bit = 0; - taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS); - drive->io_32bit = io_32bit; - rq->errors = 0; - rq->current_nr_sectors -= nsect; - if (rq->current_nr_sectors != 0) { - ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL); - return ide_started; - } - ide_end_request(1, HWGROUP(drive)); - return ide_stopped; + pBuf = ide_map_rq(rq, &flags); + + DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n", + pBuf, nsect, rq->current_nr_sectors); + drive->io_32bit = 0; + taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS); + ide_unmap_rq(rq, pBuf, &flags); + drive->io_32bit = io_32bit; + rq->errors = 0; + rq->current_nr_sectors -= nsect; + msect -= nsect; + if (!rq->current_nr_sectors) { + if (!ide_end_request(1, HWGROUP(drive))) + return ide_stopped; + } + } while (msect); + + + /* + * more data left + */ + ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL); + return ide_started; } ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) @@ -879,10 +898,12 @@ /* (ks/hs): Fixed Multi Write */ if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) && (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) { + unsigned long flags; + char *buf = ide_map_rq(rq, &flags); /* For Write_sectors we need to stuff the first sector */ - taskfile_output_data(drive, rq->buffer, SECTOR_WORDS); + taskfile_output_data(drive, buf, SECTOR_WORDS); rq->current_nr_sectors--; - return ide_started; + ide_unmap_rq(rq, buf, &flags); } else { /* * (ks/hs): Stuff the first sector(s) @@ -913,8 +934,10 @@ byte io_32bit = drive->io_32bit; struct request *rq = HWGROUP(drive)->rq; char *pBuf = NULL; + unsigned long flags; if (!rq->current_nr_sectors) { + printk("task_out_intr: should not trigger\n"); ide_end_request(1, HWGROUP(drive)); return ide_stopped; } @@ -922,19 +945,24 @@ if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) { return ide_error(drive, "task_out_intr", stat); } + if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) { rq = HWGROUP(drive)->rq; - pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + pBuf = ide_map_rq(rq, &flags); DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors); drive->io_32bit = 0; taskfile_output_data(drive, pBuf, SECTOR_WORDS); + ide_unmap_rq(rq, pBuf, &flags); drive->io_32bit = io_32bit; rq->errors = 0; rq->current_nr_sectors--; } if (rq->current_nr_sectors <= 0) { - ide_end_request(1, HWGROUP(drive)); + if (ide_end_request(1, HWGROUP(drive))) { + ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL); + return ide_started; + } } else { ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL); return ide_started; @@ -961,14 +989,20 @@ struct request *rq = HWGROUP(drive)->rq; ide_hwgroup_t *hwgroup = HWGROUP(drive); char *pBuf = NULL; + unsigned long flags; /* * (ks/hs): Handle last IRQ on multi-sector transfer, - * occurs after all data was sent + * occurs after all data was sent in this chunk */ if (rq->current_nr_sectors == 0) { if (stat & (ERR_STAT|DRQ_STAT)) return ide_error(drive, "task_mulout_intr", stat); + + /* + * there may be more, ide_do_request will restart it if + * necessary + */ ide_end_request(1, HWGROUP(drive)); return ide_stopped; } @@ -994,10 +1028,11 @@ if (!msect) { nsect = 1; while (rq->current_nr_sectors) { - pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + pBuf = ide_map_rq(rq, &flags); DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors); drive->io_32bit = 0; taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); + ide_unmap_rq(pBuf, &flags); drive->io_32bit = io_32bit; rq->errors = 0; rq->current_nr_sectors -= nsect; @@ -1008,12 +1043,16 @@ } #endif /* ALTSTAT_SCREW_UP */ - nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors; - pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + nsect = rq->current_nr_sectors; + if (nsect > msect) + nsect = msect; + + pBuf = ide_map_rq(rq, &flags); DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors); drive->io_32bit = 0; taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); + ide_unmap_rq(rq, pBuf, &flags); drive->io_32bit = io_32bit; rq->errors = 0; rq->current_nr_sectors -= nsect; diff -urN linux-2.5.3-pre1/drivers/ide/ide.c linux/drivers/ide/ide.c --- linux-2.5.3-pre1/drivers/ide/ide.c Sat Jan 19 16:58:37 2002 +++ linux/drivers/ide/ide.c Sat Jan 19 16:58:39 2002 @@ -1458,14 +1458,11 @@ HWGROUP(drive)->rq = NULL; rq->errors = 0; - rq->sector = rq->bio->bi_sector; - rq->current_nr_sectors = bio_sectors(rq->bio); - - /* - * just to make sure... - */ - if (rq->bio) + if (rq->bio) { + rq->sector = rq->bio->bi_sector; + rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9; rq->buffer = NULL; + } } /* diff -urN linux-2.5.3-pre1/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c --- linux-2.5.3-pre1/drivers/isdn/avmb1/b1pci.c Sun Jan 6 12:23:35 2002 +++ linux/drivers/isdn/avmb1/b1pci.c Sat Jan 19 16:58:39 2002 @@ -67,26 +67,6 @@ card->interrupt = 0; } -/* ------------------------------------------------------------- */ - -static void b1pci_remove_ctr(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned int port = card->port; - - b1_reset(port); - b1_reset(port); - - di->detach_ctr(ctrl); - free_irq(card->irq, card); - release_region(card->port, AVMB1_PORTLEN); - ctrl->driverdata = 0; - kfree(card->ctrlinfo); - kfree(card); - - MOD_DEC_USE_COUNT; -} /* ------------------------------------------------------------- */ @@ -118,20 +98,18 @@ MOD_INC_USE_COUNT; - card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); - + retval = -ENOMEM; + card = kmalloc(sizeof(avmcard), GFP_KERNEL); if (!card) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - MOD_DEC_USE_COUNT; - return -ENOMEM; + goto err; } memset(card, 0, sizeof(avmcard)); - cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC); + + cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL); if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - kfree(card); - MOD_DEC_USE_COUNT; - return -ENOMEM; + goto err_kfree; } memset(cinfo, 0, sizeof(avmctrl_info)); card->ctrlinfo = cinfo; @@ -140,51 +118,38 @@ card->port = p->port; card->irq = p->irq; card->cardtype = avm_b1pci; - - if (check_region(card->port, AVMB1_PORTLEN)) { + + if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { printk(KERN_WARNING "%s: ports 0x%03x-0x%03x in use.\n", driver->name, card->port, card->port + AVMB1_PORTLEN); - kfree(card->ctrlinfo); - kfree(card); - MOD_DEC_USE_COUNT; - return -EBUSY; + goto err_kfree_ctrlinfo; } b1_reset(card->port); - if ((retval = b1_detect(card->port, card->cardtype)) != 0) { + retval = b1_detect(card->port, card->cardtype); + if (retval) { printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", - driver->name, card->port, retval); - kfree(card->ctrlinfo); - kfree(card); - MOD_DEC_USE_COUNT; - return -EIO; + driver->name, card->port, retval); + retval = -EIO; + goto err_release_region; } b1_reset(card->port); b1_getrevision(card); - - request_region(p->port, AVMB1_PORTLEN, card->name); - + retval = request_irq(card->irq, b1pci_interrupt, SA_SHIRQ, card->name, card); if (retval) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", - driver->name, card->irq); - release_region(card->port, AVMB1_PORTLEN); - kfree(card->ctrlinfo); - kfree(card); - MOD_DEC_USE_COUNT; - return -EBUSY; + driver->name, card->irq); + retval = -EBUSY; + goto err_release_region; } - + cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo); if (!cinfo->capi_ctrl) { printk(KERN_ERR "%s: attach controller failed.\n", - driver->name); - free_irq(card->irq, card); - release_region(card->port, AVMB1_PORTLEN); - kfree(card->ctrlinfo); - kfree(card); - MOD_DEC_USE_COUNT; - return -EBUSY; + driver->name); + retval = -EBUSY; + goto err_free_irq; } if (card->revision >= 4) { @@ -198,6 +163,37 @@ } return 0; + + err_free_irq: + free_irq(card->irq, card); + err_release_region: + release_region(card->port, AVMB1_PORTLEN); + err_kfree_ctrlinfo: + kfree(card->ctrlinfo); + err_kfree: + kfree(card); + err: + MOD_DEC_USE_COUNT; + return retval; +} + +static void b1pci_remove_ctr(struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + unsigned int port = card->port; + + b1_reset(port); + b1_reset(port); + + di->detach_ctr(ctrl); + free_irq(card->irq, card); + release_region(card->port, AVMB1_PORTLEN); + ctrl->driverdata = 0; + kfree(card->ctrlinfo); + kfree(card); + + MOD_DEC_USE_COUNT; } /* ------------------------------------------------------------- */ @@ -226,25 +222,6 @@ /* ------------------------------------------------------------- */ -static void b1pciv4_remove_ctr(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - - b1dma_reset(card); - - div4->detach_ctr(ctrl); - free_irq(card->irq, card); - iounmap(card->mbase); - release_region(card->port, AVMB1_PORTLEN); - ctrl->driverdata = 0; - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - - MOD_DEC_USE_COUNT; -} - static char *b1pciv4_procinfo(struct capi_ctr *ctrl) { avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); @@ -274,28 +251,23 @@ MOD_INC_USE_COUNT; - card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); - + retval = -ENOMEM; + card = kmalloc(sizeof(avmcard), GFP_KERNEL); if (!card) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - MOD_DEC_USE_COUNT; - return -ENOMEM; + goto err; } memset(card, 0, sizeof(avmcard)); + card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128); if (!card->dma) { printk(KERN_WARNING "%s: dma alloc.\n", driver->name); - kfree(card); - MOD_DEC_USE_COUNT; - return -ENOMEM; + goto err_kfree; } - cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC); + cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL); if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -ENOMEM; + goto err_dma_free; } memset(cinfo, 0, sizeof(avmctrl_info)); card->ctrlinfo = cinfo; @@ -306,69 +278,47 @@ card->membase = p->membase; card->cardtype = avm_b1pci; - if (check_region(card->port, AVMB1_PORTLEN)) { + if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { printk(KERN_WARNING "%s: ports 0x%03x-0x%03x in use.\n", driver->name, card->port, card->port + AVMB1_PORTLEN); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EBUSY; + retval = -EBUSY; + goto err_kfree_ctrlinfo; } card->mbase = ioremap_nocache(card->membase, 64); if (!card->mbase) { printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", driver->name, card->membase); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EIO; + retval = -EIO; + goto err_release_region; } b1dma_reset(card); - if ((retval = b1pciv4_detect(card)) != 0) { + retval = b1pciv4_detect(card); + if (retval) { printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", driver->name, card->port, retval); - iounmap(card->mbase); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EIO; + retval = -EIO; + goto err_unmap; } b1dma_reset(card); b1_getrevision(card); - request_region(p->port, AVMB1_PORTLEN, card->name); - retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card); if (retval) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", driver->name, card->irq); - iounmap(card->mbase); - release_region(card->port, AVMB1_PORTLEN); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EBUSY; + retval = -EBUSY; + goto err_unmap; } cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo); if (!cinfo->capi_ctrl) { printk(KERN_ERR "%s: attach controller failed.\n", driver->name); - iounmap(card->mbase); - free_irq(card->irq, card); - release_region(card->port, AVMB1_PORTLEN); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EBUSY; + retval = -EBUSY; + goto err_free_irq; } card->cardnr = cinfo->capi_ctrl->cnr; @@ -378,6 +328,42 @@ card->membase, card->revision); return 0; + + err_free_irq: + free_irq(card->irq, card); + err_unmap: + iounmap(card->mbase); + err_release_region: + release_region(card->port, AVMB1_PORTLEN); + err_kfree_ctrlinfo: + kfree(card->ctrlinfo); + err_dma_free: + avmcard_dma_free(card->dma); + err_kfree: + kfree(card); + err: + MOD_DEC_USE_COUNT; + return retval; + +} + +static void b1pciv4_remove_ctr(struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + + b1dma_reset(card); + + div4->detach_ctr(ctrl); + free_irq(card->irq, card); + iounmap(card->mbase); + release_region(card->port, AVMB1_PORTLEN); + ctrl->driverdata = 0; + kfree(card->ctrlinfo); + avmcard_dma_free(card->dma); + kfree(card); + + MOD_DEC_USE_COUNT; } /* ------------------------------------------------------------- */ @@ -402,8 +388,6 @@ #endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */ -static int ncards = 0; - static int __devinit b1pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { @@ -470,6 +454,7 @@ struct capi_driver *driverv4 = &b1pciv4_driver; #endif char *p; + int ncards; MOD_INC_USE_COUNT; diff -urN linux-2.5.3-pre1/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c --- linux-2.5.3-pre1/drivers/isdn/avmb1/c4.c Sun Jan 6 12:23:35 2002 +++ linux/drivers/isdn/avmb1/c4.c Sat Jan 19 16:58:39 2002 @@ -1133,28 +1133,23 @@ MOD_INC_USE_COUNT; - card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); - + retval = -ENOMEM; + card = kmalloc(sizeof(avmcard), GFP_ATOMIC); if (!card) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - MOD_DEC_USE_COUNT; - return -ENOMEM; + goto err; } memset(card, 0, sizeof(avmcard)); + card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128); if (!card->dma) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - kfree(card); - MOD_DEC_USE_COUNT; - return -ENOMEM; + goto err_kfree; } cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC); if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -ENOMEM; + goto err_dma_free; } memset(cinfo, 0, sizeof(avmctrl_info)*4); card->ctrlinfo = cinfo; @@ -1168,53 +1163,37 @@ card->membase = p->membase; card->cardtype = nr == 4 ? avm_c4 : avm_c2; - if (check_region(card->port, AVMB1_PORTLEN)) { + if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { printk(KERN_WARNING "%s: ports 0x%03x-0x%03x in use.\n", driver->name, card->port, card->port + AVMB1_PORTLEN); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EBUSY; + retval = -EBUSY; + goto err_kfree_ctrlinfo; } card->mbase = ioremap_nocache(card->membase, 128); if (card->mbase == 0) { printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", driver->name, card->membase); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EIO; + retval = -EIO; + goto err_release_region; } - if ((retval = c4_detect(card)) != 0) { + retval = c4_detect(card); + if (retval != 0) { printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", driver->name, card->port, retval); - iounmap(card->mbase); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EIO; + retval = -EIO; + goto err_unmap; } c4_reset(card); - request_region(p->port, AVMB1_PORTLEN, card->name); - retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card); if (retval) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", driver->name, card->irq); - iounmap(card->mbase); - release_region(card->port, AVMB1_PORTLEN); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EBUSY; + retval = -EBUSY; + goto err_unmap; } for (i=0; i < nr ; i++) { @@ -1228,14 +1207,7 @@ cinfo = &card->ctrlinfo[i]; di->detach_ctr(cinfo->capi_ctrl); } - iounmap(card->mbase); - free_irq(card->irq, card); - release_region(card->port, AVMB1_PORTLEN); - avmcard_dma_free(card->dma); - kfree(card->ctrlinfo); - kfree(card); - MOD_DEC_USE_COUNT; - return -EBUSY; + goto err_free_irq; } if (i == 0) card->cardnr = cinfo->capi_ctrl->cnr; @@ -1246,6 +1218,22 @@ driver->name, nr, card->port, card->irq, card->membase); return 0; + + err_free_irq: + free_irq(card->irq, card); + err_unmap: + iounmap(card->mbase); + err_release_region: + release_region(card->port, AVMB1_PORTLEN); + err_kfree_ctrlinfo: + kfree(card->ctrlinfo); + err_dma_free: + avmcard_dma_free(card->dma); + err_kfree: + kfree(card); + err: + MOD_DEC_USE_COUNT; + return retval; } /* ------------------------------------------------------------- */ diff -urN linux-2.5.3-pre1/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c --- linux-2.5.3-pre1/drivers/isdn/avmb1/t1pci.c Sun Jan 6 12:23:35 2002 +++ linux/drivers/isdn/avmb1/t1pci.c Sat Jan 19 16:58:39 2002 @@ -49,27 +49,6 @@ /* ------------------------------------------------------------- */ -static void t1pci_remove_ctr(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - - b1dma_reset(card); - - di->detach_ctr(ctrl); - free_irq(card->irq, card); - iounmap(card->mbase); - release_region(card->port, AVMB1_PORTLEN); - ctrl->driverdata = 0; - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - - MOD_DEC_USE_COUNT; -} - -/* ------------------------------------------------------------- */ - static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p, struct pci_dev *dev) @@ -80,28 +59,22 @@ MOD_INC_USE_COUNT; - card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); - + retval = -ENOMEM; + card = kmalloc(sizeof(avmcard), GFP_KERNEL); if (!card) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - MOD_DEC_USE_COUNT; - return -ENOMEM; + goto err; } memset(card, 0, sizeof(avmcard)); card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128); if (!card->dma) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - kfree(card); - MOD_DEC_USE_COUNT; - return -ENOMEM; + goto err_kfree; } - cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC); + cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL); if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -ENOMEM; + goto err_dma_free; } memset(cinfo, 0, sizeof(avmctrl_info)); card->ctrlinfo = cinfo; @@ -112,72 +85,50 @@ card->membase = p->membase; card->cardtype = avm_t1pci; - if (check_region(card->port, AVMB1_PORTLEN)) { + if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { printk(KERN_WARNING "%s: ports 0x%03x-0x%03x in use.\n", driver->name, card->port, card->port + AVMB1_PORTLEN); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EBUSY; + retval = -EBUSY; + goto err_kfree_ctrlinfo; } card->mbase = ioremap_nocache(card->membase, 64); if (!card->mbase) { printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", driver->name, card->membase); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EIO; + retval = -EIO; + goto err_release_region; } b1dma_reset(card); - if ((retval = t1pci_detect(card)) != 0) { + retval = t1pci_detect(card); + if (retval != 0) { if (retval < 6) printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", driver->name, card->port, retval); else printk(KERN_NOTICE "%s: card at 0x%x, but cabel not connected or T1 has no power (%d)\n", driver->name, card->port, retval); - iounmap(card->mbase); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EIO; + retval = -EIO; + goto err_unmap; } b1dma_reset(card); - request_region(p->port, AVMB1_PORTLEN, card->name); - retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card); if (retval) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", driver->name, card->irq); - iounmap(card->mbase); - release_region(card->port, AVMB1_PORTLEN); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EBUSY; + retval = -EBUSY; + goto err_unmap; } cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo); if (!cinfo->capi_ctrl) { printk(KERN_ERR "%s: attach controller failed.\n", driver->name); - iounmap(card->mbase); - free_irq(card->irq, card); - release_region(card->port, AVMB1_PORTLEN); - kfree(card->ctrlinfo); - avmcard_dma_free(card->dma); - kfree(card); - MOD_DEC_USE_COUNT; - return -EBUSY; + retval = -EBUSY; + goto err_free_irq; } card->cardnr = cinfo->capi_ctrl->cnr; @@ -186,6 +137,43 @@ driver->name, card->port, card->irq, card->membase); return 0; + + err_free_irq: + free_irq(card->irq, card); + err_unmap: + iounmap(card->mbase); + err_release_region: + release_region(card->port, AVMB1_PORTLEN); + err_kfree_ctrlinfo: + kfree(card->ctrlinfo); + err_dma_free: + avmcard_dma_free(card->dma); + err_kfree: + kfree(card); + err: + MOD_DEC_USE_COUNT; + return retval; +} + +/* ------------------------------------------------------------- */ + +static void t1pci_remove_ctr(struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + + b1dma_reset(card); + + di->detach_ctr(ctrl); + free_irq(card->irq, card); + iounmap(card->mbase); + release_region(card->port, AVMB1_PORTLEN); + ctrl->driverdata = 0; + kfree(card->ctrlinfo); + avmcard_dma_free(card->dma); + kfree(card); + + MOD_DEC_USE_COUNT; } /* ------------------------------------------------------------- */ diff -urN linux-2.5.3-pre1/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- linux-2.5.3-pre1/drivers/isdn/isdn_common.c Thu Jan 3 12:20:10 2002 +++ linux/drivers/isdn/isdn_common.c Sat Jan 19 16:58:39 2002 @@ -65,7 +65,6 @@ #endif /* CONFIG_ISDN_DIVERSION */ -static int isdn_writebuf_stub(int, int, const u_char *, int, int); static void set_global_features(void); static void isdn_register_devfs(int); static void isdn_unregister_devfs(int); @@ -946,7 +945,9 @@ return istatbuf; } -/* Module interface-code */ +/* + * /dev/isdninfo + */ void isdn_info_update(void) @@ -960,234 +961,309 @@ wake_up_interruptible(&(dev->info_waitq)); } +static int +isdn_status_open(struct inode *ino, struct file *filep) +{ + infostruct *p; + + p = kmalloc(sizeof(infostruct), GFP_KERNEL); + if (!p) + return -ENOMEM; + + p->next = (char *) dev->infochain; + p->private = (char *) &(filep->private_data); + dev->infochain = p; + /* At opening we allow a single update */ + filep->private_data = (char *) 1; + + return 0; +} + +static int +isdn_status_release(struct inode *ino, struct file *filep) +{ + infostruct *p = dev->infochain; + infostruct *q = NULL; + + lock_kernel(); + + while (p) { + if (p->private == (char *) &(filep->private_data)) { + if (q) + q->next = p->next; + else + dev->infochain = (infostruct *) (p->next); + kfree(p); + goto out; + } + q = p; + p = (infostruct *) (p->next); + } + printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); + + out: + unlock_kernel(); + return 0; +} + static ssize_t -isdn_read(struct file *file, char *buf, size_t count, loff_t * off) +isdn_status_read(struct file *file, char *buf, size_t count, loff_t * off) { - uint minor = minor(file->f_dentry->d_inode->i_rdev); - int len = 0; - ulong flags; - int drvidx; - int chidx; int retval; + int len = 0; char *p; if (off != &file->f_pos) return -ESPIPE; lock_kernel(); - if (minor == ISDN_MINOR_STATUS) { - if (!file->private_data) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto out; - } - interruptible_sleep_on(&(dev->info_waitq)); - } - p = isdn_statstr(); - file->private_data = 0; - if ((len = strlen(p)) <= count) { - if (copy_to_user(buf, p, len)) { - retval = -EFAULT; - goto out; - } - *off += len; - retval = len; + if (!file->private_data) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; goto out; } - retval = 0; - goto out; - } - if (!dev->drivers) { - retval = -ENODEV; - goto out; + interruptible_sleep_on(&(dev->info_waitq)); } - if (minor <= ISDN_MINOR_BMAX) { - printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor); - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) { - retval = -ENODEV; - goto out; - } - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) { - retval = -ENODEV; + p = isdn_statstr(); + file->private_data = 0; + if ((len = strlen(p)) <= count) { + if (copy_to_user(buf, p, len)) { + retval = -EFAULT; goto out; } - chidx = isdn_minor2chan(minor); - if (!(p = kmalloc(count, GFP_KERNEL))) { - retval = -ENOMEM; - goto out; - } - save_flags(flags); - cli(); - len = isdn_readbchan(drvidx, chidx, p, 0, count, - &dev->drv[drvidx]->rcv_waitq[chidx]); - *off += len; - restore_flags(flags); - if (copy_to_user(buf,p,len)) - len = -EFAULT; - kfree(p); - retval = len; - goto out; - } - if (minor <= ISDN_MINOR_CTRLMAX) { - drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) { - retval = -ENODEV; - goto out; - } - if (!dev->drv[drvidx]->stavail) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto out; - } - interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq)); - } - if (dev->drv[drvidx]->interface->readstat) { - if (count > dev->drv[drvidx]->stavail) - count = dev->drv[drvidx]->stavail; - len = dev->drv[drvidx]->interface-> - readstat(buf, count, 1, drvidx, - isdn_minor2chan(minor)); - } else { - len = 0; - } - save_flags(flags); - cli(); - if (len) - dev->drv[drvidx]->stavail -= len; - else - dev->drv[drvidx]->stavail = 0; - restore_flags(flags); *off += len; retval = len; goto out; } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) { - retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count); - goto out; - } -#endif - retval = -ENODEV; + retval = 0; + goto out; + out: unlock_kernel(); return retval; } static ssize_t -isdn_write(struct file *file, const char *buf, size_t count, loff_t * off) +isdn_status_write(struct file *file, const char *buf, size_t count, loff_t *off) +{ + return -EPERM; +} + +static unsigned int +isdn_status_poll(struct file *file, poll_table *wait) +{ + unsigned int mask = 0; + + lock_kernel(); + + poll_wait(file, &(dev->info_waitq), wait); + if (file->private_data) + mask |= POLLIN | POLLRDNORM; + + unlock_kernel(); + return mask; +} + +static int +isdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) +{ + int ret; + union iocpar { + char name[10]; + char bname[22]; + isdn_ioctl_struct iocts; + isdn_net_ioctl_phone phone; + isdn_net_ioctl_cfg cfg; + } iocpar; + +#define name iocpar.name +#define bname iocpar.bname +#define iocts iocpar.iocts +#define phone iocpar.phone +#define cfg iocpar.cfg + + switch (cmd) { + case IIOCGETDVR: + return (TTY_DV + + (NET_DV << 8) + + (INF_DV << 16)); + case IIOCGETCPS: + if (arg) { + ulong *p = (ulong *) arg; + int i; + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(ulong) * ISDN_MAX_CHANNELS * 2))) + return ret; + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + put_user(dev->ibytes[i], p++); + put_user(dev->obytes[i], p++); + } + return 0; + } else + return -EINVAL; + break; +#ifdef CONFIG_NETDEVICES + case IIOCNETGPN: + /* Get peer phone number of a connected + * isdn network interface */ + if (arg) { + if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + return -EFAULT; + return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg); + } else + return -EINVAL; +#endif + default: + return -EINVAL; + } + +#undef name +#undef bname +#undef iocts +#undef phone +#undef cfg +} + +/* + * /dev/isdnctrlX + */ + +static int +isdn_ctrl_open(struct inode *ino, struct file *filep) +{ + uint minor = minor(ino->i_rdev); + int drvidx; + + drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); + if (drvidx < 0) + return -ENODEV; + + isdn_lock_drivers(); + return 0; +} + +static int +isdn_ctrl_release(struct inode *ino, struct file *filep) +{ + lock_kernel(); + + if (dev->profd == current) + dev->profd = NULL; + + isdn_unlock_drivers(); + + unlock_kernel(); + return 0; +} + +static ssize_t +isdn_ctrl_read(struct file *file, char *buf, size_t count, loff_t * off) { uint minor = minor(file->f_dentry->d_inode->i_rdev); + ulong flags; + int len = 0; int drvidx; - int chidx; int retval; if (off != &file->f_pos) return -ESPIPE; - if (minor == ISDN_MINOR_STATUS) - return -EPERM; - if (!dev->drivers) - return -ENODEV; - lock_kernel(); - if (minor <= ISDN_MINOR_BMAX) { - printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor); - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) { - retval = -ENODEV; - goto out; - } - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) { - retval = -ENODEV; - goto out; - } - chidx = isdn_minor2chan(minor); - while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count) - interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]); - retval = count; + + drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); + if (drvidx < 0) { + retval = -ENODEV; goto out; } - if (minor <= ISDN_MINOR_CTRLMAX) { - drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) { - retval = -ENODEV; + if (!dev->drv[drvidx]->stavail) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; goto out; } - /* - * We want to use the isdnctrl device to load the firmware - * - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; - */ - if (dev->drv[drvidx]->interface->writecmd) - retval = dev->drv[drvidx]->interface-> - writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor)); - else - retval = count; - goto out; + interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq)); } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) { - retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count); - goto out; + if (dev->drv[drvidx]->interface->readstat) { + if (count > dev->drv[drvidx]->stavail) + count = dev->drv[drvidx]->stavail; + len = dev->drv[drvidx]->interface-> + readstat(buf, count, 1, drvidx, + isdn_minor2chan(minor)); + } else { + len = 0; } -#endif - retval = -ENODEV; + save_flags(flags); + cli(); + if (len) + dev->drv[drvidx]->stavail -= len; + else + dev->drv[drvidx]->stavail = 0; + restore_flags(flags); + *off += len; + retval = len; + out: unlock_kernel(); return retval; } -static unsigned int -isdn_poll(struct file *file, poll_table * wait) +static ssize_t +isdn_ctrl_write(struct file *file, const char *buf, size_t count, loff_t *off) { - unsigned int mask = 0; - unsigned int minor = minor(file->f_dentry->d_inode->i_rdev); - int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); + uint minor = minor(file->f_dentry->d_inode->i_rdev); + int drvidx; + int retval; + + if (off != &file->f_pos) + return -ESPIPE; lock_kernel(); - if (minor == ISDN_MINOR_STATUS) { - poll_wait(file, &(dev->info_waitq), wait); - /* mask = POLLOUT | POLLWRNORM; */ - if (file->private_data) { - mask |= POLLIN | POLLRDNORM; - } - goto out; - } - if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) { - if (drvidx < 0) { - /* driver deregistered while file open */ - mask = POLLHUP; - goto out; - } - poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait); - mask = POLLOUT | POLLWRNORM; - if (dev->drv[drvidx]->stavail) { - mask |= POLLIN | POLLRDNORM; - } + + drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); + if (drvidx < 0) { + retval = -ENODEV; goto out; } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) { - mask = isdn_ppp_poll(file, wait); + if (!dev->drv[drvidx]->interface->writecmd) { + retval = -EINVAL; goto out; } -#endif - mask = POLLERR; + retval = dev->drv[drvidx]->interface-> + writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL)); + out: unlock_kernel(); + return retval; +} + +static unsigned int +isdn_ctrl_poll(struct file *file, poll_table *wait) +{ + unsigned int mask = 0; + unsigned int minor = minor(file->f_dentry->d_inode->i_rdev); + int drvidx; + + drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); + if (drvidx < 0) + /* driver deregistered while file open */ + return POLLHUP; + + lock_kernel(); + + poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait); + mask = POLLOUT | POLLWRNORM; + if (dev->drv[drvidx]->stavail) + mask |= POLLIN | POLLRDNORM; + + unlock_kernel(); return mask; } static int -isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) +isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) { - uint minor = minor(inode->i_rdev); isdn_ctrl c; int drvidx; - int chidx; int ret; int i; char *p; @@ -1205,55 +1281,6 @@ #define iocts iocpar.iocts #define phone iocpar.phone #define cfg iocpar.cfg - - if (minor == ISDN_MINOR_STATUS) { - switch (cmd) { - case IIOCGETDVR: - return (TTY_DV + - (NET_DV << 8) + - (INF_DV << 16)); - case IIOCGETCPS: - if (arg) { - ulong *p = (ulong *) arg; - int i; - if ((ret = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(ulong) * ISDN_MAX_CHANNELS * 2))) - return ret; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - put_user(dev->ibytes[i], p++); - put_user(dev->obytes[i], p++); - } - return 0; - } else - return -EINVAL; - break; -#ifdef CONFIG_NETDEVICES - case IIOCNETGPN: - /* Get peer phone number of a connected - * isdn network interface */ - if (arg) { - if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) - return -EFAULT; - return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg); - } else - return -EINVAL; -#endif - default: - return -EINVAL; - } - } - if (!dev->drivers) - return -ENODEV; - if (minor <= ISDN_MINOR_BMAX) { - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) - return -ENODEV; - chidx = isdn_minor2chan(minor); - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; - return 0; - } - if (minor <= ISDN_MINOR_CTRLMAX) { /* * isdn net devices manage lots of configuration variables as linked lists. * Those lists must only be manipulated from user space. Some of the ioctl's @@ -1261,366 +1288,360 @@ * manipulating the lists and ioctl's sleeping while accessing the lists * are serialized by means of a semaphore. */ - switch (cmd) { - case IIOCNETDWRSET: - printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n"); - return(-EINVAL); - case IIOCNETLCR: - printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n"); - return -ENODEV; + switch (cmd) { + case IIOCNETDWRSET: + printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n"); + return(-EINVAL); + case IIOCNETLCR: + printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n"); + return -ENODEV; #ifdef CONFIG_NETDEVICES - case IIOCNETAIF: - /* Add a network-interface */ - if (arg) { - if (copy_from_user(name, (char *) arg, sizeof(name))) - return -EFAULT; - s = name; - } else { - s = NULL; - } - ret = down_interruptible(&dev->sem); - if( ret ) return ret; - if ((s = isdn_net_new(s, NULL))) { - if (copy_to_user((char *) arg, s, strlen(s) + 1)){ - ret = -EFAULT; - } else { - ret = 0; + case IIOCNETAIF: + /* Add a network-interface */ + if (arg) { + if (copy_from_user(name, (char *) arg, sizeof(name))) + return -EFAULT; + s = name; + } else { + s = NULL; + } + ret = down_interruptible(&dev->sem); + if( ret ) return ret; + if ((s = isdn_net_new(s, NULL))) { + if (copy_to_user((char *) arg, s, strlen(s) + 1)){ + ret = -EFAULT; + } else { + ret = 0; + } + } else + ret = -ENODEV; + up(&dev->sem); + return ret; + case IIOCNETASL: + /* Add a slave to a network-interface */ + if (arg) { + if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1)) + return -EFAULT; + } else + return -EINVAL; + ret = down_interruptible(&dev->sem); + if( ret ) return ret; + if ((s = isdn_net_newslave(bname))) { + if (copy_to_user((char *) arg, s, strlen(s) + 1)){ + ret = -EFAULT; + } else { + ret = 0; + } + } else + ret = -ENODEV; + up(&dev->sem); + return ret; + case IIOCNETDIF: + /* Delete a network-interface */ + if (arg) { + if (copy_from_user(name, (char *) arg, sizeof(name))) + return -EFAULT; + ret = down_interruptible(&dev->sem); + if( ret ) return ret; + ret = isdn_net_rm(name); + up(&dev->sem); + return ret; + } else + return -EINVAL; + case IIOCNETSCF: + /* Set configurable parameters of a network-interface */ + if (arg) { + if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) + return -EFAULT; + return isdn_net_setcfg(&cfg); + } else + return -EINVAL; + case IIOCNETGCF: + /* Get configurable parameters of a network-interface */ + if (arg) { + if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) + return -EFAULT; + if (!(ret = isdn_net_getcfg(&cfg))) { + if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg))) + return -EFAULT; + } + return ret; + } else + return -EINVAL; + case IIOCNETANM: + /* Add a phone-number to a network-interface */ + if (arg) { + if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + return -EFAULT; + ret = down_interruptible(&dev->sem); + if( ret ) return ret; + ret = isdn_net_addphone(&phone); + up(&dev->sem); + return ret; + } else + return -EINVAL; + case IIOCNETGNM: + /* Get list of phone-numbers of a network-interface */ + if (arg) { + if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + return -EFAULT; + ret = down_interruptible(&dev->sem); + if( ret ) return ret; + ret = isdn_net_getphones(&phone, (char *) arg); + up(&dev->sem); + return ret; + } else + return -EINVAL; + case IIOCNETDNM: + /* Delete a phone-number of a network-interface */ + if (arg) { + if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + return -EFAULT; + ret = down_interruptible(&dev->sem); + if( ret ) return ret; + ret = isdn_net_delphone(&phone); + up(&dev->sem); + return ret; + } else + return -EINVAL; + case IIOCNETDIL: + /* Force dialing of a network-interface */ + if (arg) { + if (copy_from_user(name, (char *) arg, sizeof(name))) + return -EFAULT; + return isdn_net_force_dial(name); + } else + return -EINVAL; +#ifdef CONFIG_ISDN_PPP + case IIOCNETALN: + if (!arg) + return -EINVAL; + if (copy_from_user(name, (char *) arg, sizeof(name))) + return -EFAULT; + return isdn_ppp_dial_slave(name); + case IIOCNETDLN: + if (!arg) + return -EINVAL; + if (copy_from_user(name, (char *) arg, sizeof(name))) + return -EFAULT; + return isdn_ppp_hangup_slave(name); +#endif + case IIOCNETHUP: + /* Force hangup of a network-interface */ + if (!arg) + return -EINVAL; + if (copy_from_user(name, (char *) arg, sizeof(name))) + return -EFAULT; + return isdn_net_force_hangup(name); + break; +#endif /* CONFIG_NETDEVICES */ + case IIOCSETVER: + dev->net_verbose = arg; + printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose); + return 0; + case IIOCSETGST: + if (arg) + dev->global_flags |= ISDN_GLOBAL_STOPPED; + else + dev->global_flags &= ~ISDN_GLOBAL_STOPPED; + printk(KERN_INFO "isdn: Global Mode %s\n", + (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running"); + return 0; + case IIOCSETBRJ: + drvidx = -1; + if (arg) { + int i; + char *p; + if (copy_from_user((char *) &iocts, (char *) arg, + sizeof(isdn_ioctl_struct))) + return -EFAULT; + if (strlen(iocts.drvid)) { + if ((p = strchr(iocts.drvid, ','))) + *p = 0; + drvidx = -1; + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + if (!(strcmp(dev->drvid[i], iocts.drvid))) { + drvidx = i; + break; } - } else - ret = -ENODEV; - up(&dev->sem); + } + } + if (drvidx == -1) + return -ENODEV; + if (iocts.arg) + dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS; + else + dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS; + return 0; + case IIOCSIGPRF: + dev->profd = current; + return 0; + break; + case IIOCGETPRF: + /* Get all Modem-Profiles */ + if (arg) { + char *p = (char *) arg; + int i; + + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, + (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) + * ISDN_MAX_CHANNELS))) return ret; - case IIOCNETASL: - /* Add a slave to a network-interface */ - if (arg) { - if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1)) - return -EFAULT; - } else - return -EINVAL; - ret = down_interruptible(&dev->sem); - if( ret ) return ret; - if ((s = isdn_net_newslave(bname))) { - if (copy_to_user((char *) arg, s, strlen(s) + 1)){ - ret = -EFAULT; - } else { - ret = 0; - } - } else - ret = -ENODEV; - up(&dev->sem); + + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + if (copy_to_user(p, dev->mdm.info[i].emu.profile, + ISDN_MODEM_NUMREG)) + return -EFAULT; + p += ISDN_MODEM_NUMREG; + if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN)) + return -EFAULT; + p += ISDN_MSNLEN; + if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN)) + return -EFAULT; + p += ISDN_LMSNLEN; + } + return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; + } else + return -EINVAL; + break; + case IIOCSETPRF: + /* Set all Modem-Profiles */ + if (arg) { + char *p = (char *) arg; + int i; + + if ((ret = verify_area(VERIFY_READ, (void *) arg, + (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) + * ISDN_MAX_CHANNELS))) return ret; - case IIOCNETDIF: - /* Delete a network-interface */ - if (arg) { - if (copy_from_user(name, (char *) arg, sizeof(name))) - return -EFAULT; - ret = down_interruptible(&dev->sem); - if( ret ) return ret; - ret = isdn_net_rm(name); - up(&dev->sem); - return ret; - } else - return -EINVAL; - case IIOCNETSCF: - /* Set configurable parameters of a network-interface */ - if (arg) { - if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) - return -EFAULT; - return isdn_net_setcfg(&cfg); - } else - return -EINVAL; - case IIOCNETGCF: - /* Get configurable parameters of a network-interface */ - if (arg) { - if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) - return -EFAULT; - if (!(ret = isdn_net_getcfg(&cfg))) { - if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg))) - return -EFAULT; - } - return ret; - } else - return -EINVAL; - case IIOCNETANM: - /* Add a phone-number to a network-interface */ - if (arg) { - if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) - return -EFAULT; - ret = down_interruptible(&dev->sem); - if( ret ) return ret; - ret = isdn_net_addphone(&phone); - up(&dev->sem); - return ret; - } else - return -EINVAL; - case IIOCNETGNM: - /* Get list of phone-numbers of a network-interface */ - if (arg) { - if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) - return -EFAULT; - ret = down_interruptible(&dev->sem); - if( ret ) return ret; - ret = isdn_net_getphones(&phone, (char *) arg); - up(&dev->sem); - return ret; - } else - return -EINVAL; - case IIOCNETDNM: - /* Delete a phone-number of a network-interface */ - if (arg) { - if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) - return -EFAULT; - ret = down_interruptible(&dev->sem); - if( ret ) return ret; - ret = isdn_net_delphone(&phone); - up(&dev->sem); - return ret; - } else - return -EINVAL; - case IIOCNETDIL: - /* Force dialing of a network-interface */ - if (arg) { - if (copy_from_user(name, (char *) arg, sizeof(name))) - return -EFAULT; - return isdn_net_force_dial(name); - } else - return -EINVAL; -#ifdef CONFIG_ISDN_PPP - case IIOCNETALN: - if (!arg) - return -EINVAL; - if (copy_from_user(name, (char *) arg, sizeof(name))) + + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + if (copy_from_user(dev->mdm.info[i].emu.profile, p, + ISDN_MODEM_NUMREG)) return -EFAULT; - return isdn_ppp_dial_slave(name); - case IIOCNETDLN: - if (!arg) - return -EINVAL; - if (copy_from_user(name, (char *) arg, sizeof(name))) + p += ISDN_MODEM_NUMREG; + if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN)) return -EFAULT; - return isdn_ppp_hangup_slave(name); -#endif - case IIOCNETHUP: - /* Force hangup of a network-interface */ - if (!arg) - return -EINVAL; - if (copy_from_user(name, (char *) arg, sizeof(name))) + p += ISDN_LMSNLEN; + if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)) return -EFAULT; - return isdn_net_force_hangup(name); - break; -#endif /* CONFIG_NETDEVICES */ - case IIOCSETVER: - dev->net_verbose = arg; - printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose); - return 0; - case IIOCSETGST: - if (arg) - dev->global_flags |= ISDN_GLOBAL_STOPPED; - else - dev->global_flags &= ~ISDN_GLOBAL_STOPPED; - printk(KERN_INFO "isdn: Global Mode %s\n", - (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running"); - return 0; - case IIOCSETBRJ: + p += ISDN_MSNLEN; + } + return 0; + } else + return -EINVAL; + break; + case IIOCSETMAP: + case IIOCGETMAP: + /* Set/Get MSN->EAZ-Mapping for a driver */ + if (arg) { + + if (copy_from_user((char *) &iocts, + (char *) arg, + sizeof(isdn_ioctl_struct))) + return -EFAULT; + if (strlen(iocts.drvid)) { drvidx = -1; - if (arg) { - int i; - char *p; - if (copy_from_user((char *) &iocts, (char *) arg, - sizeof(isdn_ioctl_struct))) - return -EFAULT; - if (strlen(iocts.drvid)) { - if ((p = strchr(iocts.drvid, ','))) - *p = 0; - drvidx = -1; - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (!(strcmp(dev->drvid[i], iocts.drvid))) { - drvidx = i; - break; - } - } - } - if (drvidx == -1) - return -ENODEV; - if (iocts.arg) - dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS; - else - dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS; - return 0; - case IIOCSIGPRF: - dev->profd = current; - return 0; - break; - case IIOCGETPRF: - /* Get all Modem-Profiles */ - if (arg) { - char *p = (char *) arg; - int i; - - if ((ret = verify_area(VERIFY_WRITE, (void *) arg, - (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) - * ISDN_MAX_CHANNELS))) - return ret; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (copy_to_user(p, dev->mdm.info[i].emu.profile, - ISDN_MODEM_NUMREG)) - return -EFAULT; - p += ISDN_MODEM_NUMREG; - if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN)) - return -EFAULT; - p += ISDN_MSNLEN; - if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN)) - return -EFAULT; - p += ISDN_LMSNLEN; - } - return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; - } else - return -EINVAL; - break; - case IIOCSETPRF: - /* Set all Modem-Profiles */ - if (arg) { - char *p = (char *) arg; - int i; - - if ((ret = verify_area(VERIFY_READ, (void *) arg, - (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) - * ISDN_MAX_CHANNELS))) - return ret; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (copy_from_user(dev->mdm.info[i].emu.profile, p, - ISDN_MODEM_NUMREG)) - return -EFAULT; - p += ISDN_MODEM_NUMREG; - if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN)) - return -EFAULT; - p += ISDN_LMSNLEN; - if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)) - return -EFAULT; - p += ISDN_MSNLEN; + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + if (!(strcmp(dev->drvid[i], iocts.drvid))) { + drvidx = i; + break; } - return 0; - } else - return -EINVAL; - break; - case IIOCSETMAP: - case IIOCGETMAP: - /* Set/Get MSN->EAZ-Mapping for a driver */ - if (arg) { - - if (copy_from_user((char *) &iocts, - (char *) arg, - sizeof(isdn_ioctl_struct))) - return -EFAULT; - if (strlen(iocts.drvid)) { - drvidx = -1; - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (!(strcmp(dev->drvid[i], iocts.drvid))) { - drvidx = i; - break; - } - } else - drvidx = 0; - if (drvidx == -1) - return -ENODEV; - if (cmd == IIOCSETMAP) { - int loop = 1; - - p = (char *) iocts.arg; - i = 0; - while (loop) { - int j = 0; - - while (1) { - if ((ret = verify_area(VERIFY_READ, p, 1))) - return ret; - get_user(bname[j], p++); - switch (bname[j]) { - case '\0': - loop = 0; - /* Fall through */ - case ',': - bname[j] = '\0'; - strcpy(dev->drv[drvidx]->msn2eaz[i], bname); - j = ISDN_MSNLEN; - break; - default: - j++; - } - if (j >= ISDN_MSNLEN) - break; - } - if (++i > 9) - break; - } - } else { - p = (char *) iocts.arg; - for (i = 0; i < 10; i++) { - sprintf(bname, "%s%s", - strlen(dev->drv[drvidx]->msn2eaz[i]) ? - dev->drv[drvidx]->msn2eaz[i] : "_", - (i < 9) ? "," : "\0"); - if (copy_to_user(p, bname, strlen(bname) + 1)) - return -EFAULT; - p += strlen(bname); + } else + drvidx = 0; + if (drvidx == -1) + return -ENODEV; + if (cmd == IIOCSETMAP) { + int loop = 1; + + p = (char *) iocts.arg; + i = 0; + while (loop) { + int j = 0; + + while (1) { + if ((ret = verify_area(VERIFY_READ, p, 1))) + return ret; + get_user(bname[j], p++); + switch (bname[j]) { + case '\0': + loop = 0; + /* Fall through */ + case ',': + bname[j] = '\0'; + strcpy(dev->drv[drvidx]->msn2eaz[i], bname); + j = ISDN_MSNLEN; + break; + default: + j++; } + if (j >= ISDN_MSNLEN) + break; } - return 0; - } else - return -EINVAL; - case IIOCDBGVAR: - if (arg) { - if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong))) - return -EFAULT; - return 0; - } else - return -EINVAL; - break; - default: - if ((cmd & IIOCDRVCTL) == IIOCDRVCTL) - cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK; - else - return -EINVAL; - if (arg) { - int i; - char *p; - if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct))) - return -EFAULT; - if (strlen(iocts.drvid)) { - if ((p = strchr(iocts.drvid, ','))) - *p = 0; - drvidx = -1; - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (!(strcmp(dev->drvid[i], iocts.drvid))) { - drvidx = i; - break; - } - } else - drvidx = 0; - if (drvidx == -1) - return -ENODEV; - if ((ret = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(isdn_ioctl_struct)))) - return ret; - c.driver = drvidx; - c.command = ISDN_CMD_IOCTL; - c.arg = cmd; - memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong)); - ret = isdn_command(&c); - memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong)); - if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct))) + if (++i > 9) + break; + } + } else { + p = (char *) iocts.arg; + for (i = 0; i < 10; i++) { + sprintf(bname, "%s%s", + strlen(dev->drv[drvidx]->msn2eaz[i]) ? + dev->drv[drvidx]->msn2eaz[i] : "_", + (i < 9) ? "," : "\0"); + if (copy_to_user(p, bname, strlen(bname) + 1)) return -EFAULT; - return ret; - } else - return -EINVAL; - } + p += strlen(bname); + } + } + return 0; + } else + return -EINVAL; + case IIOCDBGVAR: + if (arg) { + if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong))) + return -EFAULT; + return 0; + } else + return -EINVAL; + break; + default: + if ((cmd & IIOCDRVCTL) == IIOCDRVCTL) + cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK; + else + return -EINVAL; + if (arg) { + int i; + char *p; + if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct))) + return -EFAULT; + if (strlen(iocts.drvid)) { + if ((p = strchr(iocts.drvid, ','))) + *p = 0; + drvidx = -1; + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + if (!(strcmp(dev->drvid[i], iocts.drvid))) { + drvidx = i; + break; + } + } else + drvidx = 0; + if (drvidx == -1) + return -ENODEV; + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(isdn_ioctl_struct)))) + return ret; + c.driver = drvidx; + c.command = ISDN_CMD_IOCTL; + c.arg = cmd; + memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong)); + ret = isdn_command(&c); + memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong)); + if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct))) + return -EFAULT; + return ret; + } else + return -EINVAL; } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) - return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg)); -#endif - return -ENODEV; #undef name #undef bname @@ -1630,67 +1651,120 @@ } /* + * + */ + +static ssize_t +isdn_read(struct file *file, char *buf, size_t count, loff_t * off) +{ + uint minor = minor(file->f_dentry->d_inode->i_rdev); + + if (minor < ISDN_MINOR_CTRL) + return -ENODEV; + + if (minor <= ISDN_MINOR_CTRLMAX) + return isdn_ctrl_read(file, buf, count, off); + +#ifdef CONFIG_ISDN_PPP + if (minor <= ISDN_MINOR_PPPMAX) + return isdn_ppp_read(file, buf, count, off); +#endif + + if (minor == ISDN_MINOR_STATUS) + return isdn_status_read(file, buf, count, off); + + return -ENODEV; +} + +static ssize_t +isdn_write(struct file *file, const char *buf, size_t count, loff_t * off) +{ + uint minor = minor(file->f_dentry->d_inode->i_rdev); + + if (minor < ISDN_MINOR_CTRL) + return -ENODEV; + + if (minor <= ISDN_MINOR_CTRLMAX) + return isdn_ctrl_write(file, buf, count, off); + +#ifdef CONFIG_ISDN_PPP + if (minor <= ISDN_MINOR_PPPMAX) + return isdn_ppp_write(file, buf, count, off); +#endif + + if (minor == ISDN_MINOR_STATUS) + return isdn_status_write(file, buf, count, off); + + return -ENODEV; +} + +static unsigned int +isdn_poll(struct file *file, poll_table * wait) +{ + unsigned int minor = minor(file->f_dentry->d_inode->i_rdev); + + if (minor < ISDN_MINOR_CTRL) + return POLLERR; + + if (minor <= ISDN_MINOR_CTRLMAX) + return isdn_ctrl_poll(file, wait); + +#ifdef CONFIG_ISDN_PPP + if (minor <= ISDN_MINOR_PPPMAX) + return isdn_ppp_poll(file, wait); +#endif + + if (minor == ISDN_MINOR_STATUS) + return isdn_status_poll(file, wait); + + return POLLERR; +} + +static int +isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) +{ + uint minor = minor(inode->i_rdev); + + if (minor == ISDN_MINOR_STATUS) + return isdn_status_ioctl(inode, file, cmd, arg); + + if (minor < ISDN_MINOR_CTRL) + return -ENODEV; + + if (minor <= ISDN_MINOR_CTRLMAX) + return isdn_ctrl_ioctl(inode, file, cmd, arg); + +#ifdef CONFIG_ISDN_PPP + if (minor <= ISDN_MINOR_PPPMAX) + return isdn_ppp_ioctl(inode, file, cmd, arg); +#endif + + return -ENODEV; +} + +/* * Open the device code. */ static int isdn_open(struct inode *ino, struct file *filep) { uint minor = minor(ino->i_rdev); - int drvidx; - int chidx; - int retval = -ENODEV; + if (minor < ISDN_MINOR_CTRL) + return -ENODEV; - if (minor == ISDN_MINOR_STATUS) { - infostruct *p; + if (minor <= ISDN_MINOR_CTRLMAX) + return isdn_ctrl_open(ino, filep); + + if (minor == ISDN_MINOR_STATUS) + return isdn_status_open(ino, filep); - if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) { - p->next = (char *) dev->infochain; - p->private = (char *) &(filep->private_data); - dev->infochain = p; - /* At opening we allow a single update */ - filep->private_data = (char *) 1; - retval = 0; - goto out; - } else { - retval = -ENOMEM; - goto out; - } - } - if (!dev->channels) - goto out; - if (minor <= ISDN_MINOR_BMAX) { - printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor); - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) - goto out; - chidx = isdn_minor2chan(minor); - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - goto out; - if (!(dev->drv[drvidx]->online & (1 << chidx))) - goto out; - isdn_lock_drivers(); - retval = 0; - goto out; - } - if (minor <= ISDN_MINOR_CTRLMAX) { - drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) - goto out; - isdn_lock_drivers(); - retval = 0; - goto out; - } #ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) { - retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep); - if (retval == 0) - isdn_lock_drivers(); - goto out; - } + if (minor <= ISDN_MINOR_PPPMAX) + return isdn_ppp_open(ino, filep); #endif - out: - return retval; + + return -ENODEV; } static int @@ -1698,42 +1772,21 @@ { uint minor = minor(ino->i_rdev); - lock_kernel(); - if (minor == ISDN_MINOR_STATUS) { - infostruct *p = dev->infochain; - infostruct *q = NULL; - - while (p) { - if (p->private == (char *) &(filep->private_data)) { - if (q) - q->next = p->next; - else - dev->infochain = (infostruct *) (p->next); - kfree(p); - goto out; - } - q = p; - p = (infostruct *) (p->next); - } - printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); - goto out; - } - isdn_unlock_drivers(); - if (minor <= ISDN_MINOR_BMAX) - goto out; - if (minor <= ISDN_MINOR_CTRLMAX) { - if (dev->profd == current) - dev->profd = NULL; - goto out; - } + if (minor == ISDN_MINOR_STATUS) + return isdn_status_release(ino, filep); + + if (minor < ISDN_MINOR_CTRL) + return -ENODEV; + + if (minor <= ISDN_MINOR_CTRLMAX) + return isdn_ctrl_release(ino, filep); + #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) - isdn_ppp_release(minor - ISDN_MINOR_PPP, filep); + return isdn_ppp_release(ino, filep); #endif - out: - unlock_kernel(); - return 0; + return -ENODEV; } static struct file_operations isdn_fops = @@ -1875,32 +1928,6 @@ return; } restore_flags(flags); -} - -/* - * writebuf replacement for SKB_ABLE drivers - */ -static int -isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len, - int user) -{ - int ret; - int hl = dev->drv[drvidx]->interface->hl_hdrlen; - struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC); - - if (!skb) - return 0; - skb_reserve(skb, hl); - if (user) - copy_from_user(skb_put(skb, len), buf, len); - else - memcpy(skb_put(skb, len), buf, len); - ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb); - if (ret <= 0) - dev_kfree_skb(skb); - if (ret > 0) - dev->obytes[isdn_dc2minor(drvidx, chan)] += ret; - return ret; } /* diff -urN linux-2.5.3-pre1/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h --- linux-2.5.3-pre1/drivers/isdn/isdn_common.h Sun Sep 30 12:26:06 2001 +++ linux/drivers/isdn/isdn_common.h Sat Jan 19 16:58:39 2002 @@ -27,6 +27,8 @@ /* Prototypes */ extern void isdn_MOD_INC_USE_COUNT(void); extern void isdn_MOD_DEC_USE_COUNT(void); +extern void isdn_lock_drivers(void); +extern void isdn_unlock_drivers(void); extern void isdn_free_channel(int di, int ch, int usage); extern void isdn_all_eaz(int di, int ch); extern int isdn_command(isdn_ctrl *); diff -urN linux-2.5.3-pre1/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- linux-2.5.3-pre1/drivers/isdn/isdn_ppp.c Thu Jan 3 12:20:10 2002 +++ linux/drivers/isdn/isdn_ppp.c Sat Jan 19 16:58:39 2002 @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -269,21 +270,19 @@ */ int -isdn_ppp_open(int min, struct file *file) +isdn_ppp_open(struct inode *ino, struct file *file) { + uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP; int slot; struct ippp_struct *is; - if (min < 0 || min > ISDN_MAX_CHANNELS) - return -ENODEV; - slot = isdn_ppp_get_slot(); if (slot < 0) { return -EBUSY; } is = file->private_data = ippp_table[slot]; - printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state); + printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, minor, is->state); /* compression stuff */ is->link_compressor = is->compressor = NULL; @@ -306,7 +305,7 @@ init_waitqueue_head(&is->wq); is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ is->last = is->rq; - is->minor = min; + is->minor = minor; #ifdef CONFIG_ISDN_PPP_VJ /* * VJ header compression init @@ -315,6 +314,7 @@ #endif is->state = IPPP_OPEN; + isdn_lock_drivers(); return 0; } @@ -322,18 +322,19 @@ /* * release ippp device */ -void -isdn_ppp_release(int min, struct file *file) +int +isdn_ppp_release(struct inode *ino, struct file *file) { + uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP; int i; struct ippp_struct *is; - if (min < 0 || min >= ISDN_MAX_CHANNELS) - return; + lock_kernel(); + is = file->private_data; if (is->debug & 0x1) - printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp); + printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) is->lp); if (is->lp) { /* a lp address says: this link is still up */ isdn_net_dev *p = is->lp->netdev; @@ -381,6 +382,11 @@ /* this slot is ready for new connections */ is->state = 0; + + isdn_unlock_drivers(); + + unlock_kernel(); + return 0; } /* @@ -413,7 +419,7 @@ * ippp device ioctl */ int -isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) +isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long val; int r,i,j; @@ -425,7 +431,7 @@ lp = is->lp; if (is->debug & 0x1) - printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state); + printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", is->minor, cmd, is->state); if (!(is->state & IPPP_OPEN)) return -EINVAL; @@ -438,7 +444,7 @@ if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", - (int) min, (int) is->unit, (int) val); + (int) is->minor, (int) is->unit, (int) val); return isdn_ppp_bundle(is, val); #else return -1; @@ -582,6 +588,7 @@ unsigned long flags; struct ippp_struct *is; + lock_kernel(); is = file->private_data; if (is->debug & 0x2) @@ -592,10 +599,13 @@ poll_wait(file, &is->wq, wait); if (!(is->state & IPPP_OPEN)) { - if(is->state == IPPP_CLOSEWAIT) - return POLLHUP; + if(is->state == IPPP_CLOSEWAIT) { + mask = POLLHUP; + goto out; + } printk(KERN_DEBUG "isdn_ppp: device not open\n"); - return POLLERR; + mask = POLLERR; + goto out; } /* we're always ready to send .. */ mask = POLLOUT | POLLWRNORM; @@ -612,6 +622,9 @@ mask |= POLLIN | POLLRDNORM; } restore_flags(flags); + + out: + unlock_kernel(); return mask; } @@ -678,21 +691,28 @@ */ int -isdn_ppp_read(int min, struct file *file, char *buf, int count) +isdn_ppp_read(struct file *file, char *buf, int count, loff_t *off) { struct ippp_struct *is; struct ippp_buf_queue *b; - int r; unsigned long flags; unsigned char *save_buf; + int retval; - is = file->private_data; + if (off != &file->f_pos) + return -ESPIPE; + + lock_kernel(); - if (!(is->state & IPPP_OPEN)) - return 0; + is = file->private_data; - if ((r = verify_area(VERIFY_WRITE, (void *) buf, count))) - return r; + if (!(is->state & IPPP_OPEN)) { + retval = 0; + goto out; + } + retval = verify_area(VERIFY_WRITE, (void *) buf, count); + if (retval) + goto out; save_flags(flags); cli(); @@ -701,7 +721,8 @@ save_buf = b->buf; if (!save_buf) { restore_flags(flags); - return -EAGAIN; + retval = -EAGAIN; + goto out; } if (b->len < count) count = b->len; @@ -713,7 +734,11 @@ copy_to_user(buf, save_buf, count); kfree(save_buf); - return count; + retval = count; + + out: + unlock_kernel(); + return retval; } /* @@ -721,17 +746,25 @@ */ int -isdn_ppp_write(int min, struct file *file, const char *buf, int count) +isdn_ppp_write(struct file *file, const char *buf, int count, loff_t *off) { isdn_net_local *lp; struct ippp_struct *is; int proto; unsigned char protobuf[4]; + int retval; + + if (off != &file->f_pos) + return -ESPIPE; + + lock_kernel(); is = file->private_data; - if (!(is->state & IPPP_CONNECT)) - return 0; + if (!(is->state & IPPP_CONNECT)) { + retval = 0; + goto out; + } lp = is->lp; @@ -744,15 +777,18 @@ * Don't reset huptimer for * LCP packets. (Echo requests). */ - if (copy_from_user(protobuf, buf, 4)) - return -EFAULT; + if (copy_from_user(protobuf, buf, 4)) { + retval = -EFAULT; + goto out; + } proto = PPP_PROTOCOL(protobuf); if (proto != PPP_LCP) lp->huptimer = 0; - if (lp->isdn_device < 0 || lp->isdn_channel < 0) - return 0; - + if (lp->isdn_device < 0 || lp->isdn_channel < 0) { + retval = 0; + goto out; + } if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) && lp->dialstate == 0 && (lp->flags & ISDN_NET_CONNECTED)) { @@ -767,13 +803,15 @@ skb = alloc_skb(hl+count, GFP_ATOMIC); if (!skb) { printk(KERN_WARNING "isdn_ppp_write: out of memory!\n"); - return count; + retval = count; + goto out; } skb_reserve(skb, hl); if (copy_from_user(skb_put(skb, count), buf, count)) { kfree_skb(skb); - return -EFAULT; + retval = -EFAULT; + goto out; } if (is->debug & 0x40) { printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len); @@ -785,7 +823,11 @@ isdn_net_write_super(lp, skb); } } - return count; + retval = count; + + out: + unlock_kernel(); + return retval; } /* diff -urN linux-2.5.3-pre1/drivers/isdn/isdn_ppp.h linux/drivers/isdn/isdn_ppp.h --- linux-2.5.3-pre1/drivers/isdn/isdn_ppp.h Sun Sep 30 12:26:06 2001 +++ linux/drivers/isdn/isdn_ppp.h Sat Jan 19 16:58:39 2002 @@ -12,9 +12,13 @@ #include /* for PPP_PROTOCOL */ #include /* for isdn_ppp info */ -extern int isdn_ppp_read(int, struct file *, char *, int); -extern int isdn_ppp_write(int, struct file *, const char *, int); -extern int isdn_ppp_open(int, struct file *); +extern int isdn_ppp_open(struct inode *, struct file *); +extern int isdn_ppp_release(struct inode *, struct file *); +extern int isdn_ppp_read(struct file *, char *, int, loff_t *off); +extern int isdn_ppp_write(struct file *, const char *, int, loff_t *off); +extern int isdn_ppp_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *); + extern int isdn_ppp_init(void); extern void isdn_ppp_cleanup(void); extern int isdn_ppp_free(isdn_net_local *); @@ -22,9 +26,6 @@ extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *); extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *); extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int); -extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *); -extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long); -extern void isdn_ppp_release(int, struct file *); extern int isdn_ppp_dial_slave(char *); extern void isdn_ppp_wakeup_daemon(isdn_net_local *); diff -urN linux-2.5.3-pre1/drivers/md/md.c linux/drivers/md/md.c --- linux-2.5.3-pre1/drivers/md/md.c Thu Jan 10 10:15:38 2002 +++ linux/drivers/md/md.c Sat Jan 19 16:58:39 2002 @@ -3458,8 +3458,7 @@ * about not overloading the IO subsystem. (things like an * e2fsck being done on the RAID array should execute fast) */ - if (current->need_resched) - schedule(); + cond_resched(); currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1; diff -urN linux-2.5.3-pre1/drivers/media/radio/radio-sf16fmi.c linux/drivers/media/radio/radio-sf16fmi.c --- linux-2.5.3-pre1/drivers/media/radio/radio-sf16fmi.c Sun Sep 30 12:26:06 2001 +++ linux/drivers/media/radio/radio-sf16fmi.c Sat Jan 19 16:58:39 2002 @@ -94,8 +94,7 @@ for(i=0; i< 100; i++) { udelay(1400); - if(current->need_resched) - schedule(); + cond_resched(); } /* If this becomes allowed use it ... current->state = TASK_UNINTERRUPTIBLE; @@ -121,8 +120,7 @@ for(i=0; i< 100; i++) { udelay(1400); - if(current->need_resched) - schedule(); + cond_resched(); } /* If this becomes allowed use it ... current->state = TASK_UNINTERRUPTIBLE; diff -urN linux-2.5.3-pre1/drivers/media/video/c-qcam.c linux/drivers/media/video/c-qcam.c --- linux-2.5.3-pre1/drivers/media/video/c-qcam.c Sun Sep 30 12:26:06 2001 +++ linux/drivers/media/video/c-qcam.c Sat Jan 19 16:58:39 2002 @@ -425,8 +425,7 @@ wantlen -= t; if (t < s) break; - if (current->need_resched) - schedule(); + cond_resched(); } len = outptr; @@ -445,8 +444,7 @@ int l; do { l = qcam_read_bytes(q, tmpbuf, 3); - if (current->need_resched) - schedule(); + cond_resched(); } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); if (force_rgb) { if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) @@ -478,8 +476,7 @@ int l; do { l = qcam_read_bytes(q, tmpbuf, 1); - if (current->need_resched) - schedule(); + cond_resched(); } while (l && tmpbuf[0] == 0x7e); l = qcam_read_bytes(q, tmpbuf+1, 2); if (force_rgb) { diff -urN linux-2.5.3-pre1/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c --- linux-2.5.3-pre1/drivers/media/video/cpia.c Sat Jan 19 16:58:37 2002 +++ linux/drivers/media/video/cpia.c Sat Jan 19 16:58:39 2002 @@ -2147,8 +2147,7 @@ /* loop until image ready */ do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0); while (cam->params.status.streamState != STREAM_READY) { - if (current->need_resched) - schedule(); + cond_resched(); current->state = TASK_INTERRUPTIBLE; @@ -2163,8 +2162,7 @@ } /* grab image from camera */ - if (current->need_resched) - schedule(); + cond_resched(); oldjif = jiffies; image_size = cam->ops->streamRead(cam->lowlevel_data, @@ -2189,8 +2187,7 @@ /* decompress and convert image to by copying it from * raw_image to decompressed_frame */ - if (current->need_resched) - schedule(); + cond_resched(); cam->image_size = parse_picture(cam, image_size); if (cam->image_size <= 0) diff -urN linux-2.5.3-pre1/drivers/media/video/cpia_pp.c linux/drivers/media/video/cpia_pp.c --- linux-2.5.3-pre1/drivers/media/video/cpia_pp.c Thu Oct 25 13:53:47 2001 +++ linux/drivers/media/video/cpia_pp.c Sat Jan 19 16:58:39 2002 @@ -392,7 +392,7 @@ endseen = 0; block_size = PARPORT_CHUNK_SIZE; while( !cam->image_complete ) { - if(current->need_resched) schedule(); + cond_resched(); new_bytes = cpia_pp_read(cam->port, buffer, block_size ); if( new_bytes <= 0 ) { diff -urN linux-2.5.3-pre1/drivers/media/video/saa5249.c linux/drivers/media/video/saa5249.c --- linux-2.5.3-pre1/drivers/media/video/saa5249.c Sun Sep 30 12:26:06 2001 +++ linux/drivers/media/video/saa5249.c Sat Jan 19 16:58:39 2002 @@ -127,11 +127,7 @@ #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif -#define RESCHED \ - do { \ - if (current->need_resched) \ - schedule(); \ - } while (0) +#define RESCHED do { cond_resched(); } while(0) static struct video_device saa_template; /* Declared near bottom */ diff -urN linux-2.5.3-pre1/drivers/mtd/chips/amd_flash.c linux/drivers/mtd/chips/amd_flash.c --- linux-2.5.3-pre1/drivers/mtd/chips/amd_flash.c Thu Oct 4 15:14:59 2001 +++ linux/drivers/mtd/chips/amd_flash.c Sat Jan 19 16:58:39 2002 @@ -889,7 +889,7 @@ times_left = 500000; while (times_left-- && flash_is_busy(map, adr, private->interleave)) { - if (current->need_resched) { + if (need_resched()) { spin_unlock_bh(chip->mutex); schedule(); spin_lock_bh(chip->mutex); @@ -1126,7 +1126,7 @@ /* Latency issues. Drop the lock, wait a while and retry */ spin_unlock_bh(chip->mutex); - if (current->need_resched) + if (need_resched()) schedule(); else udelay(1); diff -urN linux-2.5.3-pre1/drivers/mtd/devices/doc2000.c linux/drivers/mtd/devices/doc2000.c --- linux-2.5.3-pre1/drivers/mtd/devices/doc2000.c Thu Oct 4 15:14:59 2001 +++ linux/drivers/mtd/devices/doc2000.c Sat Jan 19 16:58:39 2002 @@ -97,7 +97,7 @@ DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); return -EIO; } - if (current->need_resched) { + if (need_resched()) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); } diff -urN linux-2.5.3-pre1/drivers/net/acenic.h linux/drivers/net/acenic.h --- linux-2.5.3-pre1/drivers/net/acenic.h Mon Nov 19 15:19:42 2001 +++ linux/drivers/net/acenic.h Sat Jan 19 16:58:39 2002 @@ -585,7 +585,7 @@ struct ring_info { struct sk_buff *skb; - dma_addr_t mapping; + DECLARE_PCI_UNMAP_ADDR(mapping) }; @@ -596,8 +596,8 @@ */ struct tx_ring_info { struct sk_buff *skb; - dma_addr_t mapping; - int maplen; + DECLARE_PCI_UNMAP_ADDR(mapping) + DECLARE_PCI_UNMAP_LEN(maplen) }; diff -urN linux-2.5.3-pre1/drivers/net/pcmcia/wavelan.h linux/drivers/net/pcmcia/wavelan.h --- linux-2.5.3-pre1/drivers/net/pcmcia/wavelan.h Fri Mar 2 11:02:15 2001 +++ linux/drivers/net/pcmcia/wavelan.h Sat Jan 19 16:58:39 2002 @@ -88,6 +88,7 @@ */ const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; + /*************************** PC INTERFACE ****************************/ /* WaveLAN host interface definitions */ @@ -316,6 +317,7 @@ /* Calculate offset of a field in the above structure */ #define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0) + /* * Modem Management Controller (MMC) read structure. */ @@ -372,6 +374,7 @@ /* Calculate offset of a field in the above structure */ #define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0) + /* Make the two above structures one */ typedef union mm_t diff -urN linux-2.5.3-pre1/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c --- linux-2.5.3-pre1/drivers/net/pcmcia/wavelan_cs.c Fri Nov 9 15:22:54 2001 +++ linux/drivers/net/pcmcia/wavelan_cs.c Sat Jan 19 16:58:39 2002 @@ -22,7 +22,7 @@ #ifdef WAVELAN_ROAMING * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu) * based on patch by Joe Finney from Lancaster University. -#endif :-) +#endif * * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor. @@ -37,12 +37,6 @@ * Apr 2 '98 made changes to bring the i82593 control/int handling in line * with offical specs... * - * Changes: - * Arnaldo Carvalho de Melo - 08/08/2000 - * - reorganize kmallocs in wavelan_attach, checking all for failure - * and releasing the previous allocations if one fails - * - * **************************************************************************** * Copyright 1995 * Anthony D. Joseph @@ -72,6 +66,34 @@ /*------------------------------------------------------------------*/ /* + * Wrapper for disabling interrupts. + * (note : inline, so optimised away) + */ +static inline void +wv_splhi(net_local * lp, + unsigned long * pflags) +{ + spin_lock_irqsave(&lp->spinlock, *pflags); + /* Note : above does the cli(); itself */ +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper for re-enabling interrupts. + */ +static inline void +wv_splx(net_local * lp, + unsigned long * pflags) +{ + spin_unlock_irqrestore(&lp->spinlock, *pflags); + + /* Note : enabling interrupts on the hardware is done in wv_ru_start() + * via : outb(OP1_INT_ENABLE, LCCR(base)); + */ +} + +/*------------------------------------------------------------------*/ +/* * Wrapper for reporting error to cardservices */ static void cs_error(client_handle_t handle, int func, int ret) @@ -103,7 +125,7 @@ /******************* MODEM MANAGEMENT SUBROUTINES *******************/ /* - * Usefull subroutines to manage the modem of the wavelan + * Useful subroutines to manage the modem of the wavelan */ /*------------------------------------------------------------------*/ @@ -138,7 +160,7 @@ { hacr_write(base, hacr); /* delay might only be needed sometimes */ - mdelay(1L); + mdelay(1); } /* hacr_write_slow */ /*------------------------------------------------------------------*/ @@ -529,7 +551,7 @@ lp->curr_point=NULL; /* No default WavePoint */ lp->cell_search=0; - lp->cell_timer.data=(int)lp; /* Start cell expiry timer */ + lp->cell_timer.data=(long)lp; /* Start cell expiry timer */ lp->cell_timer.function=wl_cell_expiry; lp->cell_timer.expires=jiffies+CELL_TIMEOUT; add_timer(&lp->cell_timer); @@ -569,18 +591,18 @@ #endif /* Disable interrupts & save flags */ - spin_lock_irqsave (&lp->lock, flags); + wv_splhi(lp, &flags); m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00; mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1); - /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore (&lp->lock, flags); - if(mode==NWID_PROMISC) lp->cell_search=1; else - lp->cell_search=0; + lp->cell_search=0; + + /* ReEnable interrupts & restore flags */ + wv_splx(lp, &flags); } /* Find a record in the WavePoint table matching a given NWID */ @@ -737,7 +759,7 @@ ioaddr_t base = lp->dev->base_addr; mm_t m; unsigned long flags; - + if(wavepoint==lp->curr_point) /* Sanity check... */ { wv_nwid_filter(!NWID_PROMISC,lp); @@ -749,16 +771,16 @@ #endif /* Disable interrupts & save flags */ - spin_lock_irqsave(&lp->lock, flags); - + wv_splhi(lp, &flags); + m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF; m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8; mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore (&lp->lock, flags); - + wv_splx(lp, &flags); + wv_nwid_filter(!NWID_PROMISC,lp); lp->curr_point=wavepoint; } @@ -775,6 +797,11 @@ wavepoint_history *wavepoint=NULL; /* WavePoint table entry */ net_local *lp=(net_local *)dev->priv; /* Device info */ +#if 0 + /* Some people don't need this, some other may need it */ + nwid=nwid^ntohs(beacon->domain_id); +#endif + #if WAVELAN_ROAMING_DEBUG > 1 printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name); printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual); @@ -832,7 +859,9 @@ /*------------------------------------------------------------------*/ /* * Routine to synchronously send a command to the i82593 chip. - * Should be called with interrupts enabled. + * Should be called with interrupts disabled. + * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(), + * wv_82593_config() & wv_diag()) */ static int wv_82593_cmd(device * dev, @@ -841,74 +870,98 @@ int result) { ioaddr_t base = dev->base_addr; - net_local * lp = (net_local *)dev->priv; int status; + int wait_completed; long spin; - u_long flags; /* Spin until the chip finishes executing its current command (if any) */ + spin = 1000; do { - spin_lock_irqsave (&lp->lock, flags); + /* Time calibration of the loop */ + udelay(10); + + /* Read the interrupt register */ outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); status = inb(LCSR(base)); - spin_unlock_irqrestore (&lp->lock, flags); } - while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE); + while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); - /* We are waiting for command completion */ - wv_wait_completed = TRUE; + /* If the interrupt hasn't be posted */ + if(spin <= 0) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n", + str, status); +#endif + return(FALSE); + } /* Issue the command to the controller */ outb(cmd, LCCR(base)); - /* If we don't have to check the result of the command */ + /* If we don't have to check the result of the command + * Note : this mean that the irq handler will deal with that */ if(result == SR0_NO_RESULT) - { - wv_wait_completed = FALSE; - return(TRUE); - } + return(TRUE); - /* Busy wait while the LAN controller executes the command. - * Note : wv_wait_completed should be volatile */ - spin = 0; - while(wv_wait_completed && (spin++ < 1000)) - udelay(10); + /* We are waiting for command completion */ + wait_completed = TRUE; - /* If the interrupt handler hasn't be called */ - if(wv_wait_completed) + /* Busy wait while the LAN controller executes the command. */ + spin = 1000; + do { - outb(OP0_NOP, LCCR(base)); + /* Time calibration of the loop */ + udelay(10); + + /* Read the interrupt register */ + outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); status = inb(LCSR(base)); - if(status & SR0_INTERRUPT) + + /* Check if there was an interrupt posted */ + if((status & SR0_INTERRUPT)) { - /* There was an interrupt : call the interrupt handler */ -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_WARNING "wv_82593_cmd: interrupt handler not installed or interrupt disabled\n"); -#endif + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); - wavelan_interrupt(dev->irq, (void *) dev, - (struct pt_regs *) NULL); + /* Check if interrupt is a command completion */ + if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) && + ((status & SR0_BOTH_RX_TX) != 0x0) && + !(status & SR0_RECEPTION)) + { + /* Signal command completion */ + wait_completed = FALSE; + } + else + { + /* Note : Rx interrupts will be handled later, because we can + * handle multiple Rx packets at once */ +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_INFO "wv_82593_cmd: not our interrupt\n"); +#endif + } } - else - { - wv_wait_completed = 0; /* XXX */ + } + while(wait_completed && (spin-- > 0)); + + /* If the interrupt hasn't be posted */ + if(wait_completed) + { #ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "wv_82593_cmd: %s timeout, status0 0x%02x\n", - str, status); + printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n", + str, status); #endif - /* We probably should reset the controller here */ - return(FALSE); - } + return(FALSE); } - /* Check the return code provided by the interrupt handler against + /* Check the return code returned by the card (see above) against * the expected return code provided by the caller */ - if((lp->status & SR0_EVENT_MASK) != result) + if((status & SR0_EVENT_MASK) != result) { #ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "wv_82593_cmd: %s failed, status0 = 0x%x\n", - str, lp->status); + printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n", + str, status); #endif return(FALSE); } @@ -924,14 +977,16 @@ static inline int wv_diag(device * dev) { + int ret = FALSE; + if(wv_82593_cmd(dev, "wv_diag(): diagnose", OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED)) - return(TRUE); + ret = TRUE; #ifdef DEBUG_CONFIG_ERROR printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n"); #endif - return(FALSE); + return(ret); } /* wv_diag */ /*------------------------------------------------------------------*/ @@ -951,15 +1006,6 @@ int chunk_len; char * buf_ptr = buf; -#ifdef OLDIES - /* After having check skb_put (net/core/skbuff.c) in the kernel, it seem - * quite safe to remove this... */ - - /* If buf is NULL, just increment the ring buffer pointer */ - if(buf == NULL) - return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE); -#endif - /* Get all the buffer */ while(len > 0) { @@ -990,70 +1036,32 @@ * wavelan_interrupt is not an option...), so you may experience * some delay sometime... */ -static inline void wv_82593_reconfig (device * dev) +static inline void +wv_82593_reconfig(device * dev) { - net_local *lp = (net_local *) dev->priv; - dev_link_t *link = ((net_local *) dev->priv)->link; + net_local * lp = (net_local *)dev->priv; + dev_link_t * link = ((net_local *) dev->priv)->link; + unsigned long flags; + + /* Arm the flag, will be cleard in wv_82593_config() */ + lp->reconfig_82593 = TRUE; - /* Check if we can do it now ! */ - if (!(link->open)) { - lp->reconfig_82593 = TRUE; + /* Check if we can do it now ! */ + if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev))) + { + wv_splhi(lp, &flags); /* Disable interrupts */ + wv_82593_config(dev); + wv_splx(lp, &flags); /* Re-enable interrupts */ + } + else + { #ifdef DEBUG_IOCTL_INFO - printk (KERN_DEBUG "%s: wv_82593_reconfig(): delayed (link = %d)\n", - dev->name, link->open); + printk(KERN_DEBUG + "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n", + dev->name, dev->state, link->open); #endif - } else { - netif_stop_queue (dev); - - lp->reconfig_82593 = FALSE; - wv_82593_config (dev); - netif_wake_queue (dev); - } -} - -#ifdef OLDIES -/*------------------------------------------------------------------*/ -/* - * Dumps the current i82593 receive buffer to the console. - */ -static void wavelan_dump(device *dev) -{ - ioaddr_t base = dev->base_addr; - int i, c; - - /* disable receiver so we can use channel 1 */ - outb(OP0_RCV_DISABLE, LCCR(base)); - - /* reset receive DMA pointer */ - hacr_write_slow(base, HACR_PWR_STAT | HACR_RX_DMA_RESET); - hacr_write(base, HACR_DEFAULT); - - /* dump into receive buffer */ - wv_82593_cmd(dev, "wavelan_dump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE); - - /* set read pointer to start of receive buffer */ - outb(0, PIORL(base)); - outb(0, PIORH(base)); - - printk(KERN_DEBUG "wavelan_cs: dump:\n"); - printk(KERN_DEBUG " 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); - for(i = 0; i < 73; i++){ - if((i % 16) == 0) { - printk("\n0x%02x:", i); - if (!i) { - printk(" "); - continue; - } } - c = inb(PIOP(base)); - printk("%02x ", c); - } - printk("\n"); - - /* enable the receiver again */ - wv_ru_start(dev); } -#endif /********************* DEBUG & INFO SUBROUTINES *********************/ /* @@ -1171,6 +1179,8 @@ return; } + wv_splhi(lp, &flags); + /* Read the mmc */ mmc_out(base, mmwoff(0, mmw_freeze), 1); mmc_read(base, 0, (u_char *)&m, sizeof(m)); @@ -1181,6 +1191,8 @@ lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; #endif /* WIRELESS_EXT */ + wv_splx(lp, &flags); + printk(KERN_DEBUG "##### wavelan modem status registers: #####\n"); #ifdef DEBUG_SHOW_UNUSED printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", @@ -1265,6 +1277,7 @@ wv_dev_show(device * dev) { printk(KERN_DEBUG "dev:"); + printk(" state=%lX,", dev->state); printk(" trans_start=%ld,", dev->trans_start); printk(" flags=0x%x,", dev->flags); printk("\n"); @@ -1404,7 +1417,7 @@ printk("2430.5"); break; default: - printk("unknown"); + printk("???"); } } @@ -1719,7 +1732,7 @@ memcmp(dac, dac_verify, 2 * 2)) { #ifdef DEBUG_IOCTL_ERROR - printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n"); + printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n"); #endif return -EOPNOTSUPP; } @@ -1892,7 +1905,7 @@ #endif /* Disable interrupts & save flags */ - spin_lock_irqsave (&lp->lock, flags); + wv_splhi(lp, &flags); /* Look what is the request */ switch(cmd) @@ -1968,7 +1981,7 @@ case SIOCGIWFREQ: /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) - * (does it work for everybody XXX - especially old cards...) */ + * (does it work for everybody ??? - especially old cards...) */ if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { @@ -2239,15 +2252,17 @@ { struct iw_range range; - /* Set the length (very important for backward compatibility) */ - wrq->u.data.length = sizeof(struct iw_range); + /* Set the length (very important for backward compatibility) */ + wrq->u.data.length = sizeof(struct iw_range); - /* Set all the info we don't care or don't know about to zero */ - memset(&range, 0, sizeof(range)); + /* Set all the info we don't care or don't know about to zero */ + memset(&range, 0, sizeof(range)); - /* Set the Wireless Extension versions */ - range.we_version_compiled = WIRELESS_EXT; - range.we_version_source = 9; /* Nothing for us in v10 and v11 */ +#if WIRELESS_EXT > 10 + /* Set the Wireless Extension versions */ + range.we_version_compiled = WIRELESS_EXT; + range.we_version_source = 9; /* Nothing for us in v10 and v11 */ +#endif /* WIRELESS_EXT > 10 */ /* Set information in the range struct */ range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ @@ -2517,7 +2532,7 @@ } /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore (&lp->lock, flags); + wv_splx(lp, &flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); @@ -2543,11 +2558,8 @@ printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); #endif - if (lp == NULL) /* XXX will this ever occur? */ - return NULL; - /* Disable interrupts & save flags */ - spin_lock_irqsave (&lp->lock, flags); + wv_splhi(lp, &flags); wstats = &lp->wstats; @@ -2573,7 +2585,7 @@ wstats->discard.misc = 0L; /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore (&lp->lock, flags); + wv_splx(lp, &flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); @@ -2692,12 +2704,6 @@ skb->protocol = eth_type_trans(skb, dev); #ifdef DEBUG_RX_INFO - /* Another glitch : Due to the way the GET_PACKET macro is written, - * we are not sure to have the same thing in skb->data. On the other - * hand, skb->mac.raw is not defined everywhere... - * For versions between 1.2.13 and those where skb->mac.raw appear, - * I don't have a clue... - */ wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read"); #endif /* DEBUG_RX_INFO */ @@ -2731,9 +2737,7 @@ wl_roam_gather(dev, skb->data, stats); #endif /* WAVELAN_ROAMING */ - /* Spying stuff */ #ifdef WIRELESS_SPY - /* Same as above */ wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats); #endif /* WIRELESS_SPY */ #ifdef HISTOGRAM @@ -2766,6 +2770,7 @@ * called to do the actual transfer of the card's data including the * ethernet header into a packet consisting of an sk_buff chain. * (called by wavelan_interrupt()) + * Note : the spinlock is already grabbed for us and irq are disabled. */ static inline void wv_packet_rcv(device * dev) @@ -2916,7 +2921,7 @@ printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); #endif - spin_lock_irqsave (&lp->lock, flags); + wv_splhi(lp, &flags); /* Check if we need some padding */ if(clen < ETH_ZLEN) @@ -2946,15 +2951,7 @@ /* Keep stats up to date */ lp->stats.tx_bytes += length; - /* If watchdog not already active, activate it... */ - if (!timer_pending(&lp->watchdog)) - { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } - - spin_unlock_irqrestore (&lp->lock, flags); + wv_splx(lp, &flags); #ifdef DEBUG_TX_INFO wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); @@ -2963,56 +2960,57 @@ #ifdef DEBUG_TX_TRACE printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); #endif - - netif_start_queue (dev); } /*------------------------------------------------------------------*/ /* * This routine is called when we want to send a packet (NET3 callback) - * In this routine, we check if the hardware is ready to accept + * In this routine, we check if the harware is ready to accept * the packet. We also prevent reentrance. Then, we call the function * to send the packet... */ -static int wavelan_packet_xmit (struct sk_buff *skb, - device * dev) +static int +wavelan_packet_xmit(struct sk_buff * skb, + device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local * lp = (net_local *)dev->priv; + unsigned long flags; #ifdef DEBUG_TX_TRACE - printk (KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, - (unsigned) skb); + printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, + (unsigned) skb); #endif - /* - * For ethernet, fill in the header. - */ + /* + * Block a timer-based transmit from overlapping a previous transmit. + * In other words, prevent reentering this routine. + */ + netif_stop_queue(dev); - netif_stop_queue (dev); + /* If somebody has asked to reconfigure the controller, + * we can do it now */ + if(lp->reconfig_82593) + { + wv_splhi(lp, &flags); /* Disable interrupts */ + wv_82593_config(dev); + wv_splx(lp, &flags); /* Re-enable interrupts */ + /* Note : the configure procedure was totally synchronous, + * so the Tx buffer is now free */ + } - /* - * Block a timer-based transmit from overlapping a previous transmit. - * In other words, prevent reentering this routine. - */ - if (1) { - /* If somebody has asked to reconfigure the controller, we can do it now */ - if (lp->reconfig_82593) { - lp->reconfig_82593 = FALSE; - wv_82593_config (dev); - } #ifdef DEBUG_TX_ERROR - if (skb->next) - printk (KERN_INFO "skb has next\n"); + if (skb->next) + printk(KERN_INFO "skb has next\n"); #endif - wv_packet_write (dev, skb->data, skb->len); - } - dev_kfree_skb (skb); + wv_packet_write(dev, skb->data, skb->len); + + dev_kfree_skb(skb); #ifdef DEBUG_TX_TRACE - printk (KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); + printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); #endif - return (0); + return(0); } /********************** HARDWARE CONFIGURATION **********************/ @@ -3165,7 +3163,7 @@ */ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) - * (does it work for everybody XXX - especially old cards...) */ + * (does it work for everybody ??? - especially old cards...) */ /* Note : WFREQSEL verify that it is able to read from EEprom * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID * is 0xA (Xilinx version) or 0xB (Ariadne version). @@ -3223,7 +3221,7 @@ wv_ru_stop(device * dev) { ioaddr_t base = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local * lp = (net_local *) dev->priv; unsigned long flags; int status; int spin; @@ -3232,35 +3230,35 @@ printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name); #endif + wv_splhi(lp, &flags); + /* First, send the LAN controller a stop receive command */ wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv", OP0_STOP_RCV, SR0_NO_RESULT); /* Then, spin until the receive unit goes idle */ - spin = 0; + spin = 300; do { udelay(10); - spin_lock_irqsave (&lp->lock, flags); outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); status = inb(LCSR(base)); - spin_unlock_irqrestore (&lp->lock, flags); } - while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300)); + while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0)); /* Now, spin until the chip finishes executing its current command */ do { udelay(10); - spin_lock_irqsave (&lp->lock, flags); outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); status = inb(LCSR(base)); - spin_unlock_irqrestore (&lp->lock, flags); } - while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300)); + while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); + + wv_splx(lp, &flags); /* If there was a problem */ - if(spin > 300) + if(spin <= 0) { #ifdef DEBUG_CONFIG_ERROR printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n", @@ -3287,6 +3285,7 @@ { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; + unsigned long flags; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); @@ -3300,6 +3299,8 @@ if(!wv_ru_stop(dev)) return FALSE; + wv_splhi(lp, &flags); + /* Now we know that no command is being executed. */ /* Set the receive frame pointer and stop pointer */ @@ -3309,8 +3310,17 @@ /* Reset ring management. This sets the receive frame pointer to 1 */ outb(OP1_RESET_RING_MNGMT, LCCR(base)); +#if 0 + /* XXX the i82593 manual page 6-4 seems to indicate that the stop register + should be set as below */ + /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/ +#elif 0 + /* but I set it 0 instead */ + lp->stop = 0; +#else /* but I set it to 3 bytes per packet less than 8K */ lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; +#endif outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); outb(OP1_INT_ENABLE, LCCR(base)); outb(OP1_SWIT_TO_PORT_0, LCCR(base)); @@ -3326,17 +3336,15 @@ #ifdef DEBUG_I82593_SHOW { int status; - unsigned long flags; - int i = 0; + int opri; + int spin = 10000; /* spin until the chip starts receiving */ do { - spin_lock_irqsave (&lp->lock, flags); outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); status = inb(LCSR(base)); - spin_unlock_irqrestore (&lp->lock, flags); - if(i++ > 10000) + if(spin-- <= 0) break; } while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) && @@ -3345,6 +3353,9 @@ (status & SR3_RCV_STATE_MASK), i); } #endif + + wv_splx(lp, &flags); + #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); #endif @@ -3363,6 +3374,7 @@ ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; struct i82593_conf_block cfblk; + int ret = TRUE; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name); @@ -3457,7 +3469,7 @@ hacr_write(base, HACR_DEFAULT); if(!wv_82593_cmd(dev, "wv_82593_config(): configure", OP0_CONFIGURE, SR0_CONFIGURE_DONE)) - return(FALSE); + ret = FALSE; /* Initialize adapter's ethernet MAC address */ outb(TX_BASE & 0xff, PIORL(base)); @@ -3471,7 +3483,7 @@ hacr_write(base, HACR_DEFAULT); if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup", OP0_IA_SETUP, SR0_IA_SETUP_DONE)) - return(FALSE); + ret = FALSE; #ifdef WAVELAN_ROAMING /* If roaming is enabled, join the "Beacon Request" multicast group... */ @@ -3508,14 +3520,17 @@ hacr_write(base, HACR_DEFAULT); if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup", OP0_MC_SETUP, SR0_MC_SETUP_DONE)) - return(FALSE); + ret = FALSE; lp->mc_count = dev->mc_count; /* remember to avoid repeated reset */ } + /* Job done, clear the flag */ + lp->reconfig_82593 = FALSE; + #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name); #endif - return(TRUE); + return(ret); } /*------------------------------------------------------------------*/ @@ -3594,6 +3609,8 @@ { net_local * lp = (net_local *) dev->priv; ioaddr_t base = dev->base_addr; + unsigned long flags; + int ret = FALSE; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name); @@ -3612,50 +3629,78 @@ if(wv_pcmcia_reset(dev) == FALSE) return FALSE; - /* Power UP the module + reset the modem + reset host adapter - * (in fact, reset DMA channels) */ - hacr_write_slow(base, HACR_RESET); - hacr_write(base, HACR_DEFAULT); + /* Disable interrupts */ + wv_splhi(lp, &flags); - /* Check if the module has been powered up... */ - if(hasr_read(base) & HASR_NO_CLK) + /* Disguised goto ;-) */ + do { + /* Power UP the module + reset the modem + reset host adapter + * (in fact, reset DMA channels) */ + hacr_write_slow(base, HACR_RESET); + hacr_write(base, HACR_DEFAULT); + + /* Check if the module has been powered up... */ + if(hasr_read(base) & HASR_NO_CLK) + { #ifdef DEBUG_CONFIG_ERRORS - printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n", - dev->name); + printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n", + dev->name); #endif - return FALSE; - } + break; + } - /* initialize the modem */ - if(wv_mmc_init(dev) == FALSE) - return FALSE; + /* initialize the modem */ + if(wv_mmc_init(dev) == FALSE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n", + dev->name); +#endif + break; + } - /* reset the LAN controller (i82593) */ - outb(OP0_RESET, LCCR(base)); - mdelay(1); /* A bit crude ! */ - - /* Initialize the LAN controller */ - if((wv_82593_config(dev) == FALSE) || - (wv_diag(dev) == FALSE)) - { + /* reset the LAN controller (i82593) */ + outb(OP0_RESET, LCCR(base)); + mdelay(1); /* A bit crude ! */ + + /* Initialize the LAN controller */ + if(wv_82593_config(dev) == FALSE) + { #ifdef DEBUG_CONFIG_ERRORS - printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", dev->name); + printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", + dev->name); #endif - return FALSE; - } + break; + } - /* - * insert code for loopback test here - */ + /* Diagnostic */ + if(wv_diag(dev) == FALSE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n", + dev->name); +#endif + break; + } - /* The device is now configured */ - lp->configured = 1; + /* + * insert code for loopback test here + */ + + /* The device is now configured */ + lp->configured = 1; + ret = TRUE; + } + while(0); + + /* Re-enable interrupts */ + wv_splx(lp, &flags); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name); #endif - return TRUE; + return(ret); } /*------------------------------------------------------------------*/ @@ -3675,10 +3720,6 @@ printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name); #endif - /* If watchdog was activated, kill it ! */ - if (timer_pending(&lp->watchdog)) - del_timer(&lp->watchdog); - lp->nresets++; lp->configured = 0; @@ -3786,13 +3827,13 @@ } /* - * Allocate a 4K memory window. Note that the dev_link_t + * Allocate a small memory window. Note that the dev_link_t * structure provides space for one window handle -- if your * device needs several windows, you'll need to keep track of * the handles in your private data structure, link->priv. */ req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; - req.Base = 0; req.Size = 0x1000; + req.Base = req.Size = 0; req.AccessSpeed = mem_speed; link->win = (window_handle_t)link->handle; i = CardServices(RequestWindow, &link->win, &req); @@ -3803,7 +3844,7 @@ } dev->rmem_start = dev->mem_start = - (u_long)ioremap(req.Base, 0x1000); + (u_long)ioremap(req.Base, req.Size); dev->rmem_end = dev->mem_end = dev->mem_start + req.Size; mem.CardOffset = 0; mem.Page = 0; @@ -3817,7 +3858,7 @@ /* Feed device with this info... */ dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - netif_start_queue (dev); + netif_start_queue(dev); #ifdef DEBUG_CONFIG_INFO printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n", @@ -3843,7 +3884,7 @@ return FALSE; } - /* XXX Could you explain me this, Dave ? */ + strcpy(((net_local *) dev->priv)->node.dev_name, dev->name); link->dev = &((net_local *) dev->priv)->node; #ifdef DEBUG_CONFIG_TRACE @@ -3887,7 +3928,7 @@ CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); - link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG); + link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name); @@ -3896,7 +3937,7 @@ /*------------------------------------------------------------------*/ /* - * Sometimes, netwave_detach can't be performed following a call from + * Sometimes, wavelan_detach can't be performed following a call from * cardmgr (device still open, pcmcia_release not done) and the device * is put in a STALE_LINK state and remains in memory. * @@ -3970,7 +4011,19 @@ lp = (net_local *) dev->priv; base = dev->base_addr; - spin_lock (&lp->lock); +#ifdef DEBUG_INTERRUPT_INFO + /* Check state of our spinlock (it should be cleared) */ + if(spin_is_locked(&lp->spinlock)) + printk(KERN_DEBUG + "%s: wavelan_interrupt(): spinlock is already locked !!!\n", + dev->name); +#endif + + /* Prevent reentrancy. We need to do that because we may have + * multiple interrupt handler running concurently. + * It is safe because wv_splhi() disable interrupts before aquiring + * the spinlock. */ + spin_lock(&lp->spinlock); /* Treat all pending interrupts */ while(1) @@ -4015,8 +4068,6 @@ break; } - lp->status = status0; /* Save current status (for commands) */ - /* ----------------- RECEIVING PACKET ----------------- */ /* * When the wavelan signal the reception of a new packet, @@ -4054,22 +4105,6 @@ * Most likely : transmission done */ - /* If we are already waiting elsewhere for the command to complete */ - if(wv_wait_completed) - { -#ifdef DEBUG_INTERRUPT_INFO - printk(KERN_DEBUG "%s: wv_interrupt(): command completed\n", - dev->name); -#endif - - /* Signal command completion */ - wv_wait_completed = 0; - - /* Acknowledge the interrupt */ - outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); - continue; - } - /* If a transmission has been done */ if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE || (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE || @@ -4081,10 +4116,6 @@ dev->name); #endif - /* If watchdog was activated, kill it ! */ - if(timer_pending(&lp->watchdog)) - del_timer(&lp->watchdog); - /* Get transmission status */ tx_status = inb(LCSR(base)); tx_status |= (inb(LCSR(base)) << 8); @@ -4174,7 +4205,7 @@ lp->stats.collisions += (tx_status & TX_NCOL_MASK); lp->stats.tx_packets++; - netif_wake_queue (dev); + netif_wake_queue(dev); outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ } else /* if interrupt = transmit done or retransmit done */ @@ -4185,9 +4216,9 @@ #endif outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ } - } + } /* while(1) */ - spin_unlock_irq (&lp->lock); + spin_unlock(&lp->spinlock); #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); @@ -4196,30 +4227,23 @@ /*------------------------------------------------------------------*/ /* - * Watchdog : when we start a transmission, we set a timer in the - * kernel. If the transmission complete, this timer is disabled. If - * it expire, it try to unlock the hardware. + * Watchdog: when we start a transmission, a timer is set for us in the + * kernel. If the transmission completes, this timer is disabled. If + * the timer expires, we are called and we try to unlock the hardware. * - * Note : this watchdog doesn't work on the same principle as the - * watchdog in the ISA driver. I make it this way because the overhead - * of add_timer() and del_timer() is nothing and that it avoid calling - * the watchdog, saving some CPU... If you want to apply the same - * watchdog to the ISA driver, you should be a bit carefull, because - * of the many transmit buffers... - * This watchdog is also move clever, it try to abort the current - * command before reseting everything... + * Note : This watchdog is move clever than the one in the ISA driver, + * because it try to abort the current command before reseting + * everything... + * On the other hand, it's a bit simpler, because we don't have to + * deal with the multiple Tx buffers... */ static void -wavelan_watchdog(u_long a) +wavelan_watchdog(device * dev) { - device * dev; - net_local * lp; - ioaddr_t base; - int spin; - - dev = (device *) a; - base = dev->base_addr; - lp = (net_local *) dev->priv; + net_local * lp = (net_local *) dev->priv; + ioaddr_t base = dev->base_addr; + unsigned long flags; + int aborted = FALSE; #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); @@ -4230,21 +4254,21 @@ dev->name); #endif - /* We are waiting for command completion */ - wv_wait_completed = TRUE; + wv_splhi(lp, &flags); /* Ask to abort the current command */ outb(OP0_ABORT, LCCR(base)); - /* Busy wait while the LAN controller executes the command. - * Note : wv_wait_completed should be volatile */ - spin = 0; - while(wv_wait_completed && (spin++ < 250)) - udelay(10); - - /* If the interrupt handler hasn't be called or invalid status */ - if((wv_wait_completed) || - ((lp->status & SR0_EVENT_MASK) != SR0_EXECUTION_ABORTED)) + /* Wait for the end of the command (a bit hackish) */ + if(wv_82593_cmd(dev, "wavelan_watchdog(): abort", + OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED)) + aborted = TRUE; + + /* Release spinlock here so that wv_hw_reset() can grab it */ + wv_splx(lp, &flags); + + /* Check if we were successful in aborting it */ + if(!aborted) { /* It seem that it wasn't enough */ #ifdef DEBUG_INTERRUPT_ERROR @@ -4269,7 +4293,7 @@ #endif /* We are no more waiting for something... */ - netif_start_queue (dev); + netif_wake_queue(dev); #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); @@ -4322,7 +4346,7 @@ return FALSE; if(!wv_ru_start(dev)) wv_hw_reset(dev); /* If problem : reset */ - netif_start_queue (dev); + netif_start_queue(dev); /* Mark the device as used */ link->open++; @@ -4348,7 +4372,6 @@ wavelan_close(device * dev) { dev_link_t * link = ((net_local *) dev->priv)->link; - net_local * lp = (net_local *)dev->priv; ioaddr_t base = dev->base_addr; #ifdef DEBUG_CALLBACK_TRACE @@ -4356,8 +4379,6 @@ (unsigned int) dev); #endif - netif_stop_queue (dev); - /* If the device isn't open, then nothing to do */ if(!link->open) { @@ -4373,17 +4394,13 @@ wv_roam_cleanup(dev); #endif /* WAVELAN_ROAMING */ - /* If watchdog was activated, kill it ! */ - if(timer_pending(&lp->watchdog)) - del_timer(&lp->watchdog); - link->open--; MOD_DEC_USE_COUNT; /* If the card is still present */ - if (netif_device_present(dev)) + if(netif_running(dev)) { - netif_stop_queue (dev); + netif_stop_queue(dev); /* Stop receiving new messages and wait end of transmission */ wv_ru_stop(dev); @@ -4404,21 +4421,6 @@ /*------------------------------------------------------------------*/ /* - * We never need to do anything when a wavelan device is "initialized" - * by the net software, because we only register already-found cards. - */ -static int -wavelan_init(device * dev) -{ -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "<>wavelan_init()\n"); -#endif - - return(0); -} - -/*------------------------------------------------------------------*/ -/* * wavelan_attach() creates an "instance" of the driver, allocating * local data structures for one device (one interface). The device * is registered with Card Services. @@ -4445,24 +4447,8 @@ /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - if (!link) - return NULL; - - /* Allocate the generic data structure */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (!dev) - goto fail_alloc_dev; - - /* Allocate the wavelan-specific data structure. */ - lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); - if (!lp) - goto fail_alloc_dev_priv; - - memset(lp, 0, sizeof(net_local)); + if (!link) return NULL; memset(link, 0, sizeof(struct dev_link_t)); - memset(dev, 0, sizeof(struct net_device)); - - dev->priv = lp; /* Unused for the Wavelan */ link->release.function = &wv_pcmcia_release; @@ -4492,18 +4478,35 @@ link->next = dev_list; dev_list = link; + /* Allocate the generic data structure */ + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (!dev) { + kfree(link); + return NULL; + } + memset(dev, 0x00, sizeof(struct net_device)); link->priv = link->irq.Instance = dev; + /* Allocate the wavelan-specific data structure. */ + dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); + if (!lp) { + kfree(link); + kfree(dev); + return NULL; + } + memset(lp, 0x00, sizeof(net_local)); + /* Init specific data */ - wv_wait_completed = 0; - lp->status = FALSE; lp->configured = 0; lp->reconfig_82593 = FALSE; lp->nresets = 0; + /* Multicast stuff */ + lp->promiscuous = 0; + lp->allmulticast = 0; + lp->mc_count = 0; - /* Set the watchdog timer */ - lp->watchdog.function = wavelan_watchdog; - lp->watchdog.data = (unsigned long) dev; + /* Init spinlock */ + spin_lock_init(&lp->spinlock); /* back links */ lp->link = link; @@ -4513,7 +4516,6 @@ ether_setup(dev); /* wavelan NET3 callbacks */ - dev->init = &wavelan_init; dev->open = &wavelan_open; dev->stop = &wavelan_close; dev->hard_start_xmit = &wavelan_packet_xmit; @@ -4523,14 +4525,16 @@ dev->set_mac_address = &wavelan_set_mac_address; #endif /* SET_MAC_ADDRESS */ + /* Set the watchdog timer */ + dev->tx_timeout = &wavelan_watchdog; + dev->watchdog_timeo = WATCHDOG_JIFFIES; + #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ dev->do_ioctl = wavelan_ioctl; /* wireless extensions */ dev->get_wireless_stats = wavelan_get_wireless_stats; #endif /* Other specific data */ - strcpy(dev->name, ((net_local *)dev->priv)->node.dev_name); - netif_start_queue (dev); dev->mtu = WAVELAN_MTU; /* Register with Card Services */ @@ -4562,12 +4566,6 @@ #endif return link; - -fail_alloc_dev_priv: - kfree(dev); -fail_alloc_dev: - kfree(link); - return NULL; } /*------------------------------------------------------------------*/ @@ -4698,7 +4696,7 @@ if(link->state & DEV_CONFIG) { /* Accept no more transmissions */ - netif_device_detach(dev); + netif_device_detach(dev); /* Release the card */ wv_pcmcia_release((u_long) link); @@ -4720,7 +4718,7 @@ * obliged to close nicely the wavelan here. David, could you * close the device before suspending them ? And, by the way, * could you, on resume, add a "route add -net ..." after the - * ifconfig up XXX Thanks... */ + * ifconfig up ??? Thanks... */ /* Stop receiving new messages and wait end of transmission */ wv_ru_stop(dev); @@ -4735,8 +4733,7 @@ if(link->state & DEV_CONFIG) { if(link->open) - netif_device_detach(dev); - + netif_device_detach(dev); CardServices(ReleaseConfiguration, link->handle); } break; @@ -4748,7 +4745,7 @@ if(link->state & DEV_CONFIG) { CardServices(RequestConfiguration, link->handle, &link->conf); - if(link->open) /* If RESET -> True, If RESUME -> False XXX */ + if(link->open) /* If RESET -> True, If RESUME -> False ??? */ { wv_hw_reset(dev); netif_device_attach(dev); @@ -4838,4 +4835,3 @@ module_init(init_wavelan_cs); module_exit(exit_wavelan_cs); -MODULE_LICENSE("Dual BSD/GPL"); diff -urN linux-2.5.3-pre1/drivers/net/pcmcia/wavelan_cs.h linux/drivers/net/pcmcia/wavelan_cs.h --- linux-2.5.3-pre1/drivers/net/pcmcia/wavelan_cs.h Fri Oct 12 14:21:18 2001 +++ linux/drivers/net/pcmcia/wavelan_cs.h Sat Jan 19 16:58:39 2002 @@ -34,6 +34,25 @@ * I try to maintain a web page with the Wireless LAN Howto at : * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html * + * SMP + * --- + * We now are SMP compliant (I eventually fixed the remaining bugs). + * The driver has been tested on a dual P6-150 and survived my usual + * set of torture tests. + * Anyway, I spent enough time chasing interrupt re-entrancy during + * errors or reconfigure, and I designed the locked/unlocked sections + * of the driver with great care, and with the recent addition of + * the spinlock (thanks to the new API), we should be quite close to + * the truth. + * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), + * but better safe than sorry (especially at 2 Mb/s ;-). + * + * I have also looked into disabling only our interrupt on the card + * (via HACR) instead of all interrupts in the processor (via cli), + * so that other driver are not impacted, and it look like it's + * possible, but it's very tricky to do right (full of races). As + * the gain would be mostly for SMP systems, it can wait... + * * Debugging and options * --------------------- * You will find below a set of '#define" allowing a very fine control @@ -122,7 +141,7 @@ * Yunzhou Li finished is work. * Joe Finney patched the driver to start * correctly 2.00 cards (2.4 GHz with frequency selection). - * David Hinds integrated the whole in his + * David Hinds integrated the whole in his * Pcmcia package (+ bug corrections). * * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some @@ -158,8 +177,8 @@ * * This software was originally developed under Linux 1.2.3 * (Slackware 2.0 distribution). - * And then under Linux 2.0.x (Debian 1.1 - pcmcia 2.8.18-23) with - * HP OmniBook 4000 & 5500. + * And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+) + * with an HP OmniBook 4000 and then a 5500. * * It is based on other device drivers and information either written * or supplied by: @@ -174,7 +193,7 @@ * Matthew Geier (matthew@cs.su.oz.au), * Remo di Giovanni (remo@cs.su.oz.au), * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), - * David Hinds , + * David Hinds , * Jan Hoogendoorn (c/o marteijn@lucent.com), * Bruce Janson , * Anthony D. Joseph , @@ -349,6 +368,32 @@ * - Fix check for root permission (break instead of exit) * - New nwid & encoding setting (Wireless Extension 9) * + * Changes made for release in 3.1.12 : + * ---------------------------------- + * - reworked wv_82593_cmd to avoid using the IRQ handler and doing + * ugly things with interrupts. + * - Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog + * - Update to new network API (softnet - 2.3.43) : + * o replace dev->tbusy (David + me) + * o replace dev->tstart (David + me) + * o remove dev->interrupt (David) + * o add SMP locking via spinlock in splxx (me) + * o add spinlock in interrupt handler (me) + * o use kernel watchdog instead of ours (me) + * o verify that all the changes make sense and work (me) + * - Re-sync kernel/pcmcia versions (not much actually) + * - A few other cleanups (David & me)... + * + * Changes made for release in 3.1.22 : + * ---------------------------------- + * - Check that SMP works, remove annoying log message + * + * Changes made for release in 3.1.24 : + * ---------------------------------- + * - Fix unfrequent card lockup when watchdog was reseting the hardware : + * o control first busy loop in wv_82593_cmd() + * o Extend spinlock protection in wv_hw_config() + * * Wishes & dreams: * ---------------- * - Cleanup and integrate the roaming code @@ -368,6 +413,7 @@ #include #include #include +#include #include #include #include @@ -384,7 +430,7 @@ #ifdef CONFIG_NET_PCMCIA_RADIO #include /* Wireless extensions */ -#endif /* CONFIG_NET_PCMCIA_RADIO */ +#endif /* Pcmcia headers that we need */ #include @@ -437,7 +483,7 @@ #undef DEBUG_RX_INFO /* Header of the transmitted packet */ #undef DEBUG_RX_FAIL /* Normal failure conditions */ #define DEBUG_RX_ERROR /* Unexpected conditions */ -#undef DEBUG_PACKET_DUMP /* Dump packet on the screen */ +#undef DEBUG_PACKET_DUMP 32 /* Dump packet on the screen */ #undef DEBUG_IOCTL_TRACE /* Misc call by Linux */ #undef DEBUG_IOCTL_INFO /* Various debug info */ #define DEBUG_IOCTL_ERROR /* What's going wrong */ @@ -452,7 +498,7 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan_cs.c : v21 (wireless extensions) 18/10/99\n"; +static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n"; #endif /* Watchdog temporisation */ @@ -557,9 +603,9 @@ */ struct net_local { - spinlock_t lock; dev_node_t node; /* ???? What is this stuff ???? */ device * dev; /* Reverse link... */ + spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ dev_link_t * link; /* pcmcia structure */ en_stats stats; /* Ethernet interface statistics */ int nresets; /* Number of hw resets */ @@ -568,9 +614,7 @@ u_char promiscuous; /* Promiscuous mode */ u_char allmulticast; /* All Multicast mode */ int mc_count; /* Number of multicast addresses */ - timer_list watchdog; /* To avoid blocking state */ - u_char status; /* Current i82593 status */ int stop; /* Current i82593 Stop Hit Register */ int rfp; /* Last DMA machine receive pointer */ int overrunning; /* Receiver overrun flag */ @@ -617,8 +661,14 @@ #endif /* WAVELAN_ROAMING */ /* ----------------------- MISC SUBROUTINES ------------------------ */ +static inline void + wv_splhi(net_local *, /* Disable interrupts */ + unsigned long *); /* flags */ +static inline void + wv_splx(net_local *, /* ReEnable interrupts */ + unsigned long *); /* flags */ static void - cs_error(client_handle_t, /* Report error to cardmgr */ + cs_error(client_handle_t, /* Report error to cardmgr */ int, int); /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ @@ -722,16 +772,15 @@ wv_flush_stale_links(void); /* "detach" all possible devices */ /* ---------------------- INTERRUPT HANDLING ---------------------- */ static void -wavelan_interrupt(int, /* Interrupt handler */ - void *, - struct pt_regs *); + wavelan_interrupt(int, /* Interrupt handler */ + void *, + struct pt_regs *); static void - wavelan_watchdog(u_long); /* Transmission watchdog */ + wavelan_watchdog(device *); /* Transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ static int wavelan_open(device *), /* Open the device */ - wavelan_close(device *), /* Close the device */ - wavelan_init(device *); /* Do nothing */ + wavelan_close(device *); /* Close the device */ static dev_link_t * wavelan_attach(void); /* Create a new device */ static void @@ -744,11 +793,7 @@ /**************************** VARIABLES ****************************/ static dev_info_t dev_info = "wavelan_cs"; -static dev_link_t *dev_list; /* Linked list of devices */ - -/* WARNING : the following variable MUST be volatile - * It is used by wv_82593_cmd to syncronise with wavelan_interrupt */ -static volatile int wv_wait_completed; +static dev_link_t *dev_list = NULL; /* Linked list of devices */ /* * Parameters that can be set with 'insmod' @@ -761,7 +806,7 @@ static int irq_list[4] = { -1 }; /* Shared memory speed, in ns */ -static int mem_speed; +static int mem_speed = 0; /* New module interface */ MODULE_PARM(irq_mask, "i"); @@ -770,9 +815,11 @@ #ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ /* Enable roaming mode ? No ! Please keep this to 0 */ -static int do_roaming; +static int do_roaming = 0; MODULE_PARM(do_roaming, "i"); #endif /* WAVELAN_ROAMING */ + +MODULE_LICENSE("GPL"); #endif /* WAVELAN_CS_H */ diff -urN linux-2.5.3-pre1/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog --- linux-2.5.3-pre1/drivers/parport/ChangeLog Sat Jan 19 16:58:37 2002 +++ linux/drivers/parport/ChangeLog Sat Jan 19 16:58:39 2002 @@ -1,3 +1,23 @@ +2001-12-07 Tim Waugh + + * ieee1284_ops.c (parport_ieee1284_epp_write_addr, + parport_ieee1284_epp_read_addr): Actually do something useful. + +2001-12-07 Tim Waugh + + * parport_pc.c (dmaval): Don't use DMA by default. It seems to be + too buggy at the moment. Use 'dma=auto' to restore the previous + behaviour. + +2001-12-03 Rich Liu + + * parport_pc.c (sio_ite_8872_probe): ITE8873 is a single-port + serial board, not a serial+parallel. + +2001-11-30 Niels Kristian Bech Jensen + + * parport_pc.c: Fix compiler warning. + 2001-12-06 Tim Waugh * ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off diff -urN linux-2.5.3-pre1/drivers/parport/ieee1284.c linux/drivers/parport/ieee1284.c --- linux-2.5.3-pre1/drivers/parport/ieee1284.c Thu Oct 25 00:07:39 2001 +++ linux/drivers/parport/ieee1284.c Sat Jan 19 16:58:39 2002 @@ -128,7 +128,7 @@ return 0; if (signal_pending (current)) return -EINTR; - if (current->need_resched) + if (need_resched()) break; if (i >= 2) udelay (5); diff -urN linux-2.5.3-pre1/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c --- linux-2.5.3-pre1/drivers/parport/ieee1284_ops.c Sat Jan 19 16:58:37 2002 +++ linux/drivers/parport/ieee1284_ops.c Sat Jan 19 16:58:39 2002 @@ -136,7 +136,7 @@ /* Let another process run if it needs to. */ if (time_before (jiffies, expire)) if (!parport_yield_blocking (dev) - && current->need_resched) + && need_resched()) schedule (); } stop: @@ -824,35 +824,40 @@ const void *buffer, size_t len, int flags) { - /* This is untested */ unsigned char *bp = (unsigned char *) buffer; size_t ret = 0; + /* set EPP idle state (just to make sure) with strobe low */ parport_frob_control (port, PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT | - PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_INIT, PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_SELECT); + PARPORT_CONTROL_INIT); port->ops->data_forward (port); for (; len > 0; len--, bp++) { - /* Write data and assert nAStrb. */ + /* Event 56: Write data and set nAStrb low. */ parport_write_data (port, *bp); parport_frob_control (port, PARPORT_CONTROL_SELECT, PARPORT_CONTROL_SELECT); - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY, 10)) + /* Event 58: wait for busy (nWait) to go high */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10)) break; + /* Event 59: set nAStrb high */ parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5)) + /* Event 60: wait for busy (nWait) to go low */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY, 5)) break; ret++; } + /* Event 61: set strobe (nWrite) high */ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); return ret; @@ -863,28 +868,36 @@ void *buffer, size_t len, int flags) { - /* This is untested. */ unsigned char *bp = (unsigned char *) buffer; unsigned ret = 0; + /* Set EPP idle state (just to make sure) with strobe high */ parport_frob_control (port, PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_AUTOFD, 0); + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); port->ops->data_reverse (port); for (; len > 0; len--, bp++) { - parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); + /* Event 64: set nSelectIn (nAStrb) low */ + parport_frob_control (port, PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_SELECT); - /* Event 58 */ - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY, 10)) + /* Event 58: wait for Busy to go high */ + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) { break; + } *bp = parport_read_data (port); + /* Event 59: set nSelectIn (nAStrb) high */ parport_frob_control (port, PARPORT_CONTROL_SELECT, PARPORT_CONTROL_SELECT); - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5)) + /* Event 60: wait for Busy to go low */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY, 5)) break; ret++; diff -urN linux-2.5.3-pre1/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- linux-2.5.3-pre1/drivers/parport/parport_pc.c Mon Nov 12 09:44:58 2001 +++ linux/drivers/parport/parport_pc.c Sat Jan 19 16:58:39 2002 @@ -91,7 +91,9 @@ } superios[NR_SUPERIOS] __devinitdata = { {0,},}; static int user_specified __devinitdata = 0; +#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO) static int verbose_probing; +#endif static int registered_parport; /* frob_control, but for ECR */ @@ -596,7 +598,7 @@ unsigned char ecrval = inb (ECONTROL (port)); int i = 0; - if (current->need_resched && time_before (jiffies, expire)) + if (need_resched() && time_before (jiffies, expire)) /* Can't yield the port. */ schedule (); @@ -622,7 +624,7 @@ } ecrval = inb (ECONTROL (port)); if (!(ecrval & (1<<2))) { - if (current->need_resched && + if (need_resched() && time_before (jiffies, expire)) schedule (); @@ -746,8 +748,7 @@ } /* Is serviceIntr set? */ if (!(inb (ECONTROL (port)) & (1<<2))) { - if (current->need_resched) - schedule (); + cond_resched(); goto false_alarm; } @@ -758,9 +759,7 @@ count = get_dma_residue(port->dma); release_dma_lock(dmaflag); - if (current->need_resched) - /* Can't yield the port. */ - schedule (); + cond_resched(); /* Can't yield the port. */ /* Anyone else waiting for the port? */ if (port->waithead) { @@ -1093,7 +1092,7 @@ long int expire = jiffies + port->cad->timeout; unsigned char ecrval = inb (ECONTROL (port)); - if (current->need_resched && time_before (jiffies, expire)) + if (need_resched() && time_before (jiffies, expire)) /* Can't yield the port. */ schedule (); @@ -1130,7 +1129,7 @@ } ecrval = inb (ECONTROL (port)); if (!(ecrval & (1<<2))) { - if (current->need_resched && + if (need_resched() && time_before (jiffies, expire)) { schedule (); } @@ -1780,6 +1779,7 @@ return ok; } +#ifdef CONFIG_PARPORT_PC_FIFO static int __devinit parport_ECP_supported(struct parport *pb) { int i; @@ -1905,6 +1905,7 @@ return 1; } +#endif static int __devinit parport_ECPPS2_supported(struct parport *pb) { @@ -2004,7 +2005,9 @@ /* Don't bother probing for modes we know we won't use. */ static int __devinit parport_PS2_supported(struct parport *pb) { return 0; } +#ifdef CONFIG_PARPORT_PC_FIFO static int __devinit parport_ECP_supported(struct parport *pb) { return 0; } +#endif static int __devinit parport_EPP_supported(struct parport *pb) { return 0; } static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;} static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;} @@ -2453,9 +2456,8 @@ ite8872set = 0x64e00000; break; case 0x6: - printk (KERN_INFO "parport_pc: ITE8873 found (1S1P)\n"); - ite8872set = 0x64a00000; - break; + printk (KERN_INFO "parport_pc: ITE8873 found (1S)\n"); + return 0; case 0x8: DPRINTK (KERN_DEBUG "parport_pc: ITE8874 found (2S)\n"); return 0; @@ -3007,7 +3009,7 @@ static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO }; -static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO }; +static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE }; static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY }; static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, }; static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, }; @@ -3024,8 +3026,10 @@ MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); MODULE_PARM_DESC(dma, "DMA channel"); MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); -MODULE_PARM(verbose_probing, "i"); +#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO) MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation"); +MODULE_PARM(verbose_probing, "i"); +#endif int init_module(void) { diff -urN linux-2.5.3-pre1/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- linux-2.5.3-pre1/drivers/scsi/advansys.c Thu Jan 10 10:15:38 2002 +++ linux/drivers/scsi/advansys.c Sat Jan 19 16:58:39 2002 @@ -1,4 +1,4 @@ -#define ASC_VERSION "3.3G" /* AdvanSys Driver Version */ +#define ASC_VERSION "3.3GG" /* AdvanSys Driver Version */ /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters @@ -670,6 +670,9 @@ 1. Return an error from narrow boards if passed a 16 byte CDB. The wide board can already handle 16 byte CDBs. + 3.3GG (01/02/02): + 1. hacks for lk 2.5 series (D. Gilbert) + I. Known Problems/Fix List (XXX) 1. Need to add memory mapping workaround. Test the memory mapping. @@ -3610,6 +3613,23 @@ #define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif /* CONFIG_PROC_FS */ +/* + * XXX - Release and acquire the io_request_lock. These macros are needed + * because the 2.4 kernel SCSI mid-level driver holds the 'io_request_lock' + * on entry to SCSI low-level drivers. + * + * These definitions and all code that uses code should be removed when the + * SCSI mid-level driver no longer holds the 'io_request_lock' on entry to + * SCSI low-level driver detect, queuecommand, and reset entrypoints. + * + * The interrupt flags values doesn't matter in the macros because the + * SCSI mid-level will save and restore the flags values before and after + * calling advansys_detect, advansys_queuecommand, and advansys_reset where + * these macros are used. We do want interrupts enabled after the lock is + * released so an explicit sti() is done. The driver only needs interrupts + * disabled when it acquires the per board lock. + */ + /* Asc Library return codes */ #define ASC_TRUE 1 #define ASC_FALSE 0 @@ -4054,6 +4074,7 @@ ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */ } eep_config; ulong last_reset; /* Saved last reset time */ + spinlock_t lock; /* Board spinlock */ #ifdef CONFIG_PROC_FS /* /proc/scsi/advansys/[0...] */ char *prtbuf; /* /proc print buffer */ @@ -4206,7 +4227,7 @@ STATIC void advansys_interrupt(int, void *, struct pt_regs *); STATIC void advansys_select_queue_depths(struct Scsi_Host *, Scsi_Device *); -STATIC void asc_scsi_done_list(Scsi_Cmnd *); +STATIC void asc_scsi_done_list(Scsi_Cmnd *, int from_isr); STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *); STATIC int asc_build_req(asc_board_t *, Scsi_Cmnd *); STATIC int adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **); @@ -4799,6 +4820,9 @@ memset(boardp, 0, sizeof(asc_board_t)); boardp->id = asc_board_count - 1; + /* Initialize spinlock. */ + boardp->lock = SPIN_LOCK_UNLOCKED; /* replaced by host_lock dpg */ + /* * Handle both narrow and wide boards. * @@ -5511,7 +5535,7 @@ } } else { ADV_CARR_T *carrp; - int req_cnt; + int req_cnt = 0; adv_req_t *reqp = NULL; int sg_cnt = 0; @@ -5845,7 +5869,9 @@ boardp = ASC_BOARDP(shp); ASC_STATS(shp, queuecommand); - spin_lock_irqsave(&shp->host_lock, flags); + /* host_lock taken by mid-level prior to call but need to protect */ + /* against own ISR */ + spin_lock_irqsave(&boardp->lock, flags); /* * Block new commands while handling a reset or abort request. @@ -5862,7 +5888,7 @@ * handling. */ asc_enqueue(&boardp->done, scp, ASC_BACK); - spin_unlock_irqrestore(&shp->host_lock, flags); + spin_unlock_irqrestore(&boardp->lock, flags); return 0; } @@ -5902,11 +5928,11 @@ default: done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL); /* Interrupts could be enabled here. */ - asc_scsi_done_list(done_scp); + asc_scsi_done_list(done_scp, 0); break; } + spin_unlock_irqrestore(&boardp->lock, flags); - spin_unlock_irqrestore(&shp->host_lock, flags); return 0; } @@ -5952,13 +5978,13 @@ /* * Check for re-entrancy. */ - spin_lock_irqsave(&shp->host_lock, flags); + spin_lock_irqsave(&boardp->lock, flags); if (boardp->flags & ASC_HOST_IN_RESET) { - spin_unlock_irqrestore(&shp->host_lock, flags); + spin_unlock_irqrestore(&boardp->lock, flags); return FAILED; } boardp->flags |= ASC_HOST_IN_RESET; - spin_unlock_irqrestore(&shp->host_lock, flags); + spin_unlock_irqrestore(&boardp->lock, flags); if (ASC_NARROW_BOARD(boardp)) { /* @@ -5989,11 +6015,7 @@ } ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n"); - - /* - * Acquire the board lock. - */ - spin_lock_irqsave(&shp->host_lock, flags); + spin_lock_irqsave(&boardp->lock, flags); } else { /* @@ -6020,14 +6042,9 @@ ret = FAILED; break; } - /* - * Acquire the board lock and ensure all requests completed by the - * microcode have been processed by calling AdvISR(). - */ - spin_lock_irqsave(&shp->host_lock, flags); + spin_lock_irqsave(&boardp->lock, flags); (void) AdvISR(adv_dvc_varp); } - /* Board lock is held. */ /* @@ -6088,15 +6105,13 @@ /* Clear reset flag. */ boardp->flags &= ~ASC_HOST_IN_RESET; - - /* Release the board. */ - spin_unlock_irqrestore(&shp->host_lock, flags); + spin_unlock_irqrestore(&boardp->lock, flags); /* * Complete all the 'done_scp' requests. */ if (done_scp != NULL) { - asc_scsi_done_list(done_scp); + asc_scsi_done_list(done_scp, 0); } ASC_DBG1(1, "advansys_reset: ret %d\n", ret); @@ -6259,6 +6274,7 @@ asc_board_t *boardp; Scsi_Cmnd *done_scp = NULL, *last_scp = NULL; Scsi_Cmnd *new_last_scp; + struct Scsi_Host *shp; ASC_DBG(1, "advansys_interrupt: begin\n"); @@ -6267,17 +6283,17 @@ * AscISR() will call asc_isr_callback(). */ for (i = 0; i < asc_board_count; i++) { - struct Scsi_Host *shp = asc_host[i]; + shp = asc_host[i]; boardp = ASC_BOARDP(shp); ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n", i, (ulong) boardp); - spin_lock_irqsave(&shp->host_lock, flags); + spin_lock_irqsave(&boardp->lock, flags); if (ASC_NARROW_BOARD(boardp)) { /* * Narrow Board */ - if (AscIsIntPending(asc_host[i]->io_port)) { - ASC_STATS(asc_host[i], interrupt); + if (AscIsIntPending(shp->io_port)) { + ASC_STATS(shp, interrupt); ASC_DBG(1, "advansys_interrupt: before AscISR()\n"); AscISR(&boardp->dvc_var.asc_dvc_var); } @@ -6287,7 +6303,7 @@ */ ASC_DBG(1, "advansys_interrupt: before AdvISR()\n"); if (AdvISR(&boardp->dvc_var.adv_dvc_var)) { - ASC_STATS(asc_host[i], interrupt); + ASC_STATS(shp, interrupt); } } @@ -6327,7 +6343,7 @@ } } } - spin_unlock_irqrestore(&shp->host_lock, flags); + spin_unlock_irqrestore(&boardp->lock, flags); } /* @@ -6336,7 +6352,8 @@ * * Complete all requests on the done list. */ - asc_scsi_done_list(done_scp); + + asc_scsi_done_list(done_scp, 1); ASC_DBG(1, "advansys_interrupt: end\n"); return; @@ -6383,9 +6400,10 @@ * Interrupts can be enabled on entry. */ STATIC void -asc_scsi_done_list(Scsi_Cmnd *scp) +asc_scsi_done_list(Scsi_Cmnd *scp, int from_isr) { Scsi_Cmnd *tscp; + ulong flags = 0; ASC_DBG(2, "asc_scsi_done_list: begin\n"); while (scp != NULL) { @@ -6394,7 +6412,11 @@ REQPNEXT(scp) = NULL; ASC_STATS(scp->host, done); ASC_ASSERT(scp->scsi_done != NULL); + if (from_isr) + spin_lock_irqsave(&scp->host->host_lock, flags); scp->scsi_done(scp); + if (from_isr) + spin_unlock_irqrestore(&scp->host->host_lock, flags); scp = tscp; } ASC_DBG(2, "asc_scsi_done_list: done\n"); @@ -6728,7 +6750,9 @@ slp = (struct scatterlist *) scp->request_buffer; for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) { asc_sg_head.sg_list[sgcnt].addr = - cpu_to_le32(virt_to_bus(slp->address)); + cpu_to_le32(virt_to_bus(slp->address ? + (unsigned char *)slp->address : + (unsigned char *)page_address(slp->page) + slp->offset)); asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length); ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); } @@ -6986,7 +7010,9 @@ for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) { sg_block->sg_list[i].sg_addr = - cpu_to_le32(virt_to_bus(slp->address)); + cpu_to_le32(virt_to_bus(slp->address ? + (unsigned char *)slp->address : + (unsigned char *)page_address(slp->page) + slp->offset)); sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length); ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); diff -urN linux-2.5.3-pre1/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c --- linux-2.5.3-pre1/drivers/scsi/aic7xxx/aic7xxx_linux.c Thu Jan 10 10:15:38 2002 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c Sat Jan 19 16:58:39 2002 @@ -1700,6 +1700,7 @@ cmd->request_buffer, cmd->request_bufflen, scsi_to_pci_dma_dir(cmd->sc_data_direction)); + scb->sg_count = 0; scb->sg_count = ahc_linux_map_seg(ahc, scb, sg, addr, cmd->request_bufflen); diff -urN linux-2.5.3-pre1/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c --- linux-2.5.3-pre1/drivers/scsi/scsi_debug.c Sun Dec 16 12:20:20 2001 +++ linux/drivers/scsi/scsi_debug.c Sat Jan 19 16:58:39 2002 @@ -3,8 +3,19 @@ * * Copyright (C) 1992 Eric Youngdale * Simulate a host adapter with 2 disks attached. Do a lot of checking - * to make sure that we are not getting blocks mixed up, and panic if + * to make sure that we are not getting blocks mixed up, and PANIC if * anything out of the ordinary is seen. + * + * This version is more generic, simulating a variable number of disk + * (or disk like devices) sharing a common amount of RAM (default 8 MB + * but can be set at driver/module load time). + * + * For documentation see http://www.torque.net/sg/sdebug.html + * + * D. Gilbert (dpg) work for MOD device test [20010421] + * dpg, work for devfs large number of disks [20010809] + * dpg, make more generic [20011123] + * dpg, forked for lk 2.5 series [20011216, 20020101] */ #include @@ -18,7 +29,9 @@ #include #include #include +#include #include +#include #include #include @@ -27,201 +40,187 @@ #include "scsi.h" #include "hosts.h" -#include "sd.h" - #include -/* A few options that we want selected */ +#ifndef LINUX_VERSION_CODE +#include +#endif + +static char scsi_debug_version_str[] = "Version: 1.57 (20011216)"; -#define NR_HOSTS_PRESENT 1 -#define NR_FAKE_DISKS 3 -#define N_HEAD 255 -#define N_SECTOR 63 -#define N_CYLINDER 524 +#ifndef SCSI_CMD_READ_16 +#define SCSI_CMD_READ_16 0x88 +#endif +#ifndef SCSI_CMD_WRITE_16 +#define SCSI_CMD_WRITE_16 0x8a +#endif + +/* A few options that we want selected */ +#define DEF_NR_FAKE_DEVS 1 +#define DEF_DEV_SIZE_MB 8 +#define DEF_FAKE_BLK0 0 + +static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS; + +#define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1) +#define N_HEAD 8 +#define N_SECTOR 32 #define DISK_READONLY(TGT) (0) -#define DISK_REMOVEABLE(TGT) (1) -#define DEVICE_TYPE(TGT) (TGT == 2 ? TYPE_TAPE : TYPE_DISK); +#define DISK_REMOVEABLE(TGT) (0) +#define DEVICE_TYPE(TGT) (TYPE_DISK); + +#define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1) + +static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; +#define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024) +#define STORE_ELEM_ORDER 1 +#define STORE_ELEM_SIZE (PAGE_SIZE * (1 << STORE_ELEM_ORDER)) +#define STORE_ELEMENTS ((STORE_SIZE / STORE_ELEM_SIZE) + 1) + +/* default sector size is 512 bytes, 2**9 bytes */ +#define POW2_SECT_SIZE 9 +#define SECT_SIZE (1 << POW2_SECT_SIZE) + +#define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD)) + +static int scsi_debug_fake_blk0 = DEF_FAKE_BLK0; /* Do not attempt to use a timer to simulate a real disk with latency */ /* Only use this in the actual kernel, not in the simulator. */ #define IMMEDIATE -/* Skip some consistency checking. Good for benchmarking */ -#define SPEEDY -/* Read return zeros. Undefine for benchmarking */ -#define CLEAR - -/* Number of real scsi disks that will be detected ahead of time */ -static int NR_REAL = -1; - -#define NR_BLK_DEV 12 -#ifndef MAJOR_NR -#define MAJOR_NR 8 -#endif +#define SDEBUG_SG_ADDRESS + #define START_PARTITION 4 /* Time to wait before completing a command */ #define DISK_SPEED (HZ/10) /* 100ms */ #define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER) -#define SIZE(TGT) (TGT == 2 ? 2248 : 512) +#define SECT_SIZE_PER(TGT) SECT_SIZE +#define SECT_PER_ELEM (STORE_ELEM_SIZE / SECT_SIZE) static int starts[] = {N_SECTOR, N_HEAD * N_SECTOR, /* Single cylinder */ N_HEAD * N_SECTOR * 4, - CAPACITY, 0}; + 0 /* CAPACITY */, 0}; static int npart = 0; -#include "scsi_debug.h" -#ifdef DEBUG -#define DEB(x) x -#else -#define DEB(x) -#endif +typedef struct scsi_debug_store_elem { + unsigned char * p; +} Sd_store_elem; + +static Sd_store_elem * store_arr = 0; + +typedef struct sdebug_dev_info { + Scsi_Device * sdp; + unsigned short host_no; + unsigned short id; + char reset; + char sb_index; +} Sdebug_dev_info; +static Sdebug_dev_info * devInfop; + +static int num_aborts = 0; +static int num_dev_resets = 0; +static int num_bus_resets = 0; +static int num_host_resets = 0; -#ifdef SPEEDY -#define VERIFY1_DEBUG(RW) -#define VERIFY_DEBUG(RW) -#else +static spinlock_t mailbox_lock = SPIN_LOCK_UNLOCKED; +static rwlock_t sdebug_atomic_rw = RW_LOCK_UNLOCKED; -#define VERIFY1_DEBUG(RW) \ - if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");}; \ - start = 0; \ - if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \ - if (bh){ \ - if (bh->b_size != 1024) panic ("Wrong bh size"); \ - if ((bh->b_blocknr << 1) + start != block) \ - { printk("Wrong bh block# %d %d ",bh->b_blocknr, block); \ - panic ("Wrong bh block#"); \ - }; \ - if (bh->b_dev != SCpnt->request.rq_dev) \ - panic ("Bad bh target"); \ - }; - -#define VERIFY_DEBUG(RW) \ - if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");}; \ - start = 0; \ - if ((MINOR(SCpnt->request.rq_dev) & 0xf) > npart) panic ("Bad partition"); \ - if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \ - if (SCpnt->request.cmd != RW) panic ("Wrong operation"); \ - if (SCpnt->request.sector + start != block) panic("Wrong block."); \ - if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks"); \ - if (SCpnt->request.bh){ \ - if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \ - if ((SCpnt->request.bh->b_blocknr << 1) + start != block) \ - { printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block); \ - panic ("Wrong bh block#"); \ - }; \ - if (SCpnt->request.bh->b_dev != SCpnt->request.rq_dev) \ - panic ("Bad bh target");\ - }; -#endif +#include "scsi_debug.h" typedef void (*done_fct_t) (Scsi_Cmnd *); -static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] = -{NULL,}; +static volatile done_fct_t * do_done = 0; struct Scsi_Host * SHpnt = NULL; +static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, + int num, int * errstsp, Sdebug_dev_info * devip); +static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, + int num, int * errstsp, Sdebug_dev_info * devip); static void scsi_debug_send_self_command(struct Scsi_Host * shpnt); static void scsi_debug_intr_handle(unsigned long); +static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp); +static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, + int asc, int asq, int inbandLen); +static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip); -static struct timer_list timeout[SCSI_DEBUG_MAILBOXES]; - -Scsi_Cmnd *SCint[SCSI_DEBUG_MAILBOXES] = -{NULL,}; -static char SCrst[SCSI_DEBUG_MAILBOXES] = -{0,}; +static struct timer_list * timeout = 0; +static Scsi_Cmnd ** SCint = 0; /* * Semaphore used to simulate bus lockups. */ static int scsi_debug_lockup = 0; -static char sense_buffer[128] = -{0,}; +#define NUM_SENSE_BUFFS 4 +#define SENSE_BUFF_LEN 32 +static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN]; -static void scsi_dump(Scsi_Cmnd * SCpnt, int flag) +static int made_block0 = 0; + +static void scsi_debug_mkblock0(unsigned char * buff, int bufflen, + Scsi_Cmnd * SCpnt) { int i; -#if 0 - unsigned char *pnt; -#endif - unsigned int *lpnt; - struct scatterlist *sgpnt = NULL; - printk("use_sg: %d", SCpnt->use_sg); - if (SCpnt->use_sg) { - sgpnt = (struct scatterlist *) SCpnt->buffer; - for (i = 0; i < SCpnt->use_sg; i++) { - printk(":%p %d\n", sgpnt[i].address, sgpnt[i].length); - }; - } else { - printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer, - SCpnt->bufflen); - lpnt = (int *) SCpnt->request.buffer; - if (lpnt) - printk(" (Alt %x) ", lpnt[15]); - }; - lpnt = (unsigned int *) SCpnt; - for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) { - if ((i & 7) == 0) - printk("\n"); - printk("%x ", *lpnt++); - }; - printk("\n"); - if (flag == 0) - return; -#if 0 - printk("\n"); - lpnt = (unsigned int *) sgpnt[0].address; - for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) { - if ((i & 7) == 0) - printk("\n"); - printk("%x ", *lpnt++); - }; - printk("\n"); -#endif + struct partition *p; + + memset(buff, 0, bufflen); + *((unsigned short *) (buff + 510)) = 0xAA55; + p = (struct partition *) (buff + 0x1be); + i = 0; + while (starts[i + 1]) { + int start_cyl, end_cyl; + + start_cyl = starts[i] / N_HEAD / N_SECTOR; + end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR; + p->boot_ind = 0; + + p->head = (i == 0 ? 1 : 0); + p->sector = 1 | ((start_cyl >> 8) << 6); + p->cyl = (start_cyl & 0xff); + + p->end_head = N_HEAD - 1; + p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6); + p->end_cyl = (end_cyl & 0xff); + + p->start_sect = starts[i]; + p->nr_sects = starts[i + 1] - starts[i]; + p->sys_ind = 0x83; /* Linux ext2 partition */ + p++; + i++; + } + if (!npart) + npart = i; + made_block0 = 1; + i = (bufflen > STORE_ELEM_SIZE) ? STORE_ELEM_SIZE : bufflen; + memcpy(store_arr[0].p, buff, i); } int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) { unchar *cmd = (unchar *) SCpnt->cmnd; - struct partition *p; int block; - struct buffer_head *bh = NULL; + int upper_blk; unsigned char *buff; - int nbytes, sgcount; int scsi_debug_errsts; - struct scatterlist *sgpnt; int target = SCpnt->target; int bufflen = SCpnt->request_bufflen; - unsigned long flags; - int i; - sgcount = 0; - sgpnt = NULL; - -#ifdef CONFIG_SMP - /* - * The io_request_lock *must* be held at this point. - */ - if( io_request_lock.lock == 0 ) - { - printk("Warning - io_request_lock is not held in queuecommand\n"); - } -#endif + unsigned long iflags; + int i, num, capac; + Sdebug_dev_info * devip = NULL; + char * sbuff; /* - * If we are being notified of the mid-level reposessing a command due to timeout, - * just return. + * If we are being notified of the mid-level reposessing a command + * due to timeout, just return. */ if (done == NULL) { return 0; } - DEB(if (target >= NR_FAKE_DISKS) { - SCpnt->result = DID_TIME_OUT << 16; done(SCpnt); return 0; - } - ); buff = (unsigned char *) SCpnt->request_buffer; @@ -229,249 +228,201 @@ * If a command comes for the ID of the host itself, just print * a silly message and return. */ - if( target == 7 ) { + if(target == 7) { printk("How do you do!\n"); SCpnt->result = 0; done(SCpnt); return 0; } - if (target >= NR_FAKE_DISKS || SCpnt->lun != 0) { + if ((target > 7) || (SCpnt->lun != 0)) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } - if (SCrst[target] != 0 && !scsi_debug_lockup) { - SCrst[target] = 0; - memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); - SCpnt->sense_buffer[0] = 0x70; - SCpnt->sense_buffer[2] = UNIT_ATTENTION; - SCpnt->result = (CHECK_CONDITION << 1); - done(SCpnt); +#if 0 + printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n", + (int)SCpnt->device->host->host_no, (int)SCpnt->device->id, + SCpnt->device, (int)(unsigned char)*cmd); +#endif + if (NULL == SCpnt->device->hostdata) { + devip = devInfoReg(SCpnt->device); + if (NULL == devip) { + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; + } + SCpnt->device->hostdata = devip; } + devip = SCpnt->device->hostdata; + switch (*cmd) { - case REQUEST_SENSE: + case REQUEST_SENSE: /* mandatory */ SCSI_LOG_LLQUEUE(3, printk("Request sense...\n")); -#ifndef DEBUG - { - int i; - printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen); - for (i = 0; i < 12; i++) - printk("%d ", sense_buffer[i]); - printk("\n"); - }; -#endif - memset(buff, 0, bufflen); - memcpy(buff, sense_buffer, bufflen); - memset(sense_buffer, 0, sizeof(sense_buffer)); + if (devip) { + sbuff = &sense_buffers[(int)devip->sb_index][0]; + devip->sb_index = 0; + } + else + sbuff = &sense_buffers[0][0]; + memcpy(buff, sbuff, (bufflen < SENSE_BUFF_LEN) ? + bufflen : SENSE_BUFF_LEN); + memset(sbuff, 0, SENSE_BUFF_LEN); + sbuff[0] = 0x70; SCpnt->result = 0; done(SCpnt); return 0; case START_STOP: + if (check_reset(SCpnt, devip)) { + done(SCpnt); + return 0; + } SCSI_LOG_LLQUEUE(3, printk("START_STOP\n")); scsi_debug_errsts = 0; break; case ALLOW_MEDIUM_REMOVAL: + if (check_reset(SCpnt, devip)) { + done(SCpnt); + return 0; + } if (cmd[4]) { - SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited...")); + SCSI_LOG_LLQUEUE(2, printk( + "Medium removal inhibited...")); } else { - SCSI_LOG_LLQUEUE(2, printk("Medium removal enabled...")); + SCSI_LOG_LLQUEUE(2, + printk("Medium removal enabled...")); } scsi_debug_errsts = 0; break; - case INQUIRY: + case INQUIRY: /* mandatory */ SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen)); memset(buff, 0, bufflen); buff[0] = DEVICE_TYPE(target); - buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ - buff[2] = 1; - buff[4] = 33 - 5; - memcpy(&buff[8], "Foo Inc", 7); - memcpy(&buff[16], "XYZZY", 5); - memcpy(&buff[32], "1", 1); + buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0; + /* Removable disk */ + buff[2] = 2; /* claim SCSI 2 */ + buff[4] = 36 - 5; + memcpy(&buff[8], "Linux ", 8); + memcpy(&buff[16], "scsi_debug ", 16); + memcpy(&buff[32], "0002", 4); + scsi_debug_errsts = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) + if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) + SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; +#endif + break; + case SEND_DIAGNOSTIC: /* mandatory */ + SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n")); + if (buff) + memset(buff, 0, bufflen); scsi_debug_errsts = 0; break; - case TEST_UNIT_READY: + case TEST_UNIT_READY: /* mandatory */ SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen)); if (buff) memset(buff, 0, bufflen); scsi_debug_errsts = 0; break; case READ_CAPACITY: + if (check_reset(SCpnt, devip)) { + done(SCpnt); + return 0; + } SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n")); SHpnt = SCpnt->host; - if (NR_REAL < 0) - NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f; memset(buff, 0, bufflen); - buff[0] = (CAPACITY >> 24); - buff[1] = (CAPACITY >> 16) & 0xff; - buff[2] = (CAPACITY >> 8) & 0xff; - buff[3] = CAPACITY & 0xff; + capac = CAPACITY - 1; + buff[0] = (capac >> 24); + buff[1] = (capac >> 16) & 0xff; + buff[2] = (capac >> 8) & 0xff; + buff[3] = capac & 0xff; buff[4] = 0; buff[5] = 0; - buff[6] = (SIZE(target) >> 8) & 0xff; /* 512 byte sectors */ - buff[7] = SIZE(target) & 0xff; + buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; + buff[7] = SECT_SIZE_PER(target) & 0xff; scsi_debug_errsts = 0; break; + case SCSI_CMD_READ_16: /* SBC-2 */ + case READ_12: case READ_10: case READ_6: -#ifdef DEBUG - printk("Read..."); -#endif - if ((*cmd) == READ_10) - block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); - else - block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); - VERIFY_DEBUG(READ); -#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE) - { - int delay = SCSI_SETUP_LATENCY; - - delay += SCpnt->request.nr_sectors * SCSI_DATARATE; - if (delay) - usleep(delay); - }; -#endif - -#ifdef DEBUG - printk("(r%d)", SCpnt->request.nr_sectors); -#endif - nbytes = bufflen; - if (SCpnt->use_sg) { - sgcount = 0; - sgpnt = (struct scatterlist *) buff; - buff = sgpnt[sgcount].address; - bufflen = sgpnt[sgcount].length; - bh = SCpnt->request.bh; - }; - scsi_debug_errsts = 0; - do { - VERIFY1_DEBUG(READ); - /* For the speedy test, we do not even want to fill the buffer with anything */ -#ifdef CLEAR - memset(buff, 0, bufflen); -#endif - /* If this is block 0, then we want to read the partition table for this - * device. Let's make one up */ - if (block == 0) { - int i; - memset(buff, 0, bufflen); - *((unsigned short *) (buff + 510)) = 0xAA55; - p = (struct partition *) (buff + 0x1be); - i = 0; - while (starts[i + 1]) { - int start_cyl, end_cyl; - - start_cyl = starts[i] / N_HEAD / N_SECTOR; - end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR; - p->boot_ind = 0; - - p->head = (i == 0 ? 1 : 0); - p->sector = 1 | ((start_cyl >> 8) << 6); - p->cyl = (start_cyl & 0xff); - - p->end_head = N_HEAD - 1; - p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6); - p->end_cyl = (end_cyl & 0xff); - - p->start_sect = starts[i]; - p->nr_sects = starts[i + 1] - starts[i]; - p->sys_ind = 0x81; /* Linux partition */ - p++; - i++; - }; - if (!npart) - npart = i; - scsi_debug_errsts = 0; - break; - }; -#ifdef DEBUG - if (SCpnt->use_sg) - printk("Block %x (%d %d)\n", block, SCpnt->request.nr_sectors, - SCpnt->request.current_nr_sectors); -#endif - -#if 0 - /* Simulate a disk change */ - if (block == 0xfff0) { - sense_buffer[0] = 0x70; - sense_buffer[2] = UNIT_ATTENTION; - starts[0] += 10; - starts[1] += 10; - starts[2] += 10; - -#ifdef DEBUG - { - int i; - printk("scsi_debug: Filling sense buffer:"); - for (i = 0; i < 12; i++) - printk("%d ", sense_buffer[i]); - printk("\n"); - }; -#endif - scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); - break; - } /* End phony disk change code */ -#endif - -#ifdef CLEAR - memcpy(buff, &target, sizeof(target)); - memcpy(buff + sizeof(target), cmd, 24); - memcpy(buff + 60, &block, sizeof(block)); - memcpy(buff + 64, SCpnt, sizeof(Scsi_Cmnd)); -#endif - nbytes -= bufflen; - if (SCpnt->use_sg) { -#ifdef CLEAR - memcpy(buff + 128, bh, sizeof(struct buffer_head)); -#endif - block += bufflen >> 9; - bh = bh->b_reqnext; - sgcount++; - if (nbytes) { - if (!bh) - panic("Too few blocks for linked request."); - buff = sgpnt[sgcount].address; - bufflen = sgpnt[sgcount].length; - }; - } - } while (nbytes); - + if (check_reset(SCpnt, devip)) { + done(SCpnt); + return 0; + } + upper_blk = 0; + if ((*cmd) == SCSI_CMD_READ_16) { + upper_blk = cmd[5] + (cmd[4] << 8) + + (cmd[3] << 16) + (cmd[2] << 24); + block = cmd[9] + (cmd[8] << 8) + + (cmd[7] << 16) + (cmd[6] << 24); + num = cmd[13] + (cmd[12] << 8) + + (cmd[11] << 16) + (cmd[10] << 24); + } + else if ((*cmd) == READ_12) { + block = cmd[5] + (cmd[4] << 8) + + (cmd[3] << 16) + (cmd[2] << 24); + num = cmd[9] + (cmd[8] << 8) + + (cmd[7] << 16) + (cmd[6] << 24); + } + else if ((*cmd) == READ_10) { + block = cmd[5] + (cmd[4] << 8) + + (cmd[3] << 16) + (cmd[2] << 24); + num = cmd[8] + (cmd[7] << 8); + } + else { + block = cmd[3] + (cmd[2] << 8) + + ((cmd[1] & 0x1f) << 16); + num = cmd[4]; + } + if (scsi_debug_read(SCpnt, upper_blk, block, num, + &scsi_debug_errsts, devip)) + break; SCpnt->result = 0; - (done) (SCpnt); +/* calls bottom half in upper layers before return from scsi_do_...() */ + (done) (SCpnt); return 0; - - if (SCpnt->use_sg && !scsi_debug_errsts) - if (bh) - scsi_dump(SCpnt, 0); - break; + case SCSI_CMD_WRITE_16: /* SBC-2 */ + case WRITE_12: case WRITE_10: case WRITE_6: -#ifdef DEBUG - printk("Write\n"); -#endif - if ((*cmd) == WRITE_10) - block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); - else - block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); - VERIFY_DEBUG(WRITE); - /* printk("(w%d)",SCpnt->request.nr_sectors); */ - if (SCpnt->use_sg) { - if ((bufflen >> 9) != SCpnt->request.nr_sectors) - panic("Trying to write wrong number of blocks\n"); - sgpnt = (struct scatterlist *) buff; - buff = sgpnt[sgcount].address; - }; -#if 0 - if (block != *((unsigned long *) (buff + 60))) { - printk("%x %x :", block, *((unsigned long *) (buff + 60))); - scsi_dump(SCpnt, 1); - panic("Bad block written.\n"); - }; -#endif - scsi_debug_errsts = 0; - break; + if (check_reset(SCpnt, devip)) { + done(SCpnt); + return 0; + } + upper_blk = 0; + if ((*cmd) == SCSI_CMD_WRITE_16) { + upper_blk = cmd[5] + (cmd[4] << 8) + + (cmd[3] << 16) + (cmd[2] << 24); + block = cmd[9] + (cmd[8] << 8) + + (cmd[7] << 16) + (cmd[6] << 24); + num = cmd[13] + (cmd[12] << 8) + + (cmd[11] << 16) + (cmd[10] << 24); + } + else if ((*cmd) == WRITE_12) { + block = cmd[5] + (cmd[4] << 8) + + (cmd[3] << 16) + (cmd[2] << 24); + num = cmd[9] + (cmd[8] << 8) + + (cmd[7] << 16) + (cmd[6] << 24); + } + else if ((*cmd) == WRITE_10) { + block = cmd[5] + (cmd[4] << 8) + + (cmd[3] << 16) + (cmd[2] << 24); + num = cmd[8] + (cmd[7] << 8); + } + else { + block = cmd[3] + (cmd[2] << 8) + + ((cmd[1] & 0x1f) << 16); + num = cmd[4]; + } + if (scsi_debug_write(SCpnt, upper_blk, block, num, + &scsi_debug_errsts, devip)) + break; + SCpnt->result = 0; +/* calls bottom half in upper layers before return from scsi_do_...() */ + (done) (SCpnt); + return 0; case MODE_SENSE: /* * Used to detect write protected status. @@ -480,26 +431,36 @@ memset(buff, 0, 6); break; default: +#if 0 SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd)); SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; - }; +#else + if (check_reset(SCpnt, devip)) { + done(SCpnt); + return 0; + } + scsi_debug_errsts = (COMMAND_COMPLETE << 8) | + (CHECK_CONDITION << 1); + mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14); + break; +#endif + } - save_flags(flags); - cli(); + spin_lock_irqsave(&mailbox_lock, iflags); for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) { if (timeout[i].function == NULL) break; - }; + } /* - * If all of the slots are full, just return 1. The new error handling scheme - * allows this, and the mid-level should queue things. + * If all of the slots are full, just return 1. The new error + * handling scheme allows this, and the mid-level should queue things. */ if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) { SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n")); - restore_flags(flags); + spin_unlock_irqrestore(&mailbox_lock, iflags); return 1; } SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i)); @@ -511,7 +472,7 @@ do_done[i] = done; scsi_debug_intr_handle(i); /* No timer - do this one right away */ } - restore_flags(flags); + spin_unlock_irqrestore(&mailbox_lock, iflags); #else SCpnt->result = scsi_debug_errsts; @@ -521,19 +482,200 @@ SCint[i] = SCpnt; do_done[i] = done; - restore_flags(flags); + spin_unlock_irqrestore(&mailbox_lock, iflags); add_timer(&timeout[i]); if (!done) - panic("scsi_debug_queuecommand: done can't be NULL\n"); + printk("scsi_debug_queuecommand: done can't be NULL\n"); #if 0 - printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies); + printk("Sending command (%d %x %d %d)...", i, done, + timeout[i].expires, jiffies); #endif #endif return 0; } +static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip) +{ + if (devip->reset) { + devip->reset = 0; + mk_sense_buffer(devip, 3, UNIT_ATTENTION, 0x29, 0, 14); + SCpnt->result = (COMMAND_COMPLETE << 8) | + (CHECK_CONDITION << 1); + return 1; + } + return 0; +} + +static inline +unsigned char * sdebug_scatg2virt(const struct scatterlist * sclp) +{ + if (NULL == sclp) + return NULL; + else if (sclp->page) + return (unsigned char *)page_address(sclp->page) + + sclp->offset; + else { +#ifdef SDEBUG_SG_ADDRESS + return sclp->address; +#else + return NULL; +#endif + } +} + +static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, + int num, int * errstsp, Sdebug_dev_info * devip) +{ + unsigned char *buff = (unsigned char *) SCpnt->request_buffer; + int nbytes, sgcount; + struct scatterlist *sgpnt = NULL; + int bufflen = SCpnt->request_bufflen; + unsigned long iflags; + + if (upper_blk || (block + num > CAPACITY)) { + *errstsp = (COMMAND_COMPLETE << 8) | + (CHECK_CONDITION << 1); + mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14); + return 1; + } +#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE) + { + int delay = SCSI_SETUP_LATENCY; + + delay += SCpnt->request.nr_sectors * SCSI_DATARATE; + if (delay) + usleep(delay); + } +#endif + + read_lock_irqsave(&sdebug_atomic_rw, iflags); + sgcount = 0; + nbytes = bufflen; + /* printk("scsi_debug_read: block=%d, tot_bufflen=%d\n", + block, bufflen); */ + if (SCpnt->use_sg) { + sgcount = 0; + sgpnt = (struct scatterlist *) buff; + buff = sdebug_scatg2virt(&sgpnt[sgcount]); + bufflen = sgpnt[sgcount].length; + } + *errstsp = 0; + do { + int resid, k, off, len, rem, blk; + unsigned char * bp; + + /* If this is block 0, then we want to read the partition + * table for this device. Let's make one up */ + if (scsi_debug_fake_blk0 && (block == 0) && (! made_block0)) { + scsi_debug_mkblock0(buff, bufflen, SCpnt); + *errstsp = 0; + break; + } + bp = buff; + blk = block; + for (resid = bufflen; resid > 0; resid -= len) { + k = blk / SECT_PER_ELEM; + off = (blk % SECT_PER_ELEM) * SECT_SIZE; + rem = STORE_ELEM_SIZE - off; + len = (resid > rem) ? rem : resid; +/* printk("sdr: blk=%d k=%d off=%d rem=%d resid" + "=%d len=%d sgcount=%d\n", blk, k, + off, rem, resid, len, sgcount); */ + memcpy(bp, store_arr[k].p + off, len); + bp += len; + blk += len / SECT_SIZE; + } +#if 0 + /* Simulate a disk change */ + if (block == 0xfff0) { + sense_buffer[0] = 0x70; + sense_buffer[2] = UNIT_ATTENTION; + starts[0] += 10; + starts[1] += 10; + starts[2] += 10; + + *errstsp = (COMMAND_COMPLETE << 8) | + (CHECK_CONDITION << 1); + read_unlock_irqrestore(&sdebug_atomic_rw, iflags); + return 1; + } /* End phony disk change code */ +#endif + nbytes -= bufflen; + if (SCpnt->use_sg) { + block += bufflen >> POW2_SECT_SIZE; + sgcount++; + if (nbytes) { + buff = sdebug_scatg2virt(&sgpnt[sgcount]); + bufflen = sgpnt[sgcount].length; + } + } + else if (nbytes > 0) + printk("sdebug_read: unexpected nbytes=%d\n", nbytes); + } while (nbytes); + read_unlock_irqrestore(&sdebug_atomic_rw, iflags); + return 0; +} + +static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, + int num, int * errstsp, Sdebug_dev_info * devip) +{ + unsigned char *buff = (unsigned char *) SCpnt->request_buffer; + int nbytes, sgcount; + struct scatterlist *sgpnt = NULL; + int bufflen = SCpnt->request_bufflen; + unsigned long iflags; + + if (upper_blk || (block + num > CAPACITY)) { + *errstsp = (COMMAND_COMPLETE << 8) | + (CHECK_CONDITION << 1); + mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14); + return 1; + } + + write_lock_irqsave(&sdebug_atomic_rw, iflags); + sgcount = 0; + nbytes = bufflen; + if (SCpnt->use_sg) { + sgcount = 0; + sgpnt = (struct scatterlist *) buff; + buff = sdebug_scatg2virt(&sgpnt[sgcount]); + bufflen = sgpnt[sgcount].length; + } + *errstsp = 0; + do { + int resid, k, off, len, rem, blk; + unsigned char * bp; + + bp = buff; + blk = block; + for (resid = bufflen; resid > 0; resid -= len) { + k = blk / SECT_PER_ELEM; + off = (blk % SECT_PER_ELEM) * SECT_SIZE; + rem = STORE_ELEM_SIZE - off; + len = (resid > rem) ? rem : resid; + memcpy(store_arr[k].p + off, bp, len); + bp += len; + blk += len / SECT_SIZE; + } + + nbytes -= bufflen; + if (SCpnt->use_sg) { + block += bufflen >> POW2_SECT_SIZE; + sgcount++; + if (nbytes) { + buff = sdebug_scatg2virt(&sgpnt[sgcount]); + bufflen = sgpnt[sgcount].length; + } + } + else if (nbytes > 0) + printk("sdebug_write: unexpected nbytes=%d\n", nbytes); + } while (nbytes); + write_unlock_irqrestore(&sdebug_atomic_rw, iflags); + return 0; +} + static void scsi_debug_send_self_command(struct Scsi_Host * shpnt) { static unsigned char cmd[6] = @@ -581,10 +723,6 @@ { Scsi_Cmnd *SCtmp; void (*my_done) (Scsi_Cmnd *); -#ifdef DEBUG - int to; -#endif - #if 0 del_timer(&timeout[indx]); #endif @@ -599,59 +737,219 @@ printk("scsi_debug_intr_handle: Unexpected interrupt\n"); return; } -#ifdef DEBUG +#if 0 printk("In intr_handle..."); printk("...done %d %x %d %d\n", i, my_done, to, jiffies); printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done); #endif my_done(SCtmp); -#ifdef DEBUG +#if 0 printk("Called done.\n"); #endif } +static int initialized = 0; + +static int do_init(void) +{ + int sz; + + starts[3] = CAPACITY; + sz = sizeof(Sd_store_elem) * STORE_ELEMENTS; + store_arr = kmalloc(sz, GFP_ATOMIC); + if (NULL == store_arr) + return 1; + memset(store_arr, 0, sz); + + sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES; + do_done = kmalloc(sz, GFP_ATOMIC); + if (NULL == do_done) + goto out; + memset((void *)do_done, 0, sz); + + sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES; + timeout = kmalloc(sz, GFP_ATOMIC); + if (NULL == timeout) + goto out; + memset(timeout, 0, sz); + + sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES; + SCint = kmalloc(sz, GFP_ATOMIC); + if (NULL == SCint) + goto out; + memset(SCint, 0, sz); + + return 0; + +out: + if (store_arr) + kfree(store_arr); + if (do_done) + kfree((void *)do_done); + if (timeout) + kfree(timeout); + if (SCint) + kfree(SCint); + return 1; +} + +static void do_end(void) +{ + kfree(SCint); + kfree(timeout); + kfree((void *)do_done); + kfree(store_arr); +} + int scsi_debug_detect(Scsi_Host_Template * tpnt) { - int i; + int k, num, sz; + + if (0 == initialized) { + ++initialized; + sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs; + devInfop = kmalloc(sz, GFP_ATOMIC); + if (NULL == devInfop) { + printk("scsi_debug_detect: out of memory, 0.5\n"); + return 0; + } + memset(devInfop, 0, sz); + if (do_init()) { + printk("scsi_debug_detect: out of memory, 0\n"); + return 0; + } + for (k = 0; k < STORE_ELEMENTS; ++k) { + store_arr[k].p = (unsigned char *) + __get_free_pages(GFP_ATOMIC, STORE_ELEM_ORDER); + if (0 == store_arr[k].p) + goto detect_err; + memset(store_arr[k].p, 0, STORE_ELEM_SIZE); + } + for (k = 0; k < NUM_SENSE_BUFFS; ++k) + sense_buffers[k][0] = 0x70; + for (k = 0; k < NR_HOSTS_PRESENT; k++) { + tpnt->proc_name = "scsi_debug"; /* In the loop??? */ + scsi_register(tpnt, 0); + } + return NR_HOSTS_PRESENT; + } + else { + printk("scsi_debug_detect: called again\n"); + return 0; + } - for (i = 0; i < NR_HOSTS_PRESENT; i++) { - tpnt->proc_name = "scsi_debug"; /* Huh? In the loop??? */ - scsi_register(tpnt, 0); +detect_err: + num = k; + for (k = 0; k < STORE_ELEMENTS; ++k) { + if (0 != store_arr[k].p) { + free_pages((unsigned long)store_arr[k].p, + STORE_ELEM_ORDER); + store_arr[k].p = NULL; + } } - return NR_HOSTS_PRESENT; + printk("scsi_debug_detect: out of memory: %d out of %d bytes\n", + (int)(num * STORE_ELEM_SIZE), + (int)(scsi_debug_dev_size_mb * 1024 * 1024)); + return 0; +} + + +static int num_releases = 0; + +int scsi_debug_release(struct Scsi_Host * hpnt) +{ + int k; + + scsi_unregister(hpnt); + if (++num_releases != NR_HOSTS_PRESENT) + return 0; + + for (k = 0; k < STORE_ELEMENTS; ++k) { + if (0 != store_arr[k].p) { + free_pages((unsigned long)store_arr[k].p, + STORE_ELEM_ORDER); + store_arr[k].p = NULL; + } + } + do_end(); + kfree(devInfop); + return 0; +} + +static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp) +{ + int k; + unsigned short host_no, id; + Sdebug_dev_info * devip; + + host_no = sdp->host->host_no; + id = (unsigned short)sdp->id; + for (k = 0; k < scsi_debug_num_devs; ++k) { + devip = &devInfop[k]; + if (devip->sdp && (host_no == devip->host_no) && + (id == devip->id)) { + devip->sdp = sdp; /* overwrite previous sdp */ + return devip; + } + if (NULL == devip->sdp) { + devip->sdp = sdp; + devip->host_no = host_no; + devip->id = id; + devip->reset = 1; + devip->sb_index = 0; + return devip; + } + } + return NULL; +} + +static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, + int asc, int asq, int inbandLen) +{ + char * sbuff; + if ((index < 0) || (index >= NUM_SENSE_BUFFS)) + return; + if (devip) + devip->sb_index = index; + sbuff = &sense_buffers[index][0]; + memset(sbuff, 0, SENSE_BUFF_LEN); + sbuff[0] = 0x70; + sbuff[2] = key; + sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0; + sbuff[12] = asc; + sbuff[13] = asq; } int scsi_debug_abort(Scsi_Cmnd * SCpnt) { -#if 0 +#if 1 + ++num_aborts; + return SUCCESS; +#else int j; void (*my_done) (Scsi_Cmnd *); - unsigned long flags; -#endif - - DEB(printk("scsi_debug_abort\n")); -#if 0 + unsigned long iflags; SCpnt->result = SCpnt->abort_reason << 16; for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) { if (SCpnt == SCint[j]) { my_done = do_done[j]; my_done(SCpnt); - save_flags(flags); - cli(); + spin_lock_irqsave(&mailbox_lock, iflags); timeout[j] = 0; SCint[j] = NULL; do_done[j] = NULL; - restore_flags(flags); - }; - }; -#endif + spin_unlock_irqrestore(&mailbox_lock, iflags); + } + } return SCSI_ABORT_SNOOZE; +#endif } int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info) { + /* int size = disk->capacity; */ info[0] = N_HEAD; info[1] = N_SECTOR; info[2] = N_CYLINDER; @@ -660,35 +958,130 @@ return 0; } +#if 0 int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why) { int i; - unsigned long flags; + unsigned long iflags; void (*my_done) (Scsi_Cmnd *); printk("Bus unlocked by reset - %d\n", why); scsi_debug_lockup = 0; - DEB(printk("scsi_debug_reset called\n")); for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) { if (SCint[i] == NULL) continue; SCint[i]->result = DID_RESET << 16; my_done = do_done[i]; my_done(SCint[i]); - save_flags(flags); - cli(); + spin_lock_irqsave(&mailbox_lock, iflags); SCint[i] = NULL; do_done[i] = NULL; timeout[i].function = NULL; - restore_flags(flags); + spin_unlock_irqrestore(&mailbox_lock, iflags); } return SCSI_RESET_SUCCESS; } +#endif + +int scsi_debug_device_reset(Scsi_Cmnd * SCpnt) +{ + Scsi_Device * sdp; + int k; + + ++num_dev_resets; + if (SCpnt && ((sdp = SCpnt->device))) { + for (k = 0; k < scsi_debug_num_devs; ++k) { + if (sdp->hostdata == (devInfop + k)) + break; + } + if (k < scsi_debug_num_devs) + devInfop[k].reset = 1; + } + return SUCCESS; +} -const char *scsi_debug_info(void) +int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt) { - static char buffer[] = " "; /* looks nicer without anything here */ - return buffer; + Scsi_Device * sdp; + struct Scsi_Host * hp; + int k; + + ++num_bus_resets; + if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { + for (k = 0; k < scsi_debug_num_devs; ++k) { + if (hp == devInfop[k].sdp->host) + devInfop[k].reset = 1; + } + } + return SUCCESS; +} + +int scsi_debug_host_reset(Scsi_Cmnd * SCpnt) +{ + int k; + + ++num_host_resets; + for (k = 0; k < scsi_debug_num_devs; ++k) + devInfop[k].reset = 1; + + return SUCCESS; +} + +#ifndef MODULE +static int __init scsi_debug_num_devs_setup(char *str) +{ + int tmp; + + if (get_option(&str, &tmp) == 1) { + if (tmp > 0) + scsi_debug_num_devs = tmp; + return 1; + } else { + printk("scsi_debug_num_devs: usage scsi_debug_num_devs= " + "( can be from 1 to around 2000)\n"); + return 0; + } +} + +__setup("scsi_debug_num_devs=", scsi_debug_num_devs_setup); + +static int __init scsi_debug_dev_size_mb_setup(char *str) +{ + int tmp; + + if (get_option(&str, &tmp) == 1) { + if (tmp > 0) + scsi_debug_dev_size_mb = tmp; + return 1; + } else { + printk("scsi_debug_dev_size_mb: usage scsi_debug_dev_size_mb=\n" + " ( is number of MB ram shared by all devs\n"); + return 0; + } +} + +__setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup); +#endif + +MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); +MODULE_DESCRIPTION("SCSI debug adapter driver"); +MODULE_PARM(scsi_debug_num_devs, "i"); +MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate"); +MODULE_PARM(scsi_debug_dev_size_mb, "i"); +MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs"); + +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +static char sdebug_info[256]; + +const char * scsi_debug_info(struct Scsi_Host * shp) +{ + sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, " + "dev_size_mb=%d\n", scsi_debug_version_str, + scsi_debug_num_devs, scsi_debug_dev_size_mb); + return sdebug_info; } /* scsi_debug_proc_info @@ -738,10 +1131,20 @@ } begin = 0; - pos = len = sprintf(buffer, - "This driver is not a real scsi driver, but it plays one on TV.\n" + pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n" + "num_devs=%d, shared (ram) size=%d MB, sector_size=%d bytes\n" + "cylinders=%d, heads=%d, sectors=%d\n" + "number of aborts=%d, device_reset=%d, bus_resets=%d, " + "host_resets=%d\n", + scsi_debug_version_str, scsi_debug_num_devs, + scsi_debug_dev_size_mb, SECT_SIZE, + N_CYLINDER, N_HEAD, N_SECTOR, + num_aborts, num_dev_resets, num_bus_resets, num_host_resets); +#if 0 + "This driver is not a real scsi driver, but it plays one on TV.\n" "It is very handy for debugging specific problems because you\n" "can simulate a variety of error conditions\n"); +#endif if (pos < offset) { len = 0; begin = pos; @@ -754,44 +1157,8 @@ return (len); } -#ifdef CONFIG_USER_DEBUG -/* - * This is a hack for the user space emulator. It allows us to - * "insert" arbitrary numbers of additional drivers. - */ -void *scsi_debug_get_handle(void) -{ - static Scsi_Host_Template driver_copy = SCSI_DEBUG; - void *rtn; - rtn = kmalloc(sizeof(driver_copy), GFP_ATOMIC); - if(rtn==NULL) - return NULL; - memcpy(rtn, (void *) &driver_copy, sizeof(driver_copy)); - return rtn; -} -#endif - /* Eventually this will go into an include file, but this will be later */ -static Scsi_Host_Template driver_template = SCSI_DEBUG; +static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE; #include "scsi_module.c" -/* - * Overrides for Emacs so that we almost follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ -MODULE_LICENSE("GPL"); diff -urN linux-2.5.3-pre1/drivers/scsi/scsi_debug.h linux/drivers/scsi/scsi_debug.h --- linux-2.5.3-pre1/drivers/scsi/scsi_debug.h Wed Nov 28 10:22:27 2001 +++ linux/drivers/scsi/scsi_debug.h Sat Jan 19 16:58:39 2002 @@ -8,34 +8,41 @@ int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int scsi_debug_abort(Scsi_Cmnd *); int scsi_debug_biosparam(Disk *, kdev_t, int[]); -int scsi_debug_reset(Scsi_Cmnd *, unsigned int); +int scsi_debug_bus_reset(Scsi_Cmnd *); +int scsi_debug_dev_reset(Scsi_Cmnd *); +int scsi_debug_host_reset(Scsi_Cmnd *); int scsi_debug_proc_info(char *, char **, off_t, int, int, int); +const char * scsi_debug_info(struct Scsi_Host *); #ifndef NULL #define NULL 0 #endif - -#define SCSI_DEBUG_MAILBOXES 1 - /* - * Allow the driver to reject commands. Thus we accept only one, but - * and the mid-level will queue the remainder. + * This driver is written for the lk 2.5 series */ #define SCSI_DEBUG_CANQUEUE 255 -#define SCSI_DEBUG {proc_info: scsi_debug_proc_info, \ +#define SCSI_DEBUG_MAX_CMD_LEN 16 + +#define SCSI_DEBUG_TEMPLATE \ + {proc_info: scsi_debug_proc_info, \ name: "SCSI DEBUG", \ + info: scsi_debug_info, \ detect: scsi_debug_detect, \ + release: scsi_debug_release, \ queuecommand: scsi_debug_queuecommand, \ - abort: scsi_debug_abort, \ - reset: scsi_debug_reset, \ + eh_abort_handler: scsi_debug_abort, \ + eh_bus_reset_handler: scsi_debug_bus_reset, \ + eh_device_reset_handler: scsi_debug_device_reset, \ + eh_host_reset_handler: scsi_debug_host_reset, \ bios_param: scsi_debug_biosparam, \ can_queue: SCSI_DEBUG_CANQUEUE, \ this_id: 7, \ - sg_tablesize: 16, \ + sg_tablesize: 64, \ cmd_per_lun: 3, \ unchecked_isa_dma: 0, \ use_clustering: ENABLE_CLUSTERING, \ } + #endif diff -urN linux-2.5.3-pre1/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- linux-2.5.3-pre1/drivers/scsi/sg.c Thu Jan 3 11:35:33 2002 +++ linux/drivers/scsi/sg.c Sat Jan 19 16:58:39 2002 @@ -19,9 +19,9 @@ */ #include #ifdef CONFIG_PROC_FS - static char sg_version_str[] = "Version: 3.1.20 (20010814)"; + static char sg_version_str[] = "Version: 3.5.23 (20020103)"; #endif - static int sg_version_num = 30120; /* 2 digits for each component */ + static int sg_version_num = 30523; /* 2 digits for each component */ /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First @@ -76,12 +76,18 @@ #include #endif /* LINUX_VERSION_CODE */ +#define SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST + #define SG_ALLOW_DIO_DEF 0 #define SG_ALLOW_DIO_CODE /* compile out be commenting this define */ #ifdef SG_ALLOW_DIO_CODE #include #endif +#define SG_NEW_KIOVEC 0 /* use alloc_kiovec(), not alloc_kiovec_sz() */ + +#define SG_MAX_DEVS_MASK ((1U << KDEV_MINOR_BITS) - 1) + int sg_big_buff = SG_DEF_RESERVED_SIZE; /* N.B. This variable is readable and writeable via /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer @@ -95,14 +101,8 @@ #define SG_SECTOR_SZ 512 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) -#define SG_LOW_POOL_THRESHHOLD 30 -#define SG_MAX_POOL_SECTORS 320 /* Max. number of pool sectors to take */ - -static int sg_pool_secs_avail = SG_MAX_POOL_SECTORS; - #define SG_HEAP_PAGE 1 /* heap from kernel via get_free_pages() */ #define SG_HEAP_KMAL 2 /* heap from kernel via kmalloc() */ -#define SG_HEAP_POOL 3 /* heap from scsi dma pool (mid-level) */ #define SG_USER_MEM 4 /* memory belongs to user space */ #define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */ @@ -136,10 +136,10 @@ typedef struct sg_scatter_hold /* holding area for scsi scatter gather info */ { unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */ - unsigned short sglist_len; /* size of malloc'd scatter-gather list */ + unsigned short sglist_len; /* size of malloc'd scatter-gather list ++ */ unsigned bufflen; /* Size of (aggregate) data buffer */ unsigned b_malloc_len; /* actual len malloc'ed in buffer */ - void * buffer; /* Data buffer or scatter list,12 bytes each*/ + void * buffer; /* Data buffer or scatter list + mem_src_arr */ struct kiobuf * kiobp; /* for direct IO information */ char mapped; /* indicates kiobp has locked pages */ char buffer_mem_src; /* heap whereabouts of 'buffer' */ @@ -182,6 +182,7 @@ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ + char mmap_called; /* 0 -> mmap() never called on this fd */ } Sg_fd; /* 2760 bytes long on i386 */ typedef struct sg_device /* holds the state of each scsi generic device */ @@ -203,7 +204,8 @@ static int sg_start_req(Sg_request * srp); static void sg_finish_rem_req(Sg_request * srp); static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size); -static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp); +static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, + int tablesize); static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count, Sg_request * srp); static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count, @@ -233,13 +235,15 @@ static Sg_request * sg_add_request(Sg_fd * sfp); static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); static int sg_res_in_use(Sg_fd * sfp); -static void sg_clr_srpnt(Scsi_Request * SRpnt); static int sg_ms_to_jif(unsigned int msecs); -static unsigned sg_jif_to_ms(int jifs); +static inline unsigned sg_jif_to_ms(int jifs); static int sg_allow_access(unsigned char opcode, char dev_type); static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len); static void sg_unmap_and(Sg_scatter_hold * schp, int free_also); static Sg_device * sg_get_dev(int dev); +static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp); +static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp); +static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp); #ifdef CONFIG_PROC_FS static int sg_last_dev(void); #endif @@ -337,9 +341,8 @@ Sg_device * sdp; Sg_fd * sfp; - if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) { + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; - } SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", minor(sdp->i_rdev))); sg_fasync(-1, filp, 0); /* remove filp from async notification list */ if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */ @@ -615,6 +618,20 @@ sg_remove_request(sfp, srp); return -ENOSYS; } + if (hp->flags & SG_FLAG_MMAP_IO) { + if (hp->dxfer_len > sfp->reserve.bufflen) { + sg_remove_request(sfp, srp); + return -ENOMEM; /* MMAP_IO size must fit in reserve buffer */ + } + if (hp->flags & SG_FLAG_DIRECT_IO) { + sg_remove_request(sfp, srp); + return -EINVAL; /* either MMAP_IO or DIRECT_IO (not both) */ + } + if (sg_res_in_use(sfp)) { + sg_remove_request(sfp, srp); + return -EBUSY; /* reserve buffer already being used */ + } + } timeout = sg_ms_to_jif(srp->header.timeout); if ((! hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof(cmnd))) { sg_remove_request(sfp, srp); @@ -681,7 +698,6 @@ srp->my_cmdp = SRpnt; q = &SRpnt->sr_device->request_queue; SRpnt->sr_request.rq_dev = sdp->i_rdev; - SRpnt->sr_request.rq_status = RQ_ACTIVE; SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_cmd_len = hp->cmd_len; if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) { @@ -849,7 +865,7 @@ result = get_user(val, (int *)arg); if (result) return result; if (val != sfp->reserve.bufflen) { - if (sg_res_in_use(sfp)) + if (sg_res_in_use(sfp) || sfp->mmap_called) return -EBUSY; sg_remove_scat(&sfp->reserve); sg_build_reserve(sfp, val); @@ -1030,6 +1046,146 @@ return (retval < 0) ? retval : 0; } +static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp) +{ + return (sclp && sclp->page) ? + (unsigned char *)page_address(sclp->page) + sclp->offset : + NULL; +} + +static void sg_rb_correct4mmap(Sg_scatter_hold * rsv_schp, int startFinish) +{ + void * page_ptr; + struct page * page; + int k, m; + + SCSI_LOG_TIMEOUT(3, printk("sg_rb_correct4mmap: startFinish=%d, " + "scatg=%d\n", startFinish, rsv_schp->k_use_sg)); + /* N.B. correction _not_ applied to base page of aech allocation */ + if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */ + struct scatterlist * sclp = rsv_schp->buffer; + + for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) { + for (m = PAGE_SIZE; m < sclp->length; m += PAGE_SIZE) { + page_ptr = sg_scatg2virt(sclp) + m; + page = virt_to_page(page_ptr); + if (startFinish) + get_page(page); /* increment page count */ + else { + if (page_count(page) > 0) + put_page_testzero(page); /* decrement page count */ + } + } + } + } + else { /* reserve buffer is just a single allocation */ + for (m = PAGE_SIZE; m < rsv_schp->bufflen; m += PAGE_SIZE) { + page_ptr = (unsigned char *)rsv_schp->buffer + m; + page = virt_to_page(page_ptr); + if (startFinish) + get_page(page); /* increment page count */ + else { + if (page_count(page) > 0) + put_page_testzero(page); /* decrement page count */ + } + } + } +} + +static struct page * sg_vma_nopage(struct vm_area_struct *vma, + unsigned long addr, int unused) +{ + Sg_fd * sfp; + struct page * page = NOPAGE_SIGBUS; + void * page_ptr = NULL; + unsigned long offset; + Sg_scatter_hold * rsv_schp; + + if ((NULL == vma) || (! (sfp = (Sg_fd *)vma->vm_private_data))) + return page; + rsv_schp = &sfp->reserve; + offset = addr - vma->vm_start; + if (offset >= rsv_schp->bufflen) + return page; + SCSI_LOG_TIMEOUT(3, printk("sg_vma_nopage: offset=%lu, scatg=%d\n", + offset, rsv_schp->k_use_sg)); + if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */ + int k; + unsigned long sa = vma->vm_start; + unsigned long len; + struct scatterlist * sclp = rsv_schp->buffer; + + for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end); + ++k, ++sclp) { + len = vma->vm_end - sa; + len = (len < sclp->length) ? len : sclp->length; + if (offset < len) { + page_ptr = sg_scatg2virt(sclp) + offset; + page = virt_to_page(page_ptr); + get_page(page); /* increment page count */ + break; + } + sa += len; + offset -= len; + } + } + else { /* reserve buffer is just a single allocation */ + page_ptr = (unsigned char *)rsv_schp->buffer + offset; + page = virt_to_page(page_ptr); + get_page(page); /* increment page count */ + } + return page; +} + +static struct vm_operations_struct sg_mmap_vm_ops = { + nopage : sg_vma_nopage, +}; + +static int sg_mmap(struct file * filp, struct vm_area_struct *vma) +{ + Sg_fd * sfp; + unsigned long req_sz = vma->vm_end - vma->vm_start; + Sg_scatter_hold * rsv_schp; + + if ((! filp) || (! vma) || (! (sfp = (Sg_fd *)filp->private_data))) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n", + (void *)vma->vm_start, (int)req_sz)); + if (vma->vm_pgoff) + return -EINVAL; /* want no offset */ + rsv_schp = &sfp->reserve; + if (req_sz > rsv_schp->bufflen) + return -ENOMEM; /* cannot map more than reserved buffer */ + + if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */ + int k; + unsigned long sa = vma->vm_start; + unsigned long len; + struct scatterlist * sclp = rsv_schp->buffer; + + for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end); + ++k, ++sclp) { + if (0 != sclp->offset) + return -EFAULT; /* non page aligned memory ?? */ + len = vma->vm_end - sa; + len = (len < sclp->length) ? len : sclp->length; + sa += len; + } + } + else { /* reserve buffer is just a single allocation */ + if ((unsigned long)rsv_schp->buffer & (PAGE_SIZE - 1)) + return -EFAULT; /* non page aligned memory ?? */ + } + if (0 == sfp->mmap_called) { + sg_rb_correct4mmap(rsv_schp, 1); /* do only once per fd lifetime */ + sfp->mmap_called = 1; + } + vma->vm_flags |= (VM_RESERVED | VM_IO); + vma->vm_private_data = sfp; + vma->vm_ops = &sg_mmap_vm_ops; + return 0; +} + /* This function is a "bottom half" handler that is called by the * mid level when a command is completed (or has failed). */ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) @@ -1076,7 +1232,14 @@ srp->data.sglist_len = SRpnt->sr_sglist_len; srp->data.bufflen = SRpnt->sr_bufflen; srp->data.buffer = SRpnt->sr_buffer; - sg_clr_srpnt(SRpnt); + /* now clear out request structure */ + SRpnt->sr_use_sg = 0; + SRpnt->sr_sglist_len = 0; + SRpnt->sr_bufflen = 0; + SRpnt->sr_buffer = NULL; + SRpnt->sr_underflow = 0; + SRpnt->sr_request.rq_dev = mk_kdev(0, 0); /* "sg" _disowns_ request blk */ + srp->my_cmdp = NULL; srp->done = 1; read_unlock(&sg_dev_arr_lock); @@ -1121,14 +1284,15 @@ if (NULL == sfp->headrp) { SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, final cleanup\n")); - sg_remove_sfp(sdp, sfp); + if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */ + sdp->device->access_count--; + if (sdp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); + } + if (sg_template.module) + __MOD_DEC_USE_COUNT(sg_template.module); sfp = NULL; } - sdp->device->access_count--; - if (sg_template.module) - __MOD_DEC_USE_COUNT(sg_template.module); - if (sdp->device->host->hostt->module) - __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); } else if (srp && srp->orphan) { if (sfp->keep_orphan) @@ -1152,6 +1316,7 @@ poll: sg_poll, ioctl: sg_ioctl, open: sg_open, + mmap: sg_mmap, release: sg_release, fasync: sg_fasync, }; @@ -1176,7 +1341,7 @@ if(!sg_registered) { if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) { - printk("Unable to get major %d for generic SCSI device\n", + printk(KERN_ERR "Unable to get major %d for generic SCSI device\n", SCSI_GENERIC_MAJOR); write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return 1; @@ -1189,7 +1354,7 @@ sg_dev_arr = (Sg_device **)kmalloc(sg_template.dev_max * sizeof(Sg_device *), GFP_ATOMIC); if (NULL == sg_dev_arr) { - printk("sg_init: no space for sg_dev_arr\n"); + printk(KERN_ERR "sg_init: no space for sg_dev_arr\n"); write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return 1; } @@ -1212,8 +1377,8 @@ sg_big_buff = tmp; return 1; } else { - printk("sg_def_reserved_size : usage sg_def_reserved_size=n " - "(n could be 65536, 131072 or 262144)\n"); + printk(KERN_WARNING "sg_def_reserved_size : usage " + "sg_def_reserved_size=n (n could be 65536, 131072 or 262144)\n"); return 0; } } @@ -1238,7 +1403,7 @@ if (NULL == tmp_da) { scsidp->attached--; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - printk("sg_attach: device array cannot be resized\n"); + printk(KERN_ERR "sg_attach: device array cannot be resized\n"); return 1; } memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *)); @@ -1250,13 +1415,13 @@ for(k = 0; k < sg_template.dev_max; k++) if(! sg_dev_arr[k]) break; - if (k > MINORMASK) { + if (k > SG_MAX_DEVS_MASK) { scsidp->attached--; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - printk("Unable to attach sg device <%d, %d, %d, %d>" + printk(KERN_WARNING "Unable to attach sg device <%d, %d, %d, %d>" " type=%d, minor number exceed %d\n", scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, scsidp->type, - MINORMASK); + SG_MAX_DEVS_MASK); return 1; } if(k < sg_template.dev_max) @@ -1266,7 +1431,7 @@ if (NULL == sdp) { scsidp->attached--; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - printk("sg_attach: Sg_device cannot be allocated\n"); + printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n"); return 1; } @@ -1293,8 +1458,8 @@ case TYPE_WORM: case TYPE_TAPE: break; default: - printk("Attached scsi generic sg%d at scsi%d, channel %d, id %d," - " lun %d, type %d\n", k, scsidp->host->host_no, + printk(KERN_NOTICE "Attached scsi generic sg%d at scsi%d, channel" + " %d, id %d, lun %d, type %d\n", k, scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, scsidp->type); } return 0; @@ -1371,7 +1536,10 @@ MODULE_AUTHOR("Douglas Gilbert"); MODULE_DESCRIPTION("SCSI generic (sg) driver"); + +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif MODULE_PARM(def_reserved_size, "i"); MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); @@ -1417,9 +1585,8 @@ if (res <= 0) /* -ve -> error, 0 -> done, 1 -> try indirect */ return res; } - if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen)) { + if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen)) sg_link_reserve(sfp, srp, dxfer_len); - } else { res = sg_build_indi(req_schp, sfp, dxfer_len); if (res) { @@ -1445,23 +1612,24 @@ sg_remove_request(sfp, srp); } -static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp) +static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, + int tablesize) { int mem_src, ret_sz; - int sg_bufflen = PAGE_SIZE; int elem_sz = sizeof(struct scatterlist) + sizeof(char); - int mx_sc_elems = (sg_bufflen / elem_sz) - 1; + /* scatter gather array, followed by mem_src_arr (array of chars) */ + int sg_bufflen = tablesize * elem_sz; + int mx_sc_elems = tablesize; mem_src = SG_HEAP_KMAL; - schp->buffer = (struct scatterlist *)sg_malloc(sfp, sg_bufflen, - &ret_sz, &mem_src); - schp->buffer_mem_src = (char)mem_src; + schp->buffer = sg_malloc(sfp, sg_bufflen, &ret_sz, &mem_src); if (! schp->buffer) return -ENOMEM; else if (ret_sz != sg_bufflen) { sg_bufflen = ret_sz; - mx_sc_elems = (sg_bufflen / elem_sz) - 1; + mx_sc_elems = sg_bufflen / elem_sz; } + schp->buffer_mem_src = (char)mem_src; schp->sglist_len = sg_bufflen; memset(schp->buffer, 0, sg_bufflen); return mx_sc_elems; /* number of scat_gath elements allocated */ @@ -1470,13 +1638,15 @@ static void sg_unmap_and(Sg_scatter_hold * schp, int free_also) { #ifdef SG_ALLOW_DIO_CODE + int nbhs = 0; + if (schp && schp->kiobp) { if (schp->mapped) { unmap_kiobuf(schp->kiobp); schp->mapped = 0; } if (free_also) { - free_kiovec(1, &schp->kiobp); + sg_free_kiovec(1, &schp->kiobp, &nbhs); schp->kiobp = NULL; } } @@ -1494,10 +1664,12 @@ sg_io_hdr_t * hp = &srp->header; Sg_scatter_hold * schp = &srp->data; int sg_tablesize = sfp->parentdp->sg_tablesize; + int nbhs = 0; - res = alloc_kiovec(1, &schp->kiobp); + res = sg_alloc_kiovec(1, &schp->kiobp, &nbhs); if (0 != res) { - SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: alloc_kiovec res=%d\n", res)); + SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: sg_alloc_kiovec res=%d\n", + res)); return 1; } res = map_user_kiobuf((SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0, @@ -1527,7 +1699,7 @@ hp->info |= SG_INFO_DIRECT_IO; return 0; } - mx_sc_elems = sg_build_sgat(schp, sfp); + mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize); if (mx_sc_elems <= 1) { sg_unmap_and(schp, 1); sg_remove_scat(schp); @@ -1535,19 +1707,22 @@ } mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist)); for (k = 0, sclp = schp->buffer, rem_sz = dxfer_len; - (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems); + (rem_sz > 0) && (k < mx_sc_elems); ++k, ++sclp) { offset = (0 == k) ? kp->offset : 0; num = (rem_sz > (PAGE_SIZE - offset)) ? (PAGE_SIZE - offset) : rem_sz; + sclp->page = kp->maplist[k]; + sclp->offset = offset; +#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST sclp->address = page_address(kp->maplist[k]) + offset; - sclp->page = NULL; +#endif sclp->length = num; mem_src_arr[k] = SG_USER_MEM; rem_sz -= num; SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: k=%d, a=0x%p, len=%d, ms=%d\n", - k, sclp->address, num, mem_src_arr[k])); + k, sg_scatg2virt(sclp), num, mem_src_arr[k])); } schp->k_use_sg = k; SCSI_LOG_TIMEOUT(5, @@ -1569,7 +1744,7 @@ { int ret_sz, mem_src; int blk_size = buff_size; - char * p = NULL; + unsigned char * p = NULL; if ((blk_size < 0) || (! sfp)) return -EFAULT; @@ -1609,14 +1784,14 @@ char * mem_src_arr; /* N.B. ret_sz and mem_src carried into this block ... */ - mx_sc_elems = sg_build_sgat(schp, sfp); + mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize); if (mx_sc_elems < 0) return mx_sc_elems; /* most likely -ENOMEM */ mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist)); for (k = 0, sclp = schp->buffer, rem_sz = blk_size; - (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems); + (rem_sz > 0) && (k < mx_sc_elems); ++k, rem_sz -= ret_sz, ++sclp) { if (first) first = 0; @@ -1627,14 +1802,17 @@ if (! p) break; } + sclp->page = virt_to_page(p); + sclp->offset = (unsigned long)p & ~PAGE_MASK; +#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST sclp->address = p; - sclp->page = NULL; +#endif sclp->length = ret_sz; mem_src_arr[k] = mem_src; SCSI_LOG_TIMEOUT(5, printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n", - k, sclp->address, ret_sz, mem_src)); + k, sg_scatg2virt(sclp), ret_sz, mem_src)); } /* end of for loop */ schp->k_use_sg = k; SCSI_LOG_TIMEOUT(5, @@ -1664,7 +1842,8 @@ if (schp->bufflen < num_xfer) num_xfer = schp->bufflen; } - if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags))) + if ((num_xfer <= 0) || + (new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags))) return 0; SCSI_LOG_TIMEOUT(4, @@ -1698,14 +1877,15 @@ struct scatterlist * sclp = (struct scatterlist *)schp->buffer; char * mem_src_arr = sg_get_sgat_msa(schp); ksglen = (int)sclp->length; - p = sclp->address; + p = sg_scatg2virt(sclp); for (j = 0, k = 0; j < onum; ++j) { res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up); if (res) return res; for (; (k < schp->k_use_sg) && p; - ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) { + ++k, ++sclp, ksglen = (int)sclp->length, + p = sg_scatg2virt(sclp)) { ok = (SG_USER_MEM != mem_src_arr[k]); if (usglen <= 0) break; @@ -1766,7 +1946,7 @@ static char * sg_get_sgat_msa(Sg_scatter_hold * schp) { int elem_sz = sizeof(struct scatterlist) + sizeof(char); - int mx_sc_elems = (schp->sglist_len / elem_sz) - 1; + int mx_sc_elems = schp->sglist_len / elem_sz; return schp->buffer + (sizeof(struct scatterlist) * mx_sc_elems); } @@ -1779,14 +1959,17 @@ struct scatterlist * sclp = (struct scatterlist *)schp->buffer; char * mem_src_arr = sg_get_sgat_msa(schp); - for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) { + for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) { mem_src = mem_src_arr[k]; SCSI_LOG_TIMEOUT(5, printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n", - k, sclp->address, sclp->length, mem_src)); - sg_free(sclp->address, sclp->length, mem_src); - sclp->address = NULL; + k, sg_scatg2virt(sclp), sclp->length, mem_src)); + sg_free(sg_scatg2virt(sclp), sclp->length, mem_src); sclp->page = NULL; + sclp->offset = 0; +#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST + sclp->address = 0; +#endif sclp->length = 0; } sg_free(schp->buffer, schp->sglist_len, schp->buffer_mem_src); @@ -1814,7 +1997,8 @@ if (schp->bufflen < num_xfer) num_xfer = schp->bufflen; } - if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags))) + if ((num_xfer <= 0) || + (new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags))) return 0; SCSI_LOG_TIMEOUT(4, @@ -1848,14 +2032,15 @@ struct scatterlist * sclp = (struct scatterlist *)schp->buffer; char * mem_src_arr = sg_get_sgat_msa(schp); ksglen = (int)sclp->length; - p = sclp->address; + p = sg_scatg2virt(sclp); for (j = 0, k = 0; j < onum; ++j) { res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up); if (res) return res; for (; (k < schp->k_use_sg) && p; - ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) { + ++k, ++sclp, ksglen = (int)sclp->length, + p = sg_scatg2virt(sclp)) { ok = (SG_USER_MEM != mem_src_arr[k]); if (usglen <= 0) break; @@ -1896,14 +2081,14 @@ int k, num; struct scatterlist * sclp = (struct scatterlist *)schp->buffer; - for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) { + for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) { num = (int)sclp->length; if (num > num_read_xfer) { - __copy_to_user(outp, sclp->address, num_read_xfer); + __copy_to_user(outp, sg_scatg2virt(sclp), num_read_xfer); break; } else { - __copy_to_user(outp, sclp->address, num); + __copy_to_user(outp, sg_scatg2virt(sclp), num); num_read_xfer -= num; if (num_read_xfer <= 0) break; @@ -1949,7 +2134,7 @@ if (rem <= num) { if (0 == k) { req_schp->k_use_sg = 0; - req_schp->buffer = sclp->address; + req_schp->buffer = sg_scatg2virt(sclp); } else { sfp->save_scat_len = num; @@ -2189,6 +2374,8 @@ if (sfp->reserve.bufflen > 0) { SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp: bufflen=%d, k_use_sg=%d\n", (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg)); + if (sfp->mmap_called) + sg_rb_correct4mmap(&sfp->reserve, 0); /* undo correction */ sg_remove_scat(&sfp->reserve); } sfp->parentdp = NULL; @@ -2237,7 +2424,7 @@ /* MOD_INC's to inhibit unloading sg and associated adapter driver */ if (sg_template.module) __MOD_INC_USE_COUNT(sg_template.module); - if (sdp->device->host->hostt->module) + if (sdp->device->host->hostt->module) __MOD_INC_USE_COUNT(sdp->device->host->hostt->module); SCSI_LOG_TIMEOUT(1, printk( "sg_remove_sfp: worrisome, %d writes pending\n", dirty)); @@ -2270,30 +2457,6 @@ if (resp && retSzp) *retSzp = rqSz; return resp; } - if (SG_HEAP_POOL == mem_src) { - int num_sect = rqSz / SG_SECTOR_SZ; - - if (0 != (rqSz & SG_SECTOR_MSK)) { - if (! retSzp) - return resp; - ++num_sect; - rqSz = num_sect * SG_SECTOR_SZ; - } - while (num_sect > 0) { - if ((num_sect <= sg_pool_secs_avail)) { - resp = kmalloc(rqSz, page_mask); - if (resp) { - if (retSzp) *retSzp = rqSz; - sg_pool_secs_avail -= num_sect; - return resp; - } - } - if (! retSzp) - return resp; - num_sect /= 2; /* try half as many */ - rqSz = num_sect * SG_SECTOR_SZ; - } - } else if (SG_HEAP_PAGE == mem_src) { int order, a_size; int resSz = rqSz; @@ -2311,7 +2474,8 @@ if (retSzp) *retSzp = resSz; } else - printk("sg_low_malloc: bad mem_src=%d, rqSz=%df\n", mem_src, rqSz); + printk(KERN_ERR "sg_low_malloc: bad mem_src=%d, rqSz=%df\n", + mem_src, rqSz); return resp; } @@ -2330,29 +2494,20 @@ switch (*mem_srcp) { case SG_HEAP_PAGE: - l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE; + l_ms = (size < PAGE_SIZE) ? SG_HEAP_KMAL : SG_HEAP_PAGE; resp = sg_low_malloc(size, low_dma, l_ms, 0); if (resp) break; resp = sg_low_malloc(size, low_dma, l_ms, &size); if (! resp) { - l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL; + l_ms = (SG_HEAP_KMAL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_KMAL; resp = sg_low_malloc(size, low_dma, l_ms, &size); - if (! resp) { - l_ms = SG_HEAP_KMAL; - resp = sg_low_malloc(size, low_dma, l_ms, &size); - } } if (resp && retSzp) *retSzp = size; break; case SG_HEAP_KMAL: - l_ms = SG_HEAP_PAGE; + l_ms = SG_HEAP_KMAL; /* was SG_HEAP_PAGE */ resp = sg_low_malloc(size, low_dma, l_ms, 0); - if (resp) - break; - l_ms = SG_HEAP_POOL; - resp = sg_low_malloc(size, low_dma, l_ms, &size); - if (resp && retSzp) *retSzp = size; break; default: SCSI_LOG_TIMEOUT(1, printk("sg_malloc: bad ms=%d\n", *mem_srcp)); @@ -2365,18 +2520,19 @@ return resp; } +static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp) +{ +#if SG_NEW_KIOVEC + return alloc_kiovec_sz(nr, bufp, szp); +#else + return alloc_kiovec(nr, bufp); +#endif +} + static void sg_low_free(char * buff, int size, int mem_src) { if (! buff) return; switch (mem_src) { - case SG_HEAP_POOL: - { - int num_sect = size / SG_SECTOR_SZ; - - kfree(buff); - sg_pool_secs_avail += num_sect; - } - break; case SG_HEAP_KMAL: kfree(buff); /* size not used */ break; @@ -2392,7 +2548,7 @@ case SG_USER_MEM: break; /* nothing to do */ default: - printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n", + printk(KERN_ERR "sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n", mem_src, buff, size); break; } @@ -2408,14 +2564,13 @@ sg_low_free(buff, size, mem_src); } -static void sg_clr_srpnt(Scsi_Request * SRpnt) +static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp) { - SRpnt->sr_use_sg = 0; - SRpnt->sr_sglist_len = 0; - SRpnt->sr_bufflen = 0; - SRpnt->sr_buffer = NULL; - SRpnt->sr_underflow = 0; - SRpnt->sr_request.rq_dev = mk_kdev(0, 0); /* "sg" _disowns_ command blk */ +#if SG_NEW_KIOVEC + free_kiovec_sz(nr, bufp, szp); +#else + free_kiovec(nr, bufp); +#endif } static int sg_ms_to_jif(unsigned int msecs) @@ -2427,7 +2582,7 @@ : (((int)msecs / 1000) * HZ); } -static unsigned sg_jif_to_ms(int jifs) +static inline unsigned sg_jif_to_ms(int jifs) { if (jifs <= 0) return 0U; @@ -2477,8 +2632,8 @@ if (sg_dev_arr && (dev >= 0)) { read_lock_irqsave(&sg_dev_arr_lock, iflags); - if (dev < sg_template.dev_max) - sdp = sg_dev_arr[dev]; + if (dev < sg_template.dev_max) + sdp = sg_dev_arr[dev]; read_unlock_irqrestore(&sg_dev_arr_lock, iflags); } return sdp; @@ -2671,7 +2826,7 @@ { Sg_device * sdp; const sg_io_hdr_t * hp; - int j, max_dev; + int j, max_dev, new_interface; if (NULL == sg_dev_arr) { PRINT_PROC("sg_dev_arr NULL, driver not initialized\n"); @@ -2680,8 +2835,7 @@ max_dev = sg_last_dev(); PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n", sg_template.dev_max, max_dev); - PRINT_PROC(" sg_pool_secs_aval=%d def_reserved_size=%d\n", - sg_pool_secs_avail, sg_big_buff); + PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff); for (j = 0; j < max_dev; ++j) { if ((sdp = sg_get_dev(j))) { Sg_fd * fp; @@ -2717,8 +2871,10 @@ (int)fp->keep_orphan, (int)fp->closed); for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) { hp = &srp->header; + new_interface = (hp->interface_id == '\0') ? 0 : 1; /* stop indenting so far ... */ - PRINT_PROC(srp->res_used ? " rb>> " : + PRINT_PROC(srp->res_used ? ((new_interface && + (SG_FLAG_MMAP_IO & hp->flags)) ? " mmap>> " : " rb>> ") : ((SG_INFO_DIRECT_IO_MASK & hp->info) ? " dio>> " : " ")); blen = srp->my_cmdp ? srp->my_cmdp->sr_bufflen : srp->data.bufflen; usg = srp->my_cmdp ? srp->my_cmdp->sr_use_sg : srp->data.k_use_sg; @@ -2728,8 +2884,8 @@ if (srp->done) PRINT_PROC(" dur=%d", hp->duration); else - PRINT_PROC(" t_o/elap=%d/%d", ((hp->interface_id == '\0') ? - sg_jif_to_ms(fp->timeout) : hp->timeout), + PRINT_PROC(" t_o/elap=%d/%d", new_interface ? hp->timeout : + sg_jif_to_ms(fp->timeout), sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0)); PRINT_PROC("ms sgat=%d op=0x%02x\n", usg, (int)srp->data.cmd_opcode); /* reset indenting */ diff -urN linux-2.5.3-pre1/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- linux-2.5.3-pre1/drivers/scsi/sr.c Thu Jan 3 11:35:33 2002 +++ linux/drivers/scsi/sr.c Sat Jan 19 16:58:39 2002 @@ -331,7 +331,7 @@ SCSI_LOG_HLQUEUE(2, printk("sr%d : %s %d/%ld 512 byte blocks.\n", devm, - (SCpnt->request.cmd == WRITE) ? "writing" : "reading", + (rq_data_dir(&SCpnt->request) == WRITE) ? "writing" : "reading", this_count, SCpnt->request.nr_sectors)); SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ? diff -urN linux-2.5.3-pre1/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c --- linux-2.5.3-pre1/drivers/sound/via82cxxx_audio.c Mon Dec 10 10:39:20 2001 +++ linux/drivers/sound/via82cxxx_audio.c Sat Jan 19 16:58:39 2002 @@ -1995,7 +1995,7 @@ /* just to be a nice neighbor */ /* Thomas Sailer: * But also to ourselves, release semaphore if we do so */ - if (current->need_resched) { + if (need_resched()) { up(&card->syscall_sem); schedule (); ret = via_syscall_down (card, nonblock); @@ -2171,7 +2171,7 @@ /* just to be a nice neighbor */ /* Thomas Sailer: * But also to ourselves, release semaphore if we do so */ - if (current->need_resched) { + if (need_resched()) { up(&card->syscall_sem); schedule (); ret = via_syscall_down (card, nonblock); diff -urN linux-2.5.3-pre1/drivers/usb/hcd/ehci-hcd.c linux/drivers/usb/hcd/ehci-hcd.c --- linux-2.5.3-pre1/drivers/usb/hcd/ehci-hcd.c Mon Jan 14 10:10:43 2002 +++ linux/drivers/usb/hcd/ehci-hcd.c Sat Jan 19 16:58:39 2002 @@ -70,9 +70,15 @@ * Brad Hards * Rory Bolt * ... + * + * HISTORY: + * 2002-01-14 Minor cleanup; version synch. + * 2002-01-08 Fix roothub handoff of FS/LS to companion controllers. + * 2002-01-04 Control/Bulk queuing behaves. + * 2001-12-12 Initial patch version for Linux 2.5.1 kernel. */ -#define DRIVER_VERSION "$Revision: 0.25 $" +#define DRIVER_VERSION "$Revision: 0.26 $" #define DRIVER_AUTHOR "David Brownell" #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" @@ -97,9 +103,6 @@ static int log2_irq_thresh = 0; // 0 to 6 MODULE_PARM (log2_irq_thresh, "i"); MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); - -/* Some A steppings of the NEC controller need soft retries */ -//#define EHCI_SOFT_RETRIES 5 /* after CERR-induced fault */ #define INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT) diff -urN linux-2.5.3-pre1/drivers/usb/hcd/ehci-hub.c linux/drivers/usb/hcd/ehci-hub.c --- linux-2.5.3-pre1/drivers/usb/hcd/ehci-hub.c Tue Jan 1 13:52:10 2002 +++ linux/drivers/usb/hcd/ehci-hub.c Sat Jan 19 16:58:39 2002 @@ -82,11 +82,12 @@ for (i = 0; i < ports; i++) { temp = readl (&ehci->regs->port_status [i]); if (temp & PORT_OWNER) { - // get disconnected ports back if no companion driver - if (temp & PORT_CONNECT) - continue; - temp &= ~(PORT_OWNER|PORT_CSC); - writel (temp, &ehci->regs->port_status [i]); + /* don't report this in GetPortStatus */ + if (temp & PORT_CSC) { + temp &= ~PORT_CSC; + writel (temp, &ehci->regs->port_status [i]); + } + continue; } if (!(temp & PORT_CONNECT)) ehci->reset_done [i] = 0; diff -urN linux-2.5.3-pre1/drivers/usb/hcd/ehci-q.c linux/drivers/usb/hcd/ehci-q.c --- linux-2.5.3-pre1/drivers/usb/hcd/ehci-q.c Tue Jan 8 13:15:52 2002 +++ linux/drivers/usb/hcd/ehci-q.c Sat Jan 19 16:58:39 2002 @@ -883,11 +883,10 @@ /* can't get here without STS_ASS set */ if (ehci->hcd.state != USB_STATE_HALT) { if (cmd & CMD_PSE) - writel (cmd & __constant_cpu_to_le32 (~CMD_ASE), - &ehci->regs->command); + writel (cmd & ~CMD_ASE, &ehci->regs->command); else { ehci_ready (ehci); - while (!(readl (&ehci->regs->status) & STS_ASS)) + while (readl (&ehci->regs->status) & STS_ASS) udelay (100); } } diff -urN linux-2.5.3-pre1/drivers/usb/hcd/ehci-sched.c linux/drivers/usb/hcd/ehci-sched.c --- linux-2.5.3-pre1/drivers/usb/hcd/ehci-sched.c Mon Jan 14 10:10:43 2002 +++ linux/drivers/usb/hcd/ehci-sched.c Sat Jan 19 16:58:39 2002 @@ -381,7 +381,7 @@ vdbg ("qh %p usecs %d period %d starting frame %d.%d", qh, qh->usecs, period, frame, uframe); do { - if (unlikely ((long)ehci->pshadow [frame].ptr)) { + if (unlikely (ehci->pshadow [frame].ptr != 0)) { // FIXME -- just link to the end, before any qh with a shorter period, // AND handle it already being (implicitly) linked into this frame BUG (); diff -urN linux-2.5.3-pre1/drivers/usb/hcd.c linux/drivers/usb/hcd.c --- linux-2.5.3-pre1/drivers/usb/hcd.c Mon Jan 14 10:10:43 2002 +++ linux/drivers/usb/hcd.c Sat Jan 19 16:58:39 2002 @@ -1081,20 +1081,20 @@ if (!urb) return -EINVAL; - // FIXME: add some explicit records to flag the - // state where the URB is "in periodic completion". - // Workaround is for driver to set the urb status - // to "-EINPROGRESS", so it can get through here - // and unlink from the completion handler. - /* * we contend for urb->status with the hcd core, * which changes it while returning the urb. + * + * Caller guaranteed that the urb pointer hasn't been freed, and + * that it was submitted. But as a rule it can't know whether or + * not it's already been unlinked ... so we respect the reversed + * lock sequence needed for the usb_hcd_giveback_urb() code paths + * (urb lock, then hcd_data_lock) in case some other CPU is now + * unlinking it. */ spin_lock_irqsave (&urb->lock, flags); - if (!urb->hcpriv - || urb->status != -EINPROGRESS - || urb->transfer_flags & USB_TIMEOUT_KILLED) { + spin_lock (&hcd_data_lock); + if (!urb->hcpriv || urb->transfer_flags & USB_TIMEOUT_KILLED) { retval = -EINVAL; goto done; } @@ -1103,6 +1103,8 @@ retval = -ENODEV; goto done; } + + /* giveback clears dev; non-null means it's linked at this level */ dev = urb->dev->hcpriv; hcd = urb->dev->bus->hcpriv; if (!dev || !hcd) { @@ -1110,6 +1112,27 @@ goto done; } + /* For non-periodic transfers, any status except -EINPROGRESS means + * the HCD has already started to unlink this URB from the hardware. + * In that case, there's no more work to do. + * + * For periodic transfers, this is the only way to trigger unlinking + * from the hardware. Since we (currently) overload urb->status to + * tell the driver to unlink, error status might get clobbered ... + * unless that transfer hasn't yet restarted. One such case is when + * the URB gets unlinked from its completion handler. + * + * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED + */ + switch (usb_pipetype (urb->pipe)) { + case PIPE_CONTROL: + case PIPE_BULK: + if (urb->status != -EINPROGRESS) { + retval = 0; + goto done; + } + } + /* maybe set up to block on completion notification */ if ((urb->transfer_flags & USB_TIMEOUT_KILLED)) urb->status = -ETIMEDOUT; @@ -1130,6 +1153,7 @@ /* asynchronous unlink */ urb->status = -ECONNRESET; } + spin_unlock (&hcd_data_lock); spin_unlock_irqrestore (&urb->lock, flags); if (urb == (struct urb *) hcd->rh_timer.data) { @@ -1154,6 +1178,7 @@ } goto bye; done: + spin_unlock (&hcd_data_lock); spin_unlock_irqrestore (&urb->lock, flags); bye: if (retval) diff -urN linux-2.5.3-pre1/drivers/usb/hpusbscsi.c linux/drivers/usb/hpusbscsi.c --- linux-2.5.3-pre1/drivers/usb/hpusbscsi.c Tue Dec 25 17:04:40 2001 +++ linux/drivers/usb/hpusbscsi.c Sat Jan 19 16:58:39 2002 @@ -272,7 +272,7 @@ if (!srb->bufflen) { usb_callback = simple_command_callback; } else { - if (srb->use_sg) { + if (likely(srb->use_sg)) { usb_callback = scatter_gather_callback; hpusbscsi->fragment = 0; } else { @@ -288,10 +288,6 @@ TRACE_STATE; - if (hpusbscsi->state != HP_STATE_FREE) { - printk(KERN_CRIT"hpusbscsi - Ouch: queueing violation!\n"); - return 1; /* This must not happen */ - } /* We zero the sense buffer to avoid confusing user space */ memset(srb->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); @@ -313,10 +309,10 @@ hpusbscsi->srb = srb; res = usb_submit_urb(&hpusbscsi->dataurb); - if (res) { + if (unlikely(res)) { hpusbscsi->state = HP_STATE_FREE; TRACE_STATE; - if (callback) { + if (likely(callback != NULL)) { srb->result = DID_ERROR; callback(srb); } @@ -355,7 +351,7 @@ static void handle_usb_error (struct hpusbscsi *hpusbscsi) { - if (hpusbscsi->scallback != NULL) { + if (likely(hpusbscsi->scallback != NULL)) { hpusbscsi->srb->result = DID_ERROR; hpusbscsi->scallback(hpusbscsi->srb); } @@ -367,8 +363,8 @@ struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context; DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte); - if(u->status < 0) { - if (hpusbscsi->state != HP_STATE_FREE) + if(unlikely(u->status < 0)) { + if (likely(hpusbscsi->state != HP_STATE_FREE)) handle_usb_error(hpusbscsi); return; } @@ -402,7 +398,7 @@ static void simple_command_callback(struct urb *u) { struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context; - if (u->status<0) { + if (unlikely(u->status<0)) { handle_usb_error(hpusbscsi); return; } @@ -411,7 +407,7 @@ TRACE_STATE; hpusbscsi->state = HP_STATE_WAIT; } else { - if (hpusbscsi->scallback != NULL) + if (likely(hpusbscsi->scallback != NULL)) hpusbscsi->scallback(hpusbscsi->srb); hpusbscsi->state = HP_STATE_FREE; TRACE_STATE; @@ -426,7 +422,7 @@ int res; DEBUG("Going through scatter/gather\n"); - if (u->status < 0) { + if (unlikely(u->status < 0)) { handle_usb_error(hpusbscsi); return; } @@ -452,7 +448,7 @@ ); res = usb_submit_urb(u); - if (res) + if (unlikely(res)) hpusbscsi->state = HP_STATE_ERROR; TRACE_STATE; } @@ -461,20 +457,20 @@ { struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context; - if (u->status < 0) { + if (unlikely(u->status < 0)) { handle_usb_error(hpusbscsi); return; } DEBUG("Data transfer done\n"); TRACE_STATE; if (hpusbscsi->state != HP_STATE_PREMATURE) { - if (u->status < 0) + if (unlikely(u->status < 0)) hpusbscsi->state = HP_STATE_ERROR; else hpusbscsi->state = HP_STATE_WAIT; TRACE_STATE; } else { - if (hpusbscsi->scallback != NULL) + if (likely(hpusbscsi->scallback != NULL)) hpusbscsi->scallback(hpusbscsi->srb); hpusbscsi->state = HP_STATE_FREE; } @@ -485,7 +481,7 @@ struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context; int res; - if (u->status<0) { + if (unlikely(u->status<0)) { handle_usb_error(hpusbscsi); return; } @@ -501,7 +497,7 @@ ); res = usb_submit_urb(u); - if (res) { + if (unlikely(res)) { handle_usb_error(hpusbscsi); return; } @@ -510,10 +506,11 @@ hpusbscsi->state = HP_STATE_WORKING; TRACE_STATE; } else { - if (hpusbscsi->scallback != NULL) + if (likely(hpusbscsi->scallback != NULL)) hpusbscsi->scallback(hpusbscsi->srb); hpusbscsi->state = HP_STATE_FREE; TRACE_STATE; } } + diff -urN linux-2.5.3-pre1/drivers/usb/hub.c linux/drivers/usb/hub.c --- linux-2.5.3-pre1/drivers/usb/hub.c Tue Jan 1 13:52:10 2002 +++ linux/drivers/usb/hub.c Sat Jan 19 16:58:39 2002 @@ -557,6 +557,10 @@ dbg("port %d, portstatus %x, change %x, %s", port + 1, portstatus, portchange, portspeed (portstatus)); + /* Device went away? */ + if (!(portstatus & USB_PORT_STAT_CONNECTION)) + return 1; + /* bomb out completely if something weird happened */ if ((portchange & USB_PORT_STAT_C_CONNECTION)) return -1; diff -urN linux-2.5.3-pre1/drivers/usb/microtek.c linux/drivers/usb/microtek.c --- linux-2.5.3-pre1/drivers/usb/microtek.c Tue Dec 25 17:04:40 2001 +++ linux/drivers/usb/microtek.c Sat Jan 19 16:58:39 2002 @@ -320,11 +320,6 @@ #endif - -/* static inline int mts_is_aborting(struct mts_desc* desc) { - return (atomic_read(&desc->context.do_abort)); -} */ - static inline void mts_urb_abort(struct mts_desc* desc) { MTS_DEBUG_GOT_HERE(); mts_debug_dump(desc); @@ -504,7 +499,7 @@ transfer->status = 0; res = usb_submit_urb( transfer ); - if ( res ) { + if ( unlikely(res) ) { MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res ); context->srb->result = DID_ERROR << 16; mts_transfer_cleanup(transfer); @@ -518,7 +513,7 @@ { MTS_INT_INIT(); - if ( context->final_callback ) + if ( likely(context->final_callback != NULL) ) context->final_callback(context->srb); } @@ -556,7 +551,7 @@ if ( context->data_length != transfer->actual_length ) { context->srb->resid = context->data_length - transfer->actual_length; - } else if ( transfer->status ) { + } else if ( unlikely(transfer->status) ) { context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; } @@ -571,7 +566,7 @@ { MTS_INT_INIT(); - if ( transfer->status ) { + if ( unlikely(transfer->status) ) { if (transfer->status == -ENOENT) { /* We are being killed */ MTS_DEBUG_GOT_HERE(); @@ -605,7 +600,7 @@ MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg); - if (transfer->status) { + if (unlikely(transfer->status)) { context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; mts_transfer_cleanup(transfer); } @@ -703,7 +698,7 @@ srb->result = DID_BAD_TARGET << 16; - if(callback) + if(likely(callback != NULL)) callback(srb); goto out; @@ -725,11 +720,11 @@ res=usb_submit_urb(&desc->urb); - if(res){ + if(unlikely(res)){ MTS_ERROR("error %d submitting URB\n",(int)res); srb->result = DID_ERROR << 16; - if(callback) + if(likely(callback != NULL)) callback(srb); } @@ -1061,4 +1056,5 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); + diff -urN linux-2.5.3-pre1/drivers/usb/serial/ir-usb.c linux/drivers/usb/serial/ir-usb.c --- linux-2.5.3-pre1/drivers/usb/serial/ir-usb.c Sun Jan 6 18:49:21 2002 +++ linux/drivers/usb/serial/ir-usb.c Sat Jan 19 16:58:39 2002 @@ -2,6 +2,7 @@ * USB IR Dongle driver * * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +21,12 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * 2002_Jan_14 gb + * Added module parameter to force specific number of XBOFs. + * Added ir_xbof_change(). + * Reorganized read_bulk_callback error handling. + * Switched from FILL_BULK_URB() to usb_fill_bulk_urb(). + * * 2001_Nov_08 greg kh * Changed the irda_usb_find_class_desc() function based on comments and * code from Martin Diehl. @@ -62,13 +69,15 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.3" +#define DRIVER_VERSION "v0.4" #define DRIVER_AUTHOR "Greg Kroah-Hartman " #define DRIVER_DESC "USB IR Dongle driver" /* if overridden by the user, then use their value for the size of the read and * write urbs */ static int buffer_size = 0; +/* if overridden by the user, then use the specified number of XBOFs */ +static int xbof = -1; static int ir_startup (struct usb_serial *serial); static int ir_open (struct usb_serial_port *port, struct file *filep); @@ -78,6 +87,9 @@ static void ir_read_bulk_callback (struct urb *urb); static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static u8 ir_baud = 0; +static u8 ir_xbof = 0; +static u8 ir_add_bof = 0; static __devinitdata struct usb_device_id id_table [] = { { USB_DEVICE(0x050f, 0x0180) }, /* KC Technology, KC-180 */ @@ -148,14 +160,16 @@ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500)); - dbg(__FUNCTION__ " - ret=%d", ret); + dbg("%s - ret=%d", __FUNCTION__, ret); if (ret < sizeof(*desc)) { - dbg(__FUNCTION__ " - class descriptor read %s (%d)", - (ret<0) ? "failed" : "too short", ret); + dbg("%s - class descriptor read %s (%d)", + __FUNCTION__, + (ret<0) ? "failed" : "too short", + ret); goto error; } if (desc->bDescriptorType != USB_DT_IRDA) { - dbg(__FUNCTION__ " - bad class descriptor type"); + dbg("%s - bad class descriptor type", __FUNCTION__); goto error; } @@ -166,6 +180,28 @@ return NULL; } + +static u8 ir_xbof_change(u8 xbof) +{ + u8 result; + /* reference irda-usb.c */ + switch(xbof) { + case 48: result = 0x10; break; + case 28: + case 24: result = 0x20; break; + default: + case 12: result = 0x30; break; + case 5: + case 6: result = 0x40; break; + case 3: result = 0x50; break; + case 2: result = 0x60; break; + case 1: result = 0x70; break; + case 0: result = 0x80; break; + } + return(result); +} + + static int ir_startup (struct usb_serial *serial) { struct irda_class_desc *irda_desc; @@ -175,16 +211,30 @@ err ("IRDA class descriptor not found, device not bound"); return -ENODEV; } - dbg (__FUNCTION__" - Baud rates supported: %s%s%s%s%s%s%s%s%s", - (irda_desc->wBaudRate & 0x0001) ? "2400 " : "", - irda_desc->wBaudRate & 0x0002 ? "9600 " : "", - irda_desc->wBaudRate & 0x0004 ? "19200 " : "", - irda_desc->wBaudRate & 0x0008 ? "38400 " : "", - irda_desc->wBaudRate & 0x0010 ? "57600 " : "", - irda_desc->wBaudRate & 0x0020 ? "115200 " : "", - irda_desc->wBaudRate & 0x0040 ? "576000 " : "", - irda_desc->wBaudRate & 0x0080 ? "1152000 " : "", - irda_desc->wBaudRate & 0x0100 ? "4000000 " : ""); + + dbg ("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s", + __FUNCTION__, + (irda_desc->wBaudRate & 0x0001) ? " 2400" : "", + (irda_desc->wBaudRate & 0x0002) ? " 9600" : "", + (irda_desc->wBaudRate & 0x0004) ? " 19200" : "", + (irda_desc->wBaudRate & 0x0008) ? " 38400" : "", + (irda_desc->wBaudRate & 0x0010) ? " 57600" : "", + (irda_desc->wBaudRate & 0x0020) ? " 115200" : "", + (irda_desc->wBaudRate & 0x0040) ? " 576000" : "", + (irda_desc->wBaudRate & 0x0080) ? " 1152000" : "", + (irda_desc->wBaudRate & 0x0100) ? " 4000000" : ""); + + switch( irda_desc->bmAdditionalBOFs ) { + case 0x01: ir_add_bof = 48; break; + case 0x02: ir_add_bof = 24; break; + case 0x04: ir_add_bof = 12; break; + case 0x08: ir_add_bof = 6; break; + case 0x10: ir_add_bof = 3; break; + case 0x20: ir_add_bof = 2; break; + case 0x40: ir_add_bof = 1; break; + case 0x80: ir_add_bof = 0; break; + default: + } kfree (irda_desc); @@ -200,7 +250,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); down (&port->sem); @@ -211,7 +261,7 @@ /* override the default buffer sizes */ buffer = kmalloc (buffer_size, GFP_KERNEL); if (!buffer) { - err (__FUNCTION__ " - out of memory."); + err ("%s - out of memory.", __FUNCTION__); return -ENOMEM; } kfree (port->read_urb->transfer_buffer); @@ -220,7 +270,7 @@ buffer = kmalloc (buffer_size, GFP_KERNEL); if (!buffer) { - err (__FUNCTION__ " - out of memory."); + err ("%s - out of memory.", __FUNCTION__); return -ENOMEM; } kfree (port->write_urb->transfer_buffer); @@ -230,13 +280,18 @@ } /* Start reading from the device */ - FILL_BULK_URB(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, - ir_read_bulk_callback, port); + usb_fill_bulk_urb ( + port->read_urb, + serial->dev, + usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, + port->read_urb->transfer_buffer_length, + ir_read_bulk_callback, + port); + port->read_urb->transfer_flags = USB_QUEUE_BULK; result = usb_submit_urb(port->read_urb); if (result) - err(__FUNCTION__ " - failed submitting read urb, error %d", result); + err("%s - failed submitting read urb, error %d", __FUNCTION__, result); } up (&port->sem); @@ -251,7 +306,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); serial = get_usb_serial (port, __FUNCTION__); if (!serial) @@ -276,11 +331,12 @@ { unsigned char *transfer_buffer; int result; + int transfer_size; - dbg(__FUNCTION__ " - port = %d, count = %d", port->number, count); + dbg("%s - port = %d, count = %d", __FUNCTION__, port->number, count); if (!port->tty) { - err (__FUNCTION__ " - no tty???"); + err ("%s - no tty???", __FUNCTION__); return 0; } @@ -288,37 +344,49 @@ return 0; if (port->write_urb->status == -EINPROGRESS) { - dbg (__FUNCTION__ " - already writing"); + dbg ("%s - already writing", __FUNCTION__); return 0; } + transfer_buffer = port->write_urb->transfer_buffer; + transfer_size = min(count, port->bulk_out_size - 1); + /* - * The first byte of the packet we send to the device contains a BOD - * and baud rate change. So we set it to 0. + * The first byte of the packet we send to the device contains an + * inband header which indicates an additional number of BOFs and + * a baud rate change. + * * See section 5.4.2.2 of the USB IrDA spec. */ - transfer_buffer = port->write_urb->transfer_buffer; - count = min (port->bulk_out_size-1, count); + *transfer_buffer = ir_xbof | ir_baud; + ++transfer_buffer; + if (from_user) { - if (copy_from_user (&transfer_buffer[1], buf, count)) + if (copy_from_user (transfer_buffer, buf, transfer_size)) return -EFAULT; } else { - memcpy (&transfer_buffer[1], buf, count); + memcpy (transfer_buffer, buf, transfer_size); } - /* use 12 XBOF's as default */ - transfer_buffer[0] = 0x30; - - usb_serial_debug_data (__FILE__, __FUNCTION__, count+1, transfer_buffer); + usb_fill_bulk_urb ( + port->write_urb, + port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, + transfer_size + 1, + ir_write_bulk_callback, + port); + + port->write_urb->transfer_flags + = USB_QUEUE_BULK + | USB_ZERO_PACKET; - port->write_urb->transfer_buffer_length = count + 1; - port->write_urb->dev = port->serial->dev; - port->write_urb->transfer_flags |= USB_ZERO_PACKET; result = usb_submit_urb (port->write_urb); if (result) - err(__FUNCTION__ " - failed submitting write urb, error %d", result); + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); else - result = count; + result = transfer_size; return result; } @@ -330,13 +398,19 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (urb->status) { - dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; } + usb_serial_debug_data ( + __FILE__, + __FUNCTION__, + urb->actual_length, + urb->transfer_buffer); + queue_task(&port->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); @@ -354,34 +428,87 @@ if (port_paranoia_check (port, __FUNCTION__)) return; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) { - dbg(__FUNCTION__ " - bad serial pointer, exiting"); + dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } - if (urb->status) { - dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + if (!port->open_count) { + dbg("%s - port closed.", __FUNCTION__); return; } - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + switch (urb->status) { + + case 0: /* Successful */ + + /* + * The first byte of the packet we get from the device + * contains a busy indicator and baud rate change. + * See section 5.4.1.2 of the USB IrDA spec. + */ + if((*data & 0x0f) > 0) ir_baud = *data & 0x0f; + + usb_serial_debug_data ( + __FILE__, + __FUNCTION__, + urb->actual_length, + data); + + /* + * Bypass flip-buffers, and feed the ldisc directly + * due to our potentally large buffer size. Since we + * used to set low_latency, this is exactly what the + * tty layer did anyway :) + */ + tty = port->tty; + + tty->ldisc.receive_buf( + tty, + data+1, + NULL, + urb->actual_length-1); + + /* + * No break here. + * We want to resubmit the urb so we can read + * again. + */ + + case -EPROTO: /* taking inspiration from pl2303.c */ + + /* Continue trying to always read */ + usb_fill_bulk_urb ( + port->read_urb, + serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, + port->read_urb->transfer_buffer_length, + ir_read_bulk_callback, + port); + + port->read_urb->transfer_flags = USB_QUEUE_BULK; + + result = usb_submit_urb(port->read_urb); + + if (result) + err("%s - failed resubmitting read urb, error %d", + __FUNCTION__, + result); + + break ; + + default: + dbg("%s - nonzero read bulk status received: %d", + __FUNCTION__, + urb->status); + break ; + + } - /* Bypass flip-buffers, and feed the ldisc directly due to our - * potentally large buffer size. Since we used to set low_latency, - * this is exactly what the tty layer did anyway :) */ - tty = port->tty; - tty->ldisc.receive_buf(tty, data+1, NULL, urb->actual_length-1); - - /* Continue trying to always read */ - FILL_BULK_URB(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, - ir_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb); - if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); return; } @@ -390,12 +517,11 @@ unsigned char *transfer_buffer; unsigned int cflag; int result; - u8 baud; - dbg(__FUNCTION__ " - port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if ((!port->tty) || (!port->tty->termios)) { - dbg(__FUNCTION__" - no tty structures"); + dbg("%s - no tty structures", __FUNCTION__); return; } @@ -404,44 +530,70 @@ if (old_termios) { if ((cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { - dbg(__FUNCTION__ " - nothing to change..."); + dbg("%s - nothing to change...", __FUNCTION__); return; } } /* All we can change is the baud rate */ if (cflag & CBAUD) { - dbg (__FUNCTION__ " - asking for baud %d", tty_get_baud_rate(port->tty)); + + dbg ("%s - asking for baud %d", + __FUNCTION__, + tty_get_baud_rate(port->tty)); + /* * FIXME, we should compare the baud request against the * capability stated in the IR header that we got in the * startup funtion. */ switch (cflag & CBAUD) { - case B2400: baud = SPEED_2400; break; - case B9600: baud = SPEED_9600; break; - case B19200: baud = SPEED_19200; break; - case B38400: baud = SPEED_38400; break; - case B57600: baud = SPEED_57600; break; - case B115200: baud = SPEED_115200; break; - case B576000: baud = SPEED_576000; break; - case B1152000: baud = SPEED_1152000; break; - case B4000000: baud = SPEED_4000000; break; + case B2400: ir_baud = SPEED_2400; break; default: - err ("ir-usb driver does not support the baudrate (%d) requested", tty_get_baud_rate(port->tty)); - return; + case B9600: ir_baud = SPEED_9600; break; + case B19200: ir_baud = SPEED_19200; break; + case B38400: ir_baud = SPEED_38400; break; + case B57600: ir_baud = SPEED_57600; break; + case B115200: ir_baud = SPEED_115200; break; + case B576000: ir_baud = SPEED_576000; break; + case B1152000: ir_baud = SPEED_1152000; break; + case B4000000: ir_baud = SPEED_4000000; break; } - + + if (xbof == -1) { + ir_xbof = ir_xbof_change(ir_add_bof); + } else { + ir_xbof = ir_xbof_change(xbof) ; + } + + /* Notify the tty driver that the termios have changed. */ + port->tty->ldisc.set_termios(port->tty, NULL); + /* FIXME need to check to see if our write urb is busy right - * now, or use a urb pool. */ - /* send the baud change out on an "empty" data packet */ + * now, or use a urb pool. + * + * send the baud change out on an "empty" data packet + */ transfer_buffer = port->write_urb->transfer_buffer; - transfer_buffer[0] = baud; - port->write_urb->transfer_buffer_length = 1; - port->write_urb->dev = port->serial->dev; + *transfer_buffer = ir_xbof | ir_baud; + + usb_fill_bulk_urb ( + port->write_urb, + port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, + 1, + ir_write_bulk_callback, + port); + + port->write_urb->transfer_flags + = USB_QUEUE_BULK + | USB_ZERO_PACKET; + result = usb_submit_urb (port->write_urb); if (result) - err(__FUNCTION__ " - failed submitting write urb, error %d", result); + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); } return; } @@ -470,6 +622,8 @@ MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); +MODULE_PARM(xbof, "i"); +MODULE_PARM_DESC(xbof, "Force specific number of XBOFs"); MODULE_PARM(buffer_size, "i"); MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers"); diff -urN linux-2.5.3-pre1/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c --- linux-2.5.3-pre1/drivers/usb/serial/keyspan.c Sun Jan 6 18:49:21 2002 +++ linux/drivers/usb/serial/keyspan.c Sat Jan 19 16:58:39 2002 @@ -178,15 +178,7 @@ /* Functions used by new usb-serial code. */ static int __init keyspan_init (void) { - usb_serial_register (&keyspan_usa18x_pre_device); - usb_serial_register (&keyspan_usa19_pre_device); - usb_serial_register (&keyspan_usa19w_pre_device); - usb_serial_register (&keyspan_usa28_pre_device); - usb_serial_register (&keyspan_usa28x_pre_device); - usb_serial_register (&keyspan_usa28xa_pre_device); - usb_serial_register (&keyspan_usa28xb_pre_device); - usb_serial_register (&keyspan_usa49w_pre_device); - + usb_serial_register (&keyspan_pre_device); usb_serial_register (&keyspan_usa18x_device); usb_serial_register (&keyspan_usa19_device); usb_serial_register (&keyspan_usa19w_device); @@ -203,15 +195,7 @@ static void __exit keyspan_exit (void) { - usb_serial_deregister (&keyspan_usa18x_pre_device); - usb_serial_deregister (&keyspan_usa19_pre_device); - usb_serial_deregister (&keyspan_usa19w_pre_device); - usb_serial_deregister (&keyspan_usa28_pre_device); - usb_serial_deregister (&keyspan_usa28x_pre_device); - usb_serial_deregister (&keyspan_usa28xa_pre_device); - usb_serial_deregister (&keyspan_usa28xb_pre_device); - usb_serial_deregister (&keyspan_usa49w_pre_device); - + usb_serial_deregister (&keyspan_pre_device); usb_serial_deregister (&keyspan_usa18x_device); usb_serial_deregister (&keyspan_usa19_device); usb_serial_deregister (&keyspan_usa19w_device); diff -urN linux-2.5.3-pre1/drivers/usb/serial/keyspan.h linux/drivers/usb/serial/keyspan.h --- linux-2.5.3-pre1/drivers/usb/serial/keyspan.h Sun Jan 6 18:49:21 2002 +++ linux/drivers/usb/serial/keyspan.h Sat Jan 19 16:58:39 2002 @@ -372,42 +372,15 @@ ID pattern. But, for now, it looks like we need slightly different behavior for each match. */ -static __devinitdata struct usb_device_id keyspan_usa18x_pre_ids[] = { +/* usb_device_id table for the pre-firmware download keyspan devices */ +static __devinitdata struct usb_device_id keyspan_pre_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, - { } /* Terminating entry */ -}; - -static __devinitdata struct usb_device_id keyspan_usa19_pre_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) }, - { } /* Terminating entry */ -}; - -static __devinitdata struct usb_device_id keyspan_usa19w_pre_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) }, - { } /* Terminating entry */ -}; - -static __devinitdata struct usb_device_id keyspan_usa28_pre_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) }, - { } /* Terminating entry */ -}; - -static __devinitdata struct usb_device_id keyspan_usa28x_pre_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) }, - { } /* Terminating entry */ -}; - -static __devinitdata struct usb_device_id keyspan_usa28xa_pre_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) }, - { } /* Terminating entry */ -}; - -static __devinitdata struct usb_device_id keyspan_usa28xb_pre_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) }, - { } /* Terminating entry */ -}; - -static __devinitdata struct usb_device_id keyspan_usa49w_pre_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) }, { } /* Terminating entry */ }; @@ -448,10 +421,10 @@ }; /* Structs for the devices, pre and post renumeration. */ -static struct usb_serial_device_type keyspan_usa18x_pre_device = { +static struct usb_serial_device_type keyspan_pre_device = { owner: THIS_MODULE, - name: "Keyspan USA18X - (without firmware)", - id_table: keyspan_usa18x_pre_ids, + name: "Keyspan - (without firmware)", + id_table: keyspan_pre_ids, num_interrupt_in: NUM_DONT_CARE, num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, @@ -459,84 +432,6 @@ startup: keyspan_fake_startup }; -static struct usb_serial_device_type keyspan_usa19_pre_device = { - owner: THIS_MODULE, - name: "Keyspan USA19 - (without firmware)", - id_table: keyspan_usa19_pre_ids, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 1, - startup: keyspan_fake_startup -}; - - -static struct usb_serial_device_type keyspan_usa19w_pre_device = { - owner: THIS_MODULE, - name: "Keyspan USA19W - (without firmware)", - id_table: keyspan_usa19w_pre_ids, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 1, - startup: keyspan_fake_startup -}; - - -static struct usb_serial_device_type keyspan_usa28_pre_device = { - owner: THIS_MODULE, - name: "Keyspan USA28 - (without firmware)", - id_table: keyspan_usa28_pre_ids, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 2, - startup: keyspan_fake_startup -}; - -static struct usb_serial_device_type keyspan_usa28x_pre_device = { - owner: THIS_MODULE, - name: "Keyspan USA28X - (without firmware)", - id_table: keyspan_usa28x_pre_ids, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 2, - startup: keyspan_fake_startup -}; - -static struct usb_serial_device_type keyspan_usa28xa_pre_device = { - owner: THIS_MODULE, - name: "Keyspan USA28XA - (without firmware)", - id_table: keyspan_usa28xa_pre_ids, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 2, - startup: keyspan_fake_startup -}; - -static struct usb_serial_device_type keyspan_usa28xb_pre_device = { - owner: THIS_MODULE, - name: "Keyspan USA28XB - (without firmware)", - id_table: keyspan_usa28xb_pre_ids, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 2, - startup: keyspan_fake_startup -}; - -static struct usb_serial_device_type keyspan_usa49w_pre_device = { - owner: THIS_MODULE, - name: "Keyspan USA49W - (without firmware)", - id_table: keyspan_usa49w_pre_ids, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 4, - startup: keyspan_fake_startup -}; static struct usb_serial_device_type keyspan_usa18x_device = { owner: THIS_MODULE, @@ -550,8 +445,6 @@ close: keyspan_close, write: keyspan_write, write_room: keyspan_write_room, - //write_bulk_callback: Not used - we define our own herbs - //read_int_callback: keyspan_usa26_read_int_callback, chars_in_buffer: keyspan_chars_in_buffer, throttle: keyspan_rx_throttle, unthrottle: keyspan_rx_unthrottle, @@ -574,8 +467,6 @@ close: keyspan_close, write: keyspan_write, write_room: keyspan_write_room, -// write_bulk_callback: keyspan_write_bulk_callback, -// read_int_callback: keyspan_usa28_read_int_callback, chars_in_buffer: keyspan_chars_in_buffer, throttle: keyspan_rx_throttle, unthrottle: keyspan_rx_unthrottle, @@ -599,8 +490,6 @@ close: keyspan_close, write: keyspan_write, write_room: keyspan_write_room, - //write_bulk_callback: Not used - we define our own herbs - //read_int_callback: keyspan_usa26_read_int_callback, chars_in_buffer: keyspan_chars_in_buffer, throttle: keyspan_rx_throttle, unthrottle: keyspan_rx_unthrottle, @@ -640,8 +529,6 @@ close: keyspan_close, write: keyspan_write, write_room: keyspan_write_room, -// write_bulk_callback: keyspan_write_bulk_callback, -// read_int_callback: keyspan_usa26_read_int_callback, chars_in_buffer: keyspan_chars_in_buffer, throttle: keyspan_rx_throttle, unthrottle: keyspan_rx_unthrottle, @@ -665,8 +552,6 @@ close: keyspan_close, write: keyspan_write, write_room: keyspan_write_room, -// write_bulk_callback: keyspan_write_bulk_callback, -// read_int_callback: keyspan_usa26_read_int_callback, chars_in_buffer: keyspan_chars_in_buffer, throttle: keyspan_rx_throttle, unthrottle: keyspan_rx_unthrottle, @@ -690,8 +575,6 @@ close: keyspan_close, write: keyspan_write, write_room: keyspan_write_room, - //write_bulk_callback: Not used - we define our own herbs - //read_int_callback: keyspan_usa26_read_int_callback, chars_in_buffer: keyspan_chars_in_buffer, throttle: keyspan_rx_throttle, unthrottle: keyspan_rx_unthrottle, diff -urN linux-2.5.3-pre1/drivers/usb/storage/protocol.c linux/drivers/usb/storage/protocol.c --- linux-2.5.3-pre1/drivers/usb/storage/protocol.c Sun Jul 29 21:11:50 2001 +++ linux/drivers/usb/storage/protocol.c Sat Jan 19 16:58:39 2002 @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: protocol.c,v 1.10 2001/07/30 00:27:59 mdharm Exp $ + * $Id: protocol.c,v 1.11 2002/01/13 06:40:25 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -76,7 +76,7 @@ data_ptr = (unsigned char *)srb->request_buffer; /* Change the SCSI revision number */ - data_ptr[2] |= 0x2; + data_ptr[2] = (data_ptr[2] & ~7) | 2; } /*********************************************************************** diff -urN linux-2.5.3-pre1/drivers/usb/storage/unusual_devs.h linux/drivers/usb/storage/unusual_devs.h --- linux-2.5.3-pre1/drivers/usb/storage/unusual_devs.h Mon Jan 14 13:30:20 2002 +++ linux/drivers/usb/storage/unusual_devs.h Sat Jan 19 16:58:39 2002 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Ununsual Devices File * - * $Id: unusual_devs.h,v 1.24 2001/12/29 03:12:45 mdharm Exp $ + * $Id: unusual_devs.h,v 1.25 2002/01/13 06:39:17 mdharm Exp $ * * Current development and maintenance by: * (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -458,6 +458,14 @@ US_SC_ISD200, US_PR_BULK, isd200_Initialization, 0 ), #endif + +/* Submitted by Brian Hall + * Needed for START_STOP flag */ +UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100, + "JMTek", + "USBDrive", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_START_STOP ), /* Reported by Dan Pilone * The device needs the flags only. diff -urN linux-2.5.3-pre1/drivers/usb/storage/usb.c linux/drivers/usb/storage/usb.c --- linux-2.5.3-pre1/drivers/usb/storage/usb.c Sat Jan 19 16:58:37 2002 +++ linux/drivers/usb/storage/usb.c Sat Jan 19 16:58:39 2002 @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: usb.c,v 1.69 2001/11/11 03:33:03 mdharm Exp $ + * $Id: usb.c,v 1.70 2002/01/06 07:14:12 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -315,6 +315,13 @@ * so get rid of all our resources.. */ daemonize(); + + /* avoid getting signals */ + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); /* set our name for identification purposes */ sprintf(current->comm, "usb-storage-%d", us->host_number); diff -urN linux-2.5.3-pre1/drivers/usb/stv680.c linux/drivers/usb/stv680.c --- linux-2.5.3-pre1/drivers/usb/stv680.c Sat Jan 19 16:58:37 2002 +++ linux/drivers/usb/stv680.c Sat Jan 19 16:58:39 2002 @@ -43,6 +43,13 @@ * Took out sharpen function, ran code through * Lindent, and did other minor tweaks to get * things to work properly with 2.5.1 + * + * ver 0.24 Jan, 2002 (kjs) + * Fixed the problem with webcam crashing after + * two pictures. Changed the way pic is halved to + * improve quality. Got rid of green line around + * frame. Fix brightness reset when changing size + * bug. Adjusted gamma filters slightly. */ #include @@ -65,7 +72,8 @@ #include "stv680.h" static int video_nr = -1; -static int swapRGB = 0; +static int swapRGB = 0; /* default for auto sleect */ +static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */ static unsigned int debug = 0; @@ -79,7 +87,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.23" +#define DRIVER_VERSION "v0.24" #define DRIVER_AUTHOR "Kevin Sisson " #define DRIVER_DESC "STV0680 USB Camera Driver" @@ -88,8 +96,8 @@ MODULE_LICENSE ("GPL"); MODULE_PARM (debug, "i"); MODULE_PARM_DESC (debug, "Debug enabled or not"); -MODULE_PARM (swapRGB, "i"); -MODULE_PARM_DESC (swapRGB, "Swap red and blue, e.g., for xawtv"); +MODULE_PARM (swapRGB_on, "i"); +MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never"); MODULE_PARM (video_nr, "i"); EXPORT_NO_SYMBOLS; @@ -521,8 +529,15 @@ stv680->palette = STV_VIDEO_PALETTE; stv680->depth = 24; /* rgb24 bits */ swapRGB = 0; - PDEBUG (1, "STV(i): swapRGB is OFF"); - + if ((swapRGB_on == 0) && (swapRGB == 0)) + PDEBUG (1, "STV(i): swapRGB is (auto) OFF"); + else if ((swapRGB_on == 1) && (swapRGB == 1)) + PDEBUG (1, "STV(i): swapRGB is (auto) ON"); + else if (swapRGB_on == 1) + PDEBUG (1, "STV(i): swapRGB is (forced) ON"); + else if (swapRGB_on == -1) + PDEBUG (1, "STV(i): swapRGB is (forced) OFF"); + if (stv_set_video_mode (stv680) < 0) { PDEBUG (0, "STV(e): Could not set video mode in stv_init"); return -1; @@ -543,6 +558,7 @@ extern struct proc_dir_entry *video_proc_entry; #define YES_NO(x) ((x) ? "yes" : "no") +#define ON_OFF(x) ((x) ? "(auto) on" : "(auto) off") static int stv680_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -559,7 +575,13 @@ out += sprintf (out, "num_frames : %d\n", STV680_NUMFRAMES); out += sprintf (out, "Current size : %ix%i\n", stv680->vwidth, stv680->vheight); - out += sprintf (out, "swapRGB : %s\n", YES_NO (swapRGB)); + if (swapRGB_on == 0) + out += sprintf (out, "swapRGB : %s\n", ON_OFF (swapRGB)); + else if (swapRGB_on == 1) + out += sprintf (out, "swapRGB : (forced) on\n"); + else if (swapRGB_on == -1) + out += sprintf (out, "swapRGB : (forced) off\n"); + out += sprintf (out, "Palette : %i", stv680->palette); out += sprintf (out, "\n"); @@ -671,9 +693,7 @@ if (stv680->brightness != p->brightness) { stv680->chgbright = 1; stv680->brightness = p->brightness; - } else { - stv680->chgbright = 0; - } + } stv680->whiteness = p->whiteness; /* greyscale */ stv680->colour = p->colour; @@ -888,7 +908,7 @@ { int x, y, i; int w = stv680->cwidth; - int vw = stv680->cwidth, vh = stv680->cheight, vstep = 1; + int vw = stv680->cwidth, vh = stv680->cheight; unsigned int p = 0; int colour = 0, bayer = 0; unsigned char *raw = buffer->data; @@ -908,46 +928,23 @@ return; } - if ((stv680->vwidth == 322) || (stv680->vwidth == 320)) { + if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) { vw = 320; vh = 240; - vstep = 1; } - if ((stv680->vwidth == 352)) { + if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) { vw = 352; vh = 288; - vstep = 1; } - if ((stv680->vwidth == 160)) { - vw = 160; - vh = 120; - vstep = 2; - } - if ((stv680->vwidth == 176)) { - vw = 176; - vh = 144; - vstep = 2; - } - memset (output, 0, 3 * vw * vh); /* clear output matrix. Maybe not necessary. */ + + memset (output, 0, 3 * vw * vh); /* clear output matrix. */ for (y = 0; y < vh; y++) { for (x = 0; x < vw; x++) { - - switch (vstep) { - case 1: - if (x & 1) - p = *(raw + y * w + (x >> 1)); - else - p = *(raw + y * w + (x >> 1) + (w >> 1)); - break; - - case 2: - if (x & 1) - p = *(raw + ((y * w) << 1) + x); - else - p = *(raw + ((y * w) << 1) + x + (w >> 1)); - break; - } + if (x & 1) + p = *(raw + y * w + (x >> 1)); + else + p = *(raw + y * w + (x >> 1) + (w >> 1)); if (y & 1) bayer = 2; @@ -968,9 +965,10 @@ colour = 2; break; } - i = (y * vw + x) * 3; /* output already zeroed out with memset */ + i = (y * vw + x) * 3; *(output + i + colour) = (unsigned char) p; } /* for x */ + } /* for y */ /****** gamma correction plus hardcoded white balance */ @@ -979,6 +977,7 @@ (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1vwidth == 160) || (stv680->vwidth == 176)) { + i = 0; + for (y = 0; y < vh; y++) { + if (!(y & 1)) { + for (x = 0; x < vw; x++) { + p = (y * vw + x) * 3; + if (!(x & 1)) { + *(output + i) = *(output + p); + *(output + i + 1) = *(output + p + 1); + *(output + i + 2) = *(output + p + 2); + i += 3; + } + } /* for x */ + } + } /* for y */ + } + /* reset to proper width */ + if ((stv680->vwidth == 160)) { + vw = 160; + vh = 120; + } + if ((stv680->vwidth == 176)) { + vw = 176; + vh = 144; + } + /* output is RGB; some programs want BGR */ - if (swapRGB == 1) { + /* swapRGB_on=0 -> program decides; swapRGB_on=1, always swap */ + /* swapRGB_on=-1, never swap */ + if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) { for (y = 0; y < vh; y++) { for (x = 0; x < vw; x++) { i = (y * vw + x) * 3; @@ -1242,7 +1280,7 @@ return -EFAULT; } copy_from_user (&p, arg, sizeof (p)); - PDEBUG (2, "STV(i): palette set to RGB in VIDIOSPICT"); + PDEBUG (2, "STV(i): palette set to %i in VIDIOSPICT", p.palette); if (stv680_set_pict (stv680, &p)) return -EINVAL; @@ -1309,8 +1347,8 @@ if (vm.format != STV_VIDEO_PALETTE) { PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)", vm.format, STV_VIDEO_PALETTE); - if (vm.format == 3) { - PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is ON"); + if ((vm.format == 3) && (swapRGB_on == 0)) { + PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON"); /* this may fix those apps (e.g., xawtv) that want BGR */ swapRGB = 1; } @@ -1320,8 +1358,10 @@ PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES"); return -EINVAL; } - if (stv680->frame[vm.frame].grabstate != FRAME_UNUSED) { - PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate != FRAME_UNUSED"); + if ((stv680->frame[vm.frame].grabstate == FRAME_ERROR) + || (stv680->frame[vm.frame].grabstate == FRAME_GRABBING)) { + PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error", + stv680->frame[vm.frame].grabstate); return -EBUSY; } /* Is this according to the v4l spec??? */ diff -urN linux-2.5.3-pre1/drivers/usb/stv680.h linux/drivers/usb/stv680.h --- linux-2.5.3-pre1/drivers/usb/stv680.h Thu Jan 3 13:21:28 2002 +++ linux/drivers/usb/stv680.h Sat Jan 19 16:58:39 2002 @@ -43,7 +43,7 @@ #define USB_PENCAM_PRODUCT_ID 0x0202 #define PENCAM_TIMEOUT 1000 /* fmt 4 */ -#define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24 +#define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24 static __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)}, @@ -146,77 +146,78 @@ int nullpackets; }; -unsigned char red[256] = { - 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, - 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, - 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, - 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, - 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, - 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, - 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, - 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, - 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, - 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, - 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, - 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, - 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, - 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, - 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, - 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, - 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, - 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, - 245, 245, 246, 246 -}; + +unsigned char red[256] = { + 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, + 44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, + 71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, + 88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, + 134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, + 143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, + 152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, + 159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, + 167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, + 173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, + 180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, + 187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, + 192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, + 198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, + 204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, + 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, + 215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, + 220, 220, 221, 221 +}; unsigned char green[256] = { - 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 32, 39, 45, 50, 54, - 58, 62, 65, 69, 71, 74, 77, 79, 83, 85, 87, 90, - 92, 93, 95, 98, 100, 101, 104, 106, 107, 109, 111, 113, - 114, 116, 118, 119, 121, 122, 124, 126, 127, 128, 129, 132, - 133, 134, 135, 136, 138, 140, 141, 142, 143, 145, 146, 147, - 148, 149, 150, 152, 153, 154, 155, 156, 157, 159, 160, 161, - 162, 163, 164, 166, 167, 168, 168, 169, 170, 171, 173, 174, - 175, 176, 176, 177, 179, 180, 181, 182, 182, 183, 184, 186, - 187, 187, 188, 189, 190, 191, 191, 193, 194, 195, 195, 196, - 197, 198, 198, 200, 201, 201, 202, 203, 204, 204, 205, 207, - 207, 208, 209, 209, 210, 211, 212, 212, 214, 215, 215, 216, - 217, 217, 218, 218, 219, 221, 221, 222, 223, 223, 224, 225, - 225, 226, 226, 228, 229, 229, 230, 231, 231, 232, 232, 233, - 235, 235, 236, 236, 237, 238, 238, 239, 239, 241, 241, 242, - 243, 243, 244, 244, 245, 245, 246, 248, 248, 249, 249, 250, - 250, 251, 251, 252, 253, 253, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255 -}; + 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, + 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, + 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, + 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, + 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, + 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, + 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, + 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, + 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, + 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, + 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, + 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, + 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, + 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, + 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, + 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, + 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, + 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, + 245, 245, 246, 246 +}; unsigned char blue[256] = { - 0, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 41, 50, 57, 63, 69, - 74, 78, 82, 87, 90, 94, 97, 100, 105, 108, 111, 113, - 116, 118, 121, 124, 127, 128, 131, 134, 136, 139, 140, 143, - 145, 148, 149, 150, 153, 155, 156, 159, 161, 162, 164, 167, - 168, 170, 171, 173, 174, 177, 179, 180, 182, 183, 185, 186, - 187, 189, 190, 192, 193, 195, 196, 198, 199, 201, 202, 204, - 205, 207, 208, 210, 211, 213, 213, 214, 216, 217, 219, 220, - 222, 223, 223, 224, 226, 227, 229, 230, 230, 232, 233, 235, - 236, 236, 238, 239, 241, 242, 242, 244, 245, 247, 247, 248, - 250, 251, 251, 253, 254, 254, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255 -}; + 0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, + 55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, + 86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, + 107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, + 125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, + 165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, + 176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, + 185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, + 194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, + 204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, + 212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, + 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, + 228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, + 235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, + 243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, + 249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255 +}; diff -urN linux-2.5.3-pre1/drivers/usb/usb.c linux/drivers/usb/usb.c --- linux-2.5.3-pre1/drivers/usb/usb.c Sun Jan 6 18:49:21 2002 +++ linux/drivers/usb/usb.c Sat Jan 19 16:58:39 2002 @@ -2252,6 +2252,14 @@ return -EINVAL; } + /* 9.4.10 says devices don't need this, if the interface + only has one alternate setting */ + if (iface->num_altsetting == 1) { + warn("ignoring set_interface for dev %d, iface %d, alt %d", + dev->devnum, interface, alternate); + return 0; + } + if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate, interface, NULL, 0, HZ * 5)) < 0) diff -urN linux-2.5.3-pre1/drivers/video/vesafb.c linux/drivers/video/vesafb.c --- linux-2.5.3-pre1/drivers/video/vesafb.c Sat Jan 19 16:58:37 2002 +++ linux/drivers/video/vesafb.c Thu Jan 3 12:20:18 2002 @@ -550,7 +550,7 @@ ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */ if (ypan || pmi_setpal) { - pmi_base = (unsigned short*)isa_bus_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off); + pmi_base = (unsigned short*)bus_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off); pmi_start = (void*)((char*)pmi_base + pmi_base[1]); pmi_pal = (void*)((char*)pmi_base + pmi_base[2]); printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal); diff -urN linux-2.5.3-pre1/fs/Makefile.lib linux/fs/Makefile.lib --- linux-2.5.3-pre1/fs/Makefile.lib Thu Jan 10 16:23:46 2002 +++ linux/fs/Makefile.lib Sat Jan 19 16:58:39 2002 @@ -1,2 +1,2 @@ -obj-$(CONFIG_FS_JFFS2) += crc32.o +obj-$(CONFIG_JFFS2_FS) += crc32.o obj-$(CONFIG_EFI_PARTITION) += crc32.o diff -urN linux-2.5.3-pre1/fs/binfmt_misc.c linux/fs/binfmt_misc.c --- linux-2.5.3-pre1/fs/binfmt_misc.c Sat Oct 20 19:14:42 2001 +++ linux/fs/binfmt_misc.c Sat Jan 19 16:58:39 2002 @@ -49,6 +49,8 @@ } Node; static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED; +static struct vfsmount *bm_mnt; +static int entry_count = 0; /* * Check if we support the binfmt @@ -390,10 +392,15 @@ Node *e = inode->u.generic_ip; if (e) { + struct vfsmount *mnt; write_lock(&entries_lock); list_del(&e->list); + mnt = bm_mnt; + if (!--entry_count) + bm_mnt = NULL; write_unlock(&entries_lock); kfree(e); + mntput(mnt); } } @@ -404,8 +411,7 @@ write_lock(&entries_lock); dentry = e->dentry; if (dentry) { - list_del(&e->list); - INIT_LIST_HEAD(&e->list); + list_del_init(&e->list); e->dentry = NULL; } write_unlock(&entries_lock); @@ -484,12 +490,16 @@ write: bm_entry_write, }; +static struct file_system_type bm_fs_type; + /* /register */ static ssize_t bm_register_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { Node *e; + struct inode *inode; + struct vfsmount *mnt = NULL; struct dentry *root, *dentry; struct super_block *sb = file->f_vfsmnt->mnt_sb; int err = 0; @@ -503,31 +513,52 @@ down(&root->d_inode->i_sem); dentry = lookup_one_len(e->name, root, strlen(e->name)); err = PTR_ERR(dentry); - if (!IS_ERR(dentry)) { - down(&root->d_inode->i_zombie); - if (dentry->d_inode) { - err = -EEXIST; - } else { - struct inode * inode = bm_get_inode(sb, S_IFREG | 0644); - err = -ENOMEM; + if (IS_ERR(dentry)) + goto out; - if (inode) { - write_lock(&entries_lock); + down(&root->d_inode->i_zombie); - e->dentry = dget(dentry); - inode->u.generic_ip = e; - inode->i_fop = &bm_entry_operations; - d_instantiate(dentry, inode); + err = -EEXIST; + if (dentry->d_inode) + goto out2; - list_add(&e->list, &entries); - write_unlock(&entries_lock); + inode = bm_get_inode(sb, S_IFREG | 0644); - err = 0; - } + err = -ENOMEM; + if (!inode) + goto out2; + + write_lock(&entries_lock); + if (!bm_mnt) { + write_unlock(&entries_lock); + mnt = kern_mount(&bm_fs_type); + if (IS_ERR(mnt)) { + err = PTR_ERR(mnt); + iput(inode); + inode = NULL; + goto out2; } - up(&root->d_inode->i_zombie); - dput(dentry); + write_lock(&entries_lock); + if (!bm_mnt) + bm_mnt = mnt; } + mntget(bm_mnt); + entry_count++; + + e->dentry = dget(dentry); + inode->u.generic_ip = e; + inode->i_fop = &bm_entry_operations; + d_instantiate(dentry, inode); + + list_add(&e->list, &entries); + write_unlock(&entries_lock); + + mntput(mnt); + err = 0; +out2: + up(&root->d_inode->i_zombie); + dput(dentry); +out: up(&root->d_inode->i_sem); dput(root); @@ -687,23 +718,13 @@ static DECLARE_FSTYPE(bm_fs_type, "binfmt_misc", bm_read_super, FS_SINGLE|FS_LITTER); -static struct vfsmount *bm_mnt; - static int __init init_misc_binfmt(void) { int err = register_filesystem(&bm_fs_type); if (!err) { - bm_mnt = kern_mount(&bm_fs_type); - err = PTR_ERR(bm_mnt); - if (IS_ERR(bm_mnt)) + err = register_binfmt(&misc_format); + if (err) unregister_filesystem(&bm_fs_type); - else { - err = register_binfmt(&misc_format); - if (err) { - unregister_filesystem(&bm_fs_type); - kern_umount(bm_mnt); - } - } } return err; } @@ -712,7 +733,6 @@ { unregister_binfmt(&misc_format); unregister_filesystem(&bm_fs_type); - kern_umount(bm_mnt); } EXPORT_NO_SYMBOLS; diff -urN linux-2.5.3-pre1/fs/block_dev.c linux/fs/block_dev.c --- linux-2.5.3-pre1/fs/block_dev.c Mon Jan 14 09:38:37 2002 +++ linux/fs/block_dev.c Sat Jan 19 16:58:39 2002 @@ -220,17 +220,19 @@ static struct super_block *bd_read_super(struct super_block *sb, void *data, int silent) { static struct super_operations sops = {}; - struct inode *root = new_inode(sb); - if (!root) - return NULL; - root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; - root->i_uid = root->i_gid = 0; - root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; + struct inode *root; + sb->s_maxbytes = ~0ULL; sb->s_blocksize = 1024; sb->s_blocksize_bits = 10; sb->s_magic = 0x62646576; sb->s_op = &sops; + root = new_inode(sb); + if (!root) + return NULL; + root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; + root->i_uid = root->i_gid = 0; + root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; sb->s_root = d_alloc(NULL, &(const struct qstr) { "bdev:", 5, 0 }); if (!sb->s_root) { iput(root); diff -urN linux-2.5.3-pre1/fs/buffer.c linux/fs/buffer.c --- linux-2.5.3-pre1/fs/buffer.c Mon Jan 14 09:38:37 2002 +++ linux/fs/buffer.c Sat Jan 19 16:58:39 2002 @@ -582,23 +582,13 @@ return bh; } -void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode) +void buffer_insert_list(struct buffer_head *bh, struct list_head *list) { spin_lock(&lru_list_lock); if (bh->b_inode) list_del(&bh->b_inode_buffers); - bh->b_inode = inode; - list_add(&bh->b_inode_buffers, &inode->i_dirty_buffers); - spin_unlock(&lru_list_lock); -} - -void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode) -{ - spin_lock(&lru_list_lock); - if (bh->b_inode) - list_del(&bh->b_inode_buffers); - bh->b_inode = inode; - list_add(&bh->b_inode_buffers, &inode->i_dirty_data_buffers); + bh->b_inode = 1; + list_add(&bh->b_inode_buffers, list); spin_unlock(&lru_list_lock); } @@ -606,7 +596,7 @@ remove_inode_queue functions. */ static void __remove_inode_queue(struct buffer_head *bh) { - bh->b_inode = NULL; + bh->b_inode = 0; list_del(&bh->b_inode_buffers); } @@ -826,73 +816,24 @@ * any newly dirty buffers for write. */ -int fsync_inode_buffers(struct inode *inode) -{ - struct buffer_head *bh; - struct inode tmp; - int err = 0, err2; - - INIT_LIST_HEAD(&tmp.i_dirty_buffers); - - spin_lock(&lru_list_lock); - - while (!list_empty(&inode->i_dirty_buffers)) { - bh = BH_ENTRY(inode->i_dirty_buffers.next); - list_del(&bh->b_inode_buffers); - if (!buffer_dirty(bh) && !buffer_locked(bh)) - bh->b_inode = NULL; - else { - bh->b_inode = &tmp; - list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers); - if (buffer_dirty(bh)) { - get_bh(bh); - spin_unlock(&lru_list_lock); - ll_rw_block(WRITE, 1, &bh); - brelse(bh); - spin_lock(&lru_list_lock); - } - } - } - - while (!list_empty(&tmp.i_dirty_buffers)) { - bh = BH_ENTRY(tmp.i_dirty_buffers.prev); - remove_inode_queue(bh); - get_bh(bh); - spin_unlock(&lru_list_lock); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) - err = -EIO; - brelse(bh); - spin_lock(&lru_list_lock); - } - - spin_unlock(&lru_list_lock); - err2 = osync_inode_buffers(inode); - - if (err) - return err; - else - return err2; -} - -int fsync_inode_data_buffers(struct inode *inode) +int fsync_buffers_list(struct list_head *list) { struct buffer_head *bh; - struct inode tmp; + struct list_head tmp; int err = 0, err2; - INIT_LIST_HEAD(&tmp.i_dirty_data_buffers); + INIT_LIST_HEAD(&tmp); spin_lock(&lru_list_lock); - while (!list_empty(&inode->i_dirty_data_buffers)) { - bh = BH_ENTRY(inode->i_dirty_data_buffers.next); + while (!list_empty(list)) { + bh = BH_ENTRY(list->next); list_del(&bh->b_inode_buffers); if (!buffer_dirty(bh) && !buffer_locked(bh)) - bh->b_inode = NULL; + bh->b_inode = 0; else { - bh->b_inode = &tmp; - list_add(&bh->b_inode_buffers, &tmp.i_dirty_data_buffers); + bh->b_inode = 1; + list_add(&bh->b_inode_buffers, &tmp); if (buffer_dirty(bh)) { get_bh(bh); spin_unlock(&lru_list_lock); @@ -903,8 +844,8 @@ } } - while (!list_empty(&tmp.i_dirty_data_buffers)) { - bh = BH_ENTRY(tmp.i_dirty_data_buffers.prev); + while (!list_empty(&tmp)) { + bh = BH_ENTRY(tmp.prev); remove_inode_queue(bh); get_bh(bh); spin_unlock(&lru_list_lock); @@ -916,7 +857,7 @@ } spin_unlock(&lru_list_lock); - err2 = osync_inode_data_buffers(inode); + err2 = osync_buffers_list(list); if (err) return err; @@ -935,19 +876,19 @@ * write will not be flushed to disk by the osync. */ -int osync_inode_buffers(struct inode *inode) +int osync_buffers_list(struct list_head *list) { struct buffer_head *bh; - struct list_head *list; + struct list_head *p; int err = 0; spin_lock(&lru_list_lock); repeat: - for (list = inode->i_dirty_buffers.prev; - bh = BH_ENTRY(list), list != &inode->i_dirty_buffers; - list = bh->b_inode_buffers.prev) { + for (p = list->prev; + bh = BH_ENTRY(p), p != list; + p = bh->b_inode_buffers.prev) { if (buffer_locked(bh)) { get_bh(bh); spin_unlock(&lru_list_lock); @@ -963,36 +904,6 @@ spin_unlock(&lru_list_lock); return err; } - -int osync_inode_data_buffers(struct inode *inode) -{ - struct buffer_head *bh; - struct list_head *list; - int err = 0; - - spin_lock(&lru_list_lock); - - repeat: - - for (list = inode->i_dirty_data_buffers.prev; - bh = BH_ENTRY(list), list != &inode->i_dirty_data_buffers; - list = bh->b_inode_buffers.prev) { - if (buffer_locked(bh)) { - get_bh(bh); - spin_unlock(&lru_list_lock); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) - err = -EIO; - brelse(bh); - spin_lock(&lru_list_lock); - goto repeat; - } - } - - spin_unlock(&lru_list_lock); - return err; -} - /* * Invalidate any and all dirty buffers on a given inode. We are diff -urN linux-2.5.3-pre1/fs/devpts/inode.c linux/fs/devpts/inode.c --- linux-2.5.3-pre1/fs/devpts/inode.c Thu Oct 25 00:02:26 2001 +++ linux/fs/devpts/inode.c Sat Jan 19 16:58:39 2002 @@ -139,6 +139,11 @@ printk("devpts: called with bogus options\n"); goto fail_free; } + s->u.generic_sbp = (void *) sbi; + s->s_blocksize = 1024; + s->s_blocksize_bits = 10; + s->s_magic = DEVPTS_SUPER_MAGIC; + s->s_op = &devpts_sops; inode = new_inode(s); if (!inode) @@ -153,11 +158,6 @@ inode->i_fop = &devpts_root_operations; inode->i_nlink = 2; - s->u.generic_sbp = (void *) sbi; - s->s_blocksize = 1024; - s->s_blocksize_bits = 10; - s->s_magic = DEVPTS_SUPER_MAGIC; - s->s_op = &devpts_sops; s->s_root = d_alloc_root(inode); if (s->s_root) return s; diff -urN linux-2.5.3-pre1/fs/ext2/balloc.c linux/fs/ext2/balloc.c --- linux-2.5.3-pre1/fs/ext2/balloc.c Sun Dec 16 12:23:00 2001 +++ linux/fs/ext2/balloc.c Sat Jan 19 16:58:39 2002 @@ -42,19 +42,20 @@ unsigned long group_desc; unsigned long desc; struct ext2_group_desc * gdp; + struct ext2_sb_info *sbi = &sb->u.ext2_sb; - if (block_group >= sb->u.ext2_sb.s_groups_count) { + if (block_group >= sbi->s_groups_count) { ext2_error (sb, "ext2_get_group_desc", "block_group >= groups_count - " "block_group = %d, groups_count = %lu", - block_group, sb->u.ext2_sb.s_groups_count); + block_group, sbi->s_groups_count); return NULL; } group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); desc = block_group % EXT2_DESC_PER_BLOCK(sb); - if (!sb->u.ext2_sb.s_group_desc[group_desc]) { + if (!sbi->s_group_desc[group_desc]) { ext2_error (sb, "ext2_get_group_desc", "Group descriptor not loaded - " "block_group = %d, group_desc = %lu, desc = %lu", @@ -62,10 +63,9 @@ return NULL; } - gdp = (struct ext2_group_desc *) - sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + gdp = (struct ext2_group_desc *) sbi->s_group_desc[group_desc]->b_data; if (bh) - *bh = sb->u.ext2_sb.s_group_desc[group_desc]; + *bh = sbi->s_group_desc[group_desc]; return gdp + desc; } @@ -73,37 +73,26 @@ * Read the bitmap for a given block_group, reading into the specified * slot in the superblock's bitmap cache. * - * Return >=0 on success or a -ve error code. + * Return buffer_head on success or NULL in case of failure. */ -static int read_block_bitmap (struct super_block * sb, - unsigned int block_group, - unsigned long bitmap_nr) +static struct buffer_head *read_block_bitmap(struct super_block *sb, + unsigned int block_group) { struct ext2_group_desc * gdp; struct buffer_head * bh = NULL; - int retval = -EIO; gdp = ext2_get_group_desc (sb, block_group, NULL); if (!gdp) goto error_out; - retval = 0; bh = sb_bread(sb, le32_to_cpu(gdp->bg_block_bitmap)); - if (!bh) { + if (!bh) ext2_error (sb, "read_block_bitmap", "Cannot read block bitmap - " "block_group = %d, block_bitmap = %lu", block_group, (unsigned long) gdp->bg_block_bitmap); - retval = -EIO; - } - /* - * On IO error, just leave a zero in the superblock's block pointer for - * this group. The IO will be retried next time. - */ error_out: - sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group; - sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh; - return retval; + return bh; } /* @@ -117,134 +106,65 @@ * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups, * this function reads the bitmap without maintaining a LRU cache. * - * Return the slot used to store the bitmap, or a -ve error code. + * Return the buffer_head of the bitmap or ERR_PTR(-ve). */ -static int __load_block_bitmap (struct super_block * sb, - unsigned int block_group) +static struct buffer_head *load_block_bitmap(struct super_block * sb, + unsigned int block_group) { - int i, j, retval = 0; - unsigned long block_bitmap_number; - struct buffer_head * block_bitmap; + struct ext2_sb_info *sbi = &sb->u.ext2_sb; + int i, slot = 0; + struct buffer_head *bh = sbi->s_block_bitmap[0]; - if (block_group >= sb->u.ext2_sb.s_groups_count) + if (block_group >= sbi->s_groups_count) ext2_panic (sb, "load_block_bitmap", "block_group >= groups_count - " "block_group = %d, groups_count = %lu", - block_group, sb->u.ext2_sb.s_groups_count); - - if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) { - if (sb->u.ext2_sb.s_block_bitmap[block_group]) { - if (sb->u.ext2_sb.s_block_bitmap_number[block_group] == - block_group) - return block_group; - ext2_error (sb, "__load_block_bitmap", - "block_group != block_bitmap_number"); - } - retval = read_block_bitmap (sb, block_group, block_group); - if (retval < 0) - return retval; - return block_group; - } - - for (i = 0; i < sb->u.ext2_sb.s_loaded_block_bitmaps && - sb->u.ext2_sb.s_block_bitmap_number[i] != block_group; i++) - ; - if (i < sb->u.ext2_sb.s_loaded_block_bitmaps && - sb->u.ext2_sb.s_block_bitmap_number[i] == block_group) { - block_bitmap_number = sb->u.ext2_sb.s_block_bitmap_number[i]; - block_bitmap = sb->u.ext2_sb.s_block_bitmap[i]; - for (j = i; j > 0; j--) { - sb->u.ext2_sb.s_block_bitmap_number[j] = - sb->u.ext2_sb.s_block_bitmap_number[j - 1]; - sb->u.ext2_sb.s_block_bitmap[j] = - sb->u.ext2_sb.s_block_bitmap[j - 1]; - } - sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number; - sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap; - - /* - * There's still one special case here --- if block_bitmap == 0 - * then our last attempt to read the bitmap failed and we have - * just ended up caching that failure. Try again to read it. - */ - if (!block_bitmap) - retval = read_block_bitmap (sb, block_group, 0); - } else { - if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED) - sb->u.ext2_sb.s_loaded_block_bitmaps++; - else - brelse (sb->u.ext2_sb.s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]); - for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) { - sb->u.ext2_sb.s_block_bitmap_number[j] = - sb->u.ext2_sb.s_block_bitmap_number[j - 1]; - sb->u.ext2_sb.s_block_bitmap[j] = - sb->u.ext2_sb.s_block_bitmap[j - 1]; - } - retval = read_block_bitmap (sb, block_group, 0); - } - return retval; -} - -/* - * Load the block bitmap for a given block group. First of all do a couple - * of fast lookups for common cases and then pass the request onto the guts - * of the bitmap loader. - * - * Return the slot number of the group in the superblock bitmap cache's on - * success, or a -ve error code. - * - * There is still one inconsistency here --- if the number of groups in this - * filesystems is <= EXT2_MAX_GROUP_LOADED, then we have no way of - * differentiating between a group for which we have never performed a bitmap - * IO request, and a group for which the last bitmap read request failed. - */ -static inline int load_block_bitmap (struct super_block * sb, - unsigned int block_group) -{ - int slot; + block_group, sbi->s_groups_count); /* * Do the lookup for the slot. First of all, check if we're asking * for the same slot as last time, and did we succeed that last time? */ - if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 && - sb->u.ext2_sb.s_block_bitmap_number[0] == block_group && - sb->u.ext2_sb.s_block_bitmap[0]) { - return 0; - } - /* - * Or can we do a fast lookup based on a loaded group on a filesystem - * small enough to be mapped directly into the superblock? - */ - else if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED && - sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group && - sb->u.ext2_sb.s_block_bitmap[block_group]) { + if (sbi->s_loaded_block_bitmaps > 0 && + sbi->s_block_bitmap_number[0] == block_group && bh) + goto found; + + if (sbi->s_groups_count <= EXT2_MAX_GROUP_LOADED) { slot = block_group; - } - /* - * If not, then do a full lookup for this block group. - */ - else { - slot = __load_block_bitmap (sb, block_group); + bh = sbi->s_block_bitmap[slot]; + if (!bh) + goto read_it; + if (sbi->s_block_bitmap_number[slot] == slot) + goto found; + ext2_panic (sb, "__load_block_bitmap", + "block_group != block_bitmap_number"); } - /* - * <0 means we just got an error - */ - if (slot < 0) - return slot; - - /* - * If it's a valid slot, we may still have cached a previous IO error, - * in which case the bh in the superblock cache will be zero. - */ - if (!sb->u.ext2_sb.s_block_bitmap[slot]) - return -EIO; - - /* - * Must have been read in OK to get this far. - */ - return slot; + bh = NULL; + for (i = 0; i < sbi->s_loaded_block_bitmaps && + sbi->s_block_bitmap_number[i] != block_group; i++) + ; + if (i < sbi->s_loaded_block_bitmaps) + bh = sbi->s_block_bitmap[i]; + else if (sbi->s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED) + sbi->s_loaded_block_bitmaps++; + else + brelse (sbi->s_block_bitmap[--i]); + + while (i--) { + sbi->s_block_bitmap_number[i+1] = sbi->s_block_bitmap_number[i]; + sbi->s_block_bitmap[i+1] = sbi->s_block_bitmap[i]; + } + +read_it: + if (!bh) + bh = read_block_bitmap(sb, block_group); + sbi->s_block_bitmap_number[slot] = block_group; + sbi->s_block_bitmap[slot] = bh; + if (!bh) + return ERR_PTR(-EIO); +found: + return bh; } /* Free given blocks, update quota and i_blocks field */ @@ -256,7 +176,6 @@ unsigned long block_group; unsigned long bit; unsigned long i; - int bitmap_nr; unsigned long overflow; struct super_block * sb; struct ext2_group_desc * gdp; @@ -293,11 +212,10 @@ overflow = bit + count - EXT2_BLOCKS_PER_GROUP(sb); count -= overflow; } - bitmap_nr = load_block_bitmap (sb, block_group); - if (bitmap_nr < 0) + bh = load_block_bitmap (sb, block_group); + if (IS_ERR(bh)) goto error_return; - bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; gdp = ext2_get_group_desc (sb, block_group, &bh2); if (!gdp) goto error_return; @@ -361,7 +279,6 @@ struct buffer_head * bh2; char * p, * r; int i, j, k, tmp; - int bitmap_nr; struct super_block * sb; struct ext2_group_desc * gdp; struct ext2_super_block * es; @@ -404,12 +321,10 @@ if (j) goal_attempts++; #endif - bitmap_nr = load_block_bitmap (sb, i); - if (bitmap_nr < 0) + bh = load_block_bitmap (sb, i); + if (IS_ERR(bh)) goto io_error; - bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; - ext2_debug ("goal is at %d:%d.\n", i, j); if (!ext2_test_bit(j, bh->b_data)) { @@ -477,11 +392,10 @@ } if (k >= sb->u.ext2_sb.s_groups_count) goto out; - bitmap_nr = load_block_bitmap (sb, i); - if (bitmap_nr < 0) + bh = load_block_bitmap (sb, i); + if (IS_ERR(bh)) goto io_error; - bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; r = memscan(bh->b_data, 0, EXT2_BLOCKS_PER_GROUP(sb) >> 3); j = (r - bh->b_data) << 3; if (j < EXT2_BLOCKS_PER_GROUP(sb)) @@ -619,7 +533,6 @@ #ifdef EXT2FS_DEBUG struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x; - int bitmap_nr; struct ext2_group_desc * gdp; int i; @@ -629,16 +542,16 @@ bitmap_count = 0; gdp = NULL; for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { + struct buffer_head *bh; gdp = ext2_get_group_desc (sb, i, NULL); if (!gdp) continue; desc_count += le16_to_cpu(gdp->bg_free_blocks_count); - bitmap_nr = load_block_bitmap (sb, i); - if (bitmap_nr < 0) + bh = load_block_bitmap (sb, i); + if (IS_ERR(bh)) continue; - x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr], - sb->s_blocksize); + x = ext2_count_free (bh, sb->s_blocksize); printk ("group %d: stored = %d, counted = %lu\n", i, le16_to_cpu(gdp->bg_free_blocks_count), x); bitmap_count += x; @@ -720,7 +633,6 @@ struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x, j; unsigned long desc_blocks; - int bitmap_nr; struct ext2_group_desc * gdp; int i; @@ -733,11 +645,9 @@ if (!gdp) continue; desc_count += le16_to_cpu(gdp->bg_free_blocks_count); - bitmap_nr = load_block_bitmap (sb, i); - if (bitmap_nr < 0) + bh = load_block_bitmap (sb, i); + if (IS_ERR(bh)) continue; - - bh = EXT2_SB(sb)->s_block_bitmap[bitmap_nr]; if (ext2_bg_has_super(sb, i) && !ext2_test_bit(0, bh->b_data)) ext2_error(sb, __FUNCTION__, diff -urN linux-2.5.3-pre1/fs/fat/inode.c linux/fs/fat/inode.c --- linux-2.5.3-pre1/fs/fat/inode.c Sat Jan 19 16:58:37 2002 +++ linux/fs/fat/inode.c Sat Jan 19 16:58:39 2002 @@ -559,9 +559,9 @@ struct buffer_head *bh; struct fat_boot_sector *b; struct msdos_sb_info *sbi = MSDOS_SB(sb); - int logical_sector_size, fat_clusters; + int logical_sector_size, fat_clusters, debug, cp; unsigned int total_sectors, rootdir_sectors; - int debug, cp; + long error = -EIO; char buf[50]; int i; char cvf_format[21]; @@ -786,9 +786,8 @@ return sb; out_invalid: - if (!silent) - printk("VFS: Can't find a valid FAT filesystem on dev %s.\n", - sb->s_id); + error = 0; + out_fail: if (sbi->nls_io) unload_nls(sbi->nls_io); @@ -799,8 +798,8 @@ if (sbi->private_data) kfree(sbi->private_data); sbi->private_data = NULL; - - return NULL; + + return ERR_PTR(error); } int fat_statfs(struct super_block *sb,struct statfs *buf) diff -urN linux-2.5.3-pre1/fs/inode.c linux/fs/inode.c --- linux-2.5.3-pre1/fs/inode.c Mon Jan 14 10:10:43 2002 +++ linux/fs/inode.c Sat Jan 19 16:58:39 2002 @@ -75,13 +75,53 @@ static kmem_cache_t * inode_cachep; -#define alloc_inode() \ - ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL)) +static struct inode *alloc_inode(struct super_block *sb) +{ + static struct address_space_operations empty_aops; + static struct inode_operations empty_iops; + static struct file_operations empty_fops; + struct inode *inode; + + if (sb->s_op->alloc_inode) + inode = sb->s_op->alloc_inode(sb); + else + inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL); + + if (inode) { + inode->i_sb = sb; + inode->i_dev = sb->s_dev; + inode->i_blkbits = sb->s_blocksize_bits; + inode->i_flags = 0; + atomic_set(&inode->i_count, 1); + inode->i_sock = 0; + inode->i_op = &empty_iops; + inode->i_fop = &empty_fops; + inode->i_nlink = 1; + atomic_set(&inode->i_writecount, 0); + inode->i_size = 0; + inode->i_blocks = 0; + inode->i_generation = 0; + memset(&inode->i_dquot, 0, sizeof(inode->i_dquot)); + inode->i_pipe = NULL; + inode->i_bdev = NULL; + inode->i_cdev = NULL; + inode->i_data.a_ops = &empty_aops; + inode->i_data.host = inode; + inode->i_data.gfp_mask = GFP_HIGHUSER; + inode->i_mapping = &inode->i_data; + memset(&inode->u, 0, sizeof(inode->u)); + } + return inode; +} + static void destroy_inode(struct inode *inode) { if (inode_has_buffers(inode)) BUG(); - kmem_cache_free(inode_cachep, (inode)); + if (inode->i_sb->s_op->destroy_inode) + inode->i_sb->s_op->destroy_inode(inode); + else + kmem_cache_free(inode_cachep, (inode)); } @@ -90,27 +130,30 @@ * once, because the fields are idempotent across use * of the inode, so let the slab aware of that. */ +void inode_init_once(struct inode *inode) +{ + memset(inode, 0, sizeof(*inode)); + init_waitqueue_head(&inode->i_wait); + INIT_LIST_HEAD(&inode->i_hash); + INIT_LIST_HEAD(&inode->i_data.clean_pages); + INIT_LIST_HEAD(&inode->i_data.dirty_pages); + INIT_LIST_HEAD(&inode->i_data.locked_pages); + INIT_LIST_HEAD(&inode->i_dentry); + INIT_LIST_HEAD(&inode->i_dirty_buffers); + INIT_LIST_HEAD(&inode->i_dirty_data_buffers); + INIT_LIST_HEAD(&inode->i_devices); + sema_init(&inode->i_sem, 1); + sema_init(&inode->i_zombie, 1); + spin_lock_init(&inode->i_data.i_shared_lock); +} + static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) { struct inode * inode = (struct inode *) foo; if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) - { - memset(inode, 0, sizeof(*inode)); - init_waitqueue_head(&inode->i_wait); - INIT_LIST_HEAD(&inode->i_hash); - INIT_LIST_HEAD(&inode->i_data.clean_pages); - INIT_LIST_HEAD(&inode->i_data.dirty_pages); - INIT_LIST_HEAD(&inode->i_data.locked_pages); - INIT_LIST_HEAD(&inode->i_dentry); - INIT_LIST_HEAD(&inode->i_dirty_buffers); - INIT_LIST_HEAD(&inode->i_dirty_data_buffers); - INIT_LIST_HEAD(&inode->i_devices); - sema_init(&inode->i_sem, 1); - sema_init(&inode->i_zombie, 1); - spin_lock_init(&inode->i_data.i_shared_lock); - } + inode_init_once(inode); } /* @@ -768,72 +811,28 @@ return inode; } -/* - * This just initializes the inode fields - * to known values before returning the inode.. - * - * i_sb, i_ino, i_count, i_state and the lists have - * been initialized elsewhere.. - */ -static void clean_inode(struct inode *inode) -{ - static struct address_space_operations empty_aops; - static struct inode_operations empty_iops; - static struct file_operations empty_fops; - memset(&inode->u, 0, sizeof(inode->u)); - inode->i_sock = 0; - inode->i_op = &empty_iops; - inode->i_fop = &empty_fops; - inode->i_nlink = 1; - atomic_set(&inode->i_writecount, 0); - inode->i_size = 0; - inode->i_blocks = 0; - inode->i_generation = 0; - memset(&inode->i_dquot, 0, sizeof(inode->i_dquot)); - inode->i_pipe = NULL; - inode->i_bdev = NULL; - inode->i_cdev = NULL; - inode->i_data.a_ops = &empty_aops; - inode->i_data.host = inode; - inode->i_data.gfp_mask = GFP_HIGHUSER; - inode->i_mapping = &inode->i_data; -} - /** - * get_empty_inode - obtain an inode + * new_inode - obtain an inode + * @sb: superblock * - * This is called by things like the networking layer - * etc that want to get an inode without any inode - * number, or filesystems that allocate new inodes with - * no pre-existing information. - * - * On a successful return the inode pointer is returned. On a failure - * a %NULL pointer is returned. The returned inode is not on any superblock - * lists. + * Allocates a new inode for given superblock. */ -struct inode * get_empty_inode(void) +struct inode *new_inode(struct super_block *sb) { static unsigned long last_ino; struct inode * inode; spin_lock_prefetch(&inode_lock); - inode = alloc_inode(); - if (inode) - { + inode = alloc_inode(sb); + if (inode) { spin_lock(&inode_lock); inodes_stat.nr_inodes++; list_add(&inode->i_list, &inode_in_use); - inode->i_sb = NULL; - inode->i_dev = NODEV; - inode->i_blkbits = 0; inode->i_ino = ++last_ino; - inode->i_flags = 0; - atomic_set(&inode->i_count, 1); inode->i_state = 0; spin_unlock(&inode_lock); - clean_inode(inode); } return inode; } @@ -848,7 +847,7 @@ { struct inode * inode; - inode = alloc_inode(); + inode = alloc_inode(sb); if (inode) { struct inode * old; @@ -859,16 +858,9 @@ inodes_stat.nr_inodes++; list_add(&inode->i_list, &inode_in_use); list_add(&inode->i_hash, head); - inode->i_sb = sb; - inode->i_dev = sb->s_dev; - inode->i_blkbits = sb->s_blocksize_bits; inode->i_ino = ino; - inode->i_flags = 0; - atomic_set(&inode->i_count, 1); inode->i_state = I_LOCK; spin_unlock(&inode_lock); - - clean_inode(inode); /* reiserfs specific hack right here. We don't ** want this to last, and are looking for VFS changes diff -urN linux-2.5.3-pre1/fs/intermezzo/kml_reint.c linux/fs/intermezzo/kml_reint.c --- linux-2.5.3-pre1/fs/intermezzo/kml_reint.c Sun Nov 11 10:20:21 2001 +++ linux/fs/intermezzo/kml_reint.c Sat Jan 19 16:58:39 2002 @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff -urN linux-2.5.3-pre1/fs/jbd/commit.c linux/fs/jbd/commit.c --- linux-2.5.3-pre1/fs/jbd/commit.c Sun Dec 30 16:59:00 2001 +++ linux/fs/jbd/commit.c Sat Jan 19 16:58:39 2002 @@ -224,14 +224,13 @@ } } while (jh != last_jh); - if (bufs || current->need_resched) { + if (bufs || need_resched()) { jbd_debug(2, "submit %d writes\n", bufs); spin_unlock(&journal_datalist_lock); unlock_journal(journal); if (bufs) ll_rw_block(WRITE, bufs, wbuf); - if (current->need_resched) - schedule(); + cond_resched(); journal_brelse_array(wbuf, bufs); lock_journal(journal); spin_lock(&journal_datalist_lock); @@ -458,8 +457,7 @@ bh->b_end_io = journal_end_buffer_io_sync; submit_bh(WRITE, bh); } - if (current->need_resched) - schedule(); + cond_resched(); lock_journal(journal); /* Force a new descriptor to be generated next diff -urN linux-2.5.3-pre1/fs/jffs2/background.c linux/fs/jffs2/background.c --- linux-2.5.3-pre1/fs/jffs2/background.c Mon Jan 7 12:55:16 2002 +++ linux/fs/jffs2/background.c Sat Jan 19 16:58:39 2002 @@ -127,8 +127,7 @@ schedule(); } - if (current->need_resched) - schedule(); + cond_resched(); /* Put_super will send a SIGKILL and then wait on the sem. */ diff -urN linux-2.5.3-pre1/fs/jffs2/erase.c linux/fs/jffs2/erase.c --- linux-2.5.3-pre1/fs/jffs2/erase.c Thu Jan 10 16:23:46 2002 +++ linux/fs/jffs2/erase.c Sat Jan 19 16:58:39 2002 @@ -131,8 +131,7 @@ jffs2_erase_block(c, jeb); /* Be nice */ - if (current->need_resched) - schedule(); + cond_resched(); spin_lock_bh(&c->erase_completion_lock); } spin_unlock_bh(&c->erase_completion_lock); diff -urN linux-2.5.3-pre1/fs/jffs2/nodemgmt.c linux/fs/jffs2/nodemgmt.c --- linux-2.5.3-pre1/fs/jffs2/nodemgmt.c Thu Oct 4 15:13:18 2001 +++ linux/fs/jffs2/nodemgmt.c Sat Jan 19 16:58:39 2002 @@ -101,8 +101,7 @@ if (ret) return ret; - if (current->need_resched) - schedule(); + cond_resched(); if (signal_pending(current)) return -EINTR; diff -urN linux-2.5.3-pre1/fs/msdos/msdosfs_syms.c linux/fs/msdos/msdosfs_syms.c --- linux-2.5.3-pre1/fs/msdos/msdosfs_syms.c Sun Dec 30 16:58:58 2001 +++ linux/fs/msdos/msdosfs_syms.c Sat Jan 19 16:58:39 2002 @@ -23,7 +23,6 @@ EXPORT_SYMBOL(msdos_rename); EXPORT_SYMBOL(msdos_rmdir); EXPORT_SYMBOL(msdos_unlink); -EXPORT_SYMBOL(msdos_read_super); EXPORT_SYMBOL(msdos_put_super); static DECLARE_FSTYPE_DEV(msdos_fs_type, "msdos", msdos_read_super); diff -urN linux-2.5.3-pre1/fs/msdos/namei.c linux/fs/msdos/namei.c --- linux-2.5.3-pre1/fs/msdos/namei.c Sun Dec 30 10:53:53 2001 +++ linux/fs/msdos/namei.c Sat Jan 19 16:58:39 2002 @@ -589,7 +589,15 @@ MSDOS_SB(sb)->options.isvfat = 0; res = fat_read_super(sb, data, silent, &msdos_dir_inode_operations); - if (res) - sb->s_root->d_op = &msdos_dentry_operations; + if (IS_ERR(res)) + return NULL; + if (res == NULL) { + if (!silent) + printk(KERN_INFO "VFS: Can't find a valid" + " MSDOS filesystem on dev %s.\n", sb->s_id); + return NULL; + } + + sb->s_root->d_op = &msdos_dentry_operations; return res; } diff -urN linux-2.5.3-pre1/fs/namei.c linux/fs/namei.c --- linux-2.5.3-pre1/fs/namei.c Mon Jan 14 09:41:57 2002 +++ linux/fs/namei.c Sat Jan 19 16:58:39 2002 @@ -339,7 +339,7 @@ goto loop; if (current->total_link_count >= 40) goto loop; - if (current->need_resched) { + if (need_resched()) { current->state = TASK_RUNNING; schedule(); } diff -urN linux-2.5.3-pre1/fs/pipe.c linux/fs/pipe.c --- linux-2.5.3-pre1/fs/pipe.c Fri Sep 28 18:03:48 2001 +++ linux/fs/pipe.c Sat Jan 19 16:58:39 2002 @@ -608,16 +608,18 @@ static struct super_block * pipefs_read_super(struct super_block *sb, void *data, int silent) { - struct inode *root = new_inode(sb); + struct inode *root; + + sb->s_blocksize = 1024; + sb->s_blocksize_bits = 10; + sb->s_magic = PIPEFS_MAGIC; + sb->s_op = &pipefs_ops; + root = new_inode(sb); if (!root) return NULL; root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; root->i_uid = root->i_gid = 0; root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; - sb->s_blocksize = 1024; - sb->s_blocksize_bits = 10; - sb->s_magic = PIPEFS_MAGIC; - sb->s_op = &pipefs_ops; sb->s_root = d_alloc(NULL, &(const struct qstr) { "pipe:", 5, 0 }); if (!sb->s_root) { iput(root); diff -urN linux-2.5.3-pre1/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c --- linux-2.5.3-pre1/fs/reiserfs/inode.c Fri Jan 4 09:42:12 2002 +++ linux/fs/reiserfs/inode.c Sat Jan 19 16:58:39 2002 @@ -101,9 +101,9 @@ } static void add_to_flushlist(struct inode *inode, struct buffer_head *bh) { - struct inode *jinode = &(SB_JOURNAL(inode->i_sb)->j_dummy_inode) ; + struct list_head *list = &(SB_JOURNAL(inode->i_sb)->j_dirty_buffers) ; - buffer_insert_inode_queue(bh, jinode) ; + buffer_insert_list(bh, list) ; } // @@ -808,8 +808,7 @@ /* inserting indirect pointers for a hole can take a ** long time. reschedule if needed */ - if (current->need_resched) - schedule() ; + cond_resched(); retval = search_for_position_by_key (inode->i_sb, &key, &path); if (retval == IO_ERROR) { diff -urN linux-2.5.3-pre1/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c --- linux-2.5.3-pre1/fs/reiserfs/journal.c Mon Jan 14 09:38:46 2002 +++ linux/fs/reiserfs/journal.c Sat Jan 19 16:58:39 2002 @@ -1897,7 +1897,7 @@ memset(journal_writers, 0, sizeof(char *) * 512) ; /* debug code */ INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ; - INIT_LIST_HEAD(&(SB_JOURNAL(p_s_sb)->j_dummy_inode.i_dirty_buffers)) ; + INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_dirty_buffers) ; reiserfs_allocate_list_bitmaps(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_bitmap, SB_BMAP_NR(p_s_sb)) ; allocate_bitmap_nodes(p_s_sb) ; @@ -2902,7 +2902,7 @@ SB_JOURNAL_LIST_INDEX(p_s_sb) = jindex ; /* write any buffers that must hit disk before this commit is done */ - fsync_inode_buffers(&(SB_JOURNAL(p_s_sb)->j_dummy_inode)) ; + fsync_buffers_list(&(SB_JOURNAL(p_s_sb)->j_dirty_buffers)) ; /* honor the flush and async wishes from the caller */ if (flush) { diff -urN linux-2.5.3-pre1/fs/umsdos/inode.c linux/fs/umsdos/inode.c --- linux-2.5.3-pre1/fs/umsdos/inode.c Tue Jan 1 18:55:00 2002 +++ linux/fs/umsdos/inode.c Sat Jan 19 16:58:39 2002 @@ -363,10 +363,17 @@ * Call msdos-fs to mount the disk. * Note: this returns res == sb or NULL */ - res = msdos_read_super (sb, data, silent); + MSDOS_SB(sb)->options.isvfat = 0; + res = fat_read_super(sb, data, silent, &umsdos_rdir_inode_operations); - if (!res) - goto out_fail; + if (IS_ERR(res)) + return NULL; + if (res == NULL) { + if (!silent) + printk(KERN_INFO "VFS: Can't find a valid " + "UMSDOS filesystem on dev %s.\n", sb->s_id); + return NULL; + } printk (KERN_INFO "UMSDOS 0.86k " "(compatibility level %d.%d, fast msdos)\n", @@ -394,10 +401,6 @@ dget (sb->s_root); sb->s_root = dget(new_root); } return sb; - -out_fail: - printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n"); - return NULL; } /* diff -urN linux-2.5.3-pre1/fs/vfat/namei.c linux/fs/vfat/namei.c --- linux-2.5.3-pre1/fs/vfat/namei.c Sat Jan 19 16:58:37 2002 +++ linux/fs/vfat/namei.c Sat Jan 19 16:58:39 2002 @@ -1266,10 +1266,15 @@ struct super_block *res; MSDOS_SB(sb)->options.isvfat = 1; - res = fat_read_super(sb, data, silent, &vfat_dir_inode_operations); - if (res == NULL) + if (IS_ERR(res)) return NULL; + if (res == NULL) { + if (!silent) + printk(KERN_INFO "VFS: Can't find a valid" + " VFAT filesystem on dev %s.\n", sb->s_id); + return NULL; + } if (parse_options((char *) data, &(MSDOS_SB(sb)->options))) { MSDOS_SB(sb)->options.dotsOK = 0; diff -urN linux-2.5.3-pre1/include/asm-arm/arch-arc/system.h linux/include/asm-arm/arch-arc/system.h --- linux-2.5.3-pre1/include/asm-arm/arch-arc/system.h Sun Aug 12 11:14:00 2001 +++ linux/include/asm-arm/arch-arc/system.h Sat Jan 19 16:58:39 2002 @@ -10,7 +10,7 @@ static void arch_idle(void) { - while (!current->need_resched && !hlt_counter); + while (!need_resched() && !hlt_counter); } static inline void arch_reset(char mode) diff -urN linux-2.5.3-pre1/include/asm-arm/arch-cl7500/system.h linux/include/asm-arm/arch-cl7500/system.h --- linux-2.5.3-pre1/include/asm-arm/arch-cl7500/system.h Thu Apr 12 12:20:31 2001 +++ linux/include/asm-arm/arch-cl7500/system.h Sat Jan 19 16:58:39 2002 @@ -10,7 +10,7 @@ static void arch_idle(void) { - while (!current->need_resched && !hlt_counter) + while (!need_resched() && !hlt_counter) iomd_writeb(0, IOMD_SUSMODE); } diff -urN linux-2.5.3-pre1/include/asm-arm/arch-ebsa110/system.h linux/include/asm-arm/arch-ebsa110/system.h --- linux-2.5.3-pre1/include/asm-arm/arch-ebsa110/system.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-ebsa110/system.h Sat Jan 19 16:58:39 2002 @@ -17,7 +17,7 @@ * will stop our MCLK signal (which provides the clock for the glue * logic, and therefore the timer interrupt). * - * Instead, we spin, waiting for either hlt_counter or need_resched + * Instead, we spin, waiting for either hlt_counter or need_resched() * to be set. If we have been spinning for 2cs, then we drop the * core clock down to the memory clock. */ @@ -28,13 +28,13 @@ start_idle = jiffies; do { - if (current->need_resched || hlt_counter) + if (need_resched() || hlt_counter) goto slow_out; } while (time_before(jiffies, start_idle + HZ/50)); cpu_do_idle(IDLE_CLOCK_SLOW); - while (!current->need_resched && !hlt_counter) { + while (!need_resched() && !hlt_counter) { /* do nothing slowly */ } diff -urN linux-2.5.3-pre1/include/asm-arm/arch-ebsa285/system.h linux/include/asm-arm/arch-ebsa285/system.h --- linux-2.5.3-pre1/include/asm-arm/arch-ebsa285/system.h Sun Aug 12 11:14:00 2001 +++ linux/include/asm-arm/arch-ebsa285/system.h Sat Jan 19 16:58:39 2002 @@ -20,14 +20,14 @@ start_idle = jiffies; do { - if (current->need_resched || hlt_counter) + if (need_resched() || hlt_counter) goto slow_out; cpu_do_idle(IDLE_WAIT_FAST); } while (time_before(jiffies, start_idle + HZ/50)); cpu_do_idle(IDLE_CLOCK_SLOW); - while (!current->need_resched && !hlt_counter) { + while (!need_resched() && !hlt_counter) { cpu_do_idle(IDLE_WAIT_SLOW); } diff -urN linux-2.5.3-pre1/include/asm-arm/arch-nexuspci/system.h linux/include/asm-arm/arch-nexuspci/system.h --- linux-2.5.3-pre1/include/asm-arm/arch-nexuspci/system.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-nexuspci/system.h Sat Jan 19 16:58:39 2002 @@ -16,7 +16,7 @@ static void arch_idle(void) { - while (!current->need_resched && !hlt_counter) + while (!need_resched() && !hlt_counter) cpu_do_idle(IDLE_WAIT_SLOW); } diff -urN linux-2.5.3-pre1/include/asm-arm/arch-rpc/system.h linux/include/asm-arm/arch-rpc/system.h --- linux-2.5.3-pre1/include/asm-arm/arch-rpc/system.h Sun Aug 12 11:14:00 2001 +++ linux/include/asm-arm/arch-rpc/system.h Sat Jan 19 16:58:39 2002 @@ -18,14 +18,14 @@ start_idle = jiffies; do { - if (current->need_resched || hlt_counter) + if (need_resched() || hlt_counter) goto slow_out; cpu_do_idle(IDLE_WAIT_FAST); } while (time_before(jiffies, start_idle + HZ/50)); cpu_do_idle(IDLE_CLOCK_SLOW); - while (!current->need_resched && !hlt_counter) { + while (!need_resched() && !hlt_counter) { cpu_do_idle(IDLE_WAIT_SLOW); } diff -urN linux-2.5.3-pre1/include/asm-arm/arch-sa1100/system.h linux/include/asm-arm/arch-sa1100/system.h --- linux-2.5.3-pre1/include/asm-arm/arch-sa1100/system.h Thu Oct 25 13:53:54 2001 +++ linux/include/asm-arm/arch-sa1100/system.h Sat Jan 19 16:58:39 2002 @@ -10,7 +10,7 @@ if (!hlt_counter) { int flags; local_irq_save(flags); - if (!current->need_resched) + if (!need_resched()) cpu_do_idle(0); local_irq_restore(flags); } diff -urN linux-2.5.3-pre1/include/asm-arm/arch-tbox/system.h linux/include/asm-arm/arch-tbox/system.h --- linux-2.5.3-pre1/include/asm-arm/arch-tbox/system.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/arch-tbox/system.h Sat Jan 19 16:58:39 2002 @@ -13,14 +13,14 @@ start_idle = jiffies; do { - if (current->need_resched || hlt_counter) + if (need_resched() || hlt_counter) goto slow_out; cpu_do_idle(IDLE_WAIT_FAST); } while (time_before(jiffies, start_idle + HZ/50)); cpu_do_idle(IDLE_CLOCK_SLOW); - while (!current->need_resched && !hlt_counter) { + while (!need_resched() && !hlt_counter) { cpu_do_idle(IDLE_WAIT_SLOW); } diff -urN linux-2.5.3-pre1/include/asm-i386/mmu_context.h linux/include/asm-i386/mmu_context.h --- linux-2.5.3-pre1/include/asm-i386/mmu_context.h Mon Jan 14 13:27:07 2002 +++ linux/include/asm-i386/mmu_context.h Sat Jan 19 16:58:39 2002 @@ -1,5 +1,5 @@ -#ifndef __I386_MMU_CONTEXT_H -#define __I386_MMU_CONTEXT_H +#ifndef __I386_SCHED_H +#define __I386_SCHED_H #include #include @@ -16,14 +16,13 @@ # error update this function. #endif -static inline int sched_find_first_zero_bit(char *bitmap) +static inline int sched_find_first_zero_bit(unsigned long *b) { - unsigned int *b = (unsigned int *)bitmap; unsigned int rt; rt = b[0] & b[1] & b[2] & b[3]; if (unlikely(rt != 0xffffffff)) - return find_first_zero_bit(bitmap, MAX_RT_PRIO); + return find_first_zero_bit(b, MAX_RT_PRIO); if (b[4] != ~0) return ffz(b[4]) + MAX_RT_PRIO; diff -urN linux-2.5.3-pre1/include/asm-i386/smplock.h linux/include/asm-i386/smplock.h --- linux-2.5.3-pre1/include/asm-i386/smplock.h Mon Jan 14 13:27:16 2002 +++ linux/include/asm-i386/smplock.h Sat Jan 19 16:58:39 2002 @@ -19,8 +19,8 @@ do { \ if (unlikely(task->lock_depth >= 0)) { \ spin_unlock(&kernel_flag); \ - release_irqlock(cpu); \ - __sti(); \ + if (global_irq_holder == (cpu)) \ + BUG(); \ } \ } while (0) diff -urN linux-2.5.3-pre1/include/linux/blk.h linux/include/linux/blk.h --- linux-2.5.3-pre1/include/linux/blk.h Mon Jan 14 13:28:11 2002 +++ linux/include/linux/blk.h Sat Jan 19 16:58:39 2002 @@ -90,9 +90,9 @@ #define _elv_add_request(q, rq, back, p) do { \ if ((back)) \ - _elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \ + _elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \ else \ - _elv_add_request_core((q), (rq), &(q)->queue_head, 0); \ + _elv_add_request_core((q), (rq), &(q)->queue_head, (p)); \ } while (0) #define elv_add_request(q, rq, back) _elv_add_request((q), (rq), (back), 1) diff -urN linux-2.5.3-pre1/include/linux/cciss_ioctl.h linux/include/linux/cciss_ioctl.h --- linux-2.5.3-pre1/include/linux/cciss_ioctl.h Tue May 1 16:05:00 2001 +++ linux/include/linux/cciss_ioctl.h Sat Jan 19 16:58:39 2002 @@ -184,6 +184,11 @@ #define CCISS_GETDRIVVER _IOR(CCISS_IOC_MAGIC, 9, DriverVer_type) #define CCISS_REVALIDVOLS _IO(CCISS_IOC_MAGIC, 10) #define CCISS_PASSTHRU _IOWR(CCISS_IOC_MAGIC, 11, IOCTL_Command_struct) +#define CCISS_DEREGDISK _IO(CCISS_IOC_MAGIC, 12) +/* no longer used... use REGNEWD instead */ +#define CCISS_REGNEWDISK _IOW(CCISS_IOC_MAGIC, 13, int) + +#define CCISS_REGNEWD _IO(CCISS_IOC_MAGIC, 14) #endif diff -urN linux-2.5.3-pre1/include/linux/file.h linux/include/linux/file.h --- linux-2.5.3-pre1/include/linux/file.h Sat Jan 19 16:58:37 2002 +++ linux/include/linux/file.h Sat Jan 19 16:58:39 2002 @@ -5,12 +5,9 @@ #ifndef __LINUX_FILE_H #define __LINUX_FILE_H -#ifndef _LINUX_POSIX_TYPES_H /* __FD_CLR */ +#include #include -#endif -#ifndef __LINUX_COMPILER_H /* unlikely */ #include -#endif /* * The default fd array needs to be at least BITS_PER_LONG, diff -urN linux-2.5.3-pre1/include/linux/fs.h linux/include/linux/fs.h --- linux-2.5.3-pre1/include/linux/fs.h Mon Jan 14 13:27:08 2002 +++ linux/include/linux/fs.h Sat Jan 19 16:58:39 2002 @@ -262,7 +262,7 @@ wait_queue_head_t b_wait; - struct inode * b_inode; + int b_inode; /* will go away */ struct list_head b_inode_buffers; /* doubly linked list of inode dirty buffers */ }; @@ -859,6 +859,9 @@ * without the big kernel lock held in all filesystems. */ struct super_operations { + struct inode *(*alloc_inode)(struct super_block *sb); + void (*destroy_inode)(struct inode *); + void (*read_inode) (struct inode *); /* reiserfs kludge. reiserfs needs 64 bits of information to @@ -1151,7 +1154,16 @@ extern void FASTCALL(__mark_dirty(struct buffer_head *bh)); extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh)); extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh)); -extern void FASTCALL(buffer_insert_inode_data_queue(struct buffer_head *, struct inode *)); +extern void FASTCALL(buffer_insert_list(struct buffer_head *, struct list_head *)); + +static inline void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode) +{ + buffer_insert_list(bh, &inode->i_dirty_buffers); +} +static inline void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode) +{ + buffer_insert_list(bh, &inode->i_dirty_data_buffers); +} #define atomic_set_buffer_dirty(bh) test_and_set_bit(BH_Dirty, &(bh)->b_state) @@ -1219,10 +1231,16 @@ extern int fsync_super(struct super_block *); extern int fsync_no_super(struct block_device *); extern void sync_inodes_sb(struct super_block *); -extern int osync_inode_buffers(struct inode *); -extern int osync_inode_data_buffers(struct inode *); -extern int fsync_inode_buffers(struct inode *); -extern int fsync_inode_data_buffers(struct inode *); +extern int osync_buffers_list(struct list_head *); +extern int fsync_buffers_list(struct list_head *); +static inline int fsync_inode_buffers(struct inode *inode) +{ + return fsync_buffers_list(&inode->i_dirty_buffers); +} +static inline int fsync_inode_data_buffers(struct inode *inode) +{ + return fsync_buffers_list(&inode->i_dirty_data_buffers); +} extern int inode_has_buffers(struct inode *); extern void filemap_fdatasync(struct address_space *); extern void filemap_fdatawait(struct address_space *); @@ -1327,6 +1345,7 @@ #define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd) #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd) +extern void inode_init_once(struct inode *); extern void iput(struct inode *); extern void force_delete(struct inode *); extern struct inode * igrab(struct inode *); @@ -1340,20 +1359,8 @@ } extern void clear_inode(struct inode *); -extern struct inode * get_empty_inode(void); - -static inline struct inode * new_inode(struct super_block *sb) -{ - struct inode *inode = get_empty_inode(); - if (inode) { - inode->i_sb = sb; - inode->i_dev = sb->s_dev; - inode->i_blkbits = sb->s_blocksize_bits; - } - return inode; -} +extern struct inode *new_inode(struct super_block *); extern void remove_suid(struct inode *inode); - extern void insert_inode_hash(struct inode *); extern void remove_inode_hash(struct inode *); extern struct file * get_empty_filp(void); diff -urN linux-2.5.3-pre1/include/linux/ide.h linux/include/linux/ide.h --- linux-2.5.3-pre1/include/linux/ide.h Sat Jan 19 16:58:37 2002 +++ linux/include/linux/ide.h Sat Jan 19 16:58:39 2002 @@ -884,6 +884,9 @@ */ #define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9) +#define task_rq_offset(rq) \ + (((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE) + extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags) { return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq); @@ -892,6 +895,24 @@ extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags) { bio_kunmap_irq(buffer, flags); +} + +/* + * for now, taskfile requests are special :/ + */ +extern inline char *ide_map_rq(struct request *rq, unsigned long *flags) +{ + if (rq->bio) + return ide_map_buffer(rq, flags); + else + return rq->buffer + task_rq_offset(rq); +} + +extern inline void ide_unmap_rq(struct request *rq, char *buf, + unsigned long *flags) +{ + if (rq->bio) + ide_unmap_buffer(buf, flags); } /* diff -urN linux-2.5.3-pre1/include/linux/init_task.h linux/include/linux/init_task.h --- linux-2.5.3-pre1/include/linux/init_task.h Sat Jan 19 16:58:37 2002 +++ linux/include/linux/init_task.h Sat Jan 19 16:58:39 2002 @@ -1,9 +1,7 @@ #ifndef _LINUX__INIT_TASK_H #define _LINUX__INIT_TASK_H -#ifndef __LINUX_FILE_H #include -#endif #define INIT_FILES \ { \ diff -urN linux-2.5.3-pre1/include/linux/isdn.h linux/include/linux/isdn.h --- linux-2.5.3-pre1/include/linux/isdn.h Sun Dec 30 10:31:51 2001 +++ linux/include/linux/isdn.h Sat Jan 19 16:58:39 2002 @@ -178,8 +178,6 @@ * the correspondent code in isdn.c */ -#define ISDN_MINOR_B 0 -#define ISDN_MINOR_BMAX (ISDN_MAX_CHANNELS-1) #define ISDN_MINOR_CTRL 64 #define ISDN_MINOR_CTRLMAX (64 + (ISDN_MAX_CHANNELS-1)) #define ISDN_MINOR_PPP 128 diff -urN linux-2.5.3-pre1/include/linux/mtd/cfi.h linux/include/linux/mtd/cfi.h --- linux-2.5.3-pre1/include/linux/mtd/cfi.h Thu Oct 4 15:13:18 2001 +++ linux/include/linux/mtd/cfi.h Sat Jan 19 16:58:39 2002 @@ -368,7 +368,7 @@ static inline void cfi_udelay(int us) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - if (current->need_resched) { + if (need_resched()) { unsigned long t = us * HZ / 1000000; if (t < 1) t = 1; diff -urN linux-2.5.3-pre1/include/linux/reiserfs_fs_sb.h linux/include/linux/reiserfs_fs_sb.h --- linux-2.5.3-pre1/include/linux/reiserfs_fs_sb.h Mon Jan 14 13:27:06 2002 +++ linux/include/linux/reiserfs_fs_sb.h Sat Jan 19 16:58:39 2002 @@ -300,7 +300,7 @@ int j_free_bitmap_nodes ; int j_used_bitmap_nodes ; struct list_head j_bitmap_nodes ; - struct inode j_dummy_inode ; + struct list_head j_dirty_buffers ; struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS] ; /* array of bitmaps to record the deleted blocks */ struct reiserfs_journal_list j_journal_list[JOURNAL_LIST_COUNT] ; /* array of all the journal lists */ struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE] ; /* hash table for real buffer heads in current trans */ diff -urN linux-2.5.3-pre1/include/linux/sched.h linux/include/linux/sched.h --- linux-2.5.3-pre1/include/linux/sched.h Sat Jan 19 16:58:37 2002 +++ linux/include/linux/sched.h Sat Jan 19 16:58:39 2002 @@ -25,6 +25,7 @@ #include #include #include +#include struct exec_domain; @@ -136,6 +137,8 @@ extern rwlock_t tasklist_lock; extern spinlock_t mmlist_lock; +typedef struct task_struct task_t; + extern void sched_init(void); extern void init_idle(void); extern void show_state(void); @@ -144,8 +147,7 @@ extern void update_process_times(int user); extern void update_one_process(struct task_struct *p, unsigned long user, unsigned long system, int cpu); -extern void expire_task(struct task_struct *p); -extern void idle_tick(void); +extern void scheduler_tick(struct task_struct *p); #define MAX_SCHEDULE_TIMEOUT LONG_MAX extern signed long FASTCALL(schedule_timeout(signed long timeout)); @@ -221,7 +223,6 @@ extern struct user_struct root_user; #define INIT_USER (&root_user) -typedef struct task_struct task_t; typedef struct prio_array prio_array_t; struct task_struct { @@ -251,7 +252,10 @@ prio_array_t *array; unsigned int time_slice; - unsigned long sleep_jtime; + + #define MAX_SLEEP_AVG (2*HZ) + unsigned long sleep_avg; + unsigned long sleep_timestamp; unsigned long policy; unsigned long cpus_allowed; @@ -390,30 +394,47 @@ * them out at 128 to make it easier to search the * scheduler bitmap. */ -#define MAX_RT_PRIO 128 +#define MAX_RT_PRIO 128 /* * The lower the priority of a process, the more likely it is * to run. Priority of a process goes from 0 to 167. The 0-99 * priority range is allocated to RT tasks, the 128-167 range * is for SCHED_OTHER tasks. */ -#define MAX_PRIO (MAX_RT_PRIO+40) -#define DEF_USER_NICE 0 +#define MAX_PRIO (MAX_RT_PRIO + 40) /* - * Default timeslice is 80 msecs, maximum is 160 msecs. + * Scales user-nice values [ -20 ... 0 ... 19 ] + * to static priority [ 128 ... 167 (MAX_PRIO-1) ] + * + * User-nice value of -20 == static priority 128, and + * user-nice value 19 == static priority 167. The lower + * the priority value, the higher the task's priority. + */ +#define NICE_TO_PRIO(n) (MAX_RT_PRIO + (n) + 20) +#define DEF_USER_NICE 0 + +/* + * Default timeslice is 90 msecs, maximum is 180 msecs. * Minimum timeslice is 10 msecs. */ -#define MIN_TIMESLICE (10 * HZ / 1000) -#define MAX_TIMESLICE (160 * HZ / 1000) +#define MIN_TIMESLICE ( 10 * HZ / 1000) +#define MAX_TIMESLICE (180 * HZ / 1000) -#define USER_PRIO(p) ((p)-MAX_RT_PRIO) -#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO)) -#define DEF_PRIO (MAX_RT_PRIO + MAX_USER_PRIO / 3) -#define NICE_TO_PRIO(n) (MAX_PRIO-1 + (n) - 19) +#define USER_PRIO(p) ((p)-MAX_RT_PRIO) +#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO)) -#define NICE_TO_TIMESLICE(n) (MIN_TIMESLICE + \ - ((MAX_TIMESLICE - MIN_TIMESLICE) * (19 - (n))) / 39) +/* + * NICE_TO_TIMESLICE scales nice values [ -20 ... 19 ] + * to time slice values. + * + * The higher a process's priority, the bigger timeslices + * it gets during one round of execution. But even the lowest + * priority process gets MIN_TIMESLICE worth of execution time. + */ + +#define NICE_TO_TIMESLICE(n) (MIN_TIMESLICE + \ + ((MAX_TIMESLICE - MIN_TIMESLICE) * (19-(n))) / 39) extern void set_cpus_allowed(task_t *p, unsigned long new_mask); extern void set_user_nice(task_t *p, long nice); @@ -541,6 +562,17 @@ static inline int signal_pending(struct task_struct *p) { return (p->sigpending != 0); +} + +static inline int need_resched(void) +{ + return unlikely(current->need_resched != 0); +} + +static inline void cond_resched(void) +{ + if (need_resched()) + schedule(); } /* diff -urN linux-2.5.3-pre1/include/scsi/sg.h linux/include/scsi/sg.h --- linux-2.5.3-pre1/include/scsi/sg.h Fri Sep 7 09:28:37 2001 +++ linux/include/scsi/sg.h Sat Jan 19 16:58:39 2002 @@ -11,78 +11,71 @@ Version 2 and 3 extensions to driver: * Copyright (C) 1998 - 2001 Douglas Gilbert - Version: 3.1.20 (20010814) - This version is for 2.4 series kernels. + Version: 3.5.23 (20011231) + This version is for 2.5 series kernels. - Changes since 3.1.19 (20010623) - - add SG_GET_ACCESS_COUNT ioctl - - make open() increment and close() decrement access_count - - only register first 256 devices, reject subsequent devices - Changes since 3.1.18 (20010505) - - fix bug that caused long wait when large buffer requested - - fix leak in error case of sg_new_read() [report: Eric Barton] - - add 'online' column to /proc/scsi/sg/devices - Changes since 3.1.17 (20000921) - - add CAP_SYS_RAWIO capability for sensitive stuff - - compile in dio stuff, procfs 'allow_dio' defaulted off (0) - - make premature close and detach more robust - - lun masked into commands <= SCSI_2 - - poll() and async notification now yield POLL_HUP on detach - - various 3rd party tweaks tracking lk 2.4 internal changes + Changes since 3.1.22 (20011208) + - branch sg driver for lk 2.5 series + - remove lock_kernel() from sg_close() + - remove code based on scsi mid level dma pool + - change scatterlist 'address' to use page + offset + - add SG_INTERFACE_ID_ORIG Map of SG verions to the Linux kernels in which they appear: ---------- ---------------------------------- original all kernels < 2.2.6 - 2.1.38 2.2.16 - 2.1.39 2.2.17 - 2.2.19 + 2.1.40 2.2.20 3.0.x optional version 3 sg driver for 2.2 series - 3.1.17 2.4.0 ++ + 3.1.17++ 2.4.0++ + 3.5.23++ 2.5.0++ Major new features in SG 3.x driver (cf SG 2.x drivers) - SG_IO ioctl() combines function if write() and read() - new interface (sg_io_hdr_t) but still supports old interface - - scatter/gather in user space and direct IO supported + - scatter/gather in user space, direct IO, and mmap supported - The term "indirect IO" refers a method by which data is DMAed into kernel - buffers from the hardware and afterwards is transferred into the user - space (or vice versa if you are writing). Transfer speeds of up to 20 to - 30MBytes/sec have been measured using indirect IO. For faster throughputs - "direct IO" which cuts out the double handling of data is required. - Direct IO is supported by the SG 3.x drivers on 2.4 series Linux kernels - and requires the use of the new interface. - - Requests for direct IO with the new interface will automatically fall back - to indirect IO mode if they cannot be fulfilled. An example of such a case - is an ISA SCSI adapter which is only capable of DMAing to the lower 16MB of - memory due to the architecture of ISA. The 'info' field in the new - interface indicates whether a direct or indirect data transfer took place. - - Obtaining memory for the kernel buffers used in indirect IO is done by - first checking if the "reserved buffer" for the current file descriptor - is available and large enough. If these conditions are _not_ met then - kernel memory is obtained on a per SCSI command basis. This corresponds - to a write(), read() sequence or a SG_IO ioctl() call. Further, the - kernel memory that is suitable for DMA may be constrained by the - architecture of the SCSI adapter (e.g. ISA adapters). + The normal action of this driver is to use the adapter (HBA) driver to DMA + data into kernel buffers and then use the CPU to copy the data into the + user space (vice versa for writes). That is called "indirect" IO due to + the double handling of data. There are two methods offered to remove the + redundant copy: 1) direct IO which uses the kernel kiobuf mechanism and + 2) using the mmap() system call to map the reserve buffer (this driver has + one reserve buffer per fd) into the user space. Both have their advantages. + In terms of absolute speed mmap() is faster. If speed is not a concern, + indirect IO should be fine. Read the documentation for more information. ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be needed. That pseudo file's content is defaulted to 0. ** + + Historical note: this SCSI pass-through driver has been known as "sg" for + a decade. In broader kernel discussions "sg" is used to refer to scatter + gather techniques. The context should clarify which "sg" is referred to. Documentation ============= - A web site for SG device drivers can be found at: + A web site for the SG device driver can be found at: http://www.torque.net/sg [alternatively check the MAINTAINERS file] - The main documents are still based on 2.x versions: + The documentation for the sg version 3 driver can be found at: + http://www.torque.net/sg/p/sg_v3_ho.html + This is a rendering from DocBook source [change the extension to "sgml" + or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon). + + The older, version 2 documents discuss the original sg interface in detail: http://www.torque.net/sg/p/scsi-generic.txt http://www.torque.net/sg/p/scsi-generic_long.txt - Documentation on the changes and additions in 3.x version of the sg driver - can be found at: http://www.torque.net/sg/p/scsi-generic_v3.txt A version of this document (potentially out of date) may also be found in the kernel source tree, probably at: /usr/src/linux/Documentation/scsi-generic.txt . - Utility and test programs are available at the sg web site. + + Utility and test programs are available at the sg web site. They are + bundled as sg_utils (for the lk 2.2 series) and sg3_utils (for the + lk 2.4 series). + + There is a HOWTO on the Linux SCSI subsystem in the lk 2.4 series at: + http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO */ + /* New interface introduced in the 3.x SG drivers follows */ typedef struct sg_iovec /* same structure as used by readv() Linux system */ @@ -119,20 +112,23 @@ unsigned int info; /* [o] auxiliary information */ } sg_io_hdr_t; /* 64 bytes long (on i386) */ +#define SG_INTERFACE_ID_ORIG 'S' + /* Use negative values to flag difference from original sg_header structure */ -#define SG_DXFER_NONE -1 /* e.g. a SCSI Test Unit Ready command */ -#define SG_DXFER_TO_DEV -2 /* e.g. a SCSI WRITE command */ -#define SG_DXFER_FROM_DEV -3 /* e.g. a SCSI READ command */ -#define SG_DXFER_TO_FROM_DEV -4 /* treated like SG_DXFER_FROM_DEV with the +#define SG_DXFER_NONE (-1) /* e.g. a SCSI Test Unit Ready command */ +#define SG_DXFER_TO_DEV (-2) /* e.g. a SCSI WRITE command */ +#define SG_DXFER_FROM_DEV (-3) /* e.g. a SCSI READ command */ +#define SG_DXFER_TO_FROM_DEV (-4) /* treated like SG_DXFER_FROM_DEV with the additional property than during indirect IO the user buffer is copied into the kernel buffers before the transfer */ -#define SG_DXFER_UNKNOWN -5 /* Unknown data direction */ +#define SG_DXFER_UNKNOWN (-5) /* Unknown data direction */ /* following flag values can be "or"-ed together */ #define SG_FLAG_DIRECT_IO 1 /* default is indirect IO */ -#define SG_FLAG_LUN_INHIBIT 2 /* default is to put device's lun into */ - /* the 2nd byte of SCSI command */ +#define SG_FLAG_LUN_INHIBIT 2 /* default is overwrite lun in SCSI */ + /* command block (when <= SCSI_2) */ +#define SG_FLAG_MMAP_IO 4 /* request memory mapped IO */ #define SG_FLAG_NO_DXFER 0x10000 /* no transfer of kernel buffers to/from */ /* user space (debug indirect IO) */ diff -urN linux-2.5.3-pre1/kernel/fork.c linux/kernel/fork.c --- linux-2.5.3-pre1/kernel/fork.c Sat Jan 19 16:58:37 2002 +++ linux/kernel/fork.c Sat Jan 19 16:58:39 2002 @@ -704,8 +704,9 @@ * runqueue lock is not a problem. */ current->time_slice = 1; - expire_task(current); + scheduler_tick(current); } + p->sleep_timestamp = jiffies; __restore_flags(flags); if (p->policy == SCHED_OTHER) diff -urN linux-2.5.3-pre1/kernel/ksyms.c linux/kernel/ksyms.c --- linux-2.5.3-pre1/kernel/ksyms.c Sat Jan 19 16:58:37 2002 +++ linux/kernel/ksyms.c Sat Jan 19 16:58:39 2002 @@ -137,6 +137,7 @@ EXPORT_SYMBOL(iunique); EXPORT_SYMBOL(iget4); EXPORT_SYMBOL(iput); +EXPORT_SYMBOL(inode_init_once); EXPORT_SYMBOL(force_delete); EXPORT_SYMBOL(follow_up); EXPORT_SYMBOL(follow_down); @@ -502,17 +503,16 @@ /* Added to make file system as module */ EXPORT_SYMBOL(sys_tz); EXPORT_SYMBOL(file_fsync); -EXPORT_SYMBOL(fsync_inode_buffers); -EXPORT_SYMBOL(fsync_inode_data_buffers); +EXPORT_SYMBOL(fsync_buffers_list); EXPORT_SYMBOL(clear_inode); EXPORT_SYMBOL(___strtok); EXPORT_SYMBOL(init_special_inode); EXPORT_SYMBOL(read_ahead); EXPORT_SYMBOL(__get_hash_table); -EXPORT_SYMBOL(get_empty_inode); +EXPORT_SYMBOL(new_inode); EXPORT_SYMBOL(insert_inode_hash); EXPORT_SYMBOL(remove_inode_hash); -EXPORT_SYMBOL(buffer_insert_inode_queue); +EXPORT_SYMBOL(buffer_insert_list); EXPORT_SYMBOL(make_bad_inode); EXPORT_SYMBOL(is_bad_inode); EXPORT_SYMBOL(event); diff -urN linux-2.5.3-pre1/kernel/printk.c linux/kernel/printk.c --- linux-2.5.3-pre1/kernel/printk.c Mon Jan 7 12:55:16 2002 +++ linux/kernel/printk.c Sat Jan 19 16:58:39 2002 @@ -524,7 +524,7 @@ */ void console_conditional_schedule(void) { - if (console_may_schedule && current->need_resched) { + if (console_may_schedule && need_resched()) { set_current_state(TASK_RUNNING); schedule(); } diff -urN linux-2.5.3-pre1/kernel/sched.c linux/kernel/sched.c --- linux-2.5.3-pre1/kernel/sched.c Sat Jan 19 16:58:37 2002 +++ linux/kernel/sched.c Sat Jan 19 16:58:39 2002 @@ -20,10 +20,7 @@ #include #include -#define BITMAP_SIZE ((MAX_PRIO+7)/8) -#define PRIO_INTERACTIVE (MAX_RT_PRIO + (MAX_PRIO - MAX_RT_PRIO) / 3) -#define TASK_INTERACTIVE(p) ((p)->prio >= MAX_RT_PRIO && (p)->prio <= PRIO_INTERACTIVE) -#define JSLEEP_TO_PRIO(t) (((t) * 20) / HZ) +#define BITMAP_SIZE ((((MAX_PRIO+7)/8)+sizeof(long)-1)/sizeof(long)) typedef struct runqueue runqueue_t; @@ -31,7 +28,7 @@ int nr_active; spinlock_t *lock; runqueue_t *rq; - char bitmap[BITMAP_SIZE]; + unsigned long bitmap[BITMAP_SIZE]; list_t queue[MAX_PRIO]; }; @@ -40,33 +37,36 @@ * * Locking rule: those places that want to lock multiple runqueues * (such as the load balancing or the process migration code), lock - * acquire operations must be ordered by rq->cpu. + * acquire operations must be ordered by the runqueue's cpu id. * * The RT event id is used to avoid calling into the the RT scheduler * if there is a RT task active in an SMP system but there is no * RT scheduling activity otherwise. */ -static struct runqueue { - int cpu; +struct runqueue { spinlock_t lock; unsigned long nr_running, nr_switches; task_t *curr, *idle; prio_array_t *active, *expired, arrays[2]; - char __pad [SMP_CACHE_BYTES]; -} runqueues [NR_CPUS] __cacheline_aligned; + int prev_nr_running[NR_CPUS]; +} ____cacheline_aligned; + +static struct runqueue runqueues[NR_CPUS] __cacheline_aligned; -#define this_rq() (runqueues + smp_processor_id()) -#define task_rq(p) (runqueues + (p)->cpu) #define cpu_rq(cpu) (runqueues + (cpu)) -#define cpu_curr(cpu) (runqueues[(cpu)].curr) +#define this_rq() cpu_rq(smp_processor_id()) +#define task_rq(p) cpu_rq((p)->cpu) +#define cpu_curr(cpu) (cpu_rq(cpu)->curr) +#define rq_cpu(rq) ((rq) - runqueues) #define rt_task(p) ((p)->policy != SCHED_OTHER) + #define lock_task_rq(rq,p,flags) \ do { \ repeat_lock_task: \ rq = task_rq(p); \ spin_lock_irqsave(&rq->lock, flags); \ - if (unlikely((rq)->cpu != (p)->cpu)) { \ + if (unlikely(rq_cpu(rq) != (p)->cpu)) { \ spin_unlock_irqrestore(&rq->lock, flags); \ goto repeat_lock_task; \ } \ @@ -94,18 +94,56 @@ p->array = array; } +/* + * A task is 'heavily interactive' if it has reached the + * bottom 25% of the SCHED_OTHER priority range - in this + * case we favor it by reinserting it on the active array, + * even after it expired its current timeslice. + * + * A task can get a priority bonus by being 'somewhat + * interactive' - and it will get a priority penalty for + * being a CPU hog. + * + * CPU-hog penalties cannot go more than 5 above the default + * priority level. Priority bonus cannot go below the minimum + * priority level. + */ +#define PRIO_INTERACTIVE (MAX_RT_PRIO + MAX_USER_PRIO/3) +#define TASK_INTERACTIVE(p) ((p)->prio <= PRIO_INTERACTIVE) + +static inline int effective_prio(task_t *p) +{ + int bonus, prio; + + /* + * Here we scale the actual sleep average [0 .... MAX_SLEEP_AVG] + * into the 20 ... -20 bonus/penalty range. + */ + bonus = MAX_USER_PRIO * p->sleep_avg / MAX_SLEEP_AVG - MAX_USER_PRIO/2; + prio = NICE_TO_PRIO(p->__nice) - bonus; + if (prio < MAX_RT_PRIO) + prio = MAX_RT_PRIO; + if (prio > MAX_PRIO-1) + prio = MAX_PRIO-1; + return prio; +} + static inline void activate_task(task_t *p, runqueue_t *rq) { prio_array_t *array = rq->active; if (!rt_task(p)) { - unsigned long prio_bonus = JSLEEP_TO_PRIO(jiffies - p->sleep_jtime); - - if (prio_bonus > MAX_PRIO) - prio_bonus = MAX_PRIO; - p->prio -= prio_bonus; - if (p->prio < MAX_RT_PRIO) - p->prio = MAX_RT_PRIO; + /* + * This code gives a bonus to interactive tasks. We update + * an 'average sleep time' value here, based on + * sleep_timestamp. The more time a task spends sleeping, + * the higher the average gets - and the higher the priority + * boost gets as well. + */ + p->sleep_avg += jiffies - p->sleep_timestamp; + if (p->sleep_avg > MAX_SLEEP_AVG) + p->sleep_avg = MAX_SLEEP_AVG; + p->prio = effective_prio(p); } enqueue_task(p, array); rq->nr_running++; @@ -116,7 +154,7 @@ rq->nr_running--; dequeue_task(p, p->array); p->array = NULL; - p->sleep_jtime = jiffies; + p->sleep_timestamp = jiffies; } static inline void resched_task(task_t *p) @@ -206,13 +244,13 @@ { runqueue_t *rq = this_rq(); - spin_lock_irq(&rq->lock); p->state = TASK_RUNNING; if (!rt_task(p)) { p->prio += MAX_USER_PRIO/10; if (p->prio > MAX_PRIO-1) p->prio = MAX_PRIO-1; } + spin_lock_irq(&rq->lock); activate_task(p, rq); spin_unlock_irq(&rq->lock); } @@ -287,59 +325,98 @@ } /* - * Current runqueue is empty, try to find work on - * other runqueues. + * Current runqueue is empty, or rebalance tick: if there is an + * inbalance (current runqueue is too short) then pull from + * busiest runqueue(s). * * We call this with the current runqueue locked, * irqs disabled. */ -static void load_balance(runqueue_t *this_rq) +static void load_balance(runqueue_t *this_rq, int idle) { - int nr_tasks, load, prev_max_load, max_load, idx, i; + int imbalance, nr_running, load, prev_max_load, + max_load, idx, i, this_cpu = smp_processor_id(); task_t *next = this_rq->idle, *tmp; - runqueue_t *busiest, *rq_tmp; + runqueue_t *busiest, *rq_src; prio_array_t *array; list_t *head, *curr; - prev_max_load = max_rq_len(); - nr_tasks = prev_max_load - this_rq->nr_running; - /* - * It needs an at least ~10% imbalance to trigger balancing: - */ - if (nr_tasks <= 1 + prev_max_load/8) - return; - prev_max_load++; - -repeat_search: /* * We search all runqueues to find the most busy one. * We do this lockless to reduce cache-bouncing overhead, - * we re-check the source CPU with the lock held. + * we re-check the 'best' source CPU later on again, with + * the lock held. + * + * We fend off statistical fluctuations in runqueue lengths by + * saving the runqueue length during the previous load-balancing + * operation and using the smaller one the current and saved lengths. + * If a runqueue is long enough for a longer amount of time then + * we recognize it and pull tasks from it. + * + * The 'current runqueue length' is a statistical maximum variable, + * for that one we take the longer one - to avoid fluctuations in + * the other direction. So for a load-balance to happen it needs + * stable long runqueue on the target CPU and stable short runqueue + * on the local runqueue. + * + * We make an exception if this CPU is about to become idle - in + * that case we are less picky about moving a task across CPUs and + * take what can be taken. */ + if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu])) + nr_running = this_rq->nr_running; + else + nr_running = this_rq->prev_nr_running[this_cpu]; + prev_max_load = 1000000000; + busiest = NULL; max_load = 0; for (i = 0; i < smp_num_cpus; i++) { - rq_tmp = cpu_rq(i); - load = rq_tmp->nr_running; + rq_src = cpu_rq(i); + if (idle || (rq_src->nr_running < this_rq->prev_nr_running[i])) + load = rq_src->nr_running; + else + load = this_rq->prev_nr_running[i]; + this_rq->prev_nr_running[i] = rq_src->nr_running; + if ((load > max_load) && (load < prev_max_load) && - (rq_tmp != this_rq)) { - busiest = rq_tmp; + (rq_src != this_rq)) { + busiest = rq_src; max_load = load; } } if (likely(!busiest)) return; - if (max_load <= this_rq->nr_running) + + imbalance = (max_load - nr_running) / 2; + + /* + * It needs an at least ~25% imbalance to trigger balancing. + * + * prev_max_load makes sure that we do not try to balance + * ad infinitum - certain tasks might be impossible to be + * pulled into this runqueue. + */ + if (!idle && (imbalance < (max_load + 3)/4)) return; prev_max_load = max_load; - if (busiest->cpu < this_rq->cpu) { + + /* + * Ok, lets do some actual balancing: + */ + + if (rq_cpu(busiest) < this_cpu) { spin_unlock(&this_rq->lock); spin_lock(&busiest->lock); spin_lock(&this_rq->lock); } else spin_lock(&busiest->lock); - if (busiest->nr_running <= this_rq->nr_running + 1) + /* + * Make sure nothing changed since we checked the + * runqueue length. + */ + if (busiest->nr_running <= nr_running + 1) goto out_unlock; /* @@ -365,15 +442,14 @@ array = busiest->active; goto new_array; } - spin_unlock(&busiest->lock); - goto repeat_search; + goto out_unlock; } head = array->queue + idx; curr = head->next; skip_queue: tmp = list_entry(curr, task_t, run_list); - if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << smp_processor_id()))) { + if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << this_cpu))) { curr = curr->next; if (curr != head) goto skip_queue; @@ -387,64 +463,96 @@ */ dequeue_task(next, array); busiest->nr_running--; - next->cpu = smp_processor_id(); + next->cpu = this_cpu; this_rq->nr_running++; enqueue_task(next, this_rq->active); if (next->prio < current->prio) current->need_resched = 1; - if (--nr_tasks) { + if (!idle && --imbalance) { if (array == busiest->expired) { array = busiest->active; goto new_array; } - spin_unlock(&busiest->lock); - goto repeat_search; } out_unlock: spin_unlock(&busiest->lock); } -/* Rebalance every 250 msecs */ -#define REBALANCE_TICK (HZ/4) +/* + * One of the idle_cpu_tick() or the busy_cpu_tick() function will + * gets called every timer tick, on every CPU. Our balancing action + * frequency and balancing agressivity depends on whether the CPU is + * idle or not. + * + * busy-rebalance every 250 msecs. idle-rebalance every 1 msec. (or on + * systems with HZ=100, every 10 msecs.) + */ +#define BUSY_REBALANCE_TICK (HZ/4 ?: 1) +#define IDLE_REBALANCE_TICK (HZ/1000 ?: 1) -void idle_tick(void) +static inline void idle_tick(void) { - unsigned long flags; - - if (!(jiffies % REBALANCE_TICK) && likely(this_rq()->curr != NULL)) { - spin_lock_irqsave(&this_rq()->lock, flags); - load_balance(this_rq()); - spin_unlock_irqrestore(&this_rq()->lock, flags); - } + if ((jiffies % IDLE_REBALANCE_TICK) || + likely(this_rq()->curr == NULL)) + return; + spin_lock(&this_rq()->lock); + load_balance(this_rq(), 1); + spin_unlock(&this_rq()->lock); } -void expire_task(task_t *p) +/* + * This function gets called by the timer code, with HZ frequency. + * We call it with interrupts disabled. + */ +void scheduler_tick(task_t *p) { + unsigned long now = jiffies; runqueue_t *rq = this_rq(); - unsigned long flags; + if (p == rq->idle || !rq->idle) + return idle_tick(); + /* Task might have expired already, but not scheduled off yet */ if (p->array != rq->active) { p->need_resched = 1; return; } + spin_lock(&rq->lock); + if (unlikely(rt_task(p))) { + /* + * RR tasks need a special form of timeslice management. + * FIFO tasks have no timeslices. + */ + if ((p->policy == SCHED_RR) && !--p->time_slice) { + p->time_slice = NICE_TO_TIMESLICE(p->__nice); + p->need_resched = 1; + + /* put it at the end of the queue: */ + dequeue_task(p, rq->active); + enqueue_task(p, rq->active); + } + goto out; + } /* - * The task cannot change CPUs because it's the current task. + * The task was running during this tick - update the + * time slice counter and the sleep average. Note: we + * do not update a process's priority until it either + * goes to sleep or uses up its timeslice. This makes + * it possible for interactive tasks to use up their + * timeslices at their high priority levels. */ - spin_lock_irqsave(&rq->lock, flags); - if ((p->policy != SCHED_FIFO) && !--p->time_slice) { - prio_array_t *array = rq->active; - p->need_resched = 1; + if (p->sleep_avg) + p->sleep_avg--; + if (!--p->time_slice) { dequeue_task(p, rq->active); - if (!rt_task(p)) { - if (++p->prio >= MAX_PRIO) - p->prio = MAX_PRIO - 1; - if (!TASK_INTERACTIVE(p)) - array = rq->expired; - } - enqueue_task(p, array); + p->need_resched = 1; + p->prio = effective_prio(p); p->time_slice = NICE_TO_TIMESLICE(p->__nice); + enqueue_task(p, TASK_INTERACTIVE(p) ? rq->active : rq->expired); } - spin_unlock_irqrestore(&rq->lock, flags); +out: + if (!(now % BUSY_REBALANCE_TICK)) + load_balance(rq, 0); + spin_unlock(&rq->lock); } void scheduling_functions_start_here(void) { } @@ -469,18 +577,18 @@ spin_lock_irq(&rq->lock); switch (prev->state) { - case TASK_INTERRUPTIBLE: - if (unlikely(signal_pending(prev))) { - prev->state = TASK_RUNNING; - break; - } - default: - deactivate_task(prev, rq); - case TASK_RUNNING: + case TASK_INTERRUPTIBLE: + if (unlikely(signal_pending(prev))) { + prev->state = TASK_RUNNING; + break; + } + default: + deactivate_task(prev, rq); + case TASK_RUNNING: } pick_next_task: if (unlikely(!rq->nr_running)) { - load_balance(rq); + load_balance(rq, 1); if (rq->nr_running) goto pick_next_task; next = rq->idle; @@ -520,7 +628,7 @@ spin_unlock_irq(&rq->lock); reacquire_kernel_lock(current); - if (unlikely(current->need_resched)) + if (need_resched()) goto need_resched_back; return; } @@ -1015,7 +1123,7 @@ p = find_process_by_pid(pid); if (p) jiffies_to_timespec(p->policy & SCHED_FIFO ? - 0 : NICE_TO_TIMESLICE(p->__nice), &t); + 0 : NICE_TO_TIMESLICE(p->prio), &t); read_unlock(&tasklist_lock); if (p) retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0; @@ -1123,7 +1231,7 @@ if (rq1 == rq2) spin_lock(&rq1->lock); else { - if (rq1->cpu < rq2->cpu) { + if (rq_cpu(rq1) < rq_cpu(rq2)) { spin_lock(&rq1->lock); spin_lock(&rq2->lock); } else { @@ -1152,7 +1260,7 @@ this_rq->curr = this_rq->idle = current; deactivate_task(current, rq); current->array = NULL; - current->prio = MAX_PRIO; + current->prio = MAX_PRIO-1; current->state = TASK_RUNNING; clear_bit(smp_processor_id(), &wait_init_idle); double_rq_unlock(this_rq, rq); @@ -1181,17 +1289,17 @@ rq->active = rq->arrays + 0; rq->expired = rq->arrays + 1; spin_lock_init(&rq->lock); - rq->cpu = i; for (j = 0; j < 2; j++) { array = rq->arrays + j; array->rq = rq; array->lock = &rq->lock; - for (k = 0; k < MAX_PRIO; k++) + for (k = 0; k < MAX_PRIO; k++) { INIT_LIST_HEAD(array->queue + k); - memset(array->bitmap, 0xff, BITMAP_SIZE); + __set_bit(k, array->bitmap); + } // zero delimiter for bitsearch - clear_bit(MAX_PRIO, array->bitmap); + __clear_bit(MAX_PRIO, array->bitmap); } } /* @@ -1202,9 +1310,6 @@ rq->curr = current; rq->idle = NULL; wake_up_process(current); - - for (i = 0; i < PIDHASH_SZ; i++) - pidhash[i] = NULL; init_timervecs(); init_bh(TIMER_BH, timer_bh); diff -urN linux-2.5.3-pre1/kernel/softirq.c linux/kernel/softirq.c --- linux-2.5.3-pre1/kernel/softirq.c Mon Jan 7 12:55:16 2002 +++ linux/kernel/softirq.c Sat Jan 19 16:58:39 2002 @@ -387,8 +387,7 @@ while (softirq_pending(cpu)) { do_softirq(); - if (current->need_resched) - schedule(); + cond_resched(); } __set_current_state(TASK_INTERRUPTIBLE); diff -urN linux-2.5.3-pre1/kernel/timer.c linux/kernel/timer.c --- linux-2.5.3-pre1/kernel/timer.c Mon Jan 7 12:55:16 2002 +++ linux/kernel/timer.c Sat Jan 19 16:58:39 2002 @@ -585,17 +585,16 @@ update_one_process(p, user_tick, system, cpu); if (p->pid) { - expire_task(p); if (p->__nice > 0) kstat.per_cpu_nice[cpu] += user_tick; else kstat.per_cpu_user[cpu] += user_tick; kstat.per_cpu_system[cpu] += system; } else { - idle_tick(); if (local_bh_count(cpu) || local_irq_count(cpu) > 1) kstat.per_cpu_system[cpu] += system; } + scheduler_tick(p); } /* diff -urN linux-2.5.3-pre1/mm/filemap.c linux/mm/filemap.c --- linux-2.5.3-pre1/mm/filemap.c Sat Jan 19 16:58:37 2002 +++ linux/mm/filemap.c Sat Jan 19 16:58:39 2002 @@ -290,7 +290,7 @@ page_cache_release(page); - if (current->need_resched) { + if (need_resched()) { __set_current_state(TASK_RUNNING); schedule(); } @@ -400,7 +400,7 @@ } page_cache_release(page); - if (current->need_resched) { + if (need_resched()) { __set_current_state(TASK_RUNNING); schedule(); } diff -urN linux-2.5.3-pre1/mm/highmem.c linux/mm/highmem.c --- linux-2.5.3-pre1/mm/highmem.c Mon Jan 14 10:10:43 2002 +++ linux/mm/highmem.c Sat Jan 19 16:58:39 2002 @@ -367,12 +367,6 @@ if (pfn >= blk_max_pfn) return; -#ifndef CONFIG_HIGHMEM - /* - * should not hit for non-highmem case - */ - BUG(); -#endif bio_gfp = GFP_NOHIGHIO; pool = page_pool; } else { diff -urN linux-2.5.3-pre1/mm/swapfile.c linux/mm/swapfile.c --- linux-2.5.3-pre1/mm/swapfile.c Sat Jan 19 16:58:37 2002 +++ linux/mm/swapfile.c Sat Jan 19 16:58:39 2002 @@ -696,7 +696,7 @@ * interactive performance. Interruptible check on * signal_pending() would be nice, but changes the spec? */ - if (current->need_resched) + if (need_resched()) schedule(); } diff -urN linux-2.5.3-pre1/mm/vmscan.c linux/mm/vmscan.c --- linux-2.5.3-pre1/mm/vmscan.c Sat Dec 29 17:30:07 2001 +++ linux/mm/vmscan.c Sat Jan 19 16:58:39 2002 @@ -300,7 +300,7 @@ counter = mmlist_nr; do { - if (unlikely(current->need_resched)) { + if (need_resched()) { __set_current_state(TASK_RUNNING); schedule(); } @@ -345,7 +345,7 @@ while (--max_scan >= 0 && (entry = inactive_list.prev) != &inactive_list) { struct page * page; - if (unlikely(current->need_resched)) { + if (need_resched()) { spin_unlock(&pagemap_lru_lock); __set_current_state(TASK_RUNNING); schedule(); @@ -625,8 +625,7 @@ for (i = pgdat->nr_zones-1; i >= 0; i--) { zone = pgdat->node_zones + i; - if (unlikely(current->need_resched)) - schedule(); + cond_resched(); if (!zone->need_balance) continue; if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) { diff -urN linux-2.5.3-pre1/net/ipv4/netfilter/ip_fw_compat_redir.c linux/net/ipv4/netfilter/ip_fw_compat_redir.c --- linux-2.5.3-pre1/net/ipv4/netfilter/ip_fw_compat_redir.c Sat Jan 19 16:58:37 2002 +++ linux/net/ipv4/netfilter/ip_fw_compat_redir.c Sat Jan 19 16:58:39 2002 @@ -270,8 +270,10 @@ if (redir) { DEBUGP("Doing tcp redirect again.\n"); do_tcp_redir(skb, redir); - if (del_timer(&redir->destroyme)) - add_timer(&redir->destroyme, jiffies + REDIR_TIMEOUT); + if (del_timer(&redir->destroyme)) { + redir->destroyme.expires = jiffies + REDIR_TIMEOUT; + add_timer(&redir->destroyme); + } } UNLOCK_BH(&redir_lock); } @@ -296,8 +298,10 @@ if (redir) { DEBUGP("Doing tcp unredirect.\n"); do_tcp_unredir(skb, redir); - if (del_timer(&redir->destroyme)) - add_timer(&redir->destroyme, jiffies + REDIR_TIMEOUT); + if (del_timer(&redir->destroyme)) { + redir->destroyme.expires = jiffies + REDIR_TIMEOUT; + add_timer(&redir->destroyme); + } } UNLOCK_BH(&redir_lock); } diff -urN linux-2.5.3-pre1/net/socket.c linux/net/socket.c --- linux-2.5.3-pre1/net/socket.c Sat Jan 19 16:58:37 2002 +++ linux/net/socket.c Sat Jan 19 16:58:39 2002 @@ -278,16 +278,17 @@ static struct super_block * sockfs_read_super(struct super_block *sb, void *data, int silent) { - struct inode *root = new_inode(sb); + struct inode *root; + sb->s_blocksize = 1024; + sb->s_blocksize_bits = 10; + sb->s_magic = SOCKFS_MAGIC; + sb->s_op = &sockfs_ops; + root = new_inode(sb); if (!root) return NULL; root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; root->i_uid = root->i_gid = 0; root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; - sb->s_blocksize = 1024; - sb->s_blocksize_bits = 10; - sb->s_magic = SOCKFS_MAGIC; - sb->s_op = &sockfs_ops; sb->s_root = d_alloc(NULL, &(const struct qstr) { "socket:", 7, 0 }); if (!sb->s_root) { iput(root); @@ -437,11 +438,11 @@ struct inode * inode; struct socket * sock; - inode = get_empty_inode(); + inode = new_inode(sock_mnt->mnt_sb); if (!inode) return NULL; - inode->i_sb = sock_mnt->mnt_sb; + inode->i_dev = NODEV; sock = socki_lookup(inode); inode->i_mode = S_IFSOCK|S_IRWXUGO; diff -urN linux-2.5.3-pre1/net/sunrpc/sched.c linux/net/sunrpc/sched.c --- linux-2.5.3-pre1/net/sunrpc/sched.c Mon Jan 14 10:10:43 2002 +++ linux/net/sunrpc/sched.c Sat Jan 19 16:58:39 2002 @@ -721,7 +721,7 @@ __rpc_execute(task); - if (++count >= 200 || current->need_resched) { + if (++count >= 200 || need_resched()) { count = 0; schedule(); }