diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
commit | 3917ac5846dd0f9ad1238166f90caab9912052e6 (patch) | |
tree | 1c298935def4f29edb39192365a65d73de999155 /drivers/block | |
parent | af2f803c8b2d469fe38e4a7ce952658dfcb6681a (diff) |
o Merge with Linux 2.1.100.
o Cleanup the machine dependencies of floppy and rtc. The driver for
the Dallas thingy in the Indy is still missing.
o Handle allocation of zero'd pages correct for R4000SC / R4400SC.
o Page colouring shit to match the virtual and physical colour of all
mapped pages. This tends to produce extreme fragmentation problems,
so it's deactivated for now. Users of R4000SC / R4400SC may re-enable
the code in arch/mips/mm/init.c by removing the definition of
CONF_GIVE_A_SHIT_ABOUT_COLOURS. Should get them somewhat further -
but don't shake to hard ...
o Fixed ptrace(2)-ing of syscalls, strace is now working again.
o Fix the interrupt forwarding from the keyboard driver to the psaux
driver, PS/2 mice are now working on the Indy. The fix is somewhat
broken as it prevents generic kernels for Indy and machines which handle
things different.
o Things I can't remember.
Diffstat (limited to 'drivers/block')
34 files changed, 716 insertions, 542 deletions
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index f04c0347f..432276973 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -1149,13 +1149,15 @@ static int acsi_ioctl( struct inode *inode, struct file *file, (long *) arg); case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!inode->i_rdev) return -EINVAL; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; case BLKRRPART: /* Re-read partition tables */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; return revalidate_acsidisk(inode->i_rdev, 1); RO_IOCTLS(inode->i_rdev,arg); default: diff --git a/drivers/block/ali14xx.c b/drivers/block/ali14xx.c index c0c7762d6..5d5ca66dc 100644 --- a/drivers/block/ali14xx.c +++ b/drivers/block/ali14xx.c @@ -134,15 +134,15 @@ static void ali14xx_tune_drive (ide_drive_t *drive, byte pio) /* stuff timing parameters into controller registers */ driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit; - save_flags(flags); - cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ outb_p(regOn, basePort); outReg(param1, regTab[driveNum].reg1); outReg(param2, regTab[driveNum].reg2); outReg(param3, regTab[driveNum].reg3); outReg(param4, regTab[driveNum].reg4); outb_p(regOff, basePort); - restore_flags(flags); + restore_flags(flags); /* all CPUs */ } /* @@ -154,8 +154,8 @@ static int findPort (void) byte t; unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ for (i = 0; i < ALI_NUM_PORTS; ++i) { basePort = ports[i]; regOff = inb(basePort); @@ -166,7 +166,7 @@ static int findPort (void) dataPort = basePort + 8; t = inReg(0) & 0xf0; outb_p(regOff, basePort); - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ if (t != 0x50) return 0; return 1; /* success */ @@ -174,7 +174,7 @@ static int findPort (void) } outb_p(regOff, basePort); } - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ return 0; } @@ -186,15 +186,15 @@ static int initRegisters (void) { byte t; unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ outb_p(regOn, basePort); for (p = initData; p->reg != 0; ++p) outReg(p->data, p->reg); outb_p(0x01, regPort); t = inb(regPort) & 0x01; outb_p(regOff, basePort); - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ return t; } diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 445e90fca..7a92f74a2 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -1631,7 +1631,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, return -EFAULT; return 0; case BLKRASET: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (param > 0xff) return -EINVAL; @@ -1641,7 +1641,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, return put_user(read_ahead[MAJOR(inode->i_rdev)], (int *) param); case BLKFLSBUF: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); diff --git a/drivers/block/dtc2278.c b/drivers/block/dtc2278.c index 63b9143b6..b656a0bd2 100644 --- a/drivers/block/dtc2278.c +++ b/drivers/block/dtc2278.c @@ -74,14 +74,14 @@ static void tune_dtc2278 (ide_drive_t *drive, byte pio) pio = ide_get_best_pio_mode(drive, pio, 4, NULL); if (pio >= 3) { - save_flags(flags); - cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ /* * This enables PIO mode4 (3?) on the first interface */ sub22(1,0xc3); sub22(0,0xa0); - restore_flags(flags); + restore_flags(flags); /* all CPUs */ } else { /* we don't know how to set it back again.. */ } @@ -97,8 +97,8 @@ void init_dtc2278 (void) { unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ /* * This enables the second interface */ @@ -114,7 +114,7 @@ void init_dtc2278 (void) sub22(1,0xc3); sub22(0,0xa0); #endif - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ ide_hwifs[0].serialized = 1; ide_hwifs[1].serialized = 1; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 088980ead..df3dcc2ec 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -1066,7 +1066,8 @@ static void setup_DMA(void) } #else fd_clear_dma_ff(FLOPPY_DMA); - fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length); + dma_cache_wback_inv((unsigned long)raw_cmd->kernel_data, + raw_cmd->length); fd_set_dma_mode(FLOPPY_DMA, (raw_cmd->flags & FD_RAW_READ) ? DMA_MODE_READ : DMA_MODE_WRITE); @@ -1826,7 +1827,6 @@ static void floppy_shutdown(void) if (!initialising) show_floppy(); cancel_activity(); - sti(); floppy_enable_hlt(); fd_disable_dma(FLOPPY_DMA); @@ -2876,7 +2876,6 @@ static void do_fd_request(void) printk("warning: usage count=0, CURRENT=%p exiting\n", CURRENT); printk("sect=%ld cmd=%d\n", CURRENT->sector, CURRENT->cmd); return; } - sti(); if (fdc_busy){ /* fdc busy, this new request will be treated when the current one is done */ @@ -3208,7 +3207,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g, (g->stretch&~(FD_STRETCH|FD_SWAPSIDES)) != 0) return -EINVAL; if (type){ - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; LOCK_FDC(drive,1); for (cnt = 0; cnt < N_DRIVE; cnt++){ @@ -3373,7 +3372,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return _COPYOUT(loc); } case BLKRASET: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(param > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = param; return 0; @@ -3381,7 +3380,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return put_user(read_ahead[MAJOR(inode->i_rdev)], (long *) param); case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 558a1b2d2..52bb33ede 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -603,7 +603,7 @@ static int hd_ioctl(struct inode * inode, struct file * file, return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; } case BLKRASET: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(arg > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = arg; return 0; @@ -616,12 +616,14 @@ static int hd_ioctl(struct inode * inode, struct file * file, return put_user(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg); case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; case BLKRRPART: /* Re-read partition tables */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; return revalidate_hddisk(inode->i_rdev, 1); RO_IOCTLS(inode->i_rdev,arg); diff --git a/drivers/block/ht6560b.c b/drivers/block/ht6560b.c index b739f39ee..6bf60e4dd 100644 --- a/drivers/block/ht6560b.c +++ b/drivers/block/ht6560b.c @@ -133,8 +133,8 @@ static void ht6560b_selectproc (ide_drive_t *drive) if (select != current_select || timing != current_timing) { current_select = select; current_timing = timing; - save_flags (flags); - cli(); + __save_flags (flags); /* local CPU only */ + __cli(); /* local CPU only */ (void) inb(HT_SELECT_PORT); (void) inb(HT_SELECT_PORT); (void) inb(HT_SELECT_PORT); @@ -150,7 +150,7 @@ static void ht6560b_selectproc (ide_drive_t *drive) */ outb (timing, IDE_SELECT_REG); (void) inb (IDE_STATUS_REG); - restore_flags (flags); + __restore_flags (flags); /* local CPU only */ #ifdef DEBUG printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, t, timing); #endif diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 98b94cadb..898d45f04 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -201,10 +201,14 @@ * now set ionly for CD-R and CD-RW drives. I had * removed this support because it produced errors. * It produced errors _only_ for non-writers. duh. + * 4.13 May 05, 1998 -- Suppress useless "in progress of becoming ready" + * messages, since this is not an error. + * -- Change error messages to be const + * -- Remove a "\t" which looks ugly in the syslogs * *************************************************************************/ -#define IDECD_VERSION "4.12" +#define IDECD_VERSION "4.13" #include <linux/module.h> #include <linux/types.h> @@ -264,11 +268,13 @@ void cdrom_analyze_sense_data (ide_drive_t *drive, return; } if (reqbuf->error_code == 0x70 && reqbuf->sense_key == 0x02 - && reqbuf->asc == 0x3a && reqbuf->ascq == 0x00) + && ((reqbuf->asc == 0x3a && reqbuf->ascq == 0x00) || + (reqbuf->asc == 0x04 && reqbuf->ascq == 0x01))) { /* - * No disc in drive ("Medium not present"), - * so keep the noise level down to a dull roar. + * Suppress the following errors: + * "Medium not present", and "in progress of becoming ready", + * to keep the noise level down to a dull roar. */ return; } @@ -276,7 +282,7 @@ void cdrom_analyze_sense_data (ide_drive_t *drive, #if VERBOSE_IDE_CD_ERRORS { int i; - char *s; + const char *s; char buf[80]; printk ("ATAPI device %s:\n", drive->name); @@ -346,7 +352,7 @@ void cdrom_analyze_sense_data (ide_drive_t *drive, lo = mid+1; } - printk (" The failed \"%s\" packet command was: \n\t\"", s); + printk (" The failed \"%s\" packet command was: \n \"", s); for (i=0; i<sizeof (failed_command->c); i++) printk ("%02x ", failed_command->c[i]); printk ("\"\n"); @@ -1020,7 +1026,7 @@ static void cdrom_start_read_continuation (ide_drive_t *drive) #define IDECD_SEEK_THRESHOLD (1000) /* 1000 blocks */ #define IDECD_SEEK_TIMER (2 * WAIT_MIN_SLEEP) /* 40 ms */ -#define IDECD_SEEK_TIMEOUT (20 * IDECD_SEEK_TIMER) /* 0.8 sec */ +#define IDECD_SEEK_TIMEOUT WAIT_CMD /* 10 sec */ static void cdrom_seek_intr (ide_drive_t *drive) { diff --git a/drivers/block/ide-cd.h b/drivers/block/ide-cd.h index 1c73b2d80..785fbe1ed 100644 --- a/drivers/block/ide-cd.h +++ b/drivers/block/ide-cd.h @@ -415,7 +415,7 @@ struct cdrom_info { /* From Table 124 of the ATAPI 1.2 spec. Unchanged in Table 140 of the ATAPI 2.6 draft standard. */ -char *sense_key_texts[16] = { +const char * const sense_key_texts[16] = { "No sense data", "Recovered error", "Not ready", @@ -436,9 +436,9 @@ char *sense_key_texts[16] = { /* From Table 37 of the ATAPI 2.6 draft standard. */ -struct { +const struct { unsigned short packet_command; - char *text; + const char * const text; } packet_command_texts[] = { { TEST_UNIT_READY, "Test Unit Ready" }, { REQUEST_SENSE, "Request Sense" }, @@ -471,9 +471,9 @@ struct { /* From Table 125 of the ATAPI 1.2 spec., with additions from Tables 141 and 142 of the ATAPI 2.6 draft standard. */ -struct { +const struct { unsigned short asc_ascq; - char *text; + const char * const text; } sense_data_texts[] = { { 0x0000, "No additional sense information" }, diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c index 5b46c8302..1ac07f698 100644 --- a/drivers/block/ide-disk.c +++ b/drivers/block/ide-disk.c @@ -18,9 +18,10 @@ * Version 1.04 add /proc configurable settings and S.M.A.R.T support * Version 1.05 add capacity support for ATA3 >= 8GB * Version 1.06 get boot-up messages to show full cyl count + * Version 1.07 disable door-locking if it fails */ -#define IDEDISK_VERSION "1.06" +#define IDEDISK_VERSION "1.07" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -185,9 +186,7 @@ static void write_intr (ide_drive_t *drive) } } else error = 1; - out: - if (error) ide_error(drive, "write_intr", stat); } @@ -258,9 +257,7 @@ static void multwrite_intr (ide_drive_t *drive) } } else error = 1; - out: - if (error) ide_error(drive, "multwrite_intr", stat); } @@ -380,7 +377,7 @@ static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long bl return; } if (!drive->unmask) - __cli(); + __cli(); /* local CPU only */ if (drive->mult_count) { HWGROUP(drive)->wrq = *rq; /* scratchpad */ ide_set_handler (drive, &multwrite_intr, WAIT_CMD); @@ -405,7 +402,8 @@ static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *dr * since the open() has already succeeded, * and the door_lock is irrelevant at this point. */ - (void) ide_wait_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL); + if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL)) + drive->doorlocking = 0; } return 0; } @@ -414,7 +412,8 @@ static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t { if (drive->removable && !drive->usage) { invalidate_buffers(inode->i_rdev); - (void) ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL); + if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL)) + drive->doorlocking = 0; } MOD_DEC_USE_COUNT; } @@ -587,8 +586,13 @@ static int set_multcount(ide_drive_t *drive, int arg) static int set_nowerr(ide_drive_t *drive, int arg) { + unsigned long flags; + + if (ide_spin_wait_hwgroup("set_nowerr", drive, &flags)) + return -EBUSY; drive->nowerr = arg; drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; + spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); return 0; } @@ -658,14 +662,12 @@ static void idedisk_setup (ide_drive_t *drive) /* check for removable disks (eg. SYQUEST), ignore 'WD' drives */ if (id->config & (1<<7)) { /* removable disk ? */ - if (id->model[0] != 'W' || id->model[1] != 'D') + if (id->model[0] != 'W' || id->model[1] != 'D') { drive->removable = 1; + drive->doorlocking = 1; + } } - /* SunDisk drives: treat as non-removable; can mess up non-Sun systems! FIXME */ - if (id->model[0] == 'S' && id->model[1] == 'u') - drive->removable = 0; - /* Extract geometry if we did not already have one for the drive */ if (!drive->cyl || !drive->head || !drive->sect) { drive->cyl = drive->bios_cyl = id->cyls; @@ -714,9 +716,10 @@ static void idedisk_setup (ide_drive_t *drive) if (drive->cyl > drive->bios_cyl) drive->bios_cyl = drive->cyl; } +#if 0 /* done instead for entire identify block in arch/ide.h stuff */ /* fix byte-ordering of buffer size field */ id->buf_size = le16_to_cpu(id->buf_size); - +#endif printk (KERN_INFO "%s: %.40s, %ldMB w/%dkB Cache, CHS=%d/%d/%d", drive->name, id->model, idedisk_capacity(drive)/2048L, id->buf_size/2, drive->bios_cyl, drive->bios_head, drive->bios_sect); diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c index 2cbed3539..c314d1c82 100644 --- a/drivers/block/ide-dma.c +++ b/drivers/block/ide-dma.c @@ -84,7 +84,7 @@ */ const char *good_dma_drives[] = {"Micropolis 2112A", "CONNER CTMA 4000", - "ST34342A", + "ST34342A", /* for Sun Ultra */ NULL}; /* @@ -128,7 +128,7 @@ void ide_dma_intr (ide_drive_t *drive) } printk("%s: dma_intr: bad DMA status\n", drive->name); } - sti(); + ide__sti(); /* local CPU only */ ide_error(drive, "dma_intr", stat); } @@ -210,7 +210,7 @@ static int config_drive_for_dma (ide_drive_t *drive) struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); - if (id && (id->capability & 1) && !HWIF(drive)->no_autodma) { + if (id && (id->capability & 1) && !hwif->no_autodma) { /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */ if (id->field_valid & 4) /* UltraDMA */ if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) @@ -250,6 +250,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; unsigned int count, reading = 0; + byte dma_stat; switch (func) { case ide_dma_off: @@ -267,22 +268,29 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) return 1; /* try PIO instead of DMA */ outl(virt_to_bus(hwif->dmatable), dma_base + 4); /* PRD table */ outb(reading, dma_base); /* specify r/w */ - outb(inb(dma_base+2)|0x06, dma_base+2); /* clear status bits */ + outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ + drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);/* issue cmd to drive */ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); case ide_dma_begin: + /* Note that this is done *after* the cmd has + * been issued to the drive, as per the BM-IDE spec. + * The Promise Ultra33 doesn't work correctly when + * we do this part before issuing the drive cmd. + */ outb(inb(dma_base)|1, dma_base); /* start DMA */ return 0; case ide_dma_end: /* returns 1 on error, 0 otherwise */ - { - byte dma_stat = inb(dma_base+2); - int rc = (dma_stat & 7) != 4; + drive->waiting_for_dma = 0; + dma_stat = inb(dma_base+2); outb(inb(dma_base)&~1, dma_base); /* stop DMA */ outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ - return rc; /* verify good DMA status */ - } + return (dma_stat & 7) != 4; /* verify good DMA status */ + case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ + dma_stat = inb(dma_base+2); + return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ default: printk("ide_dmaproc: unsupported func: %d\n", func); return 1; @@ -331,9 +339,10 @@ __initfunc(void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigne /* * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space: */ -__initfunc(unsigned long ide_get_or_set_dma_base (struct pci_dev *dev, ide_hwif_t *hwif, int extra, const char *name)) +__initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name)) { - unsigned long dma_base = 0; + unsigned long dma_base = 0; + struct pci_dev *dev = hwif->pci_dev; if (hwif->mate && hwif->mate->dma_base) { dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8); diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c index a4aa0b460..e59565e21 100644 --- a/drivers/block/ide-floppy.c +++ b/drivers/block/ide-floppy.c @@ -713,7 +713,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive) #endif /* IDEFLOPPY_DEBUG_LOG */ clear_bit (PC_DMA_IN_PROGRESS, &pc->flags); - ide_sti(); + ide__sti(); /* local CPU only */ if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) { /* Error detected */ #if IDEFLOPPY_DEBUG_LOG diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c index 9dd5487f3..811b7bed0 100644 --- a/drivers/block/ide-pci.c +++ b/drivers/block/ide-pci.c @@ -43,6 +43,7 @@ #define DEVID_NS87415 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415}) #define DEVID_HT6565 ((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565}) #define DEVID_AEC6210 ((ide_pci_devid_t){0x1191, 0x0005}) +#define DEVID_W82C105 ((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105}) #define IDE_IGNORE ((void *)-1) @@ -71,7 +72,18 @@ extern void ide_init_ns87415(ide_hwif_t *); extern void ide_init_cmd646(ide_hwif_t *); #define INIT_CMD646 &ide_init_cmd646 #else +#ifdef __sparc_v9__ #define INIT_CMD646 IDE_IGNORE +#else +#define INIT_CMD646 NULL +#endif +#endif + +#ifdef CONFIG_BLK_DEV_SL82C105 +extern void ide_init_sl82c105(ide_hwif_t *); +#define INIT_W82C105 &ide_init_sl82c105 +#else +#define INIT_W82C105 IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_RZ1000 @@ -113,6 +125,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = { {DEVID_TRM290, "TRM290", INIT_TRM290, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, {DEVID_NS87415, "NS87415", INIT_NS87415, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, {DEVID_AEC6210, "AEC6210", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, + {DEVID_W82C105, "W82C105", INIT_W82C105, {{0x40,0x01,0x01}, {0x40,0x10,0x10}} }, {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }}; /* @@ -269,7 +282,7 @@ check_if_enabled: ide_pci_enablebit_t *e = &(d->enablebits[port]); if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val)) continue; /* port not enabled */ - ctl = dev->base_address[1+2*port] & PCI_BASE_ADDRESS_IO_MASK; + ctl = dev->base_address[(2*port)+1] & PCI_BASE_ADDRESS_IO_MASK; if (!ctl) ctl = port ? 0x374 : 0x3f4; /* use default value */ base = dev->base_address[2*port] & ~7; @@ -299,7 +312,7 @@ check_if_enabled: if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) { unsigned int extra = (!mate && IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246)) ? 16 : 0; - unsigned long dma_base = ide_get_or_set_dma_base(dev, hwif, extra, d->name); + unsigned long dma_base = ide_get_or_set_dma_base(hwif, extra, d->name); if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) { /* * Set up BM-DMA capability (PnP BIOS should have done this) diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index b2ea1bfd9..7af146b28 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -47,7 +47,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_KERNEL); ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ - sti(); + ide__sti(); /* local CPU only */ ide_fix_driveid(id); #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA) @@ -195,12 +195,12 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) delay_50ms(); /* wait for IRQ and DRQ_STAT */ if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) { unsigned long flags; - save_flags(flags); - cli(); /* some systems need this */ + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only; some systems need this */ do_identify(drive, cmd); /* drive returned ID */ rc = 0; /* drive responded with ID */ (void) GET_STAT(); /* clear drive IRQ */ - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ } else rc = 2; /* drive refused ID */ if (!HWIF(drive)->irq) { @@ -398,8 +398,8 @@ static void probe_hwif (ide_hwif_t *hwif) return; } - save_flags(flags); - sti(); /* needed for jiffies and irq probing */ + __save_flags(flags); /* local CPU only */ + __sti(); /* local CPU only; needed for jiffies and irq probing */ /* * Second drive should only exist if first drive was found, * but a lot of cdrom drives are configured as single slaves. @@ -429,7 +429,7 @@ static void probe_hwif (ide_hwif_t *hwif) } while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies)); } - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; if (drive->present) { @@ -486,8 +486,8 @@ static int init_irq (ide_hwif_t *hwif) ide_hwgroup_t *hwgroup; ide_hwif_t *match = NULL; - save_flags(flags); - cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ hwif->hwgroup = NULL; #if MAX_HWIFS > 1 @@ -499,7 +499,9 @@ static int init_irq (ide_hwif_t *hwif) if (h->hwgroup) { /* scan only initialized hwif's */ if (hwif->irq == h->irq) { hwif->sharing_irq = h->sharing_irq = 1; - save_match(hwif, h, &match); + if (hwif->chipset != ide_pci || h->chipset != ide_pci) { + save_match(hwif, h, &match); + } } if (hwif->serialized) { if (hwif->mate && hwif->mate->irq == h->irq) @@ -520,10 +522,15 @@ static int init_irq (ide_hwif_t *hwif) } else { hwgroup = kmalloc(sizeof(ide_hwgroup_t), GFP_KERNEL); memset(hwgroup, 0, sizeof(ide_hwgroup_t)); - hwgroup->hwif = hwif->next = hwif; - hwgroup->rq = NULL; - hwgroup->handler = NULL; - hwgroup->drive = NULL; + hwgroup->hwif = hwif->next = hwif; + hwgroup->rq = NULL; + hwgroup->handler = NULL; + hwgroup->drive = NULL; + hwgroup->busy = 0; + hwgroup->spinlock = (spinlock_t)SPIN_LOCK_UNLOCKED; +#if (DEBUG_SPINLOCK > 0) + printk("hwgroup(%s) spinlock is %p\n", hwif->name, &hwgroup->spinlock); /* FIXME */ +#endif init_timer(&hwgroup->timer); hwgroup->timer.function = &ide_timer_expiry; hwgroup->timer.data = (unsigned long) hwgroup; @@ -533,10 +540,11 @@ static int init_irq (ide_hwif_t *hwif) * Allocate the irq, if not already obtained for another hwif */ if (!match || match->irq != hwif->irq) { - if (ide_request_irq(hwif->irq, &ide_intr, SA_INTERRUPT, hwif->name, hwgroup)) { + int sa = (hwif->chipset == ide_pci) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT; + if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) { if (!match) kfree(hwgroup); - restore_flags(flags); + restore_flags(flags); /* all CPUs */ return 1; } } @@ -558,7 +566,7 @@ static int init_irq (ide_hwif_t *hwif) hwgroup->drive->next = drive; } hwgroup->hwif = HWIF(hwgroup->drive); - restore_flags(flags); /* safe now that hwif->hwgroup is set up */ + restore_flags(flags); /* all CPUs; safe now that hwif->hwgroup is set up */ #ifndef __mc68000__ printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name, @@ -685,13 +693,17 @@ static int hwif_init (ide_hwif_t *hwif) read_ahead[hwif->major] = 8; /* (4kB) */ hwif->present = 1; /* success */ } +#if (DEBUG_SPINLOCK > 0) +{ + static int done = 0; + if (!done++) + printk("io_request_lock is %p\n", &io_request_lock); /* FIXME */ +} +#endif return hwif->present; } - -int ideprobe_init(void); - - +int ideprobe_init (void); static ide_module_t ideprobe_module = { IDE_PROBE_MODULE, ideprobe_init, diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c index a86a51fdd..26a56e740 100644 --- a/drivers/block/ide-proc.c +++ b/drivers/block/ide-proc.c @@ -111,7 +111,7 @@ static int proc_ide_write_config unsigned long startn = 0, n, flags; const char *start = NULL, *msg = NULL; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; /* * Skip over leading whitespace @@ -124,7 +124,7 @@ static int proc_ide_write_config * Do one full pass to verify all parameters, * then do another to actually write the regs. */ - save_flags(flags); + save_flags(flags); /* all CPUs */ do { const char *p; if (for_real) { @@ -133,14 +133,15 @@ static int proc_ide_write_config ide_hwgroup_t *mategroup = NULL; if (hwif->mate && hwif->mate->hwgroup) mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup); - cli(); /* ensure all writes are done together */ - while (mygroup->active || (mategroup && mategroup->active)) { - restore_flags(flags); + cli(); /* all CPUs; ensure all writes are done together */ + while (mygroup->busy || (mategroup && mategroup->busy)) { + sti(); /* all CPUs */ if (0 < (signed long)(jiffies - timeout)) { printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name); + restore_flags(flags); /* all CPUs */ return -EBUSY; } - cli(); + cli(); /* all CPUs */ } } p = buffer; @@ -155,7 +156,7 @@ static int proc_ide_write_config break; case 'P': is_pci = 1; #ifdef CONFIG_BLK_DEV_IDEPCI - if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) + if (hwif->pci_dev && !IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) break; #endif /* CONFIG_BLK_DEV_IDEPCI */ msg = "not a PCI device"; @@ -174,7 +175,7 @@ static int proc_ide_write_config msg = "bad/missing register number"; goto parse_error; } - if (--n < 0 || *p++ != ':') { + if (n-- == 0 || *p++ != ':') { msg = "missing ':'"; goto parse_error; } @@ -223,7 +224,7 @@ static int proc_ide_write_config break; } if (rc) { - restore_flags(flags); + restore_flags(flags); /* all CPUs */ printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n", msg, dev->bus->number, dev->devfn, reg, val); printk("proc_ide_write_config: error %d\n", rc); @@ -243,10 +244,10 @@ static int proc_ide_write_config } } } while (!for_real++); - restore_flags(flags); + restore_flags(flags); /* all CPUs */ return count; parse_error: - restore_flags(flags); + restore_flags(flags); /* all CPUs */ printk("parse error\n"); return xx_xx_parse_error(start, startn, msg); } @@ -259,27 +260,25 @@ static int proc_ide_read_config #ifdef CONFIG_BLK_DEV_IDEPCI ide_hwif_t *hwif = (ide_hwif_t *)data; - int reg = 0; + struct pci_dev *dev = hwif->pci_dev; + if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL) && dev && dev->bus) { + int reg = 0; - struct pci_dev *dev = hwif->pci_dev; - - out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n", - dev->bus->number, dev->devfn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel); - do { - byte val; - int rc = pci_read_config_byte(dev, reg, &val); - if (rc) { - printk("proc_ide_read_config: error reading bus %02x dev %02x reg 0x%02x\n", - dev->bus->number, dev->devfn, reg); - printk("proc_ide_read_config: error %d\n", rc); - return -EIO; - out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n'); - } else - out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n'); - } while (reg < 0x100); -#else /* CONFIG_BLK_DEV_IDEPCI */ - out += sprintf(out, "(none)\n"); + out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n", + dev->bus->number, dev->devfn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel); + do { + byte val; + int rc = pci_read_config_byte(dev, reg, &val); + if (rc) { + printk("proc_ide_read_config: error %d reading bus %02x dev %02x reg 0x%02x\n", + rc, dev->bus->number, dev->devfn, reg); + out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n'); + } else + out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n'); + } while (reg < 0x100); + } else #endif /* CONFIG_BLK_DEV_IDEPCI */ + out += sprintf(out, "(none)\n"); len = out - page; PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } @@ -425,14 +424,13 @@ static int proc_ide_write_settings (struct file *file, const char *buffer, unsigned long count, void *data) { ide_drive_t *drive = (ide_drive_t *) data; - ide_hwif_t *hwif = HWIF(drive); char name[MAX_LEN + 1]; int for_real = 0, len; - unsigned long n, flags; + unsigned long n; const char *start = NULL; ide_settings_t *setting; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; /* * Skip over leading whitespace @@ -443,27 +441,10 @@ static int proc_ide_write_settings } /* * Do one full pass to verify all parameters, - * then do another to actually write the pci regs. + * then do another to actually write the new settings. */ - save_flags(flags); do { const char *p; - if (for_real) { - unsigned long timeout = jiffies + (3 * HZ); - ide_hwgroup_t *mygroup = (ide_hwgroup_t *)(hwif->hwgroup); - ide_hwgroup_t *mategroup = NULL; - if (hwif->mate && hwif->mate->hwgroup) - mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup); - cli(); /* ensure all writes are done together */ - while (mygroup->active || (mategroup && mategroup->active)) { - restore_flags(flags); - if (0 < (signed long)(jiffies - timeout)) { - printk("/proc/ide/%s/settings: channel(s) busy, cannot write\n", drive->name); - return -EBUSY; - } - cli(); - } - } p = buffer; n = count; while (n > 0) { @@ -508,10 +489,8 @@ static int proc_ide_write_settings ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor); } } while (!for_real++); - restore_flags(flags); return count; parse_error: - restore_flags(flags); printk("proc_ide_write_settings(): parse error\n"); return -EINVAL; } @@ -573,7 +552,7 @@ static int proc_ide_write_driver { ide_drive_t *drive = (ide_drive_t *) data; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (ide_replace_subdriver(drive, buffer)) return -EINVAL; diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index c4f5c6e23..3b6e2790f 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -1432,8 +1432,8 @@ static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage) #if IDETAPE_DEBUG_LOG printk (KERN_INFO "Reached idetape_add_stage_tail\n"); #endif /* IDETAPE_DEBUG_LOG */ - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ stage->next=NULL; if (tape->last_stage != NULL) tape->last_stage->next=stage; @@ -1444,7 +1444,7 @@ static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage) tape->next_stage=tape->last_stage; tape->nr_stages++; tape->nr_pending_stages++; - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ } /* @@ -1754,7 +1754,7 @@ static void idetape_pc_intr (ide_drive_t *drive) #endif /* IDETAPE_DEBUG_LOG */ clear_bit (PC_DMA_IN_PROGRESS, &pc->flags); - ide_sti(); + ide__sti(); /* local CPU only */ if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) { /* Error detected */ #if IDETAPE_DEBUG_LOG @@ -2398,11 +2398,11 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks) */ return (idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh)); } - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ if (tape->active_stage == tape->first_stage) idetape_wait_for_request (tape->active_data_request); - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ rq_ptr = &tape->first_stage->rq; bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors); @@ -2451,13 +2451,13 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks) * Pay special attention to possible race conditions. */ while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) { - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ if (idetape_pipeline_active (tape)) { idetape_wait_for_request (tape->active_data_request); - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ } else { - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ idetape_insert_pipeline_into_queue (drive); if (idetape_pipeline_active (tape)) continue; @@ -2514,12 +2514,12 @@ static void idetape_discard_read_pipeline (ide_drive_t *drive) if (tape->first_stage == NULL) return; - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ tape->next_stage = NULL; if (idetape_pipeline_active (tape)) idetape_wait_for_request (tape->active_data_request); - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ while (tape->first_stage != NULL) idetape_remove_stage_head (drive); @@ -2539,8 +2539,8 @@ static void idetape_wait_for_pipeline (ide_drive_t *drive) if (!idetape_pipeline_active (tape)) idetape_insert_pipeline_into_queue (drive); - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ if (!idetape_pipeline_active (tape)) goto abort; #if IDETAPE_DEBUG_BUGS @@ -2550,7 +2550,7 @@ static void idetape_wait_for_pipeline (ide_drive_t *drive) #endif /* IDETAPE_DEBUG_BUGS */ idetape_wait_for_request (&tape->last_stage->rq); abort: - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ } static void idetape_pad_zeros (ide_drive_t *drive, int bcount) @@ -2795,11 +2795,11 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c * Wait until the first read-ahead request * is serviced. */ - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ if (tape->active_stage == tape->first_stage) idetape_wait_for_request (tape->active_data_request); - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK) count++; @@ -3620,14 +3620,14 @@ static int idetape_cleanup (ide_drive_t *drive) int minor = tape->minor; unsigned long flags; - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ if (test_bit (IDETAPE_BUSY, &tape->flags) || tape->first_stage != NULL || tape->merge_stage_size || drive->usage) { - restore_flags(flags); + restore_flags(flags); /* all CPUs (overkill?) */ return 1; } idetape_chrdevs[minor].drive = NULL; - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ DRIVER(drive)->busy = 0; (void) ide_unregister_subdriver (drive); drive->driver_data = NULL; diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 111186eba..191678d77 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -86,6 +86,9 @@ * Version 6.12 integrate ioctl and proc interfaces * fix parsing of "idex=" command line parameter * Version 6.13 add support for ide4/ide5 courtesy rjones@orchestream.com + * Version 6.14 fixed IRQ sharing among PCI devices + * Version 6.15 added SMP awareness to IDE drivers + * Version 6.16 fixed various bugs; even more SMP friendly * * Some additional driver compile-time options are in ide.h * @@ -155,13 +158,13 @@ static unsigned long read_timer(void) unsigned long t, flags; int i; - __save_flags(flags); - __cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ t = jiffies * 11932; outb_p(0, 0x43); i = inb_p(0x40); i |= inb(0x40) << 8; - __restore_flags(flags); + __restore_flags(flags); /* local CPU only */ return (t - i); } #endif /* DISK_RECOVERY_TIME */ @@ -178,15 +181,11 @@ static inline void set_recovery_timer (ide_hwif_t *hwif) */ static void init_hwif_data (unsigned int index) { - byte *p; unsigned int unit; ide_hwif_t *hwif = &ide_hwifs[index]; /* bulk initialize hwif & drive info with zeros */ - p = ((byte *) hwif) + sizeof(ide_hwif_t); - do { - *--p = 0; - } while (p > (byte *) hwif); + memset(hwif, 0, sizeof(ide_hwif_t)); /* fill in any non-zero initial values */ hwif->index = index; @@ -299,11 +298,11 @@ void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) #if SUPPORT_VLB_SYNC if (io_32bit & 2) { unsigned long flags; - __save_flags(flags); - __cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ do_vlb_sync(IDE_NSECTOR_REG); insl(IDE_DATA_REG, buffer, wcount); - __restore_flags(flags); + __restore_flags(flags); /* local CPU only */ } else #endif /* SUPPORT_VLB_SYNC */ insl(IDE_DATA_REG, buffer, wcount); @@ -332,11 +331,11 @@ void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) #if SUPPORT_VLB_SYNC if (io_32bit & 2) { unsigned long flags; - __save_flags(flags); - __cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ do_vlb_sync(IDE_NSECTOR_REG); outsl(IDE_DATA_REG, buffer, wcount); - __restore_flags(flags); + __restore_flags(flags); /* local CPU only */ } else #endif /* SUPPORT_VLB_SYNC */ outsl(IDE_DATA_REG, buffer, wcount); @@ -392,6 +391,85 @@ void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecoun } /* + * Needed for PCI irq sharing + */ +static inline int drive_is_ready (ide_drive_t *drive) +{ + if (drive->waiting_for_dma) + return HWIF(drive)->dmaproc(ide_dma_test_irq, drive); +#if 0 + udelay(1); /* need to guarantee 400ns since last command was issued */ +#endif + if (GET_STAT() & BUSY_STAT) + return 0; /* drive busy: definitely not interrupting */ + return 1; /* drive ready: *might* be interrupting */ +} + +#if !defined(__SMP__) && defined(DEBUG_SPINLOCKS) && (DEBUG_SPINLOCKS > 1) + +static const char *ide_lock_name(spinlock_t *spinlock) +{ + int index; + + if (spinlock == &io_request_lock) + return "io_request_lock"; + for (index = 0; index < MAX_HWIFS; index++) { + ide_hwif_t *hwif = &ide_hwifs[index]; + ide_hwgroup_t *hwgroup = hwif->hwgroup; + if (spinlock == &hwgroup->spinlock) + return hwif->name; + } + return "?"; +} + +#define IDE_SPIN_LOCK_IRQ(msg,spinlock) \ +{ \ + static int __babble = 20; \ + __cli(); \ + if ((spinlock)->lock && __babble) { \ + __babble--; \ + printk("ide_lock: %s: already locked (%s)\n", msg, ide_lock_name(spinlock)); \ + } \ + /* spin_lock_irq(spinlock); */ \ + (spinlock)->lock = 1; \ +} + +#define IDE_SPIN_LOCK_IRQSAVE(msg,spinlock,flags) \ +{ \ + __save_flags(flags); \ + IDE_SPIN_LOCK_IRQ(msg,spinlock); \ +} + +#define IDE_SPIN_UNLOCK_IRQRESTORE(msg,spinlock,flags) \ +{ \ + static int __babble = 20; \ + __cli(); \ + if (!((spinlock)->lock) && __babble) { \ + __babble--; \ + printk("ide_unlock: %s: not locked (%s)\n", msg, ide_lock_name(spinlock)); \ + } \ + /* spin_unlock_irqrestore(msg,spinlock,flags); */ \ + (spinlock)->lock = 0; \ + restore_flags(flags); \ +} + +#define IDE_SPIN_UNLOCK(msg,spinlock) \ +{ \ + unsigned long __flags; \ + __save_flags(__flags); \ + IDE_SPIN_UNLOCK_IRQRESTORE(msg,spinlock,__flags); \ +} + +#else /* DEBUG_SPINLOCKS */ + +#define IDE_SPIN_LOCK_IRQ(msg,spinlock) spin_lock_irq(spinlock) +#define IDE_SPIN_LOCK_IRQSAVE(msg,spinlock,flags) spin_lock_irqsave(spinlock,flags) +#define IDE_SPIN_UNLOCK(msg,spinlock) spin_unlock(spinlock) +#define IDE_SPIN_UNLOCK_IRQRESTORE(msg,spinlock,flags) spin_unlock_irqrestore(spinlock,flags) + +#endif /* DEBUG_SPINLOCKS */ + +/* * This should get invoked any time we exit the driver to * wait for an interrupt response from a drive. handler() points * at the appropriate code to handle the next interrupt, and a @@ -400,7 +478,10 @@ void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecoun */ void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout) { + unsigned long flags; ide_hwgroup_t *hwgroup = HWGROUP(drive); + + IDE_SPIN_LOCK_IRQSAVE("ide_set_handler", &hwgroup->spinlock, flags); #ifdef DEBUG if (hwgroup->handler != NULL) { printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n", @@ -410,6 +491,7 @@ void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int t hwgroup->handler = handler; hwgroup->timer.expires = jiffies + timeout; add_timer(&(hwgroup->timer)); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_set_handler", &hwgroup->spinlock, flags); } /* @@ -558,8 +640,8 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) ide_hwif_t *hwif = HWIF(drive); ide_hwgroup_t *hwgroup = HWGROUP(drive); - __save_flags(flags); - __cli(); /* Why ? */ + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ /* For an ATAPI device, first try an ATAPI SRST. */ if (drive->media != ide_disk && !do_not_try_atapi) { @@ -569,7 +651,7 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); - __restore_flags (flags); + __restore_flags (flags); /* local CPU only */ return; } @@ -597,7 +679,7 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) ide_set_handler (drive, &reset_pollfunc, HZ/20); #endif /* OK_TO_RESET_CONTROLLER */ - __restore_flags (flags); + __restore_flags (flags); /* local CPU only */ } /* @@ -625,15 +707,17 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err) args[2] = IN_BYTE(IDE_NSECTOR_REG); } } - __save_flags(flags); - __cli(); + IDE_SPIN_LOCK_IRQSAVE("ide_end_drive_cmd", &io_request_lock, flags); drive->queue = rq->next; blk_dev[MAJOR(rq->rq_dev)].current_request = NULL; HWGROUP(drive)->rq = NULL; rq->rq_status = RQ_INACTIVE; + IDE_SPIN_UNLOCK_IRQRESTORE("ide_end_drive_cmd", &io_request_lock, flags); + save_flags(flags); /* all CPUs; overkill? */ + cli(); /* all CPUs; overkill? */ if (rq->sem != NULL) - up(rq->sem); - __restore_flags(flags); + up(rq->sem); /* inform originator that rq has been serviced */ + restore_flags(flags); /* all CPUs; overkill? */ } /* @@ -644,8 +728,8 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat) unsigned long flags; byte err = 0; - __save_flags (flags); - /* ide_sti(); HACK */ + __save_flags (flags); /* local CPU only */ + ide__sti(); /* local CPU only */ printk("%s: %s: status=0x%02x", drive->name, msg, stat); #if FANCY_STATUS_DUMPS printk(" { "); @@ -698,7 +782,7 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat) #endif /* FANCY_STATUS_DUMPS */ printk("\n"); } - __restore_flags (flags); + __restore_flags (flags); /* local CPU only */ return err; } @@ -732,7 +816,7 @@ void ide_error (ide_drive_t *drive, const char *msg, byte stat) byte err; err = ide_dump_status(drive, msg, stat); - if ((rq = HWGROUP(drive)->rq) == NULL || drive == NULL) + if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return; /* retry only "normal" I/O: */ if (rq->cmd == IDE_DRIVE_CMD) { @@ -784,7 +868,7 @@ void ide_error (ide_drive_t *drive, const char *msg, byte stat) void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) { ide_set_handler (drive, handler, WAIT_CMD); - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ OUT_BYTE(nsect,IDE_NSECTOR_REG); OUT_BYTE(cmd,IDE_COMMAND_REG); } @@ -799,7 +883,7 @@ static void drive_cmd_intr (ide_drive_t *drive) byte stat = GET_STAT(); int retries = 10; - /* ide_sti(); HACK */ + ide__sti(); /* local CPU only */ if ((stat & DRQ_STAT) && args && args[3]) { byte io_32bit = drive->io_32bit; drive->io_32bit = 0; @@ -857,17 +941,17 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou udelay(1); /* spec allows drive 400ns to assert "BUSY" */ if ((stat = GET_STAT()) & BUSY_STAT) { - __save_flags(flags); - /* ide_sti(); HACK */ + __save_flags(flags); /* local CPU only */ + ide__sti(); /* local CPU only */ timeout += jiffies; while ((stat = GET_STAT()) & BUSY_STAT) { if (0 < (signed long)(jiffies - timeout)) { - __restore_flags(flags); + __restore_flags(flags); /* local CPU only */ ide_error(drive, "status timeout", stat); return 1; } } - __restore_flags(flags); + __restore_flags(flags); /* local CPU only */ } udelay(1); /* allow status to settle, then read it again */ if (OK_STAT((stat = GET_STAT()), good, bad)) @@ -909,17 +993,18 @@ static void execute_drive_cmd (ide_drive_t *drive, struct request *rq) } /* - * do_request() initiates handling of a new I/O request + * start_request() initiates handling of a new I/O request */ -static inline void do_request (ide_hwgroup_t *hwgroup, ide_hwif_t *hwif, ide_drive_t *drive) +static inline void start_request (ide_drive_t *drive) { unsigned long block, blockend; struct request *rq = drive->queue; unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS; + ide_hwif_t *hwif = HWIF(drive); - /* ide_sti(); HACK */ + ide__sti(); /* local CPU only */ #ifdef DEBUG - printk("%s: do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq); + printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq); #endif if (unit >= MAX_DRIVES) { printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev)); @@ -946,15 +1031,11 @@ static inline void do_request (ide_hwgroup_t *hwgroup, ide_hwif_t *hwif, ide_dri #if (DISK_RECOVERY_TIME > 0) while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME); #endif - - hwgroup->hwif = hwif; - hwgroup->drive = drive; SELECT_DRIVE(hwif, drive); if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { printk("%s: drive not ready for command\n", drive->name); return; } - if (!drive->special.all) { if (rq->cmd == IDE_DRIVE_CMD) { execute_drive_cmd(drive, rq); @@ -973,7 +1054,7 @@ kill_rq: if (drive->driver != NULL) DRIVER(drive)->end_request(0, HWGROUP(drive)); else - ide_end_request(0, hwgroup); + ide_end_request(0, HWGROUP(drive)); } /* @@ -1000,21 +1081,19 @@ repeat: best = NULL; drive = hwgroup->drive; do { - if (!drive->queue) - continue; - if (drive->sleep && 0 < (signed long)(drive->sleep - jiffies)) - continue; - if (!best) { - best = drive; - continue; + if (drive->queue && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) { + if (!best + || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep))) + || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive)))) + { + struct blk_dev_struct *bdev = &blk_dev[HWIF(drive)->major]; + if (bdev->current_request != &bdev->plug) + best = drive; + } } - if (drive->sleep && (!best->sleep || drive->sleep < best->sleep)) - best = drive; - if (!best->sleep && WAKEUP(drive) < WAKEUP(best)) - best = drive; } while ((drive = drive->next) != hwgroup->drive); - if (best != hwgroup->drive && best && best->service_time > WAIT_MIN_SLEEP && !best->sleep && best->nice1) { - long t = (signed) (WAKEUP(best) - jiffies); /* BUGGY? */ + if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) { + long t = (signed long)(WAKEUP(best) - jiffies); if (t >= WAIT_MIN_SLEEP) { /* * We *may* have some time to spare, but first let's see if @@ -1022,9 +1101,10 @@ repeat: */ drive = best->next; do { - if (drive->sleep) /* this drive tried to be nice to us */ - continue; - if (WAKEUP(drive) > (jiffies - best->service_time) && WAKEUP(drive) < (jiffies + t)) { /* BUGGY? */ + if (!drive->sleep + && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time)) + && 0 < (signed long)((jiffies + t) - WAKEUP(drive))) + { ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP)); goto repeat; } @@ -1034,33 +1114,6 @@ repeat: return best; } -static inline void ide_leave_hwgroup (ide_hwgroup_t *hwgroup) -{ - ide_drive_t *drive = hwgroup->drive; - unsigned long sleep = 0; - - hwgroup->rq = NULL; - do { - blk_dev[HWIF(drive)->major].current_request = NULL; - if (!drive->sleep) - continue; - if (!sleep) { - sleep = drive->sleep; - continue; - } - if (drive->sleep < sleep) - sleep = drive->sleep; - } while ((drive = drive->next) != hwgroup->drive); - if (sleep) { - if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) - sleep = jiffies + WAIT_MIN_SLEEP; - hwgroup->timer.expires = sleep; - add_timer(&hwgroup->timer); - } else /* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_scheduler? */ - ide_release_lock(&ide_lock); - hwgroup->active = 0; -} - /* * The driver enables interrupts as much as possible. In order to do this, * (a) the device-interrupt is always masked before entry, and @@ -1075,30 +1128,68 @@ static inline void ide_leave_hwgroup (ide_hwgroup_t *hwgroup) * tolerance for latency during I/O. For devices which don't suffer from * this problem (most don't), the unmask flag can be set using the "hdparm" * utility, to permit other interrupts during data/cmd transfers. + * + * Caller must have already acquired spinlock using *spinflags + * */ -void ide_do_request (ide_hwgroup_t *hwgroup) +static void ide_do_request (ide_hwgroup_t *hwgroup, unsigned long *hwgroup_flags, int masked_irq) { - __cli(); /* paranoia */ - if (hwgroup->handler != NULL) { - printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name); - return; - } - do { - ide_drive_t *drive = choose_drive(hwgroup); - if (drive != NULL) { - ide_hwif_t *hwif = HWIF(drive); - if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) - OUT_BYTE(hwgroup->drive->ctl|2, hwgroup->hwif->io_ports[IDE_CONTROL_OFFSET]); - drive->sleep = 0; - blk_dev[hwif->major].current_request = hwgroup->rq = drive->queue; - drive->service_start = jiffies; - do_request(hwgroup, hwif, drive); - __cli(); - } else { - ide_leave_hwgroup(hwgroup); /* no work left for this hwgroup */ + struct blk_dev_struct *bdev; + ide_drive_t *drive; + ide_hwif_t *hwif; + unsigned long io_flags; + + hwgroup->busy = 1; + while (hwgroup->handler == NULL) { + IDE_SPIN_LOCK_IRQSAVE("ide_do_request1", &io_request_lock, io_flags); + drive = choose_drive(hwgroup); + if (drive == NULL) { + unsigned long sleep = 0; + + hwgroup->rq = NULL; + drive = hwgroup->drive; + do { + bdev = &blk_dev[HWIF(drive)->major]; + if (bdev->current_request != &bdev->plug) /* FIXME: this will do for now */ + bdev->current_request = NULL; /* (broken since patch-2.1.15) */ + if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep))) + sleep = drive->sleep; + } while ((drive = drive->next) != hwgroup->drive); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_do_request2", &io_request_lock, io_flags); + if (sleep) { + if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) + sleep = jiffies + WAIT_MIN_SLEEP; + hwgroup->timer.expires = sleep; + add_timer(&hwgroup->timer); + } else { + /* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_scheduler? */ + ide_release_lock(&ide_lock); /* for atari only */ + } + hwgroup->busy = 0; return; } - } while (hwgroup->handler == NULL); + hwif = HWIF(drive); + if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) /* set nIEN for previous hwif */ + OUT_BYTE(hwgroup->drive->ctl|2, hwgroup->hwif->io_ports[IDE_CONTROL_OFFSET]); + hwgroup->hwif = hwif; + hwgroup->drive = drive; + drive->sleep = 0; + drive->service_start = jiffies; + + bdev = &blk_dev[hwif->major]; + if (bdev->current_request == &bdev->plug) /* FIXME: paranoia */ + printk("%s: Huh? nuking plugged queue\n", drive->name); + bdev->current_request = hwgroup->rq = drive->queue; + IDE_SPIN_UNLOCK_IRQRESTORE("ide_do_request3", &io_request_lock, io_flags); + + if (hwif->irq != masked_irq) + disable_irq(hwif->irq); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_do_request4", &hwgroup->spinlock, *hwgroup_flags); + start_request(drive); + IDE_SPIN_LOCK_IRQSAVE("ide_do_request5", &hwgroup->spinlock, *hwgroup_flags); + if (hwif->irq != masked_irq) + enable_irq(hwif->irq); + } } /* @@ -1106,100 +1197,136 @@ void ide_do_request (ide_hwgroup_t *hwgroup) */ struct request **ide_get_queue (kdev_t dev) { - struct blk_dev_struct *bdev = blk_dev + MAJOR(dev); - ide_hwif_t *hwif = bdev->data; + ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data; return &hwif->drives[DEVICE_NR(dev) & 1].queue; } /* - * do_hwgroup_request() invokes ide_do_request() after first masking - * all possible interrupts for the current hwgroup. This prevents race - * conditions in the event that an unexpected interrupt occurs while - * we are in the driver. - * - * Note that the io-request lock will guarantee that the driver never gets - * re-entered even on another interrupt level, so we no longer need to - * mask the irq's. + * do_hwgroup_request() invokes ide_do_request() after claiming hwgroup->busy. */ -static void do_hwgroup_request (ide_hwgroup_t *hwgroup) +static void do_hwgroup_request (const char *msg, ide_hwgroup_t *hwgroup) { - if (hwgroup->handler == NULL) { - del_timer(&hwgroup->timer); - ide_get_lock(&ide_lock, ide_intr, hwgroup); - hwgroup->active = 1; - ide_do_request (hwgroup); + unsigned long flags; + + IDE_SPIN_LOCK_IRQSAVE(msg, &hwgroup->spinlock, flags); + if (hwgroup->busy) { + IDE_SPIN_UNLOCK_IRQRESTORE(msg, &hwgroup->spinlock, flags); + return; } + del_timer(&hwgroup->timer); + ide_get_lock(&ide_lock, ide_intr, hwgroup); /* for atari only */ + ide_do_request(hwgroup, &flags, 0); + IDE_SPIN_UNLOCK_IRQRESTORE(msg, &hwgroup->spinlock, flags); +} + +/* + * As of linux-2.1.95, ll_rw_blk.c invokes our do_idex_request() + * functions with the io_request_spinlock already grabbed. + * Since we need to do our own spinlock's internally, + * on paths that don't necessarily originate through the + * do_idex_request() path. + * + * We have to undo the spinlock on entry, and restore it again on exit. + * Fortunately, this is mostly a nop for non-SMP kernels. + */ +static inline void unlock_do_hwgroup_request (ide_hwgroup_t *hwgroup) +{ + IDE_SPIN_UNLOCK("unlock_do_hwgroup_request", &io_request_lock); + do_hwgroup_request ("from unlock_do_hwgroup_request", hwgroup); + IDE_SPIN_LOCK_IRQ("unlock_do_hwgroup_request", &io_request_lock); } -void do_ide0_request (void) /* invoked with __cli() */ +void do_ide0_request (void) { - do_hwgroup_request (ide_hwifs[0].hwgroup); + unlock_do_hwgroup_request (ide_hwifs[0].hwgroup); } #if MAX_HWIFS > 1 -void do_ide1_request (void) /* invoked with __cli() */ +void do_ide1_request (void) { - do_hwgroup_request (ide_hwifs[1].hwgroup); + unlock_do_hwgroup_request (ide_hwifs[1].hwgroup); } #endif /* MAX_HWIFS > 1 */ #if MAX_HWIFS > 2 -void do_ide2_request (void) /* invoked with __cli() */ +void do_ide2_request (void) { - do_hwgroup_request (ide_hwifs[2].hwgroup); + unlock_do_hwgroup_request (ide_hwifs[2].hwgroup); } #endif /* MAX_HWIFS > 2 */ #if MAX_HWIFS > 3 -void do_ide3_request (void) /* invoked with __cli() */ +void do_ide3_request (void) { - do_hwgroup_request (ide_hwifs[3].hwgroup); + unlock_do_hwgroup_request (ide_hwifs[3].hwgroup); } #endif /* MAX_HWIFS > 3 */ #if MAX_HWIFS > 4 -void do_ide4_request (void) /* invoked with cli() */ +void do_ide4_request (void) { - do_hwgroup_request (ide_hwifs[4].hwgroup); + unlock_do_hwgroup_request (ide_hwifs[4].hwgroup); } #endif /* MAX_HWIFS > 4 */ #if MAX_HWIFS > 5 -void do_ide5_request (void) /* invoked with cli() */ +void do_ide5_request (void) { - do_hwgroup_request (ide_hwifs[5].hwgroup); + unlock_do_hwgroup_request (ide_hwifs[5].hwgroup); } #endif /* MAX_HWIFS > 5 */ +static void start_next_request (ide_hwgroup_t *hwgroup, int masked_irq) +{ + unsigned long flags; + ide_drive_t *drive; + + IDE_SPIN_LOCK_IRQSAVE("start_next_request", &hwgroup->spinlock, flags); + if (hwgroup->handler != NULL) { + IDE_SPIN_UNLOCK_IRQRESTORE("start_next_request", &hwgroup->spinlock, flags); + return; + } + drive = hwgroup->drive; + set_recovery_timer(HWIF(drive)); + drive->service_time = jiffies - drive->service_start; + ide_do_request(hwgroup, &flags, masked_irq); + IDE_SPIN_UNLOCK_IRQRESTORE("start_next_request", &hwgroup->spinlock, flags); +} + void ide_timer_expiry (unsigned long data) { ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; - ide_drive_t *drive = hwgroup->drive; + ide_drive_t *drive; ide_handler_t *handler; unsigned long flags; - __save_flags(flags); - __cli(); - - if ((handler = hwgroup->handler) != NULL) { - hwgroup->handler = NULL; - if (hwgroup->poll_timeout != 0) /* polling in progress? */ - handler(drive); - else { /* abort the operation */ - if (hwgroup->hwif->dmaproc) - (void) hwgroup->hwif->dmaproc (ide_dma_end, drive); - ide_error(drive, "irq timeout", GET_STAT()); - } - __cli(); - if (hwgroup->handler == NULL) { - set_recovery_timer(HWIF(drive)); - drive->service_time = jiffies - drive->service_start; - do_hwgroup_request (hwgroup); + IDE_SPIN_LOCK_IRQSAVE("ide_timer_expiry1", &hwgroup->spinlock, flags); + drive = hwgroup->drive; + if ((handler = hwgroup->handler) == NULL) { + IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry2", &hwgroup->spinlock, flags); + do_hwgroup_request("timer do_hwgroup_request", hwgroup); + return; + } + hwgroup->busy = 1; /* should already be "1" */ + hwgroup->handler = NULL; + if (hwgroup->poll_timeout != 0) { /* polling in progress? */ + IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry3", &hwgroup->spinlock, flags); + handler(drive); + } else if (drive_is_ready(drive)) { + printk("%s: lost interrupt\n", drive->name); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry4", &hwgroup->spinlock, flags); + handler(drive); + } else { + if (drive->waiting_for_dma) { + (void) hwgroup->hwif->dmaproc(ide_dma_end, drive); + printk("%s: timeout waiting for DMA\n", drive->name); } - } else - do_hwgroup_request (hwgroup); - __restore_flags(flags); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry5", &hwgroup->spinlock, flags); + ide_error(drive, "irq timeout", GET_STAT()); + } + del_timer(&hwgroup->timer); + start_next_request(hwgroup, 0); } /* @@ -1238,75 +1365,78 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); if (!OK_STAT(stat, READY_STAT, BAD_STAT)) { /* Try to not flood the console with msgs */ - static unsigned long last_msgtime = 0; + static unsigned long last_msgtime = 0, count = 0; + ++count; if (0 < (signed long)(jiffies - (last_msgtime + HZ))) { last_msgtime = jiffies; - printk("%s%s: unexpected interrupt, status=0x%02x\n", - hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat); + printk("%s%s: unexpected interrupt, status=0x%02x, count=%ld\n", + hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat, count); } } } } while ((hwif = hwif->next) != hwgroup->hwif); } - -#ifdef __sparc_v9__ -#define IDE_IRQ_EQUAL(irq1, irq2) (1) -#else -#define IDE_IRQ_EQUAL(irq1, irq2) ((irq1) == (irq2)) -#endif - -static void do_ide_intr (int irq, void *dev_id, struct pt_regs *regs) -{ - ide_hwgroup_t *hwgroup = dev_id; - ide_hwif_t *hwif = hwgroup->hwif; - ide_handler_t *handler; - - if (!ide_ack_intr (hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET])) - return; - - if (IDE_IRQ_EQUAL(irq, hwif->irq) - && (handler = hwgroup->handler) != NULL) { - ide_drive_t *drive = hwgroup->drive; -#if 1 /* temporary, remove later -- FIXME */ - { - struct request *rq = hwgroup->rq; - if (rq != NULL - &&( MAJOR(rq->rq_dev) != HWIF(drive)->major - || (MINOR(rq->rq_dev) >> PARTN_BITS) != drive->select.b.unit)) - { - printk("ide_intr: got IRQ from wrong device: email mlord@pobox.com!!\n"); - return; - } - } -#endif /* temporary */ - hwgroup->handler = NULL; - del_timer(&(hwgroup->timer)); - /* if (drive->unmask) - ide_sti(); HACK */ - handler(drive); - /* this is necessary, as next rq may be different irq */ - if (hwgroup->handler == NULL) { - set_recovery_timer(HWIF(drive)); - drive->service_time = jiffies - drive->service_start; - ide_do_request(hwgroup); - } - } else { - unexpected_intr(irq, hwgroup); - } - __cli(); - hwif = hwgroup->hwif; -} - /* * entry point for all interrupts, caller does __cli() for us */ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; + ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id; + ide_hwif_t *hwif; + ide_drive_t *drive; + ide_handler_t *handler; - spin_lock_irqsave(&io_request_lock, flags); - do_ide_intr(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); + __cli(); /* local CPU only */ + IDE_SPIN_LOCK_IRQSAVE("ide_intr1", &hwgroup->spinlock, flags); + hwif = hwgroup->hwif; + if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) { + /* + * Not expecting an interrupt from this drive. + * That means this could be: + * (1) an interrupt from another PCI device + * sharing the same PCI INT# as us. + * or (2) a drive just entered sleep or standby mode, + * and is interrupting to let us know. + * or (3) a spurious interrupt of unknown origin. + * + * For PCI, we cannot tell the difference, + * so in that case we just ignore it and hope it goes away. + */ +#ifdef CONFIG_BLK_DEV_IDEPCI + if (IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) +#endif /* CONFIG_BLK_DEV_IDEPCI */ + { + /* + * Probably not a shared PCI interrupt, + * so we can safely try to do something about it: + */ + (void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]); + unexpected_intr(irq, hwgroup); + } + IDE_SPIN_UNLOCK_IRQRESTORE("ide_intr2", &hwgroup->spinlock, flags); + return; + } + drive = hwgroup->drive; + if (!drive || !drive_is_ready(drive)) { + IDE_SPIN_UNLOCK_IRQRESTORE("ide_intr3", &hwgroup->spinlock, flags); + return; + } + hwgroup->handler = NULL; + (void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]); + del_timer(&(hwgroup->timer)); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_intr4", &hwgroup->spinlock, flags); + if (drive->unmask) + ide__sti(); /* local CPU only */ + handler(drive); /* service this interrupt, may set handler for next interrupt */ + /* + * Note that handler() may have set things up for another + * interrupt to occur soon, but it cannot happen until + * we exit from this routine, because it will be the + * same irq as is currently being serviced here, + * and Linux won't allow another (on any CPU) until we return. + */ + start_next_request(hwgroup, hwif->irq); } /* @@ -1390,10 +1520,8 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio if (action == ide_wait) rq->sem = &sem; - __save_flags(flags); - __cli(); + IDE_SPIN_LOCK_IRQSAVE("ide_do_drive_cmd", &io_request_lock, flags); cur_rq = drive->queue; - if (cur_rq == NULL || action == ide_preempt) { rq->next = cur_rq; drive->queue = rq; @@ -1407,13 +1535,13 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio rq->next = cur_rq->next; cur_rq->next = rq; } - if (!hwgroup->active) { - do_hwgroup_request(hwgroup); - __cli(); - } - if (action == ide_wait && rq->rq_status != RQ_INACTIVE) + IDE_SPIN_UNLOCK_IRQRESTORE("ide_do_drive_cmd", &io_request_lock, flags); + do_hwgroup_request("drive_cmd do_hwgroup_request", hwgroup); + save_flags(flags); /* all CPUs; overkill? */ + cli(); /* all CPUs; overkill? */ + if (action == ide_wait && rq->rq_status != RQ_INACTIVE) down(&sem); /* wait for it to be serviced */ - __restore_flags(flags); + restore_flags(flags); /* all CPUs; overkill? */ return rq->errors ? -EIO : 0; /* return -EIO if errors */ } @@ -1428,6 +1556,7 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio int ide_revalidate_disk(kdev_t i_rdev) { ide_drive_t *drive; + ide_hwgroup_t *hwgroup; unsigned int p, major, minor; long flags; @@ -1435,15 +1564,15 @@ int ide_revalidate_disk(kdev_t i_rdev) return -ENODEV; major = MAJOR(i_rdev); minor = drive->select.b.unit << PARTN_BITS; - __save_flags(flags); - __cli(); + hwgroup = HWGROUP(drive); + IDE_SPIN_LOCK_IRQSAVE("ide_revalidate_disk", &hwgroup->spinlock, flags); if (drive->busy || (drive->usage > 1)) { - __restore_flags(flags); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_revalidate_disk", &hwgroup->spinlock, flags); return -EBUSY; }; drive->busy = 1; MOD_INC_USE_COUNT; - __restore_flags(flags); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_revalidate_disk", &hwgroup->spinlock, flags); for (p = 0; p < (1<<PARTN_BITS); ++p) { if (drive->part[p].nr_sects > 0) { @@ -1589,8 +1718,8 @@ void ide_unregister (unsigned int index) if (index >= MAX_HWIFS) return; - __save_flags(flags); - __cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ hwif = &ide_hwifs[index]; if (!hwif->present) goto abort; @@ -1680,7 +1809,7 @@ void ide_unregister (unsigned int index) } init_hwif_data (index); /* restore hwif data to pristine status */ abort: - __restore_flags(flags); + restore_flags(flags); /* all CPUs */ } int ide_register (int arg1, int arg2, int irq) @@ -1719,7 +1848,7 @@ found: return hwif->present ? index : -1; } -void ide_add_setting(ide_drive_t *drive, char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) +void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) { ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL; @@ -1798,38 +1927,63 @@ repeat: int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting) { - if (!(setting->rw & SETTING_READ)) - return -EINVAL; - switch(setting->data_type) { - case TYPE_BYTE: - return *((u8 *) setting->data); - case TYPE_SHORT: - return *((u16 *) setting->data); - case TYPE_INT: - case TYPE_INTA: - return *((u32 *) setting->data); - default: - return -EINVAL; + int val = -EINVAL; + unsigned long flags; + + if ((setting->rw & SETTING_READ)) { + IDE_SPIN_LOCK_IRQSAVE("ide_read_setting", &HWGROUP(drive)->spinlock, flags); + switch(setting->data_type) { + case TYPE_BYTE: + val = *((u8 *) setting->data); + break; + case TYPE_SHORT: + val = *((u16 *) setting->data); + break; + case TYPE_INT: + case TYPE_INTA: + val = *((u32 *) setting->data); + break; + } + IDE_SPIN_UNLOCK_IRQRESTORE("ide_read_setting", &HWGROUP(drive)->spinlock, flags); + } + return val; +} + +int ide_spin_wait_hwgroup (const char *msg, ide_drive_t *drive, unsigned long *flags) +{ + ide_hwgroup_t *hwgroup = HWGROUP(drive); + unsigned long timeout = jiffies + (3 * HZ); + + IDE_SPIN_LOCK_IRQSAVE(msg, &hwgroup->spinlock, *flags); + while (hwgroup->busy) { + IDE_SPIN_UNLOCK_IRQRESTORE(msg, &hwgroup->spinlock, *flags); + __sti(); /* local CPU only; needed for jiffies */ + if (0 < (signed long)(jiffies - timeout)) { + printk("%s: %s: channel busy\n", drive->name, msg); + return -EBUSY; + } + IDE_SPIN_LOCK_IRQSAVE(msg, &hwgroup->spinlock, *flags); } + return 0; } int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val) { unsigned long flags; - int i, rc = 0; + int i; u32 *p; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!(setting->rw & SETTING_WRITE)) return -EPERM; if (val < setting->min || val > setting->max) return -EINVAL; - __save_flags(flags); - __cli(); if (setting->set) - rc = setting->set(drive, val); - else switch (setting->data_type) { + return setting->set(drive, val); + if (ide_spin_wait_hwgroup("ide_write_settings", drive, &flags)) + return -EBUSY; + switch (setting->data_type) { case TYPE_BYTE: *((u8 *) setting->data) = val; break; @@ -1845,8 +1999,8 @@ int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val) *p = val; break; } - __restore_flags(flags); - return rc; + IDE_SPIN_UNLOCK_IRQRESTORE("ide_write_setting4", &HWGROUP(drive)->spinlock, flags); + return 0; } static int set_io_32bit(ide_drive_t *drive, int arg) @@ -1956,7 +2110,7 @@ static int ide_ioctl (struct inode *inode, struct file *file, return 0; } case BLKFLSBUF: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; @@ -1965,21 +2119,17 @@ static int ide_ioctl (struct inode *inode, struct file *file, return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg); case BLKRRPART: /* Re-read partition tables */ - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; return ide_revalidate_disk(inode->i_rdev); + case HDIO_OBSOLETE_IDENTITY: case HDIO_GET_IDENTITY: if (MINOR(inode->i_rdev) & PARTN_MASK) return -EINVAL; if (drive->id == NULL) return -ENOMSG; -#if 0 - if (copy_to_user((char *)arg, (char *)drive->id, sizeof(*drive->id))) + if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142)) return -EFAULT; -#else - if (copy_to_user((char *)arg, (char *)drive->id, 142)) - return -EFAULT; -#endif return 0; case HDIO_GET_NICE: @@ -1993,7 +2143,7 @@ static int ide_ioctl (struct inode *inode, struct file *file, { byte args[4], *argbuf = args; int argsize = 4; - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (NULL == (void *) arg) return ide_do_drive_cmd(drive, &rq, ide_wait); if (copy_from_user(args, (void *)arg, 4)) @@ -2016,7 +2166,7 @@ static int ide_ioctl (struct inode *inode, struct file *file, case HDIO_SCAN_HWIF: { int args[3]; - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (copy_from_user(args, (void *)arg, 3 * sizeof(int))) return -EFAULT; if (ide_register(args[0], args[1], args[2]) == -1) @@ -2024,7 +2174,7 @@ static int ide_ioctl (struct inode *inode, struct file *file, return 0; } case HDIO_SET_NICE: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (drive->driver == NULL) return -EPERM; if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1)))) @@ -2311,7 +2461,7 @@ __initfunc(void ide_setup (char *s)) goto bad_option; /* chipset already specified */ if (i <= -7 && hw != 0) goto bad_hwif; /* chipset drivers are for "ide0=" only */ - if (ide_hwifs[hw^1].chipset != ide_unknown) + if (i <= -7 && ide_hwifs[hw^1].chipset != ide_unknown) goto bad_option; /* chipset for 2nd port already specified */ printk("\n"); } @@ -2528,12 +2678,6 @@ __initfunc(static void probe_for_hwifs (void)) ide_probe_for_rz100x(); } #endif /* CONFIG_BLK_DEV_RZ1000 */ -#ifdef CONFIG_BLK_DEV_SL82C105 - { - extern void ide_probe_for_sl82c105(void); - ide_probe_for_sl82c105(); - } -#endif /* CONFIG_BLK_DEV_SL82C105 */ #endif /* CONFIG_BLK_DEV_IDEPCI */ } #endif /* CONFIG_PCI */ @@ -2560,21 +2704,21 @@ __initfunc(void ide_init_builtin_drivers (void)) probe_for_hwifs (); #ifdef CONFIG_BLK_DEV_IDE -#ifdef __mc68000__ +#if defined(__mc68000__) || defined(CONFIG_APUS) if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) { - ide_get_lock(&ide_lock, NULL, NULL); + ide_get_lock(&ide_lock, NULL, NULL); /* for atari only */ disable_irq(ide_hwifs[0].irq); } -#endif /* __mc68000__ */ +#endif /* __mc68000__ || CONFIG_APUS */ (void) ideprobe_init(); -#ifdef __mc68000__ +#if defined(__mc68000__) || defined(CONFIG_APUS) if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) { enable_irq(ide_hwifs[0].irq); - ide_release_lock(&ide_lock); + ide_release_lock(&ide_lock); /* for atari only */ } -#endif /* __mc68000__ */ +#endif /* __mc68000__ || CONFIG_APUS */ #endif /* CONFIG_BLK_DEV_IDE */ #ifdef CONFIG_PROC_FS @@ -2705,16 +2849,15 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio { unsigned long flags; - __save_flags(flags); - __cli(); - if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL || - drive->busy || drive->usage) { - __restore_flags(flags); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ + if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL || drive->busy || drive->usage) { + restore_flags(flags); /* all CPUs */ return 1; } drive->driver = driver; setup_driver_defaults(drive); - __restore_flags(flags); + restore_flags(flags); /* all CPUs */ if (drive->autotune != 2) { if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) (void) (HWIF(drive)->dmaproc(ide_dma_check, drive)); @@ -2733,10 +2876,10 @@ int ide_unregister_subdriver (ide_drive_t *drive) { unsigned long flags; - __save_flags(flags); - __cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ if (drive->usage || drive->busy || drive->driver == NULL || DRIVER(drive)->busy) { - __restore_flags(flags); + restore_flags(flags); /* all CPUs */ return 1; } #ifdef CONFIG_PROC_FS @@ -2745,7 +2888,7 @@ int ide_unregister_subdriver (ide_drive_t *drive) #endif auto_remove_settings(drive); drive->driver = NULL; - __restore_flags(flags); + restore_flags(flags); /* all CPUs */ return 0; } diff --git a/drivers/block/ide.h b/drivers/block/ide.h index f4ac72a62..f0c9604f0 100644 --- a/drivers/block/ide.h +++ b/drivers/block/ide.h @@ -204,26 +204,28 @@ typedef struct ide_drive_s { unsigned long service_start; /* time we started last request */ unsigned long service_time; /* service time of last request */ special_t special; /* special action flags */ + byte keep_settings; /* restore settings after drive reset */ + byte using_dma; /* disk is using dma for read/write */ + byte waiting_for_dma; /* dma currently in progress */ + byte unmask; /* flag: okay to unmask other irqs */ + byte slow; /* flag: slow data port */ + byte bswap; /* flag: byte swap data */ + byte dsc_overlap; /* flag: DSC overlap */ + byte nice1; /* flag: give potential excess bandwidth */ unsigned present : 1; /* drive is physically present */ unsigned noprobe : 1; /* from: hdx=noprobe */ - byte keep_settings; /* restore settings after drive reset */ unsigned busy : 1; /* currently doing revalidate_disk() */ unsigned removable : 1; /* 1 if need to do check_media_change */ - byte using_dma; /* disk is using dma for read/write */ unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */ - byte unmask; /* flag: okay to unmask other irqs */ unsigned no_unmask : 1; /* disallow setting unmask bit */ unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */ unsigned nobios : 1; /* flag: do not probe bios for drive */ - byte slow; /* flag: slow data port */ - unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */ unsigned revalidate : 1; /* request revalidation */ - byte bswap; /* flag: byte swap data */ - byte dsc_overlap; /* flag: DSC overlap */ unsigned atapi_overlap : 1; /* flag: ATAPI overlap (not supported) */ unsigned nice0 : 1; /* flag: give obvious excess bandwidth */ - byte nice1; /* flag: give potential excess bandwidth */ unsigned nice2 : 1; /* flag: give a share in our own bandwidth */ + unsigned doorlocking : 1; /* flag: for removable only: door lock/unlock works */ + unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */ #if FAKE_FDISK_FOR_EZDRIVE unsigned remap_0_to_1 : 1; /* flag: partitioned with ezdrive */ #endif /* FAKE_FDISK_FOR_EZDRIVE */ @@ -274,7 +276,8 @@ typedef struct ide_drive_s { * should either try again later, or revert to PIO for the current request. */ typedef enum { ide_dma_read, ide_dma_write, ide_dma_begin, ide_dma_end, - ide_dma_check, ide_dma_on, ide_dma_off, ide_dma_off_quietly + ide_dma_check, ide_dma_on, ide_dma_off, ide_dma_off_quietly, + ide_dma_test_irq } ide_dma_action_t; typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *); @@ -344,7 +347,7 @@ typedef struct hwif_s { unsigned reset : 1; /* reset after probe */ unsigned no_autodma : 1; /* don't automatically enable DMA at boot */ byte channel; /* for dual-port chips: 0=primary, 1=secondary */ - struct pci_dev *pci_dev; /* for pci chipsets */ + struct pci_dev *pci_dev; /* for pci chipsets */ ide_pci_devid_t pci_devid; /* for pci chipsets: {VID,DID} */ #if (DISK_RECOVERY_TIME > 0) unsigned long last_time; /* time when previous rq was done */ @@ -357,14 +360,15 @@ typedef struct hwif_s { typedef void (ide_handler_t)(ide_drive_t *); typedef struct hwgroup_s { + spinlock_t spinlock; /* protects "busy" and "handler" */ ide_handler_t *handler;/* irq handler, if active */ + int busy; /* BOOL: protects all fields below */ ide_drive_t *drive; /* current drive */ ide_hwif_t *hwif; /* ptr to current hwif in linked-list */ struct request *rq; /* current request */ struct timer_list timer; /* failsafe timer */ struct request wrq; /* local copy of current write rq */ unsigned long poll_timeout; /* timeout value during long polls */ - int active; /* set when servicing requests */ } ide_hwgroup_t; /* @@ -397,7 +401,7 @@ typedef struct ide_settings_s { struct ide_settings_s *next; } ide_settings_t; -void ide_add_setting(ide_drive_t *drive, char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set); +void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set); void ide_remove_setting(ide_drive_t *drive, char *name); ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name); int ide_read_setting(ide_drive_t *t, ide_settings_t *setting); @@ -667,6 +671,7 @@ void ide_stall_queue (ide_drive_t *drive, unsigned long timeout); */ struct request **ide_get_queue (kdev_t dev); +int ide_spin_wait_hwgroup(const char *msg, ide_drive_t *drive, unsigned long *flags); void ide_timer_expiry (unsigned long data); void ide_intr (int irq, void *dev_id, struct pt_regs *regs); void ide_geninit (struct gendisk *gd); @@ -693,6 +698,9 @@ extern struct file_operations ide_fops[]; #endif #ifdef _IDE_C +#ifdef CONFIG_BLK_DEV_IDE +int ideprobe_init (void); +#endif /* CONFIG_BLK_DEV_IDE */ #ifdef CONFIG_BLK_DEV_IDEDISK int idedisk_init (void); #endif /* CONFIG_BLK_DEV_IDEDISK */ @@ -726,13 +734,9 @@ int ide_build_dmatable (ide_drive_t *drive); void ide_dma_intr (ide_drive_t *drive); int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive); void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init; -unsigned long ide_get_or_set_dma_base (struct pci_dev *dev, ide_hwif_t *hwif, int extra, const char *name) __init; +unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init; #endif -#ifdef CONFIG_BLK_DEV_IDE -int ideprobe_init (void); -#endif /* CONFIG_BLK_DEV_IDE */ - #ifdef CONFIG_BLK_DEV_PDC4030 #include "pdc4030.h" #define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 900ed785a..d1201086d 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -448,7 +448,7 @@ static int loop_get_status(struct loop_device *lo, struct loop_info *arg) info.lo_flags = lo->lo_flags; strncpy(info.lo_name, lo->lo_name, LO_NAME_SIZE); info.lo_encrypt_type = lo->lo_encrypt_type; - if (lo->lo_encrypt_key_size && suser()) { + if (lo->lo_encrypt_key_size && capable(CAP_SYS_ADMIN)) { info.lo_encrypt_key_size = lo->lo_encrypt_key_size; memcpy(info.lo_encrypt_key, lo->lo_encrypt_key, lo->lo_encrypt_key_size); diff --git a/drivers/block/md.c b/drivers/block/md.c index 674c378b1..8b4b487e1 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -622,7 +622,7 @@ static int md_ioctl (struct inode *inode, struct file *file, int minor, err; struct hd_geometry *loc = (struct hd_geometry *) arg; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (((minor=MINOR(inode->i_rdev)) & 0x80) && diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 70e445668..cd733884c 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -316,7 +316,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file, struct nbd_device *lo; int dev, error; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!inode) return -EINVAL; diff --git a/drivers/block/ns87415.c b/drivers/block/ns87415.c index f312b251c..e7006ed69 100644 --- a/drivers/block/ns87415.c +++ b/drivers/block/ns87415.c @@ -35,7 +35,8 @@ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma) struct pci_dev *dev = hwif->pci_dev; unsigned long flags; - save_flags(flags); cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ new = *old; /* adjust IRQ enable bit */ @@ -56,7 +57,7 @@ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma) *old = new; (void) pci_write_config_dword(dev, 0x40, new); } - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ } static void ns87415_selectproc (ide_drive_t *drive) @@ -66,33 +67,25 @@ static void ns87415_selectproc (ide_drive_t *drive) static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = HWIF(drive); + byte dma_stat; switch (func) { case ide_dma_end: /* returns 1 on error, 0 otherwise */ - { - byte dma_stat = inb(hwif->dma_base+2); - int rc = (dma_stat & 7) != 4; - /* from errata: stop DMA, clear INTR & ERROR */ - outb(7, hwif->dma_base); - /* clear the INTR & ERROR bits */ - outb(dma_stat|6, hwif->dma_base+2); - /* verify good DMA status */ - return rc; - } + drive->waiting_for_dma = 0; + dma_stat = inb(hwif->dma_base+2); + outb(7, hwif->dma_base); /* from errata: stop DMA, clear INTR & ERROR */ + outb(dma_stat|6, hwif->dma_base+2); /* clear the INTR & ERROR bits */ + return (dma_stat & 7) != 4; /* verify good DMA status */ case ide_dma_write: case ide_dma_read: - /* select DMA xfer */ - ns87415_prepare_drive(drive, 1); - /* use standard DMA stuff */ - if (!ide_dmaproc(func, drive)) + ns87415_prepare_drive(drive, 1); /* select DMA xfer */ + if (!ide_dmaproc(func, drive)) /* use standard DMA stuff */ return 0; - /* DMA failed: select PIO xfer */ - ns87415_prepare_drive(drive, 0); + ns87415_prepare_drive(drive, 0); /* DMA failed: select PIO xfer */ return 1; default: - /* use standard DMA stuff */ - return ide_dmaproc(func, drive); + return ide_dmaproc(func, drive); /* use standard DMA stuff */ } } @@ -100,8 +93,7 @@ __initfunc(void ide_init_ns87415 (ide_hwif_t *hwif)) { struct pci_dev *dev = hwif->pci_dev; unsigned int ctrl, using_inta; - byte progif, stat; - int timeout; + byte progif; /* * We cannot probe for IRQ: both ports share common IRQ on INTA. @@ -134,6 +126,9 @@ __initfunc(void ide_init_ns87415 (ide_hwif_t *hwif)) pci_write_config_byte(dev, 0x55, 0xee); #ifdef __sparc_v9__ +{ + int timeout; + byte stat; /* * XXX: Reset the device, if we don't it will not respond * to SELECT_DRIVE() properly during first probe_hwif(). @@ -148,6 +143,7 @@ __initfunc(void ide_init_ns87415 (ide_hwif_t *hwif)) if (stat == 0xff) break; } while ((stat & BUSY_STAT) && --timeout); +} #endif } if (!using_inta) diff --git a/drivers/block/opti621.c b/drivers/block/opti621.c index a6be01938..41b87fbbe 100644 --- a/drivers/block/opti621.c +++ b/drivers/block/opti621.c @@ -242,8 +242,8 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio) hwif->name, ax, second.data_time, second.recovery_time, drdy); #endif - save_flags(flags); - cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ reg_base = hwif->io_ports[IDE_DATA_OFFSET]; outb(0xc0, reg_base+CNTRL_REG); /* allow Register-B */ @@ -268,7 +268,7 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio) write_reg(misc, MISC_REG); /* set address setup, DRDY timings, */ /* and read prefetch for both drives */ - restore_flags(flags); + restore_flags(flags); /* all CPUs */ } /* diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index aa431ae33..c2f9473bc 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -466,7 +466,7 @@ static int pd_ioctl(struct inode *inode,struct file *file, put_user(pd_hd[dev].start_sect,(long *)&geo->start); return 0; case BLKRASET: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; if(arg > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = arg; @@ -484,12 +484,14 @@ static int pd_ioctl(struct inode *inode,struct file *file, put_user(pd_hd[dev].nr_sects,(long *) arg); return (0); case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; case BLKRRPART: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; return pd_revalidate(inode->i_rdev); RO_IOCTLS(inode->i_rdev,arg); default: diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 00d629ddd..b894e2cc9 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -416,7 +416,7 @@ static int pf_ioctl(struct inode *inode,struct file *file, put_user(0,(long *)&geo->start); return 0; case BLKRASET: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; if(arg > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = arg; @@ -434,7 +434,7 @@ static int pf_ioctl(struct inode *inode,struct file *file, put_user(PF.capacity,(long *) arg); return (0); case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); diff --git a/drivers/block/pdc4030.c b/drivers/block/pdc4030.c index 30baff570..b5b13b9cb 100644 --- a/drivers/block/pdc4030.c +++ b/drivers/block/pdc4030.c @@ -327,15 +327,9 @@ void do_pdc4030_io (ide_drive_t *drive, struct request *rq) do { stat=GET_STAT(); if(stat & DRQ_STAT) { -/* unsigned long flags; - save_flags(flags); - cli(); disable_irq(HWIF(drive)->irq); -*/ ide_intr(HWIF(drive)->irq,HWGROUP(drive),NULL); -/* enable_irq(HWIF(drive)->irq); - restore_flags(flags); -*/ + enable_irq(HWIF(drive)->irq); return; } if(IN_BYTE(IDE_SELECT_REG) & 0x01) @@ -353,7 +347,7 @@ void do_pdc4030_io (ide_drive_t *drive, struct request *rq) return; } if (!drive->unmask) - cli(); + __cli(); /* local CPU only */ HWGROUP(drive)->wrq = *rq; /* scratchpad */ promise_write(drive); return; diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index cf13eccaf..bef50bd36 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -1091,7 +1091,7 @@ static int ps2esdi_ioctl(struct inode *inode, } break; case BLKRASET: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!inode->i_rdev) return -EINVAL; @@ -1109,7 +1109,7 @@ static int ps2esdi_ioctl(struct inode *inode, } break; case BLKFLSBUF: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!inode->i_rdev) return -EINVAL; @@ -1118,6 +1118,8 @@ static int ps2esdi_ioctl(struct inode *inode, return 0; case BLKRRPART: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; return (ps2esdi_reread_partitions(inode->i_rdev)); RO_IOCTLS(inode->i_rdev, arg); } diff --git a/drivers/block/qd6580.c b/drivers/block/qd6580.c index 9c13bfea9..9c1d0ed71 100644 --- a/drivers/block/qd6580.c +++ b/drivers/block/qd6580.c @@ -49,13 +49,13 @@ static void tune_qd6580 (ide_drive_t *drive, byte pio) pio = ide_get_best_pio_mode(drive, pio, 3, NULL); - save_flags(flags); - cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ outb_p(0x8d,0xb0); outb_p(0x0 ,0xb2); outb_p(((pio+1)<<4)|0x0f,0xb3); inb(0x3f6); - restore_flags(flags); + restore_flags(flags); /* all CPUs */ } void init_qd6580 (void) diff --git a/drivers/block/raid5.c b/drivers/block/raid5.c index 2b0e97450..88e2eb133 100644 --- a/drivers/block/raid5.c +++ b/drivers/block/raid5.c @@ -1209,6 +1209,14 @@ repeat: sh->pd_idx = pd_idx; if (sh->phase != PHASE_COMPLETE && sh->phase != PHASE_BEGIN) PRINTK(("stripe %lu catching the bus!\n", sh->sector)); + if (sh->bh_new[dd_idx]) { + printk("raid5: bug: stripe->bh_new[%d], sector %lu exists\n", dd_idx, sh->sector); + printk("raid5: bh %p, bh_new %p\n", bh, sh->bh_new[dd_idx]); + lock_stripe(sh); + md_wakeup_thread(raid_conf->thread); + wait_on_stripe(sh); + goto repeat; + } add_stripe_bh(sh, bh, dd_idx, rw); md_wakeup_thread(raid_conf->thread); diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 180a090d1..a3366d04b 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -164,7 +164,7 @@ static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un switch (cmd) { case BLKFLSBUF: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; invalidate_buffers(inode->i_rdev); break; case BLKGETSIZE: /* Return device size */ diff --git a/drivers/block/sl82c105.c b/drivers/block/sl82c105.c index 83426bc5e..ef05e4656 100644 --- a/drivers/block/sl82c105.c +++ b/drivers/block/sl82c105.c @@ -19,8 +19,9 @@ int chrp_ide_ports_known = 0; ide_ioreg_t chrp_ide_regbase[MAX_HWIFS]; ide_ioreg_t chrp_idedma_regbase; -void ide_init_sl82c105(struct pci_dev *dev) { - +void ide_init_sl82c105(ide_hwif_t *hwif) +{ + struct pci_dev *dev = hwif->pci_dev; unsigned short t16; unsigned int t32; @@ -37,15 +38,7 @@ void ide_init_sl82c105(struct pci_dev *dev) { pci_write_config_dword(dev, 0x40, 0x10ff08a1); } - -void ide_probe_for_sl82c105(void) -{ - struct pci_dev *dev = NULL; - - while ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, dev))) - ide_init_sl82c105(dev); -} - +#if 0 /* nobody ever calls these.. ?? */ void chrp_ide_probe(void) { struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL); @@ -75,4 +68,4 @@ void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) if (irq != NULL) *irq = chrp_ide_irq; } - +#endif diff --git a/drivers/block/trm290.c b/drivers/block/trm290.c index 474d434a2..2b0678849 100644 --- a/drivers/block/trm290.c +++ b/drivers/block/trm290.c @@ -148,8 +148,8 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) /* select PIO or DMA */ reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82); - save_flags(flags); - cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ if (reg != hwif->select_data) { hwif->select_data = reg; @@ -164,7 +164,7 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) outw(reg, hwif->config_data+3); } - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ } static void trm290_selectproc (ide_drive_t *drive) @@ -189,15 +189,20 @@ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive) break; /* try PIO instead of DMA */ trm290_prepare_drive(drive, 1); /* select DMA xfer */ outl(virt_to_bus(hwif->dmatable)|reading|writing, hwif->dma_base); + drive->waiting_for_dma = 1; outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */ if (drive->media != ide_disk) return 0; ide_set_handler(drive, &ide_dma_intr, WAIT_CMD); OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); + return 0; case ide_dma_begin: return 0; case ide_dma_end: + drive->waiting_for_dma = 0; return (inw(hwif->dma_base+2) != 0x00ff); + case ide_dma_test_irq: + return (inw(hwif->dma_base+2) == 0x00ff); default: return ide_dmaproc(func, drive); } @@ -226,8 +231,8 @@ __initfunc(void ide_init_trm290 (ide_hwif_t *hwif)) printk("TRM290: using default config base at 0x%04lx\n", hwif->config_data); } - save_flags(flags); - cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ /* put config reg into first byte of hwif->select_data */ outb(0x51|(hwif->channel<<3), hwif->config_data+1); hwif->select_data = 0x21; /* select PIO as default */ @@ -235,13 +240,13 @@ __initfunc(void ide_init_trm290 (ide_hwif_t *hwif)) reg = inb(hwif->config_data+3); /* get IRQ info */ reg = (reg & 0x10) | 0x03; /* mask IRQs for both ports */ outb(reg, hwif->config_data+3); - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ if ((reg & 0x10)) hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */ else if (!hwif->irq && hwif->mate && hwif->mate->irq) hwif->irq = hwif->mate->irq; /* sharing IRQ with mate */ - ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 2); + ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3); hwif->dmaproc = &trm290_dmaproc; hwif->selectproc = &trm290_selectproc; hwif->no_autodma = 1; /* play it safe for now */ diff --git a/drivers/block/umc8672.c b/drivers/block/umc8672.c index 8856dad35..77121ca3e 100644 --- a/drivers/block/umc8672.c +++ b/drivers/block/umc8672.c @@ -112,39 +112,39 @@ static void tune_umc (ide_drive_t *drive, byte pio) pio = ide_get_best_pio_mode(drive, pio, 4, NULL); printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]); - save_flags(flags); - cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ if (hwgroup && hwgroup->handler != NULL) { printk("umc8672: other interface is busy: exiting tune_umc()\n"); } else { current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio]; umc_set_speeds (current_speeds); } - restore_flags(flags); + restore_flags(flags); /* all CPUs */ } void init_umc8672 (void) /* called from ide.c */ { unsigned long flags; - save_flags(flags); - cli (); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ if (check_region(0x108, 2)) { - restore_flags(flags); + __restore_flags(flags); printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n"); return; } outb_p (0x5A,0x108); /* enable umc */ if (in_umc (0xd5) != 0xa0) { - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ printk ("umc8672: not found\n"); return; } outb_p (0xa5,0x108); /* disable umc */ umc_set_speeds (current_speeds); - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ request_region(0x108, 2, "umc8672"); ide_hwifs[0].chipset = ide_umc8672; diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 7a26e28ac..b7d604db8 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -338,7 +338,7 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0; } case BLKRASET: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(arg > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = arg; return 0; @@ -348,12 +348,12 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) if (!arg) return -EINVAL; return put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(long *) arg); case BLKFLSBUF: /* Return devices size */ - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; case HDIO_SET_DMA: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (xdc_busy) return -EBUSY; nodma = !arg; if (nodma && xd_dma_buffer) { @@ -366,6 +366,8 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) case HDIO_GET_MULTCOUNT: return put_user(xd_maxsectors, (long *) arg); case BLKRRPART: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; return xd_reread_partitions(inode->i_rdev); RO_IOCTLS(inode->i_rdev,arg); default: |