@@ -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
@@ -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
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 61
+SUBLEVEL = 62
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
* 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
@@ -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");
@@ -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;
#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,
@@ -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);
}
}
@@ -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);
@@ -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
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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;
@@ -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;
@@ -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. */
@@ -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));
@@ -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 */
@@ -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);
}
@@ -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);
}
@@ -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;
@@ -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);
@@ -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 */
@@ -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);
@@ -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
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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. */
@@ -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;
}
@@ -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;
@@ -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;
@@ -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. */
@@ -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? */
@@ -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);
@@ -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);
}
@@ -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 );
}
@@ -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;
@@ -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 */
@@ -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);
@@ -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);
}
@@ -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));
@@ -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;
}
@@ -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;
}
@@ -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);
}
*/
/* 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)
@@ -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 */
@@ -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;
@@ -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);
@@ -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);
@@ -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 */
@@ -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. */
@@ -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;
}
@@ -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 */
@@ -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);
@@ -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
@@ -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);
@@ -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)
@@ -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;
@@ -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);
}
@@ -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);
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
@@ -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;
@@ -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
@@ -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;
}
#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");
}
#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
-#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;
* 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;
}
@@ -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 &&
#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);
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;
* 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;
}
@@ -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
@@ -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;
@@ -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);