Import 2.1.622.1.62
authorLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:14:00 +0000 (23 15:14 -0500)
committerLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:14:00 +0000 (23 15:14 -0500)
75 files changed:
CREDITS
Documentation/Configure.help
Makefile
arch/alpha/kernel/time.c
drivers/block/ide-probe.c
drivers/char/lp.c
drivers/isdn/avmb1/capi.c
drivers/isdn/hisax/avm_a1.c
drivers/isdn/hisax/elsa.c
drivers/isdn/hisax/isdnl1.c
drivers/isdn/hisax/ix1_micro.c
drivers/isdn/hisax/teles0.c
drivers/isdn/hisax/teles3.c
drivers/isdn/isdn_common.c
drivers/net/3c501.c
drivers/net/3c503.c
drivers/net/3c505.c
drivers/net/3c507.c
drivers/net/3c509.c
drivers/net/ac3200.c
drivers/net/apricot.c
drivers/net/arc-rimi.c
drivers/net/at1700.c
drivers/net/atp.c
drivers/net/auto_irq.c
drivers/net/com20020.c
drivers/net/com90io.c
drivers/net/com90xx.c
drivers/net/cops.c
drivers/net/cs89x0.c
drivers/net/de600.c
drivers/net/de620.c
drivers/net/depca.c
drivers/net/e2100.c
drivers/net/eepro.c
drivers/net/eexpress.c
drivers/net/es3210.c
drivers/net/eth16i.c
drivers/net/ewrk3.c
drivers/net/fmv18x.c
drivers/net/hp-plus.c
drivers/net/hp.c
drivers/net/ibmtr.c
drivers/net/lance.c
drivers/net/ltpc.c
drivers/net/ne.c
drivers/net/net_init.c
drivers/net/ni52.c
drivers/net/ni65.c
drivers/net/pi2.c
drivers/net/pt.c
drivers/net/sdla.c
drivers/net/seeq8005.c
drivers/net/sgiseeq.c
drivers/net/sk_g16.c
drivers/net/skeleton.c
drivers/net/smc-mca.c
drivers/net/smc-ultra.c
drivers/net/smc9194.c
drivers/net/wavelan.c
drivers/net/wd.c
drivers/net/znet.c
drivers/scsi/Makefile
drivers/scsi/ppa.c
drivers/scsi/ppa.h
drivers/scsi/scsi.c
drivers/scsi/sr.c
drivers/scsi/sr.h
drivers/scsi/sr_ioctl.c
drivers/scsi/sr_vendor.c
fs/dquot.c
fs/nfs/dir.c
include/linux/isdnif.h
include/linux/quota.h
kernel/ksyms.c

index 03a5965..fa6af4a 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1094,10+1094,10 @@ S: D-37083 Goettingen
 S: Germany
 
 N: David Mosberger-Tang
-E: davidm@azstarnet.com
+E: David.Mosberger@acm.org
 D: Linux/Alpha
-S: 2552 E. Copper Street
-S: Tucson, Arizona 85716-2406
+S: 35706 Runckel Lane
+S: Fremont, CA 94536
 S: USA
 
 N: Ian A. Murdock
index 1e5cbaa..522d73a 100644 (file)
@@ -1667,10+1667,10 @@ CONFIG_BLK_DEV_SR
 Enable vendor-specific extensions (for SCSI CDROM)
 CONFIG_BLK_DEV_SR_VENDOR
   This enables the usage of vendor specific SCSI commands. This is
-  required for some stuff which is newer than the SCSI-II standard:
-  MultiSession CD support and some ioctls for reading Mode 2 Form 2
-  sectors. You'll probably want to say Y here, unless you have a
-  _really old_ CD-ROM drive.
+  required to support multisession CD's on with old NEC/TOSHIBA
+  cdrom drives (and HP Writers). If you have such a drive and get
+  the first session only, try to turn this on. Most drives should
+  work fine without this.
 
 SCSI generic support
 CONFIG_CHR_DEV_SG
index 73c503a..a969c6a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6+1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 61
+SUBLEVEL = 62
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
index b289d4f..4a2ccbd 100644 (file)
  *      precision CMOS clock update
  * 1997-01-09    Adrian Sun
  *      use interval timer if CONFIG_RTC=y
+ * 1997-10-29    John Bowman (bowman@math.ualberta.ca)
+ *      fixed tick loss calculation in timer_interrupt
+ *      (round system clock to nearest tick instead of truncating)
+ *      fixed algorithm in time_init for getting time from CMOS clock
  */
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/hwrpb.h>
+#include <asm/delay.h>
 
 #include <linux/mc146818rtc.h>
 #include <linux/timex.h>
@@ -45,10+50,11 @@ static int set_rtc_mmss(unsigned long);
  */
 #define FIX_SHIFT      48
 
+static unsigned long round_ticks;
+
 /* lump static variables together for more efficient access: */
 static struct {
        __u32           last_time;              /* cycle counter last time it got invoked */
-       __u32           max_cycles_per_tick;    /* more makes us think we lost an interrupt */
        unsigned long   scaled_ticks_per_cycle; /* ticks/cycle * 2^48 */
        long            last_rtc_update;        /* last time the cmos clock got updated */
 } state;
@@ -70,19+76,15 @@ static inline __u32 rpcc(void)
 void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
 {
        __u32 delta, now;
+       int i, nticks;
 
        now = rpcc();
        delta = now - state.last_time;
        state.last_time = now;
-       if (delta > state.max_cycles_per_tick) {
-               int i, missed_ticks;
-
-               missed_ticks = ((delta * state.scaled_ticks_per_cycle) >> FIX_SHIFT) - 1;
-               for (i = 0; i < missed_ticks; ++i) {
-                       do_timer(regs);
-               }
+       nticks = ((delta * state.scaled_ticks_per_cycle+round_ticks) >> FIX_SHIFT);
+       for (i = 0; i < nticks; ++i) {
+               do_timer(regs);
        }
-       do_timer(regs);
 
        /*
         * If we have an externally synchronized Linux clock, then update
@@ -136,7+138,6 @@ void time_init(void)
 #endif
         void (*irq_handler)(int, void *, struct pt_regs *);
        unsigned int year, mon, day, hour, min, sec;
-       int i;
 
        /* The Linux interpretation of the CMOS clock register contents:
         * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
@@ -144,20+145,23 @@ void time_init(void)
         * Let's hope other operating systems interpret the RTC the same way.
         */
        /* read RTC exactly on falling edge of update flag */
-       for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
-               if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-                       break;
-       for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
-               if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-                       break;
-       do { /* Isn't this overkill ? UIP above should guarantee consistency */
-               sec = CMOS_READ(RTC_SECONDS);
-               min = CMOS_READ(RTC_MINUTES);
-               hour = CMOS_READ(RTC_HOURS);
-               day = CMOS_READ(RTC_DAY_OF_MONTH);
-               mon = CMOS_READ(RTC_MONTH);
-               year = CMOS_READ(RTC_YEAR);
-       } while (sec != CMOS_READ(RTC_SECONDS));
+       /* Wait for rise.... (may take up to 1 second) */
+       
+       while(!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
+       
+    /* Wait for fall.... */
+       
+       while(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+       
+    __delay(1000000);
+         
+       sec = CMOS_READ(RTC_SECONDS);
+       min = CMOS_READ(RTC_MINUTES);
+       hour = CMOS_READ(RTC_HOURS);
+       day = CMOS_READ(RTC_DAY_OF_MONTH);
+       mon = CMOS_READ(RTC_MONTH);
+       year = CMOS_READ(RTC_YEAR);
+
        if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
          {
            BCD_TO_BIN(sec);
@@ -186,7+190,7 @@ void time_init(void)
        }
        state.last_time = rpcc();
        state.scaled_ticks_per_cycle = ((unsigned long) HZ << FIX_SHIFT) / hwrpb->cycle_freq;
-       state.max_cycles_per_tick = (2 * hwrpb->cycle_freq) / HZ;
+       round_ticks=(unsigned long) 1 << (FIX_SHIFT-1);
        state.last_rtc_update = 0;
 
 #ifdef CONFIG_RTC 
index 66c7b48..3ce3e88 100644 (file)
@@ -123,11+123,12 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
 #endif /* CONFIG_BLK_DEV_PROMISE */
                switch (type) {
                        case ide_floppy:
-                               if (strstr (id->model, "oppy") || strstr (id->model, "poyp")) {
+                               if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP"))
+                                       printk("cdrom or floppy?, assuming ");
+                               if (drive->media != ide_cdrom) {
                                        printk ("FLOPPY");
                                        break;
                                }
-                               printk ("cdrom or floppy?, assuming ");
                                type = ide_cdrom;       /* Early cdrom models used zero */
                        case ide_cdrom:
                                printk ("CDROM");
index 0ee0c53..fdfb961 100644 (file)
@@ -272,9+272,9 @@ static inline int lp_write_buf(unsigned int minor, const char *buf, int count)
        return total_bytes_written;
 }
 
-static long lp_write(struct inode * inode, struct file * file,
-       const char * buf, unsigned long count)
+static ssize_t lp_write(struct file * file, const char * buf, size_t count, loff_t *ppos)
 {
+       struct inode *inode = file->f_dentry->d_inode;
        unsigned int minor = MINOR(inode->i_rdev);
        int retv;
 
@@ -315,9+315,9 @@ static void lp_select_in_high(int minor) {
 }
 
 /* Status readback confirming to ieee1284 */
-static long lp_read(struct inode * inode, struct file * file, 
-                  char * buf, unsigned long count)
+static ssize_t lp_read(struct file * file, char * buf, size_t count, loff_t *ppos)
 {
+       struct inode *inode = file->f_dentry->d_inode;
        unsigned char z=0, Byte=0, status;
        char *temp;
        int retval;
index 41e225e..aed5ca0 100644 (file)
 #include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/skbuff.h>
-#if (LINUX_VERSION_CODE >= 0x020117)
-#include <asm/poll.h>
-#endif
 #include <linux/capi.h>
 #include <linux/kernelcapi.h>
 
+#include <asm/poll.h>
+
 #include "compat.h"
 #include "capiutil.h"
 #include "capicmd.h"
@@ -96,29+95,16 @@ static void capi_signal(__u16 applid, __u32 minor)
 
 /* -------- file_operations ----------------------------------------- */
 
-#if LINUX_VERSION_CODE < 0x020100
-static int capi_lseek(struct inode *inode, struct file *file,
-                     off_t offset, int origin)
+static loff_t capi_llseek(struct file *file, loff_t offset, int origin)
 {
        return -ESPIPE;
 }
-#else
-static long long capi_llseek(struct inode *inode, struct file *file,
-                            long long offset, int origin)
-{
-       return -ESPIPE;
-}
-#endif
 
-#if LINUX_VERSION_CODE < 0x020100
-static int capi_read(struct inode *inode, struct file *file,
-                    char *buf, int count)
-#else
-static long capi_read(struct inode *inode, struct file *file,
-                     char *buf, unsigned long count)
-#endif
+static ssize_t capi_read(struct file *file,
+                     char *buf, size_t count,
+                     loff_t *off)
 {
-       unsigned int minor = MINOR(inode->i_rdev);
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
        struct capidev *cdev;
        struct sk_buff *skb;
        int retval;
@@ -164,15+150,11 @@ static long capi_read(struct inode *inode, struct file *file,
        return copied;
 }
 
-#if LINUX_VERSION_CODE < 0x020100
-static int capi_write(struct inode *inode, struct file *file,
-                     const char *buf, int count)
-#else
-static long capi_write(struct inode *inode, struct file *file,
-                      const char *buf, unsigned long count)
-#endif
+static ssize_t capi_write(struct file *file,
+                      const char *buf, size_t count,
+                      loff_t *off)
 {
-       unsigned int minor = MINOR(inode->i_rdev);
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
        struct capidev *cdev;
        struct sk_buff *skb;
        int retval;
@@ -215,40+197,6 @@ static long capi_write(struct inode *inode, struct file *file,
        return count;
 }
 
-#if (LINUX_VERSION_CODE < 0x020117)
-static int capi_select(struct inode *inode, struct file *file,
-                      int sel_type, select_table * wait)
-{
-       unsigned int minor = MINOR(inode->i_rdev);
-       struct capidev *cdev;
-
-       if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
-               return -ENODEV;
-
-       cdev = &capidevs[minor];
-
-       switch (sel_type) {
-       case SEL_IN:
-               if (!skb_queue_empty(&cdev->recv_queue))
-                       return 1;
-               /* fall througth */
-       case SEL_EX:
-               /* error conditions ? */
-
-               select_wait(&cdev->recv_wait, wait);
-               return 0;
-       case SEL_OUT:
-               /* 
-                  if (!queue_full())
-                  return 1;
-                  select_wait(&cdev->send_wait, wait);
-                  return 0;
-                */
-               return 1;
-       }
-       return 1;
-}
-#else
 static unsigned int
 capi_poll(struct file *file, poll_table * wait)
 {
@@ -266,7+214,6 @@ capi_poll(struct file *file, poll_table * wait)
                mask |= POLLIN | POLLRDNORM;
        return mask;
 }
-#endif
 
 static int capi_ioctl(struct inode *inode, struct file *file,
                      unsigned int cmd, unsigned long arg)
@@ -480,19+427,11 @@ capi_release(struct inode *inode, struct file *file)
 
 static struct file_operations capi_fops =
 {
-#if LINUX_VERSION_CODE < 0x020100
-       capi_lseek,
-#else
        capi_llseek,
-#endif
        capi_read,
        capi_write,
        NULL,                   /* capi_readdir */
-#if (LINUX_VERSION_CODE < 0x020117)
-       capi_select,
-#else
        capi_poll,
-#endif
        capi_ioctl,
        NULL,                   /* capi_mmap */
        capi_open,
index a175499..8b5bea4 100644 (file)
@@ -558,7+558,7 @@ avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        u_char val, sval, stat = 0;
        char tmp[32];
 
-       sp = (struct IsdnCardState *) irq2dev_map[intno];
+       sp = (struct IsdnCardState *) dev_id;
 
        if (!sp) {
                printk(KERN_WARNING "AVM A1: Spurious interrupt!\n");
@@ -798,8+798,7 @@ initavm_a1(struct IsdnCardState *sp)
                        printk(KERN_WARNING
                               "AVM A1: IRQ(%d) getting no interrupts during init\n",
                               sp->irq);
-                       irq2dev_map[sp->irq] = NULL;
-                       free_irq(sp->irq, NULL);
+                       free_irq(sp->irq, sp);
                        return (0);
                }
        }
index 9c402f4..28db332 100644 (file)
@@ -887,7+887,7 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        struct IsdnCardState *sp;
        u_char val;
 
-       sp = (struct IsdnCardState *) irq2dev_map[intno];
+       sp = (struct IsdnCardState *) dev_id;
 
        if (!sp) {
                printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
@@ -1219,8+1219,7 @@ initelsa(struct IsdnCardState *sp)
                               "Elsa: IRQ(%d) getting no interrupts during init %d\n",
                               sp->irq, 4 - cnt);
                        if (cnt == 1) {
-                               irq2dev_map[sp->irq] = NULL;
-                               free_irq(sp->irq, NULL);
+                               free_irq(sp->irq, sp);
                                return (0);
                        } else {
                                reset_elsa(sp);
index 0dc0bb5..291f846 100644 (file)
@@ -766,13+766,12 @@ get_irq(int cardnr, void *routine)
        save_flags(flags);
        cli();
        if (request_irq(card->sp->irq, routine,
-                       I4L_IRQ_FLAG, "HiSax", NULL)) {
+                       I4L_IRQ_FLAG, "HiSax", card->sp)) {
                printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
                       card->sp->irq);
                restore_flags(flags);
                return (0);
        }
-       irq2dev_map[card->sp->irq] = (void *) card->sp;
        restore_flags(flags);
        return (1);
 }
@@ -782,8+781,7 @@ release_irq(int cardnr)
 {
        struct IsdnCard *card = cards + cardnr;
 
-       irq2dev_map[card->sp->irq] = NULL;
-       free_irq(card->sp->irq, NULL);
+       free_irq(card->sp->irq, card->sp);
 }
 
 void
index ac98a4b..7076352 100644 (file)
@@ -644,7+644,7 @@ ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        struct IsdnCardState *sp;
        u_char val, stat = 0;
 
-       sp = (struct IsdnCardState *) irq2dev_map[intno];
+       sp = (struct IsdnCardState *) dev_id;
 
        if (!sp) {
                printk(KERN_WARNING "Teles: Spurious interrupt!\n");
@@ -867,8+867,7 @@ initix1micro(struct IsdnCardState *sp)
                        printk(KERN_WARNING
                               "ix1-Micro: IRQ(%d) getting no interrupts during init\n",
                               sp->irq);
-                       irq2dev_map[sp->irq] = NULL;
-                       free_irq(sp->irq, NULL);
+                       free_irq(sp->irq, sp);
                        return (0);
                }
        }
index 0c21e52..0560eff 100644 (file)
@@ -605,7+605,7 @@ telesS0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        struct IsdnCardState *sp;
        u_char val, stat = 0;
 
-       sp = (struct IsdnCardState *) irq2dev_map[intno];
+       sp = (struct IsdnCardState *) dev_id;
 
        if (!sp) {
                printk(KERN_WARNING "Teles0: Spurious interrupt!\n");
@@ -828,8+828,7 @@ initteles0(struct IsdnCardState *sp)
                        printk(KERN_WARNING
                               "Teles0: IRQ(%d) getting no interrupts during init\n",
                               sp->irq);
-                       irq2dev_map[sp->irq] = NULL;
-                       free_irq(sp->irq, NULL);
+                       free_irq(sp->irq, sp);
                        return (0);
                }
        }
index 357f21e..c83a009 100644 (file)
@@ -585,7+585,7 @@ teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        u_char val, stat = 0;
        int count = 0;
 
-       sp = (struct IsdnCardState *) irq2dev_map[intno];
+       sp = (struct IsdnCardState *) dev_id;
 
        if (!sp) {
                printk(KERN_WARNING "Teles: Spurious interrupt!\n");
@@ -829,8+829,7 @@ initteles3(struct IsdnCardState *sp)
                        printk(KERN_WARNING
                               "Teles3: IRQ(%d) getting no interrupts during init\n",
                               sp->irq);
-                       irq2dev_map[sp->irq] = NULL;
-                       free_irq(sp->irq, NULL);
+                       free_irq(sp->irq, sp);
                        return (0);
                }
        }
index 89271da..5402c5b 100644 (file)
@@ -849,9+849,9 @@ isdn_info_update(void)
 }
 
 static RWTYPE
-isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count)
+isdn_read(struct file *file, char *buf, RWARG count, loff_t *off)
 {
-       uint minor = MINOR(inode->i_rdev);
+       uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
        int len = 0;
        ulong flags;
        int drvidx;
@@ -869,7+869,7 @@ isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count)
                if ((len = strlen(p)) <= count) {
                        if (copy_to_user(buf, p, len))
                                return -EFAULT;
-                       file->f_pos += len;
+                       *off += len;
                        return len;
                }
                return 0;
@@ -886,7+886,7 @@ isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count)
                save_flags(flags);
                cli();
                len = isdn_readbchan(drvidx, chidx, buf, 0, count, 1);
-               file->f_pos += len;
+               *off += len;
                restore_flags(flags);
                return len;
        }
@@ -912,7+912,7 @@ isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count)
                else
                        dev->drv[drvidx]->stavail = 0;
                restore_flags(flags);
-               file->f_pos += len;
+               *off += len;
                return len;
        }
 #ifdef CONFIG_ISDN_PPP
@@ -928,9+928,9 @@ static LSTYPE isdn_lseek(struct file *file, LSARG offset, int orig)
 }
 
 static RWTYPE
-isdn_write(struct inode *inode, struct file *file, const char *buf, RWARG count)
+isdn_write(struct file *file, const char *buf, RWARG count, loff_t * off)
 {
-       uint minor = MINOR(inode->i_rdev);
+       uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
        int drvidx;
        int chidx;
 
index ef5abd2..d5cb133 100644 (file)
@@ -758,7+758,7 @@ static int el1_close(struct device *dev)
         *      Free and disable the IRQ.
         */
 
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
        outb(AX_RESET, AX_CMD);         /* Reset the chip */
 
        MOD_DEC_USE_COUNT;
index 774ac32..228404f 100644 (file)
@@ -369,7+369,7 @@ el2_open(struct device *dev)
 static int
 el2_close(struct device *dev)
 {
-    free_irq(dev->irq, NULL);
+    free_irq(dev->irq, dev);
     dev->irq = ei_status.saved_irq;
     outb(EGACFR_IRQOFF, E33G_GACFR);   /* disable interrupts. */
 
index 20c3e6a..ae1f06c 100644 (file)
@@ -1216,7+1216,7 @@ static int elp_close(struct device *dev)
        /*
         * release the IRQ
         */
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
 
        free_dma(dev->dma);
        free_pages((unsigned long) adapter->dma_buffer, __get_order(DMA_BUFFER_SIZE));
index 5981e29..bb0c7b7 100644 (file)
@@ -890,7+890,7 @@ cleanup_module(void)
        dev_3c507.priv = NULL;
 
        /* If we don't do this, we can't re-insmod it later. */
-       free_irq(dev_3c507.irq, NULL);
+       free_irq(dev_3c507.irq, &dev_3c507);
        release_region(dev_3c507.base_addr, EL16_IO_EXTENT);
 }
 #endif /* MODULE */
index 965cd27..febe4b5 100644 (file)
@@ -866,7+866,7 @@ cleanup_module(void)
                if (dev->priv != NULL) {
                        kfree_s(dev->priv,sizeof(struct el3_private));
                        dev->priv = NULL;
-                       free_irq(dev->irq, NULL);
+                       free_irq(dev->irq, dev);
                        release_region(dev->base_addr, EL3_IO_EXTENT);
                        unregister_netdev(dev);
                }
index 8208de6..524dc64 100644 (file)
@@ -173,7+173,7 @@ __initfunc(static int ac_probe1(int ioaddr, struct device *dev))
        /* Allocate dev->priv and fill in 8390 specific dev fields. */
        if (ethdev_init(dev)) {
                printk (" unable to allocate memory for dev->priv.\n");
-               free_irq(dev->irq, NULL);
+               free_irq(dev->irq, dev);
                return -ENOMEM;
        }
 
@@ -303,7+303,7 @@ static int ac_close_card(struct device *dev)
 #ifdef notyet
        /* We should someday disable shared memory and interrupts. */
        outb(0x00, ioaddr + 6); /* Disable interrupts. */
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
 #endif
 
        ei_close(dev);
@@ -369,7+369,7 @@ cleanup_module(void)
                        kfree(dev->priv);
                        dev->priv = NULL;
                        /* Someday free_irq may be in ac_close_card() */
-                       free_irq(dev->irq, NULL);
+                       free_irq(dev->irq, dev);
                        release_region(dev->base_addr, AC_IO_EXTENT);
                        unregister_netdev(dev);
                }
index 0cedcac..4ff31e9 100644 (file)
@@ -547,7+547,7 @@ i596_open(struct device *dev)
 
     if (i < 4)
     {
-        free_irq(dev->irq, NULL);
+        free_irq(dev->irq, dev);
         return -EAGAIN;
     }
 
@@ -930,7+930,7 @@ i596_close(struct device *dev)
                   dev->name, lp->scb.status, lp->scb.command);
            break;
        }
-    free_irq(dev->irq, NULL);
+    free_irq(dev->irq, dev);
     remove_rx_bufs(dev);
     MOD_DEC_USE_COUNT;
 
index c018163..2feb514 100644 (file)
@@ -220,7+220,7 @@ __initfunc(int arcrimi_found(struct device *dev,int node,int airq, u_long shmem)
   dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
   if (dev->priv == NULL)
     {
-      free_irq(airq,NULL);
+      free_irq(airq,dev);
       return -ENOMEM;
     }
   memset(dev->priv,0,sizeof(struct arcnet_local));
@@ -790,7+790,7 @@ void cleanup_module(void)
 
   if (dev->irq)
     {
-      free_irq(dev->irq,NULL);
+      free_irq(dev->irq,dev);
     }
 
   unregister_netdev(dev);
index e1a989f..cbe2d96 100644 (file)
@@ -654,7+654,7 @@ cleanup_module(void)
        dev_at1700.priv = NULL;
 
        /* If we don't do this, we can't re-insmod it later. */
-       free_irq(dev_at1700.irq, NULL);
+       free_irq(dev_at1700.irq, &dev_at1700);
        release_region(dev_at1700.base_addr, AT1700_IO_EXTENT);
 }
 #endif /* MODULE */
index c135d69..578a525 100644 (file)
@@ -727,7+727,7 @@ net_close(struct device *dev)
 
        /* Free the IRQ line. */
        outb(0x00, ioaddr + PAR_CONTROL);
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
 
        /* Leave the hardware in a reset state. */
     write_reg_high(ioaddr, CMR1, CMR1h_RESET);
index 2735454..efeaeb5 100644 (file)
@@ -46,8+46,11 @@ void autoirq_setup(int waittime)
        irqs = probe_irq_on();
 }
 
+#define BUSY_LOOP_UNTIL(j) while ((long)(jiffies-(j)) < 0) ;
 int autoirq_report(int waittime)
 {
+       unsigned long delay = jiffies + waittime;
+       BUSY_LOOP_UNTIL(delay)
        return probe_irq_off(irqs);
 }
 \f
index e9ea440..0b15ac9 100644 (file)
@@ -354,7+354,7 @@ __initfunc(int arc20020_found(struct device *dev,int ioaddr,int airq))
   dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
   if (dev->priv == NULL)
     {
-      free_irq(airq,NULL);
+      free_irq(airq,dev);
       release_region(ioaddr,ARCNET_TOTAL_SIZE);
       return -ENOMEM;
     }
@@ -1024,7+1024,7 @@ void cleanup_module(void)
 
   if (dev->irq)
     {
-      free_irq(dev->irq,NULL);
+      free_irq(dev->irq,dev);
     }
 
   if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE);
index 2378fe4..aac231e 100644 (file)
@@ -314,7+314,7 @@ __initfunc(int arc90io_found(struct device *dev,int ioaddr,int airq))
   dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
   if (dev->priv == NULL)
     {
-      free_irq(airq,NULL);
+      free_irq(airq,dev);
       release_region(ioaddr,ARCNET_TOTAL_SIZE);
       return -ENOMEM;
     }
@@ -903,7+903,7 @@ void cleanup_module(void)
 
   if (dev->irq)
     {
-      free_irq(dev->irq,NULL);
+      free_irq(dev->irq,dev);
     }
 
   if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE);
index 245fa80..9c572f3 100644 (file)
@@ -584,7+584,7 @@ __initfunc(static int arc90xx_found(struct device *dev,int ioaddr,int airq, u_lo
   dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
   if (dev->priv == NULL)
     {
-      free_irq(airq,NULL);
+      free_irq(airq,dev);
       release_region(ioaddr,ARCNET_TOTAL_SIZE);
       return -ENOMEM;
     }
@@ -1201,7+1201,7 @@ void cleanup_module(void)
 
   if (dev->irq)
     {
-      free_irq(dev->irq,NULL);
+      free_irq(dev->irq,dev);
     }
 
   if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE);
index 607c8fe..c1eda88 100644 (file)
@@ -1005,7+1005,7 @@ void cleanup_module(void)
 {
         /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 
-        free_irq(dev_cops.irq, NULL);
+        free_irq(dev_cops.irq, &dev_cops);
         release_region(dev_cops.base_addr, COPS_IO_EXTENT);
        unregister_netdev(&dev_cops);
 
index 9093e65..14224bf 100644 (file)
@@ -655,7+655,7 @@ net_open(struct device *dev)
                 printk("%s: EEPROM is configured for unavailable media\n", dev->name);
         release_irq:
                 writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
-                free_irq(dev->irq, NULL);
+                free_irq(dev->irq, dev);
                return -EAGAIN;
        }
 
@@ -918,7+918,7 @@ net_close(struct device *dev)
 
        dev->start = 0;
 
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
 
        /* Update the statistics here. */
 
index 2fdee46..f739398 100644 (file)
@@ -366,7+366,7 @@ de600_close(struct device *dev)
        select_prn();
 
        if (dev->start) {
-               free_irq(DE600_IRQ, NULL);
+               free_irq(DE600_IRQ, dev);
                dev->start = 0;
                MOD_DEC_USE_COUNT;
        }
index 3ac90a8..ff2251c 100644 (file)
@@ -463,7+463,7 @@ de620_close(struct device *dev)
        /* disable recv */
        de620_set_register(dev, W_TCR, RXOFF);
 
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
 
        dev->start = 0;
        MOD_DEC_USE_COUNT;
index 40841b8..7a53fe8 100644 (file)
@@ -1057,7+1057,7 @@ depca_close(struct device *dev)
   /*
   ** Free the associated irq
   */
-  free_irq(dev->irq, NULL);
+  free_irq(dev->irq, dev);
 
   MOD_DEC_USE_COUNT;
 
index ab39f79..3c2288f 100644 (file)
@@ -352,7+352,7 @@ e21_close(struct device *dev)
        if (ei_debug > 1)
                printk("%s: Shutting down ethercard.\n", dev->name);
 
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
        dev->irq = ei_status.saved_irq;
 
        /* Shut off the interrupt line and secondary interface. */
index a5e5521..bd568c2 100644 (file)
@@ -819,7+819,7 @@ eepro_close(struct device *dev)
        outb(RESET_CMD, ioaddr);
 
        /* release the interrupt */
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
 
        /* Update the statistics here. What statistics? */
 
index d92fbea..c78e798 100644 (file)
@@ -388,7+388,7 @@ static int eexp_close(struct device *dev)
        lp->started = 0;
        scb_command(dev, SCB_CUsuspend|SCB_RUsuspend);
        outb(0,ioaddr+SIGNAL_CA);
-       free_irq(irq,NULL);
+       free_irq(irq,dev);
        outb(i586_RST,ioaddr+EEPROM_Ctrl);
        release_region(ioaddr,16);
 
index de03aa7..b7e0cae 100644 (file)
@@ -225,7+225,7 @@ __initfunc(int es_probe1(struct device *dev, int ioaddr))
 
                if (mem_enabled != 0x80) {
                        printk(" shared mem disabled - giving up\n");
-                       free_irq(dev->irq, NULL);
+                       free_irq(dev->irq, dev);
                        return -ENXIO;
                }
                dev->mem_start = 0xC0000 + mem_bits*0x4000;
@@ -243,7+243,7 @@ __initfunc(int es_probe1(struct device *dev, int ioaddr))
        /* Allocate dev->priv and fill in 8390 specific dev fields. */
        if (ethdev_init(dev)) {
                printk (" unable to allocate memory for dev->priv.\n");
-               free_irq(dev->irq, NULL);
+               free_irq(dev->irq, dev);
                return -ENOMEM;
        }
 
@@ -432,7+432,7 @@ cleanup_module(void)
                if (dev->priv != NULL) {
                        kfree(dev->priv);
                        dev->priv = NULL;
-                       free_irq(dev->irq, NULL);
+                       free_irq(dev->irq, dev);
                        release_region(dev->base_addr, ES_IO_EXTENT);
                        unregister_netdev(dev);
                }
index 1c25f0c..fa5ae74 100644 (file)
@@ -1225,7+1225,7 @@ int init_module(void)
 void cleanup_module(void)
 {
        unregister_netdev( &dev_eth16i );
-       free_irq( dev_eth16i.irq, NULL );
+       free_irq( dev_eth16i.irq, &dev_eth16i );
        release_region( dev_eth16i.base_addr, ETH16I_IO_EXTENT );
 }
 
index ed9ff5e..a374794 100644 (file)
@@ -1148,7+1148,7 @@ ewrk3_close(struct device *dev)
   while (inb(EWRK3_RQ));
 
   if (!lp->hard_strapped) {
-    free_irq(dev->irq, NULL);
+    free_irq(dev->irq, dev);
   }
 
   MOD_DEC_USE_COUNT;
index a123a11..78bf20a 100644 (file)
@@ -641,7+641,7 @@ cleanup_module(void)
        dev_fmv18x.priv = NULL;
 
        /* If we don't do this, we can't re-insmod it later. */
-       free_irq(dev_fmv18x.irq, NULL);
+       free_irq(dev_fmv18x.irq, &dev_fmv18x);
        release_region(dev_fmv18x.base_addr, FMV18X_IO_EXTENT);
 }
 #endif /* MODULE */
index b76161a..c7f0a5e 100644 (file)
@@ -288,7+288,7 @@ hpp_close(struct device *dev)
        int ioaddr = dev->base_addr - NIC_OFFSET;
        int option_reg = inw(ioaddr + HPP_OPTION);
 
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
        ei_close(dev);
        outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
                 ioaddr + HPP_OPTION);
index a4e68ac..c31f978 100644 (file)
@@ -180,7+180,7 @@ __initfunc(int hp_probe1(struct device *dev, int ioaddr))
        /* Allocate dev->priv and fill in 8390 specific dev fields. */
        if (ethdev_init(dev)) {
                printk (" unable to get memory for dev->priv.\n");
-               free_irq(dev->irq, NULL);
+               free_irq(dev->irq, dev);
                return -ENOMEM;
        }
 
@@ -435,7+435,7 @@ cleanup_module(void)
                        int ioaddr = dev->base_addr - NIC_OFFSET;
                        kfree(dev->priv);
                        dev->priv = NULL;
-                       free_irq(dev->irq, NULL);
+                       free_irq(dev->irq, dev);
                        release_region(ioaddr, HP_IO_EXTENT);
                        unregister_netdev(dev);
                }
index d8ea39e..22a2e5a 100644 (file)
@@ -1577,7+1577,7 @@ void cleanup_module(void)
         for (i = 0; i < IBMTR_MAX_ADAPTERS; i++)
                if (dev_ibmtr[i]) {
                         unregister_trdev(dev_ibmtr[i]);
-                        free_irq(dev_ibmtr[i]->irq, NULL);
+                        free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]);
                         release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT);
                         kfree_s(dev_ibmtr[i]->priv, sizeof(struct tok_info));
                         kfree_s(dev_ibmtr[i], sizeof(struct device));
index f623a9d..97d0f27 100644 (file)
@@ -1129,7+1129,7 @@ lance_close(struct device *dev)
        if (dev->dma != 4)
                disable_dma(dev->dma);
 
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
 
        return 0;
 }
index 8309d44..a7ea426 100644 (file)
@@ -1023,9+1023,9 @@ __initfunc(int ltpc_probe(struct device *dev))
 
        cli();
  
-       if (!probe3) free_irq(3,NULL);
-       if (!probe4) free_irq(4,NULL);
-       if (!probe9) free_irq(9,NULL);
+       if (!probe3) free_irq(3,dev);
+       if (!probe4) free_irq(4,dev);
+       if (!probe9) free_irq(9,dev);
 
        sti();
  
@@ -1248,7+1248,7 @@ void cleanup_module(void)
        if(debug&DEBUG_VERBOSE) printk("freeing irq\n");
 
        if(dev_ltpc.irq) {
-               free_irq(dev_ltpc.irq,NULL);
+               free_irq(dev_ltpc.irq,&dev_ltpc);
                dev_ltpc.irq = 0;
        }
 
index 2550613..a962a8c 100644 (file)
@@ -440,7+440,7 @@ __initfunc(static int ne_probe1(struct device *dev, int ioaddr))
     /* Allocate dev->priv and fill in 8390 specific dev fields. */
     if (ethdev_init(dev)) {
        printk (" unable to get memory for dev->priv.\n");
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
        return -ENOMEM;
     }
 
@@ -785,7+785,7 @@ cleanup_module(void)
                if (dev->priv != NULL) {
                        kfree(dev->priv);
                        dev->priv = NULL;
-                       free_irq(dev->irq, NULL);
+                       free_irq(dev->irq, dev);
                        release_region(dev->base_addr, NE_IO_EXTENT);
                        unregister_netdev(dev);
                }
index ef15a14..ae57553 100644 (file)
 */
 
 /* The list of used and available "eth" slots (for "eth0", "eth1", etc.) */
-#define MAX_ETH_CARDS 16 /* same as the number if irq's in irq2dev[] */
+#define MAX_ETH_CARDS 16
 static struct device *ethdev_index[MAX_ETH_CARDS];
 
 
@@ -439,7+439,7 @@ void unregister_netdev(struct device *dev)
 
 #ifdef CONFIG_TR
 /* The list of used and available "tr" slots */
-#define MAX_TR_CARDS 16 /* same as the number of irq's in irq2dev[] */
+#define MAX_TR_CARDS 16
 static struct device *trdev_index[MAX_TR_CARDS];
 
 struct device *init_trdev(struct device *dev, int sizeof_priv)
index 41f150a..4b6f2fb 100644 (file)
@@ -240,7+240,7 @@ struct priv
  */
 static int ni52_close(struct device *dev)
 {
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
 
        ni_reset586(); /* the hard way to stop the receiver */
 
index d95d9ea..e0812c6 100644 (file)
@@ -285,7+285,7 @@ static int ni65_open(struct device *dev)
        }
        else
        {
-               free_irq(dev->irq,NULL);
+               free_irq(dev->irq,dev);
                dev->start = 0;
                return -EAGAIN;
        }
@@ -312,7+312,7 @@ static int ni65_close(struct device *dev)
                }
        }
 #endif
-       free_irq(dev->irq,NULL);
+       free_irq(dev->irq,dev);
        dev->tbusy = 1;
        dev->start = 0;
        MOD_DEC_USE_COUNT;
index 3153f18..09ed612 100644 (file)
@@ -1439,7+1439,7 @@ static int pi_open(struct device *dev)
     if (dev->base_addr & 2) {  /* if A channel */
        if (first_time) {
            if (request_dma(dev->dma,"pi2")) {
-               free_irq(dev->irq, NULL);
+               free_irq(dev->irq, dev);
                return -EAGAIN;
            }
        }
@@ -1669,7+1669,7 @@ int init_module(void)
 
 void cleanup_module(void)
 {
-    free_irq(pi0a.irq, NULL);  /* IRQs and IO Ports are shared */
+    free_irq(pi0a.irq, &pi0a); /* IRQs and IO Ports are shared */
     release_region(pi0a.base_addr & 0x3f0, PI_TOTAL_SIZE);
 
     kfree(pi0a.priv);
index a8cbceb..1a87511 100644 (file)
@@ -896,7+896,7 @@ static int pt_open(struct device *dev)
         {
             if (request_dma(dev->dma, "pt"))
             {
-                free_irq(dev->irq, NULL);
+                free_irq(dev->irq, dev);
                 return -EAGAIN;
             }
         }
@@ -1769,7+1769,7 @@ int init_module(void)
 
 void cleanup_module(void)
 {
-       free_irq(pt0a.irq, NULL);       /* IRQs and IO Ports are shared */
+       free_irq(pt0a.irq, &pt0a);      /* IRQs and IO Ports are shared */
        release_region(pt0a.base_addr & 0x3f0, PT_TOTAL_SIZE);
 
        kfree(pt0a.priv);
index 46c3e5c..527a8f1 100644 (file)
@@ -1694,6+1694,6 @@ void cleanup_module(void)
        if (sdla0.priv)
                kfree(sdla0.priv);
        if (sdla0.irq)
-               free_irq(sdla0.irq, NULL);
+               free_irq(sdla0.irq, &sdla0);
 }
 #endif /* MODULE */
index 7fdf711..d8372bf 100644 (file)
@@ -573,7+573,7 @@ seeq8005_close(struct device *dev)
        /* Flush the Tx and disable Rx here. */
        outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
 
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
 
        /* Update the statistics here. */
 
index 6ee6a83..54fe97d 100644 (file)
@@ -468,7+468,7 @@ static int sgiseeq_close(struct device *dev)
        /* Shutdown the Seeq. */
        reset_hpc3_and_seeq(sp->hregs, sregs);
 
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
 
        return 0;
 }
index d2bfb2e..c33e033 100644 (file)
@@ -1630,7+1630,7 @@ static int SK_close(struct device *dev)
 
     SK_write_reg(CSR0, CSR0_STOP); /* STOP the LANCE */
 
-    free_irq(dev->irq, NULL);      /* Free IRQ */
+    free_irq(dev->irq, dev);      /* Free IRQ */
 
     return 0; /* always succeed */
     
index 76a44ac..b30e62b 100644 (file)
@@ -322,7+322,7 @@ net_open(struct device *dev)
         * and clean up on failure.
         */
        if (request_dma(dev->dma, cardname)) {
-               free_irq(dev->irq, NULL);
+               free_irq(dev->irq, dev);
                return -EAGAIN;
        }
 
@@ -497,7+497,7 @@ net_close(struct device *dev)
        /* If not IRQ or DMA jumpered, free up the line. */
        outw(0x00, ioaddr+0);   /* Release the physical interrupt line. */
 
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
        free_dma(dev->dma);
 
        /* Update the statistics here. */
@@ -604,7+604,7 @@ cleanup_module(void)
         * allocate them in net_probe1().
         */
        /*
-          free_irq(this_device.irq, NULL);
+          free_irq(this_device.irq, dev);
           free_dma(this_device.dma);
        */
        release_region(this_device.base_addr, NETCARD_IO_EXTENT);
index 76d0bd4..d3fe308 100644 (file)
@@ -289,7+289,7 @@ static int ultramca_close_card(struct device *dev)
                printk("%s: Shutting down ethercard.\n", dev->name);
 
        outb(0x00, ioaddr + 6);     /* Disable interrupts. */
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
 
        NS8390_init(dev, 0);
        /* We should someday disable shared memory and change to 8-bit mode
index d8dd263..d922eb1 100644 (file)
@@ -405,7+405,7 @@ ultra_close_card(struct device *dev)
                printk("%s: Shutting down ethercard.\n", dev->name);
 
        outb(0x00, ioaddr + 6);         /* Disable interrupts. */
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
 
        NS8390_init(dev, 0);
 
index 305e9f0..3db278b 100644 (file)
@@ -1763,7+1763,7 @@ void cleanup_module(void)
        /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
        unregister_netdev(&devSMC9194);
 
-       free_irq(devSMC9194.irq, NULL );
+       free_irq(devSMC9194.irq, &devSMC9194);
        release_region(devSMC9194.base_addr, SMC_IO_EXTENT);
 
        if (devSMC9194.priv)
index e68ebf2..a7a3455 100644 (file)
@@ -3922,7+3922,7 @@ wavelan_open(device *     dev)
     }
   else
     {
-      free_irq(dev->irq, NULL);
+      free_irq(dev->irq, dev);
 #ifdef DEBUG_CONFIG_ERRORS
       printk(KERN_INFO "%s: wavelan_open(): impossible to start the card\n",
             dev->name);
@@ -3970,7+3970,7 @@ wavelan_close(device *    dev)
    */
   wv_82586_stop(dev);
 
-  free_irq(dev->irq, NULL);
+  free_irq(dev->irq, dev);
 
   MOD_DEC_USE_COUNT;
 
index 1970d5d..6e0b1a4 100644 (file)
@@ -262,7+262,7 @@ __initfunc(int wd_probe1(struct device *dev, int ioaddr))
        /* Allocate dev->priv and fill in 8390 specific dev fields. */
        if (ethdev_init(dev)) {
                printk (" unable to get memory for dev->priv.\n");
-               free_irq(dev->irq, NULL);
+               free_irq(dev->irq, dev);
                return -ENOMEM;
        }
 
@@ -499,7+499,7 @@ cleanup_module(void)
                        int ioaddr = dev->base_addr - WD_NIC_OFFSET;
                        kfree(dev->priv);
                        dev->priv = NULL;
-                       free_irq(dev->irq, NULL);
+                       free_irq(dev->irq, dev);
                        release_region(ioaddr, WD_IO_EXTENT);
                        unregister_netdev(dev);
                }
index ba14ff9..8c11e3d 100644 (file)
@@ -601,7+601,7 @@ static int znet_close(struct device *dev)
        disable_dma(zn.rx_dma);
        disable_dma(zn.tx_dma);
 
-       free_irq(dev->irq, NULL);
+       free_irq(dev->irq, dev);
 
        if (znet_debug > 1)
                printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
index 48eb8f3..7f514a4 100644 (file)
@@ -67,12+67,8 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_BLK_DEV_SR_VENDOR),y)
-SR_VENDOR = sr_vendor.o
-endif
-
 ifeq ($(CONFIG_BLK_DEV_SR),y)
-L_OBJS += sr.o sr_ioctl.o $(SR_VENDOR)
+L_OBJS += sr.o sr_ioctl.o sr_vendor.o
 else
   ifeq ($(CONFIG_BLK_DEV_SR),m)
   M_OBJS += sr_mod.o
@@ -461,8+457,8 @@ scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
                scsicam.o scsi_proc.o
        $(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
 
-sr_mod.o: sr.o sr_ioctl.o $(SR_VENDOR)
-       $(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o $(SR_VENDOR)
+sr_mod.o: sr.o sr_ioctl.o sr_vendor.o
+       $(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o sr_vendor.o
 
 sd_mod.o: sd.o sd_ioctl.o
        $(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o
index c289587..93e1b2b 100644 (file)
@@ -225,7+225,7 @@ static void ppa_wakeup(void *ref)
        return;
 }
 
-static int ppa_release(struct Scsi_Host *host)
+int ppa_release(struct Scsi_Host *host)
 {
        int host_no = host->unique_id;
 
index cdc2fda..84fa2de 100644 (file)
@@ -52,7+52,7 @@ int ppa_abort(Scsi_Cmnd *);
 int ppa_reset(Scsi_Cmnd *, unsigned int);
 int ppa_proc_info(char *, char **, off_t, int, int, int);
 int ppa_biosparam(Disk *, kdev_t, int*);
-static int ppa_release(struct Scsi_Host *);
+int ppa_release(struct Scsi_Host *);
 
 #ifndef        MODULE
 #ifdef PPA_CODE
index 4937dc9..0958798 100644 (file)
@@ -3293,6+3293,7 @@ static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
      * This does any final handling that is required.
      */
     if(tpnt->finish && tpnt->nr_dev)  (*tpnt->finish)();
+    resize_dma_pool();
     MOD_INC_USE_COUNT;
     return 0;
 }
index 5175683..12a8f37 100644 (file)
 #include <scsi/scsi_ioctl.h>   /* For the door lock/unlock commands */
 #include "constants.h"
 
+MODULE_PARM(xa_test,"i"); /* see sr_ioctl.c */
+
 #define MAX_RETRIES 3
 #define SR_TIMEOUT (30 * HZ)
 
@@ -67,12+69,15 @@ static int * sr_hardsizes = NULL;              /* Hardware sector size */
 
 static int sr_open(struct cdrom_device_info*, int);
 void get_sectorsize(int);
+void get_capabilities(int);
 
 void requeue_sr_request (Scsi_Cmnd * SCpnt);
 static int sr_media_change(struct cdrom_device_info*, int);
 
 static void sr_release(struct cdrom_device_info *cdi)
 {
+       if (scsi_CDs[MINOR(cdi->dev)].sector_size > 2048)
+               sr_set_blocklength(MINOR(cdi->dev),2048);
        sync_dev(cdi->dev);
        scsi_CDs[MINOR(cdi->dev)].device->access_count--;
        if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
@@ -89,14+94,14 @@ static struct cdrom_device_ops sr_dops = {
         sr_media_change,              /* media changed */
         sr_tray_move,                 /* tray move */
         sr_lock_door,                 /* lock door */
-        NULL,                         /* select speed */
+        sr_select_speed,              /* select speed */
         NULL,                         /* select disc */
         sr_get_last_session,          /* get last session */
         sr_get_mcn,                   /* get universal product code */
         sr_reset,                     /* hard reset */
         sr_audio_ioctl,               /* audio ioctl */
         sr_dev_ioctl,                 /* device-specific ioctl */
-        CDC_CLOSE_TRAY | CDC_OPEN_TRAY| CDC_LOCK |
+        CDC_CLOSE_TRAY | CDC_OPEN_TRAY| CDC_LOCK | CDC_SELECT_SPEED |
         CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO,
         0
 };
@@ -139,10+144,9 @@ int sr_media_change(struct cdrom_device_info *cdi, int slot){
         /* If the disk changed, the capacity will now be different,
          * so we force a re-read of this information */
         if (retval) {
-#ifdef CONFIG_BLK_DEV_SR_VENDOR
+               /* check multisession offset etc */
                 sr_cd_check(cdi);
-#endif
-
+               
                  /* 
                   * If the disk changed, the capacity will now be different,
                   * so we force a re-read of this information 
@@ -311,7+315,8 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
                }
 
                if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
-                       printk("CD-ROM error: ");
+                       printk("sr%d: CD-ROM error: ",
+                               DEVICE_NR(SCpnt->request.rq_dev));
                        print_sense("sr", SCpnt);
                        printk("command was: ");
                        print_command(SCpnt->cmnd);
@@ -329,7+334,8 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
                }
 
                if (SCpnt->sense_buffer[2] == NOT_READY) {
-                       printk(KERN_INFO "CD-ROM not ready.  Make sure you have a disc in the drive.\n");
+                       printk(KERN_INFO "sr%d: CD-ROM not ready.  Make sure you have a disc in the drive.\n",
+                               DEVICE_NR(SCpnt->request.rq_dev));
                        SCpnt = end_scsi_request(SCpnt, 0, this_count);
                        requeue_sr_request(SCpnt); /* Do next request */
                        return;
@@ -358,7+364,7 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
                    requeue_sr_request(SCpnt);
                    return;
                }
-    }
+        }
 
        /* We only get this far if we have an error we have not recognized */
        if(result) {
@@ -443,6+449,17 @@ static void do_sr_request (void)
            SDev->was_reset = 0;
        }
 
+       /* we do lazy blocksize switching (when reading XA sectors,
+        * see CDROMREADMODE2 ioctl) */
+       if (scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].sector_size > 2048) {
+           if (!in_interrupt())
+               sr_set_blocklength(DEVICE_NR(CURRENT->rq_dev),2048);
+#if 1
+            else
+                printk("sr: can't switch blocksize: in interrupt\n");
+#endif
+       }
+
        if (flag++ == 0)
            SCpnt = allocate_device(&CURRENT,
                                    scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0);
@@ -649,7+666,7 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt)
                     * ensure that all scsi operations are able to do at least a non-scatter/gather
                     * operation */
                    if(sgpnt[count].address == NULL){ /* Out of dma memory */
-                       printk("Warning: Running low on SCSI DMA buffers");
+                       printk("Warning: Running low on SCSI DMA buffers\n");
                        /* Try switching back to a non scatter-gather operation. */
                        while(--count >= 0){
                            if(sgpnt[count].alt_address)
@@ -805,17+822,7 @@ static int sr_attach(Scsi_Device * SDp){
     SDp->scsi_request_fn = do_sr_request;
     scsi_CDs[i].device = SDp;
 
-    scsi_CDs[i].cdi.ops        = &sr_dops;
-    scsi_CDs[i].cdi.handle     = &scsi_CDs[i];
-    scsi_CDs[i].cdi.dev        = MKDEV(MAJOR_NR,i);
-    scsi_CDs[i].cdi.mask       = 0;
-    scsi_CDs[i].cdi.speed      = 1;
-    scsi_CDs[i].cdi.capacity   = 1;
-    register_cdrom(&scsi_CDs[i].cdi, "sr");
-
-#ifdef CONFIG_BLK_DEV_SR_VENDOR
     sr_vendor_init(i);
-#endif
 
     sr_template.nr_dev++;
     if(sr_template.nr_dev > sr_template.dev_max)
@@ -902,7+909,7 @@ void get_sectorsize(int i){
                case 512:
                        break;
                default:
-                       printk ("scd%d : unsupported sector size %d.\n",
+                       printk ("sr%d: unsupported sector size %d.\n",
                                i, scsi_CDs[i].sector_size);
                        scsi_CDs[i].capacity = 0;
                        scsi_CDs[i].needs_sector_size = 1;
@@ -919,6+926,58 @@ void get_sectorsize(int i){
     scsi_free(buffer, 512);
 }
 
+void get_capabilities(int i){
+    unsigned char cmd[6];
+    unsigned char *buffer;
+    int           rc,n;
+
+    static char *loadmech[] = {
+        "caddy",
+        "tray",
+        "pop-up",
+        "",
+        "changer",
+        "changer",
+        "",
+        ""
+    };          
+
+    buffer = (unsigned char *) scsi_malloc(512);
+    cmd[0] = MODE_SENSE;
+    cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
+    cmd[2] = 0x2a;
+    cmd[4] = 128;
+    cmd[3] = cmd[5] = 0;
+    rc = sr_do_ioctl(i, cmd, buffer, 128, 1);
+    
+    if (-EINVAL == rc) {
+        /* failed, drive has'nt this mode page */
+        scsi_CDs[i].cdi.speed      = 1;
+        scsi_CDs[i].cdi.capacity   = 1;
+        /* disable speed select, drive probably can't do this either */
+        scsi_CDs[i].cdi.mask      |= CDC_SELECT_SPEED;
+    } else {
+        n = buffer[3]+4;
+        scsi_CDs[i].cdi.speed    = ((buffer[n+8] << 8) + buffer[n+9])/176;
+        scsi_CDs[i].cdi.capacity = 1;
+       scsi_CDs[i].readcd_known = 1;
+        scsi_CDs[i].readcd_cdda  = buffer[n+5] & 0x01;
+        /* print some capability bits */
+        printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n",i,
+               ((buffer[n+14] << 8) + buffer[n+15])/176,
+               scsi_CDs[i].cdi.speed,
+               buffer[n+3]&0x01 ? "writer " : "",   /* CD Writer */
+               buffer[n+2]&0x02 ? "cd/rw " : "",    /* can read rewriteable */
+               buffer[n+4]&0x20 ? "xa/form2 " : "", /* can read xa/from2 */
+               buffer[n+5]&0x01 ? "cdda " : "",     /* can read audio data */
+               loadmech[buffer[n+6]>>5]);
+       if ((buffer[n+6] >> 5) == 0)
+               /* caddy drives can't close tray... */
+               scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY;
+    }
+    scsi_free(buffer, 512);
+}
+
 static int sr_registered = 0;
 
 static int sr_init()
@@ -984,7+1043,16 @@ void sr_finish()
        scsi_CDs[i].use = 1;
        scsi_CDs[i].ten = 1;
        scsi_CDs[i].remap = 1;
+       scsi_CDs[i].readcd_known = 0;
+       scsi_CDs[i].readcd_cdda  = 0;
        sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
+
+       scsi_CDs[i].cdi.ops        = &sr_dops;
+       scsi_CDs[i].cdi.handle     = &scsi_CDs[i];
+       scsi_CDs[i].cdi.dev        = MKDEV(MAJOR_NR,i);
+       scsi_CDs[i].cdi.mask       = 0;
+       get_capabilities(i);
+       register_cdrom(&scsi_CDs[i].cdi, "sr");
     }
 
 
index 1c3482f..983ff18 100644 (file)
 #ifndef _SR_H
 #define _SR_H
 
-#include <linux/config.h>
-
 #include "scsi.h"
 
 typedef struct
@@ -34,13+32,15 @@ typedef struct
        unsigned        ten:1;                  /* support ten byte commands            */
        unsigned        remap:1;                /* support remapping                    */
        unsigned        use:1;                  /* is this device still supportable     */
-       unsigned        xa_flag:1;              /* CD has XA sectors */
+        unsigned       xa_flag:1;              /* CD has XA sectors ? */
+       unsigned        readcd_known:1;         /* drive supports READ_CD (0xbe) */
+       unsigned        readcd_cdda:1;          /* reading audio data using READ_CD */
        struct cdrom_device_info cdi;
        } Scsi_CD;
        
 extern Scsi_CD * scsi_CDs;
 
-int sr_do_ioctl(int, unsigned char*, void*, unsigned);
+int sr_do_ioctl(int, unsigned char*, void*, unsigned, int);
 
 int sr_lock_door(struct cdrom_device_info*, int);
 int sr_tray_move(struct cdrom_device_info*, int);
@@ -49,15+49,16 @@ int sr_disk_status(struct cdrom_device_info*);
 int sr_get_last_session(struct cdrom_device_info*, struct cdrom_multisession*);
 int sr_get_mcn(struct cdrom_device_info*, struct cdrom_mcn*);
 int sr_reset(struct cdrom_device_info*);
+int sr_select_speed(struct cdrom_device_info *cdi, int speed);
 int sr_audio_ioctl(struct cdrom_device_info*, unsigned int, void*);
 int sr_dev_ioctl(struct cdrom_device_info*, unsigned int, unsigned long);
 
-/* vendor-specific */
-#ifdef CONFIG_BLK_DEV_SR_VENDOR
-void sr_vendor_init(int minor);
-int sr_cd_check(struct cdrom_device_info*);
 int sr_read_sector(int minor, int lba, int blksize, unsigned char *dest);
+int sr_is_xa(int minor);
 
-#endif
+/* sr_vendor.c */
+void sr_vendor_init(int minor);
+int sr_cd_check(struct cdrom_device_info*);
+int sr_set_blocklength(int minor, int blocklength);
 
 #endif
index bc870df..628d39c 100644 (file)
@@ -1,4+1,3 @@
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/ucdrom.h>
 #include "sr.h"
 
+#if 0
+# define DEBUG
+#endif
+
+/* for now we borrow the "operation not supported" from the network folks */
+#define EDRIVE_CANT_DO_THIS  EOPNOTSUPP
+
+/* The sr_is_xa() seems to trigger firmware bugs with some drives :-(
+ * It is off by default and can be turned on with this module parameter */
+static int xa_test = 0;
+
 extern void get_sectorsize(int);
 
 #define IOCTL_RETRIES 3
@@ -39,12+49,14 @@ static void sr_ioctl_done(Scsi_Cmnd * SCpnt)
    error code is.  Normally the UNIT_ATTENTION code will automatically
    clear after one error */
 
-int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength)
+int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength, int quiet)
 {
     Scsi_Cmnd * SCpnt;
-    int result;
+    int result, err = 0, retries = 0;
 
     SCpnt = allocate_device(NULL, scsi_CDs[target].device, 1);
+
+retry:
     {
        struct semaphore sem = MUTEX_LOCKED;
        SCpnt->request.sem = &sem;
@@ -61,28+73,79 @@ int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned bufl
        switch(SCpnt->sense_buffer[2] & 0xf) {
        case UNIT_ATTENTION:
            scsi_CDs[target].device->changed = 1;
-           printk("Disc change detected.\n");
+           printk(KERN_INFO "sr%d: disc change detected.\n", target);
+           if (retries++ < 10)
+               goto retry;
+           err = -ENOMEDIUM;
            break;
        case NOT_READY: /* This happens if there is no disc in drive */
-           printk(KERN_INFO "CDROM not ready.  Make sure there is a disc in the drive.\n");
+            if (SCpnt->sense_buffer[12] == 0x04 &&
+                SCpnt->sense_buffer[13] == 0x01) {
+                /* sense: Logical unit is in process of becoming ready */
+                if (!quiet)
+                    printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target);
+               if (retries++ < 10) {
+                   /* sleep 2 sec and try again */
+                    current->state = TASK_INTERRUPTIBLE;
+                    current->timeout = jiffies + 200;
+                    schedule ();
+                    goto retry;
+               } else {
+                   /* 20 secs are enouth? */
+                   err = -ENOMEDIUM;
+                   break;
+               }
+            }
+            printk(KERN_INFO "sr%d: CDROM not ready.  Make sure there is a disc in the drive.\n",target);
+#ifdef DEBUG
+            print_sense("sr", SCpnt);
+#endif
+            err = -ENOMEDIUM;
            break;
        case ILLEGAL_REQUEST:
-           printk("CDROM (ioctl) reports ILLEGAL REQUEST.\n");
+            if (!quiet)
+                printk("sr%d: CDROM (ioctl) reports ILLEGAL REQUEST.\n",
+                       target);
+            if (SCpnt->sense_buffer[12] == 0x20 &&
+                SCpnt->sense_buffer[13] == 0x00) {
+                /* sense: Invalid command operation code */
+                err = -EDRIVE_CANT_DO_THIS;
+            } else {
+                err = -EINVAL;
+            }
+#ifdef DEBUG
+           print_command(sr_cmd);
+            print_sense("sr", SCpnt);
+#endif
            break;
        default:
+           printk("sr%d: CDROM (ioctl) error, command: ", target);
+           print_command(sr_cmd);
            print_sense("sr", SCpnt);
+            err = -EIO;
        };
     
     result = SCpnt->result;
     SCpnt->request.rq_status = RQ_INACTIVE; /* Deallocate */
+    /* Wake up a process waiting for device */
     wake_up(&SCpnt->device->device_wait);
-    /* Wake up a process waiting for device*/
-    return result;
+    
+    return err;
 }
 
 /* ---------------------------------------------------------------------- */
 /* interface to cdrom.c                                                   */
 
+static int test_unit_ready(int minor)
+{
+       u_char  sr_cmd[10];
+
+        sr_cmd[0] = TEST_UNIT_READY;
+        sr_cmd[1] = ((scsi_CDs[minor].device -> lun) << 5);
+        sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
+        return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1);
+}
+
 int sr_tray_move(struct cdrom_device_info *cdi, int pos)
 {
         u_char  sr_cmd[10];
@@ -92,7+155,7 @@ int sr_tray_move(struct cdrom_device_info *cdi, int pos)
         sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
         sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */;
        
-        return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255);
+        return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0);
 }
 
 int sr_lock_door(struct cdrom_device_info *cdi, int lock)
@@ -109,51+172,39 @@ int sr_drive_status(struct cdrom_device_info *cdi, int slot)
                 return -EINVAL;
         }
 
-        if (!scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,
-                        SCSI_IOCTL_TEST_UNIT_READY,0))
-                return CDS_DISC_OK;
+        if (0 == test_unit_ready(MINOR(cdi->dev)))
+            return CDS_DISC_OK;
 
-#if 1
-       /* Tell tray is open if the drive is not ready.  Seems there is
-        * no way to check whenever the tray is really open, but this way
-        * we get auto-close-on-open work. And it seems to have no ill
-         * effects with caddy drives... */
         return CDS_TRAY_OPEN;
-#else
-        return CDS_NO_DISC;
-#endif
 }
 
 int sr_disk_status(struct cdrom_device_info *cdi)
 {
        struct cdrom_tochdr    toc_h;
        struct cdrom_tocentry  toc_e;
-        int                    i;
+        int                    i,rc,have_datatracks = 0;
 
-        if (scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,SCSI_IOCTL_TEST_UNIT_READY,0))
-                return CDS_NO_DISC;
-
-        /* if the xa-bit is on, we tell it is XA... */
-        if (scsi_CDs[MINOR(cdi->dev)].xa_flag)
-                return CDS_XA_2_1;
+        /* look for data tracks */
+        if (0 != (rc = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &toc_h)))
+                return (rc == -ENOMEDIUM) ? CDS_NO_DISC : CDS_NO_INFO;
         
-        /* ...else we look for data tracks */
-        if (sr_audio_ioctl(cdi, CDROMREADTOCHDR, &toc_h))
-                return CDS_NO_INFO;
         for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) {
                 toc_e.cdte_track  = i;
                 toc_e.cdte_format = CDROM_LBA;
                 if (sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &toc_e))
                         return CDS_NO_INFO;
-                if (toc_e.cdte_ctrl & CDROM_DATA_TRACK)
-                        return CDS_DATA_1;
-#if 0
-                if (i == toc_h.cdth_trk0 && toc_e.cdte_addr.lba > 100)
-                        /* guess: looks like a "hidden track" CD */
-                        return CDS_DATA_1;
-#endif
+                if (toc_e.cdte_ctrl & CDROM_DATA_TRACK) {
+                        have_datatracks = 1;
+                        break;
+                }
         }
-        return CDS_AUDIO;
+        if (!have_datatracks)
+            return CDS_AUDIO;
+
+        if (scsi_CDs[MINOR(cdi->dev)].xa_flag)
+            return CDS_XA_2_1;
+        else
+            return CDS_DATA_1;
 }
 
 int sr_get_last_session(struct cdrom_device_info *cdi,
@@ -161,7+212,7 @@ int sr_get_last_session(struct cdrom_device_info *cdi,
 {
         ms_info->addr.lba=scsi_CDs[MINOR(cdi->dev)].ms_offset;
         ms_info->xa_flag=scsi_CDs[MINOR(cdi->dev)].xa_flag ||
-            scsi_CDs[MINOR(cdi->dev)].ms_offset > 0;
+            (scsi_CDs[MINOR(cdi->dev)].ms_offset > 0);
 
        return 0;
 }
@@ -185,7+236,7 @@ int sr_get_mcn(struct cdrom_device_info *cdi,struct cdrom_mcn *mcn)
        buffer = (unsigned char*) scsi_malloc(512);
        if(!buffer) return -ENOMEM;
        
-       result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24);
+       result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0);
        
        memcpy (mcn->medium_catalog_number, buffer + 9, 13);
         mcn->medium_catalog_number[13] = 0;
@@ -201,6+252,26 @@ int sr_reset(struct cdrom_device_info *cdi)
        return 0;        
 }
 
+int sr_select_speed(struct cdrom_device_info *cdi, int speed)
+{
+        u_char  sr_cmd[12];
+
+        if (speed == 0)
+            speed = 0xffff; /* set to max */
+        else
+            speed *= 177;   /* Nx to kbyte/s */
+        
+       memset(sr_cmd,0,12);
+       sr_cmd[0] = 0xbb; /* SET CD SPEED */
+       sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->lun) << 5;
+       sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */
+       sr_cmd[3] =  speed       & 0xff; /* LSB */
+
+        if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0))
+            return -EIO;
+       return 0;
+}
+
 /* ----------------------------------------------------------------------- */
 /* this is called by the generic cdrom driver. arg is a _kernel_ pointer,  */
 /* becauce the generic cdrom driver does the user access stuff for us.     */
@@ -224,7+295,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        sr_cmd[8] = 0;
        sr_cmd[9] = 0;
        
-       result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+       result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
        
     case CDROMRESUME:
@@ -236,7+307,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        sr_cmd[8] = 1;
        sr_cmd[9] = 0;
        
-       result = sr_do_ioctl(target, sr_cmd, NULL, 255);        
+       result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
        
     case CDROMPLAYMSF:
@@ -254,7+325,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        sr_cmd[8] = msf->cdmsf_frame1;
        sr_cmd[9] = 0;
        
-       result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+       result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
     }
 
@@ -273,7+344,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        sr_cmd[8] = blk->len;
        sr_cmd[9] = 0;
        
-       result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+       result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
     }
                
@@ -292,7+363,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        sr_cmd[8] = ti->cdti_ind1;
        sr_cmd[9] = 0;
        
-       result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+       result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
     }
        
@@ -312,7+383,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        buffer = (unsigned char *) scsi_malloc(512);
        if(!buffer) return -ENOMEM;
        
-       result = sr_do_ioctl(target, sr_cmd, buffer, 12);
+       result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0);
        
        tochdr->cdth_trk0 = buffer[2];
        tochdr->cdth_trk1 = buffer[3];
@@ -338,7+409,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        buffer = (unsigned char *) scsi_malloc(512);
        if(!buffer) return -ENOMEM;
        
-       result = sr_do_ioctl (target, sr_cmd, buffer, 12);
+       result = sr_do_ioctl (target, sr_cmd, buffer, 12, 0);
        
         tocentry->cdte_ctrl = buffer[5] & 0xf; 
         tocentry->cdte_adr = buffer[5] >> 4;
@@ -361,7+432,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
        sr_cmd[4] = 0;
        
-       result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+       result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
        
     case CDROMSTART:
@@ -370,7+441,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
        sr_cmd[4] = 1;
        
-       result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+       result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
        
     case CDROMVOLCTRL:
@@ -390,7+461,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        buffer = (unsigned char *) scsi_malloc(512);
        if(!buffer) return -ENOMEM;
        
-       if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28))) {
+       if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) {
            printk ("Hosed while obtaining audio mode page\n");
            scsi_free(buffer, 512);
             break;
@@ -410,7+481,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
             break;
        };
 
-       if ((result = sr_do_ioctl (target, sr_cmd, mask, 28))) {
+       if ((result = sr_do_ioctl (target, sr_cmd, mask, 28, 0))) {
            printk ("Hosed while obtaining mask for audio mode page\n");
            scsi_free(buffer, 512);
            scsi_free(mask, 512);
@@ -431,7+502,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        sr_cmd[4] = 28;
        sr_cmd[5] = 0;
        
-       result = sr_do_ioctl (target, sr_cmd, buffer, 28);
+       result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0);
        scsi_free(buffer, 512);
        scsi_free(mask, 512);
         break;
@@ -454,7+525,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        buffer = (unsigned char *) scsi_malloc(512);
        if(!buffer) return -ENOMEM;
        
-       if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28))) {
+       if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) {
            printk ("(CDROMVOLREAD) Hosed while obtaining audio mode page\n");
            scsi_free(buffer, 512);
             break;
@@ -487,7+558,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        buffer = (unsigned char*) scsi_malloc(512);
        if(!buffer) return -ENOMEM;
        
-       result = sr_do_ioctl(target, sr_cmd, buffer, 16);
+       result = sr_do_ioctl(target, sr_cmd, buffer, 16, 0);
        
        subchnl->cdsc_audiostatus = buffer[1];
        subchnl->cdsc_format = CDROM_MSF;
@@ -516,7+587,120 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
     
     return result;
 }
-       
+
+/* -----------------------------------------------------------------------
+ * a function to read all sorts of funny cdrom sectors using the READ_CD
+ * scsi-3 mmc command
+ *
+ * lba:     linear block address
+ * format:  0 = data (anything)
+ *          1 = audio
+ *          2 = data (mode 1)
+ *          3 = data (mode 2)
+ *          4 = data (mode 2 form1)
+ *          5 = data (mode 2 form2)
+ * blksize: 2048 | 2336 | 2340 | 2352
+ */
+
+int
+sr_read_cd(int minor, unsigned char *dest, int lba, int format, int blksize)
+{
+    unsigned char  cmd[12];
+
+#ifdef DEBUG
+    printk("sr%d: sr_read_cd lba=%d format=%d blksize=%d\n",
+           minor,lba,format,blksize);
+#endif
+
+    memset(cmd,0,12);
+    cmd[0] = 0xbe /* READ_CD */;
+    cmd[1] = (scsi_CDs[minor].device->lun << 5) | ((format & 7) << 2);
+    cmd[2] = (unsigned char)(lba >> 24) & 0xff;
+    cmd[3] = (unsigned char)(lba >> 16) & 0xff;
+    cmd[4] = (unsigned char)(lba >>  8) & 0xff;
+    cmd[5] = (unsigned char) lba        & 0xff;
+    cmd[8] = 1;
+    switch (blksize) {
+    case 2336: cmd[9] = 0x58; break;
+    case 2340: cmd[9] = 0x78; break;
+    case 2352: cmd[9] = 0xf8; break;
+    default:   cmd[9] = 0x10; break;
+    }
+    return sr_do_ioctl(minor, cmd, dest, blksize, 0);
+}
+
+/*
+ * read sectors with blocksizes other than 2048
+ */
+
+int
+sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
+{
+    unsigned char   cmd[12];    /* the scsi-command */
+    int             rc;
+
+    /* we try the READ CD command first... */
+    if (scsi_CDs[minor].readcd_known) {
+        rc = sr_read_cd(minor, dest, lba, 0, blksize);
+        if (-EDRIVE_CANT_DO_THIS != rc)
+            return rc;
+        scsi_CDs[minor].readcd_known = 0;
+        printk("CDROM does'nt support READ CD (0xbe) command\n");
+        /* fall & retry the other way */
+    }
+
+    /* ... if this fails, we switch the blocksize using MODE SELECT */
+    if (blksize != scsi_CDs[minor].sector_size)
+        if (0 != (rc = sr_set_blocklength(minor, blksize)))
+            return rc;
+
+#ifdef DEBUG
+    printk("sr%d: sr_read_sector lba=%d blksize=%d\n",minor,lba,blksize);
+#endif
+    
+    memset(cmd,0,12);
+    cmd[0] = READ_10;
+    cmd[1] = (scsi_CDs[minor].device->lun << 5);
+    cmd[2] = (unsigned char)(lba >> 24) & 0xff;
+    cmd[3] = (unsigned char)(lba >> 16) & 0xff;
+    cmd[4] = (unsigned char)(lba >>  8) & 0xff;
+    cmd[5] = (unsigned char) lba        & 0xff;
+    cmd[8] = 1;
+    rc = sr_do_ioctl(minor, cmd, dest, blksize, 0);
+    
+    return rc;
+}
+
+/*
+ * read a sector in raw mode to check the sector format
+ * ret: 1 == mode2 (XA), 0 == mode1, <0 == error 
+ */
+
+int
+sr_is_xa(int minor)
+{
+    unsigned char *raw_sector;
+    int is_xa;
+    
+    if (!xa_test)
+        return 0;
+    
+    raw_sector = (unsigned char *) scsi_malloc(2048+512);
+    if (!raw_sector) return -ENOMEM;
+    if (0 == sr_read_sector(minor,scsi_CDs[minor].ms_offset+16,
+                            CD_FRAMESIZE_RAW1,raw_sector)) {
+        is_xa = (raw_sector[3] == 0x02) ? 1 : 0;
+    } else {
+        /* read a raw sector failed for some reason. */
+        is_xa = -1;
+    }
+    scsi_free(raw_sector, 2048+512);
+#ifdef DEBUG
+    printk("sr%d: sr_is_xa: %d\n",minor,is_xa);
+#endif
+    return is_xa;
+}
+
 int sr_dev_ioctl(struct cdrom_device_info *cdi,
                  unsigned int cmd, unsigned long arg)
 {
@@ -525,33+709,31 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi,
     target = MINOR(cdi->dev);
     
     switch (cmd) {
-    /* these are compatible with the ide-cd driver */
-    case CDROMREADRAW:
     case CDROMREADMODE1:
     case CDROMREADMODE2:
-
-#if CONFIG_BLK_DEV_SR_VENDOR 
+    case CDROMREADRAW:
     {
        unsigned char      *raw;
         struct cdrom_msf   msf;
-        int                blocksize, lba, rc;
+        int                lba, rc;
+       int                blocksize = 2048;
 
-        if (cmd == CDROMREADMODE1)
-                blocksize = CD_FRAMESIZE;       /* 2048 */
-        else if (cmd == CDROMREADMODE2)
-                blocksize = CD_FRAMESIZE_RAW0;  /* 2336 */
-        else
-               /* some SCSI drives do not allow this one */
-                blocksize = CD_FRAMESIZE_RAW;   /* 2352 */
+        switch (cmd) {
+        case CDROMREADMODE2: blocksize = CD_FRAMESIZE_RAW0; break; /* 2336 */
+        case CDROMREADRAW:   blocksize = CD_FRAMESIZE_RAW;  break; /* 2352 */
+        }
 
        if (copy_from_user(&msf,(void*)arg,sizeof(msf)))
                return -EFAULT;
        if (!(raw = scsi_malloc(2048+512)))
-               return -ENOMEM;
+                return -ENOMEM;
 
        lba = (((msf.cdmsf_min0 * CD_SECS) + msf.cdmsf_sec0)
                        * CD_FRAMES + msf.cdmsf_frame0) - CD_BLOCK_OFFSET;
-       rc = sr_read_sector(target, lba, blocksize, raw);
+        if (lba < 0 || lba >= scsi_CDs[target].capacity)
+            return -EINVAL;
+
+        rc = sr_read_sector(target, lba, blocksize, raw);
        if (!rc)
                if (copy_to_user((void*)arg, raw, blocksize))
                        rc = -EFAULT;
@@ -559,11+741,44 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi,
        scsi_free(raw,2048+512);
        return rc;
     }
-#else
-       return -EINVAL;
-#endif
+    case CDROMREADAUDIO:
+    {
+       unsigned char      *raw;
+        int                lba, rc=0;
+        struct cdrom_read_audio ra;
 
-       
+        if (!scsi_CDs[target].readcd_known || !scsi_CDs[target].readcd_cdda)
+            return -EINVAL;  /* -EDRIVE_DOES_NOT_SUPPORT_THIS ? */
+        
+       if (copy_from_user(&ra,(void*)arg,sizeof(ra)))
+            return -EFAULT;
+        
+        if (ra.addr_format == CDROM_LBA)
+            lba = ra.addr.lba;
+        else
+            lba = (((ra.addr.msf.minute * CD_SECS) + ra.addr.msf.second)
+                   * CD_FRAMES + ra.addr.msf.frame) - CD_BLOCK_OFFSET;
+
+        if (lba < 0 || lba >= scsi_CDs[target].capacity)
+            return -EINVAL;
+       if (!(raw = scsi_malloc(2048+512)))
+            return -ENOMEM;
+
+        while (ra.nframes > 0) {
+            rc = sr_read_cd(target, raw, lba, 1, CD_FRAMESIZE_RAW);
+            if (!rc)
+               if (copy_to_user(ra.buf, raw, CD_FRAMESIZE_RAW))
+                    rc = -EFAULT;
+            if (rc)
+                break;
+
+            ra.buf     += CD_FRAMESIZE_RAW;
+            ra.nframes -= 1;
+            lba++;
+        }
+       scsi_free(raw,2048+512);
+        return rc;
+    }
     case BLKRAGET:
        if (!arg)
                return -EINVAL;
index e8f73f1..82d5ba7 100644 (file)
@@ -6,6+6,12 @@
  * the like) are to new to be included into the SCSI-II standard (to
  * be exact: there is'nt anything in my draft copy).
  *
+ * Aug 1997: Ha! Got a SCSI-3 cdrom spec across my fingers. SCSI-3 does
+ *           multisession using the READ TOC command (like SONY).
+ *
+ *           Rearranged stuff here: SCSI-3 is included allways, support
+ *           for NEC/TOSHIBA/HP commands is optional.
+ *
  *   Gerd Knorr <kraxel@cs.tu-berlin.de> 
  *
  * --------------------------------------------------------------------------
  *   - SONY:   Detection and support of multisession CD's.
  *              added by Thomas Quinot <thomas@cuivre.freenix.fr>
  *
- *   - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC, PHILIPS:
- *             Known to work with SONY code.
+ *   - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC, PHILIPS: known to
+ *              work with SONY (SCSI3 now)  code.
  *
  *   - HP:     Much like SONY, but a little different... (Thomas)
  *              HP-Writers only ??? Maybe other CD-Writers work with this too ?
  *             HP 6020 writers now supported.
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 
 #include <linux/ucdrom.h>
 #include "sr.h"
 
+#if 0
+# define DEBUG
+#endif
+
 /* here are some constants to sort the vendors into groups */
 
-#define VENDOR_CAN_NOT_HANDLE  1   /* don't know how to handle */
+#define VENDOR_SCSI3           1   /* default: scsi-3 mmc */
+
 #define VENDOR_NEC             2
 #define VENDOR_TOSHIBA         3
-#define VENDOR_SONY_LIKE       4   /* much drives are Sony compatible */
-#define VENDOR_HP_4020         5   /* HP 4xxx writers, others too ?? */
-#define VENDOR_HP_6020         6   /* HP 6020 writers */
+#define VENDOR_HP_4020         4   /* HP 4xxx writers, others too ?? */
+#define VENDOR_HP_6020         5   /* HP 6020 writers */
 
 #define VENDOR_ID (scsi_CDs[minor].vendor)
 
-#if 0
-#define DEBUG
-#endif
-
 void
 sr_vendor_init(int minor)
 {
+#ifndef CONFIG_BLK_DEV_SR_VENDOR
+       VENDOR_ID = VENDOR_SCSI3;
+#else
        char *vendor = scsi_CDs[minor].device->vendor;
        char *model  = scsi_CDs[minor].device->model;
-               
+
+       /* default */
+       VENDOR_ID = VENDOR_SCSI3;
+
        if ((!strncmp(vendor,"HP",2) || !strncmp(vendor,"PHILIPS",7)) &&
            scsi_CDs[minor].device->type == TYPE_WORM) {
                if (!strncmp(model,"CD-Writer 6020",14))
@@ -80,29+93,33 @@ sr_vendor_init(int minor)
        } else if (!strncmp (vendor, "TOSHIBA", 7)) {
                VENDOR_ID = VENDOR_TOSHIBA;
                
-       } else {
-               /* most drives can handled like Sony ones, so we take
-                * it as default */
-               VENDOR_ID = VENDOR_SONY_LIKE;
-#ifdef DEBUG
-               printk(KERN_DEBUG
-                      "sr: using \"Sony group\" multisession code\n");
-#endif
        }
+#endif
 }
 
 
 /* small handy function for switching block length using MODE SELECT,
  * used by sr_read_sector() */
 
-static int
-set_density_and_blocklength(int minor, unsigned char *buffer,
-                           int density, int blocklength)
+int
+sr_set_blocklength(int minor, int blocklength)
 {
+       unsigned char           *buffer;    /* the buffer for the ioctl */
        unsigned char           cmd[12];    /* the scsi-command */
        struct ccs_modesel_head *modesel;
-       int                     rc;
+       int                     rc,density = 0;
+
+#ifdef CONFIG_BLK_DEV_SR_VENDOR
+       if (VENDOR_ID == VENDOR_TOSHIBA)
+               density = (blocklength > 2048) ? 0x81 : 0x83;
+#endif
+
+       buffer = (unsigned char *) scsi_malloc(512);
+       if (!buffer) return -ENOMEM;
 
+#ifdef DEBUG
+       printk("sr%d: MODE SELECT 0x%x/%d\n",minor,density,blocklength);
+#endif
        memset(cmd,0,12);
        cmd[0] = MODE_SELECT;
        cmd[1] = (scsi_CDs[minor].device->lun << 5) | (1 << 4);
@@ -113,53+130,17 @@ set_density_and_blocklength(int minor, unsigned char *buffer,
        modesel->density           = density;
        modesel->block_length_med  = (blocklength >> 8 ) & 0xff;
        modesel->block_length_lo   =  blocklength        & 0xff;
-       rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel));
+       if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0)))
+               scsi_CDs[minor].sector_size = blocklength;
 #ifdef DEBUG
-       if (rc)
-               printk("sr: switching blocklength to %d bytes failed\n",
-                      blocklength);
+       else
+               printk("sr%d: switching blocklength to %d bytes failed\n",
+                      minor,blocklength);
 #endif
-       return rc;
-}
-
-
-/* read a sector with other than 2048 bytes length 
- * dest is assumed to be allocated with scsi_malloc
- *
- * XXX maybe we have to do some locking here.
- */
-
-int
-sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
-{
-       unsigned char   *buffer;    /* the buffer for the ioctl */
-       unsigned char   cmd[12];    /* the scsi-command */
-       int             rc, density;
-
-       density = (VENDOR_ID == VENDOR_TOSHIBA) ? 0x83 : 0;
-
-       buffer = (unsigned char *) scsi_malloc(512);
-       if (!buffer) return -ENOMEM;
-
-       rc = set_density_and_blocklength(minor, buffer, density, blksize);
-       if (!rc) {
-               memset(cmd,0,12);
-               cmd[0] = READ_10;
-               cmd[1] = (scsi_CDs[minor].device->lun << 5);
-               cmd[2] = (unsigned char)(lba >> 24) & 0xff;
-               cmd[3] = (unsigned char)(lba >> 16) & 0xff;
-               cmd[4] = (unsigned char)(lba >>  8) & 0xff;
-               cmd[5] = (unsigned char) lba        & 0xff;
-               cmd[8] = 1;
-               rc = sr_do_ioctl(minor, cmd, dest, blksize);
-               set_density_and_blocklength(minor, buffer, density, 2048);
-       }
-       
        scsi_free(buffer, 512);
        return rc;
 }
 
-
 /* This function gets called after a media change. Checks if the CD is
    multisession, asks for offset etc. */
 
@@ -169,7+150,6 @@ int sr_cd_check(struct cdrom_device_info *cdi)
 {
        unsigned long   sector,min,sec,frame;
        unsigned char   *buffer;     /* the buffer for the ioctl */
-       unsigned char   *raw_sector; 
        unsigned char   cmd[12];     /* the scsi-command */
        int             rc,is_xa,no_multi,minor;
 
@@ -187,16+167,41 @@ int sr_cd_check(struct cdrom_device_info *cdi)
     
        switch(VENDOR_ID) {
        
+       case VENDOR_SCSI3:
+               memset(cmd,0,12);
+               cmd[0] = READ_TOC;
+               cmd[1] = (scsi_CDs[minor].device->lun << 5);
+               cmd[8] = 12;
+               cmd[9] = 0x40;
+               rc = sr_do_ioctl(minor, cmd, buffer, 12, 0);    
+               if (rc != 0)
+                       break;
+               if ((buffer[0] << 8) + buffer[1] < 0x0a) {
+                       printk(KERN_INFO "sr%d: Hmm, seems the drive "
+                              "doesn't support multisession CD's\n",minor);
+                       no_multi = 1;
+                       break;
+               }
+               sector = buffer[11] + (buffer[10] << 8) +
+                       (buffer[9] << 16) + (buffer[8] << 24);
+               if (buffer[6] <= 1) {
+                       /* ignore sector offsets from first track */
+                       sector = 0;
+               }
+               break;
+               
+#ifdef CONFIG_BLK_DEV_SR_VENDOR
        case VENDOR_NEC:
                memset(cmd,0,12);
                cmd[0] = 0xde;
                cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
                cmd[2] = 0xb0;
-               rc = sr_do_ioctl(minor, cmd, buffer, 0x16);
+               rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 0);
                if (rc != 0)
                        break;
                if (buffer[14] != 0 && buffer[14] != 0xb0) {
-                       printk(KERN_INFO "sr (nec): Hmm, seems the cdrom doesn't support multisession CD's\n");
+                       printk(KERN_INFO "sr%d: Hmm, seems the cdrom "
+                              "doesn't support multisession CD's\n",minor);
                        no_multi = 1;
                        break;
                }
@@ -205,20+210,19 @@ int sr_cd_check(struct cdrom_device_info *cdi)
                frame  = BCD_TO_BIN(buffer[17]);
                sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
                break;
-               
+
        case VENDOR_TOSHIBA:
                /* we request some disc information (is it a XA-CD ?,
                 * where starts the last session ?) */
                memset(cmd,0,12);
                cmd[0] = 0xc7;
                cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
-               rc = sr_do_ioctl(minor, cmd, buffer, 4);
-               if (rc == 0x28000002 &&
-                   !scsi_ioctl(scsi_CDs[minor].device,
-                               SCSI_IOCTL_TEST_UNIT_READY, NULL)) {
-                       printk(KERN_INFO "sr (toshiba): Hmm, seems the drive doesn't support multisession CD's\n");
-                   no_multi = 1;
-                   break;
+               rc = sr_do_ioctl(minor, cmd, buffer, 4, 0);
+               if (rc == -EINVAL) {
+                       printk(KERN_INFO "sr%d: Hmm, seems the drive "
+                              "doesn't support multisession CD's\n",minor);
+                       no_multi = 1;
+                       break;
                }
                if (rc != 0)
                        break;
@@ -239,102+243,57 @@ int sr_cd_check(struct cdrom_device_info *cdi)
                        0x04 : 0x0c;
                cmd[9] = 0x40;
                rc = sr_do_ioctl(minor, cmd, buffer,
-                   (VENDOR_ID == VENDOR_HP_4020) ? 0x04 : 0x0c);
+                   (VENDOR_ID == VENDOR_HP_4020) ? 0x04 : 0x0c, 0);
                if (rc != 0) {
                        break;
                }
                if ((rc = buffer[2]) == 0) {
                        printk (KERN_WARNING
-                               "sr (hp): No finished session\n");
+                               "sr%d: No finished session\n",minor);
                        break;
                }
 
-               if (VENDOR_ID == VENDOR_HP_4020) {
-                   cmd[0] = READ_TOC; /* Read TOC */
-                   cmd[1] = (scsi_CDs[minor].device->lun << 5);
-                   cmd[6] = rc & 0x7f;  /* number of last session */
-                   cmd[8] = 0x0c;
-                   cmd[9] = 0x40;
-                   rc = sr_do_ioctl(minor, cmd, buffer, 12);   
-                   if (rc != 0) {
-                           break;
-                   }
+               if (VENDOR_ID == VENDOR_HP_4020) {
+                   cmd[0] = READ_TOC; /* Read TOC */
+                   cmd[1] = (scsi_CDs[minor].device->lun << 5);
+                   cmd[6] = rc & 0x7f;  /* number of last session */
+                   cmd[8] = 0x0c;
+                   cmd[9] = 0x40;
+                   rc = sr_do_ioctl(minor, cmd, buffer, 12, 0);        
+                   if (rc != 0) {
+                           break;
+                   }
                }
 
                sector = buffer[11] + (buffer[10] << 8) +
                        (buffer[9] << 16) + (buffer[8] << 24);
                break;
-
-       case VENDOR_SONY_LIKE:
-               memset(cmd,0,12);
-               cmd[0] = READ_TOC;
-               cmd[1] = (scsi_CDs[minor].device->lun << 5);
-               cmd[8] = 12;
-               cmd[9] = 0x40;
-               rc = sr_do_ioctl(minor, cmd, buffer, 12);       
-               if (rc != 0) {
-                       break;
-               }
-               if ((buffer[0] << 8) + buffer[1] < 0x0a) {
-                       printk(KERN_INFO "sr (sony): Hmm, seems the drive doesn't support multisession CD's\n");
-                       no_multi = 1;
-                       break;
-               }
-               sector = buffer[11] + (buffer[10] << 8) +
-                       (buffer[9] << 16) + (buffer[8] << 24);
-               if (buffer[6] <= 1) {
-                       /* ignore sector offsets from first track */
-                       sector = 0;
-               }
-               break;
-               
-       case VENDOR_CAN_NOT_HANDLE:
-               sector = 0;
-               no_multi = 1;
-               break;
+#endif /* CONFIG_BLK_DEV_SR_VENDOR */
 
        default:
                /* should not happen */
                printk(KERN_WARNING
-                      "sr: unknown vendor code (%i), not initialized ?\n",
-                      VENDOR_ID);
+                      "sr%d: unknown vendor code (%i), not initialized ?\n",
+                      minor,VENDOR_ID);
                sector = 0;
                no_multi = 1;
                break;
        }
-   
-       scsi_CDs[minor].xa_flag = 0;
-       if (CDS_AUDIO != sr_disk_status(cdi)) { 
-           /* read a sector in raw mode to check the sector format */
-           raw_sector = (unsigned char *) scsi_malloc(2048+512);
-           if (!buffer) return -ENOMEM;
-           if (0 == sr_read_sector(minor,sector+16,CD_FRAMESIZE_RAW1,
-                                   raw_sector)){
-               is_xa = (raw_sector[3] == 0x02);
-               if (sector > 0 && !is_xa)
-                       printk(KERN_INFO "sr: broken CD found: It is "
-                              "multisession, but has'nt XA sectors\n");
-           } else {
-               /* read a raw sector failed for some reason. */
-               is_xa = (sector > 0);
-           }
-           scsi_free(raw_sector, 2048+512);
-       }
-#ifdef DEBUG
-       else printk("sr: audio CD found\n");
-#endif
-
        scsi_CDs[minor].ms_offset = sector;
-       scsi_CDs[minor].xa_flag = is_xa;
+       scsi_CDs[minor].xa_flag = 0;
+       if (CDS_AUDIO != sr_disk_status(cdi) && 1 == sr_is_xa(minor))
+               scsi_CDs[minor].xa_flag = 1;
+       
+       if (2048 != scsi_CDs[minor].sector_size)
+               sr_set_blocklength(minor,2048);
        if (no_multi)
                cdi->mask |= CDC_MULTI_SESSION;
 
 #ifdef DEBUG
-       printk(KERN_DEBUG
-              "sr: multisession offset=%lu, XA=%s\n",
-              sector,is_xa ? "yes" : "no");
+       if (sector)
+               printk(KERN_DEBUG "sr%d: multisession offset=%lu\n",
+                      minor,sector);
 #endif
-
        scsi_free(buffer, 512);
        return rc;
 }
index 3b59ef8..cf2b91c 100644 (file)
@@ -223,25+223,17 @@ static void write_dquot(struct dquot *dquot)
        short type = dquot->dq_type;
        struct file *filp = dquot->dq_mnt->mnt_quotas[type];
        unsigned long fs;
+       loff_t offset;
 
        if (!(dquot->dq_flags & DQ_MOD) || (filp == (struct file *)NULL))
                return;
        lock_dquot(dquot);
        down(&dquot->dq_mnt->mnt_sem);
-       if (filp->f_op->llseek) {
-               if (filp->f_op->llseek(filp->f_dentry->d_inode, filp,
-                   dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
-                       up(&dquot->dq_mnt->mnt_sem);
-                       unlock_dquot(dquot);
-                       return;
-               }
-       } else
-               filp->f_pos = dqoff(dquot->dq_id);
+       offset = dqoff(dquot->dq_id);
        fs = get_fs();
        set_fs(KERNEL_DS);
 
-       if (filp->f_op->write(filp->f_dentry->d_inode, filp,
-          (char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk))
+       if (filp->f_op->write(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset) == sizeof(struct dqblk))
                dquot->dq_flags &= ~DQ_MOD;
 
        up(&dquot->dq_mnt->mnt_sem);
@@ -255,23+247,16 @@ static void read_dquot(struct dquot *dquot)
        short type = dquot->dq_type;
        struct file *filp = dquot->dq_mnt->mnt_quotas[type];
        unsigned long fs;
+       loff_t offset;
 
        if (filp == (struct file *)NULL)
                return;
        lock_dquot(dquot);
        down(&dquot->dq_mnt->mnt_sem);
-       if (filp->f_op->llseek) {
-               if (filp->f_op->llseek(filp->f_dentry->d_inode, filp,
-                   dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
-                       up(&dquot->dq_mnt->mnt_sem);
-                       unlock_dquot(dquot);
-                       return;
-               }
-       } else
-               filp->f_pos = dqoff(dquot->dq_id);
+       offset = dqoff(dquot->dq_id);
        fs = get_fs();
        set_fs(KERNEL_DS);
-       filp->f_op->read(filp->f_dentry->d_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk));
+       filp->f_op->read(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset);
        up(&dquot->dq_mnt->mnt_sem);
        set_fs(fs);
        if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 &&
index f830c02..115c84d 100644 (file)
 
 #include <asm/segment.h>       /* for fs functions */
 
+#define NFS_MAX_AGE 10*HZ      /* max age for dentry validation */
+
 /* needed by smbfs as well ... move to dcache? */
 extern void nfs_renew_times(struct dentry *);
 extern void nfs_invalidate_dircache_sb(struct super_block *);
@@ -51,6+53,8 @@ struct nfs_dirent {
        __u32 *                 entry;          /* three __u32's per entry */
 };
 
+static int nfs_safe_remove(struct dentry *);
+
 static int nfs_dir_open(struct inode * inode, struct file * file);
 static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *);
 static int nfs_readdir(struct file *, void *, filldir_t);
@@ -62,7+66,8 @@ static int nfs_unlink(struct inode *, struct dentry *);
 static int nfs_symlink(struct inode *, struct dentry *, const char *);
 static int nfs_link(struct inode *, struct inode *, struct dentry *);
 static int nfs_mknod(struct inode *, struct dentry *, int, int);
-static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+static int nfs_rename(struct inode *, struct dentry *,
+                     struct inode *, struct dentry *);
 
 static struct file_operations nfs_dir_operations = {
        NULL,                   /* lseek - default */
@@ -387,7+392,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
                        goto bad;
                }
                if (S_ISDIR(dentry->d_inode->i_mode))
-                       max = 10*HZ;
+                       max = NFS_MAX_AGE;
        }
 
        return (time < max) || IS_ROOT(dentry);
@@ -395,13+400,44 @@ bad:
        return 0;
 }
 
-static void nfs_silly_delete(struct dentry *);
+/*
+ * This is called from dput() when d_count is going to 0.
+ * We use it to clean up silly-renamed files, and to check
+ * for dentries that have already expired.
+ */
+static void nfs_dentry_delete(struct dentry *dentry)
+{
+       if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+               int error;
+               
+               dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+#ifdef NFS_DEBUG
+printk("nfs_dentry_delete: unlinking %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+               /* Unhash it first */
+               d_drop(dentry);
+               error = nfs_safe_remove(dentry);
+               if (error)
+                       printk("NFS: can't silly-delete %s/%s, error=%d\n",
+                               dentry->d_parent->d_name.name,
+                               dentry->d_name.name, error);
+       }
+       /*
+        * Check whether to expire the dentry ...
+        */
+       else {
+               unsigned long age = jiffies - dentry->d_time;
+               if (age > NFS_MAX_AGE)
+                       d_drop(dentry);
+       }
+}
 
 static struct dentry_operations nfs_dentry_operations = {
        nfs_lookup_revalidate,  /* d_validate(struct dentry *) */
        0,                      /* d_hash */
        0,                      /* d_compare */
-       nfs_silly_delete,       /* d_delete(struct dentry *) */
+       nfs_dentry_delete       /* d_delete(struct dentry *) */
 };
 
 /*
@@ -564,8+600,12 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 }
 
 /*
- *  Update inode->i_nlink immediately after a successful operation.
- *  (See comments for nfs_unlink.)
+ * To avoid retaining a stale inode reference, we check the dentry
+ * use count prior to the operation, and return EBUSY if it has
+ * multiple users.
+ *
+ * Update inode->i_nlink immediately after a successful operation.
+ * (See comments for nfs_unlink.)
  */
 static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
@@ -579,17+619,27 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
                return -ENOENT;
        }
 
+       error = -ENAMETOOLONG;
        if (dentry->d_name.len > NFS_MAXNAMLEN)
-               return -ENAMETOOLONG;
+               goto out;
 
+       error = -EBUSY;
+       if (dentry->d_count > 1) {
+               /* Attempt to shrink child dentries ... */
+               shrink_dcache_sb(dentry->d_sb); /* Arghhh */
+               if (dentry->d_count > 1)
+                       goto out;
+       }
+       /* Drop the dentry to force a new lookup */
+       d_drop(dentry);
        error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
        if (!error) {
                if (dentry->d_inode->i_nlink)
                        dentry->d_inode->i_nlink --;
                nfs_invalidate_dircache(dir);
                nfs_renew_times(dentry);
-               d_delete(dentry);
        }
+out:
        return error;
 }
 
@@ -606,24+656,22 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
  *
  *  Concerning my choice of the temp name: it is just nice to have
  *  i_ino part of the temp name, as this offers another check whether
- *  somebody attempts to remove the "silly renamed" dentry
- *  itself. Which is something that I consider evil. Your opinion may
- *  vary.
+ *  somebody attempts to remove the "silly renamed" dentry itself.
+ *  Which is something that I consider evil. Your opinion may vary.
  *  BUT:
  *  Now that I compute the hash value right, it should be possible to simply
  *  check for the DCACHE_NFSFS_RENAMED flag in dentry->d_flag instead of
  *  doing the string compare.
  *  WHICH MEANS:
  *  This offers the opportunity to shorten the temp name. Currently, I use
- *  the hex representation of i_ino + the hex value of jiffies. This
- *  sums up to as much as 36 characters for a 64 bit machine, and needs
- *  20 chars on a 32 bit machine. Have a look at jiffiesize etc.
+ *  the hex representation of i_ino + an event counter. This sums up to
+ *  as much as 36 characters for a 64 bit machine, and needs 20 chars on 
+ *  a 32 bit machine.
  *  QUINTESSENCE
  *  The use of i_ino is simply cosmetic. All we need is a unique temp
- *  file name for the .nfs files. The hex representation of "jiffies"
- *  seemed to be adequate. And as we retry in case such a file already
- *  exists we are guaranteed to succed (after some jiffies have passed
- *  by :)
+ *  file name for the .nfs files. The event counter seemed to be adequate.
+ *  And as we retry in case such a file already exists, we are guaranteed
+ *  to succeed.
  */
 
 static
@@ -631,15+679,11 @@ struct dentry *nfs_silly_lookup(struct dentry *parent, char *silly, int slen)
 {
        struct qstr    sqstr;
        struct dentry *sdentry;
-       unsigned long hash;
-       int i, error;
+       int error;
 
        sqstr.name = silly;
        sqstr.len  = slen;
-       hash = init_name_hash();
-       for (i= 0; i < slen; i++)
-               hash = partial_name_hash(silly[i], hash);
-       sqstr.hash = end_name_hash(hash);
+       sqstr.hash = full_name_hash(silly, slen);
        sdentry = d_lookup(parent, &sqstr);
        if (!sdentry) {
                sdentry = d_alloc(parent, &sqstr);
@@ -661,11+705,16 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
        const int      countersize = sizeof(sillycounter)*2;
        const int      slen       = strlen(".nfs") + i_inosize + countersize;
        char           silly[slen+1];
-       int            error;
        struct dentry *sdentry;
+       int            error = -EIO;
 
+       /*
+        * Note that a silly-renamed file can be deleted once it's
+        * no longer in use -- it's just an ordinary file now.
+        */
        if (dentry->d_count == 1) {
-               return -EIO;  /* No need to silly rename. */
+               dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+               goto out;  /* No need to silly rename. */
        }
 
 #ifdef NFS_PARANOIA
@@ -673,12+722,12 @@ if (!dentry->d_inode)
 printk("NFS: silly-renaming %s/%s, negative dentry??\n",
 dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
-       if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
-               return -EBUSY; /* don't allow to unlink silly inode -- nope,
-                               * think a bit: silly DENTRY, NOT inode --
-                               * itself
-                               */
-       }
+       /*
+        * We don't allow a dentry to be silly-renamed twice.
+        */
+       error = -EBUSY;
+       if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
+               goto out;
 
        sprintf(silly, ".nfs%*.*lx",
                i_inosize, i_inosize, dentry->d_inode->i_ino);
@@ -695,9+744,12 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
                         dentry->d_name.name, silly);
                
                sdentry = nfs_silly_lookup(dentry->d_parent, silly, slen);
-               if (IS_ERR(sdentry)) {
-                       return -EIO; /* FIXME ? */
-               }               
+               /*
+                * N.B. Better to return EBUSY here ... it could be
+                * dangerous to delete the file while it's in use.
+                */
+               if (IS_ERR(sdentry))
+                       goto out;
        } while(sdentry->d_inode != NULL); /* need negative lookup */
 
        error = nfs_proc_rename(NFS_SERVER(dir),
@@ -711,58+763,67 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
                /* If we return 0 we don't unlink */
        }
        dput(sdentry);
+out:
        return error;
 }
 
-static void nfs_silly_delete(struct dentry *dentry)
+/*
+ * Remove a file after making sure there are no pending writes,
+ * and after checking that the file has only one user. 
+ *
+ * Updating inode->i_nlink here rather than waiting for the next
+ * nfs_refresh_inode() is not merely cosmetic; once an object has
+ * been deleted, we want to get rid of the inode locally.  The NFS
+ * server may reuse the fileid for a new inode, and we don't want
+ * that to be confused with this inode.
+ */
+static int nfs_safe_remove(struct dentry *dentry)
 {
-       if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
-               struct inode *dir = dentry->d_parent->d_inode;
-               int error;
+       struct inode *dir = dentry->d_parent->d_inode;
+       struct inode *inode = dentry->d_inode;
+       int error;
                
-               dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
-
-               /* Unhash it first */
-               d_drop(dentry);
-               dfprintk(VFS, "trying to unlink %s\n", dentry->d_name.name);
-               error = nfs_proc_remove(NFS_SERVER(dir),
-                                       NFS_FH(dir), dentry->d_name.name);
-               if (error < 0)
-                       printk("NFS: can't silly-delete %s/%s, error=%d\n",
-                               dentry->d_parent->d_name.name,
-                               dentry->d_name.name, error);
-               if (dentry->d_inode) {
-                       if (dentry->d_inode->i_nlink)
-                               dentry->d_inode->i_nlink --;
-               } else {
+       error = -EBUSY;
+       if (inode) {
+               if (NFS_WRITEBACK(inode)) {
+                       nfs_flush_dirty_pages(inode, 0, 0, 0);
+                       if (NFS_WRITEBACK(inode)) {
 #ifdef NFS_PARANOIA
-                       printk("nfs_silly_delete: negative dentry %s/%s\n",
-                               dentry->d_parent->d_name.name,
-                               dentry->d_name.name);
+printk("nfs_safe_remove: %s/%s writes pending, d_count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
 #endif
+                               goto out;
+                       }
                }
-               nfs_invalidate_dircache(dir);
+       } else {
+#ifdef NFS_PARANOIA
+printk("nfs_safe_remove: %s/%s already negative??\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
        }
-       /*
-        * Check whether to expire the dentry ...
-        */
-       else {
-               unsigned long age = jiffies - dentry->d_time;
-               if (age > 10*HZ)
-                       d_drop(dentry);
+
+       if (dentry->d_count > 1) {
+#ifdef NFS_PARANOIA
+printk("nfs_safe_remove: %s/%s busy, d_count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
+#endif
+               goto out;
        }
+       error = nfs_proc_remove(NFS_SERVER(dir),
+                                       NFS_FH(dir), dentry->d_name.name);
+       if (!error) {
+               nfs_invalidate_dircache(dir);
+               if (inode && inode->i_nlink)
+                       inode->i_nlink --;
+       }
+out:
+       return error;
 }
 
 /*  We do silly rename. In case sillyrename() returns -EBUSY, the inode
  *  belongs to an active ".nfs..." file and we return -EBUSY.
  *
  *  If sillyrename() returns 0, we do nothing, otherwise we unlink.
- * 
- *  Updating inode->i_nlink here rather than waiting for the next
- *  nfs_refresh_inode() is not merely cosmetic; once an object has
- *  been deleted, we want to get rid of the inode locally.  The NFS
- *  server may reuse the fileid for a new inode, and we don't want
- *  that to be confused with this inode.
  */
 static int nfs_unlink(struct inode *dir, struct dentry *dentry)
 {
@@ -781,23+842,9 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
                goto out;
 
        error = nfs_sillyrename(dir, dentry);
-
        if (error && error != -EBUSY) {
-#ifdef NFS_PARANOIA
-if (dentry->d_count > 1)
-printk("nfs_unlink: dentry %s/%s, d_count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
-if (dentry->d_inode && dentry->d_inode->i_count > 1)
-printk("nfs_unlink: dentry %s/%s, inode i_count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_inode->i_count);
-#endif
-               /* N.B. should check for d_count > 1 and fail */
-               error = nfs_proc_remove(NFS_SERVER(dir),
-                                       NFS_FH(dir), dentry->d_name.name);
+               error = nfs_safe_remove(dentry);
                if (!error) {
-                       if (dentry->d_inode->i_nlink)
-                               dentry->d_inode->i_nlink --;
-                       nfs_invalidate_dircache(dir);
                        nfs_renew_times(dentry);
                        d_delete(dentry);
                }
@@ -868,31+915,13 @@ nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentry)
        if (dentry->d_name.len > NFS_MAXNAMLEN)
                goto out;
 
-       /*
-        * The NFS server may want to use a new fileid for the link,
-        * so we can't reuse the existing inode for the new dentry.
-        * To force a new lookup after the link operation, we can just
-        * drop the new dentry, as long as it's not busy. (See above.)
-        */
-       error = -EBUSY;
-       if (dentry->d_count > 1) {
-#ifdef NFS_PARANOIA
-printk("nfs_link: dentry %s/%s busy, count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
-#endif
-               goto out;
-       }
-       d_drop(dentry);
-
        error = nfs_proc_link(NFS_SERVER(inode), NFS_FH(inode), NFS_FH(dir),
                                dentry->d_name.name);
        if (!error) {
                nfs_invalidate_dircache(dir);
-#if 0
                inode->i_count ++;
                inode->i_nlink ++; /* no need to wait for nfs_refresh_inode() */
                d_instantiate(dentry, inode);
-#endif
        }
 out:
        return error;
@@ -916,23+945,16 @@ out:
  * using the inode layer
  *
  * Unfortunately, things are a little more complicated than indicated
- * above. The NFS server may decide to use a new fileid for the renamed
- * file, so we can't link the new name to the old inode. Otherwise, the
- * server might reuse the fileid after the old file has been removed, 
- * which would leave the new dentry holding an invalid fileid (possibly
- * leading to file corruption). To handle this consider these cases:
- *   (1) within-directory:
- *       -- no problem, just use nfs_proc_rename
- *   (2) cross-directory, only one user for old and new dentry:
- *       -- drop both dentries to force new lookups, then use rename
- *   (3) cross-directory, multiple users for old, one user for new:
- *       -- drop new dentry, silly-rename old dentry and make a link
- *   (4) cross-directory, multiple users for new dentry:
- *       -- sorry, we're busy.
+ * above. For a cross-directory move, we want to make sure we can get
+ * rid of the old inode after the operation.  This means there must be
+ * no pending writes (if it's a file), and the use count must be 1.
+ * If these conditions are met, we can drop the dentries before doing
+ * the rename.
  */
 static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                      struct inode *new_dir, struct dentry *new_dentry)
 {
+       struct inode *inode = old_dentry->d_inode;
        int update = 1, error;
 
 #ifdef NFS_DEBUG_VERBOSE
@@ -955,60+977,71 @@ new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
            new_dentry->d_name.len > NFS_MAXNAMLEN)
                goto out;
        /*
-        * Examine the cases as noted above.
+        * Check for within-directory rename ... no complications.
         */
        if (new_dir == old_dir)
-               goto simple_case;
+               goto do_rename;
+       /*
+        * Cross-directory move ... check whether it's a file.
+        */
        error = -EBUSY;
-       if (new_dentry->d_count > 1) {
+       if (S_ISREG(inode->i_mode)) {
+               if (NFS_WRITEBACK(inode)) {
 #ifdef NFS_PARANOIA
-printk("nfs_rename: new dentry %s/%s busy, count=%d\n",
-new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
-new_dentry->d_count);
+printk("nfs_rename: %s/%s has pending writes\n",
+old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
 #endif
-               goto out;
+                       nfs_flush_dirty_pages(inode, 0, 0, 0);
+                       if (NFS_WRITEBACK(inode)) {
+#ifdef NFS_PARANOIA
+printk("nfs_rename: %s/%s has pending writes after flush\n",
+old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
+#endif
+                               goto out;
+                       }
+               }
        }
-       d_drop(new_dentry);
-       if (old_dentry->d_count > 1)
-               goto complex_case;
-       d_drop(old_dentry);
-       update = 0;
-       
-       /* no need for silly rename, proceed as usual */
-simple_case:
-       error = nfs_proc_rename(NFS_SERVER(old_dir),
-                               NFS_FH(old_dir), old_dentry->d_name.name,
-                               NFS_FH(new_dir), new_dentry->d_name.name);
-       if (error)
-               goto out;
-       nfs_invalidate_dircache(new_dir);
-       nfs_invalidate_dircache(old_dir);
-
-       /* Update the dcache if needed */
-       if (update)
-               d_move(old_dentry, new_dentry);
-       goto out;
+       /*
+        * Moving a directory ... prune child dentries if needed.
+        */
+       else if (old_dentry->d_count > 1)
+               shrink_dcache_sb(old_dentry->d_sb); /* Arghhh */
 
        /*
-        * We don't need to update the dcache in this case ... the
-        * new dentry has been dropped, and the old one silly-renamed.
+        * Now check the use counts ... we can't safely do the
+        * rename unless we can drop the dentries first.
         */
-complex_case:
-       error = nfs_sillyrename(old_dir, old_dentry);
-       if (error)
+       if (old_dentry->d_count > 1) {
+#ifdef NFS_PARANOIA
+printk("nfs_rename: old dentry %s/%s busy, d_count=%d\n",
+old_dentry->d_parent->d_name.name,old_dentry->d_name.name,old_dentry->d_count);
+#endif
                goto out;
-       nfs_invalidate_dircache(old_dir);
+       }
 
-       error = nfs_link(old_dentry->d_inode, new_dir, new_dentry);
-       if (error)
-               goto out;
-       nfs_invalidate_dircache(new_dir);
+       if (new_dentry->d_count > 1) {
 #ifdef NFS_PARANOIA
-printk("nfs_rename: dentry %s/%s linked to %s/%s, old count=%d\n",
-new_dentry->d_parent->d_name.name,new_dentry->d_name.name,
-old_dentry->d_parent->d_name.name,old_dentry->d_name.name,old_dentry->d_count);
+printk("nfs_rename: new dentry %s/%s busy, d_count=%d\n",
+new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
 #endif
+               goto out;
+       }
 
+       d_drop(old_dentry);
+       d_drop(new_dentry);
+       update = 0;
+
+do_rename:
+       error = nfs_proc_rename(NFS_SERVER(old_dir),
+                               NFS_FH(old_dir), old_dentry->d_name.name,
+                               NFS_FH(new_dir), new_dentry->d_name.name);
+       if (!error) {
+               nfs_invalidate_dircache(new_dir);
+               nfs_invalidate_dircache(old_dir);
+               /* Update the dcache if needed */
+               if (update)
+                       d_move(old_dentry, new_dentry);
+       }
 out:
        return error;
 }
index 5b1f18a..a3f6773 100644 (file)
@@ -390,9+390,9 @@ static inline unsigned long copy_to_user(void *to, const void *from, unsigned lo
 #include <asm/uaccess.h>
 #define GET_USER get_user
 #define PUT_USER put_user
-#define RWTYPE long
+#define RWTYPE ssize_t
 #define LSTYPE long long
-#define RWARG unsigned long
+#define RWARG size_t
 #define LSARG long long
 #endif
 
index 5eebb8a..4c4de4e 100644 (file)
@@ -132,7+132,7 @@ struct dqblk {
 #define        dq_btime        dq_dqb.dqb_btime
 #define        dq_itime        dq_dqb.dqb_itime
 
-#define dqoff(UID)      ((off_t)((UID) * sizeof (struct dqblk)))
+#define dqoff(UID)      ((loff_t)((UID) * sizeof (struct dqblk)))
 
 struct dqstats {
    __u32 lookups;
index 5194d69..b8fec5e 100644 (file)
@@ -167,6+167,7 @@ EXPORT_SYMBOL(check_disk_change);
 EXPORT_SYMBOL(invalidate_buffers);
 EXPORT_SYMBOL(invalidate_inodes);
 EXPORT_SYMBOL(invalidate_inode_pages);
+EXPORT_SYMBOL(truncate_inode_pages);
 EXPORT_SYMBOL(fsync_dev);
 EXPORT_SYMBOL(permission);
 EXPORT_SYMBOL(inode_setattr);
@@ -197,6+198,7 @@ EXPORT_SYMBOL(posix_unblock_lock);
 EXPORT_SYMBOL(dput);
 EXPORT_SYMBOL(get_cached_page);
 EXPORT_SYMBOL(put_cached_page);
+EXPORT_SYMBOL(shrink_dcache_sb);
 
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 EXPORT_SYMBOL(do_nfsservctl);
close