diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
commit | 33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch) | |
tree | 2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /drivers/block | |
parent | 216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff) |
Merge with Linux 2.3.32.
Diffstat (limited to 'drivers/block')
48 files changed, 2151 insertions, 1485 deletions
diff --git a/drivers/block/Config.in b/drivers/block/Config.in index f32c86dc1..8f128700f 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -53,6 +53,9 @@ else fi bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 + if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then + bool ' AEC6210 Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_AEC6210_TUNING + fi if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_X86" = "y" ]; then bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 @@ -65,7 +68,10 @@ else if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then bool ' HPT34X DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT34X_DMA fi - bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 + bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 + if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then + bool ' HPT366 Fast Interrupt support (EXPERIMENTAL)' HPT366_FAST_IRQ_PREDICTION + fi fi if [ "$CONFIG_X86" = "y" ]; then bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX @@ -84,7 +90,7 @@ else if [ "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then bool ' Special UDMA Feature' CONFIG_PDC202XX_FORCE_BURST_BIT if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Special Mode Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_MASTER_MODE + bool ' Special Mode Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_MASTER_MODE fi fi if [ "$CONFIG_X86" = "y" ]; then @@ -219,6 +225,7 @@ if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then fi if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ + "$CONFIG_BLK_DEV_AEC6210" = "y" -o \ "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \ "$CONFIG_BLK_DEV_CMD640" = "y" -o \ "$CONFIG_BLK_DEV_CY82C693" = "y" -o \ diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index b2f24a633..6c0120458 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -1026,7 +1026,7 @@ static boolean DAC960_ReportDeviceConfiguration(DAC960_Controller_T *Controller) static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) { - static void (*RequestFunctions[DAC960_MaxControllers])(void) = + static void (*RequestFunctions[DAC960_MaxControllers])(request_queue_t *) = { DAC960_RequestFunction0, DAC960_RequestFunction1, DAC960_RequestFunction2, DAC960_RequestFunction3, DAC960_RequestFunction4, DAC960_RequestFunction5, @@ -1046,8 +1046,8 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) /* Initialize the I/O Request Function. */ - blk_dev[MajorNumber].request_fn = - RequestFunctions[Controller->ControllerNumber]; + blk_init_queue(BLK_DEFAULT_QUEUE(MajorNumber), + RequestFunctions[Controller->ControllerNumber]); /* Initialize the Disk Partitions array, Partition Sizes array, Block Sizes array, Max Sectors per Request array, and Max Segments per Request array. @@ -1113,7 +1113,7 @@ static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller) /* Remove the I/O Request Function. */ - blk_dev[MajorNumber].request_fn = NULL; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MajorNumber)); /* Remove the Disk Partitions array, Partition Sizes array, Block Sizes array, Max Sectors per Request array, and Max Segments per Request array. @@ -1272,7 +1272,7 @@ static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller, boolean WaitForCommand) { IO_Request_T **RequestQueuePointer = - &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].current_request; + &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].request_queue.current_request; IO_Request_T *Request; DAC960_Command_T *Command; char *RequestBuffer; @@ -1375,7 +1375,7 @@ static inline void DAC960_ProcessRequests(DAC960_Controller_T *Controller) DAC960_RequestFunction0 is the I/O Request Function for DAC960 Controller 0. */ -static void DAC960_RequestFunction0(void) +static void DAC960_RequestFunction0(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[0]; ProcessorFlags_T ProcessorFlags; @@ -1398,7 +1398,7 @@ static void DAC960_RequestFunction0(void) DAC960_RequestFunction1 is the I/O Request Function for DAC960 Controller 1. */ -static void DAC960_RequestFunction1(void) +static void DAC960_RequestFunction1(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[1]; ProcessorFlags_T ProcessorFlags; @@ -1421,7 +1421,7 @@ static void DAC960_RequestFunction1(void) DAC960_RequestFunction2 is the I/O Request Function for DAC960 Controller 2. */ -static void DAC960_RequestFunction2(void) +static void DAC960_RequestFunction2(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[2]; ProcessorFlags_T ProcessorFlags; @@ -1444,7 +1444,7 @@ static void DAC960_RequestFunction2(void) DAC960_RequestFunction3 is the I/O Request Function for DAC960 Controller 3. */ -static void DAC960_RequestFunction3(void) +static void DAC960_RequestFunction3(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[3]; ProcessorFlags_T ProcessorFlags; @@ -1467,7 +1467,7 @@ static void DAC960_RequestFunction3(void) DAC960_RequestFunction4 is the I/O Request Function for DAC960 Controller 4. */ -static void DAC960_RequestFunction4(void) +static void DAC960_RequestFunction4(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[4]; ProcessorFlags_T ProcessorFlags; @@ -1490,7 +1490,7 @@ static void DAC960_RequestFunction4(void) DAC960_RequestFunction5 is the I/O Request Function for DAC960 Controller 5. */ -static void DAC960_RequestFunction5(void) +static void DAC960_RequestFunction5(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[5]; ProcessorFlags_T ProcessorFlags; @@ -1513,7 +1513,7 @@ static void DAC960_RequestFunction5(void) DAC960_RequestFunction6 is the I/O Request Function for DAC960 Controller 6. */ -static void DAC960_RequestFunction6(void) +static void DAC960_RequestFunction6(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[6]; ProcessorFlags_T ProcessorFlags; @@ -1536,7 +1536,7 @@ static void DAC960_RequestFunction6(void) DAC960_RequestFunction7 is the I/O Request Function for DAC960 Controller 7. */ -static void DAC960_RequestFunction7(void) +static void DAC960_RequestFunction7(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[7]; ProcessorFlags_T ProcessorFlags; @@ -3474,7 +3474,7 @@ static void DAC960_CreateProcEntries(void) { static PROC_DirectoryEntry_T *StatusProcEntry; int ControllerNumber; - DAC960_ProcDirectoryEntry = create_proc_entry("driver/rd", S_IFDIR, NULL); + DAC960_ProcDirectoryEntry = proc_mkdir("driver/rd", NULL); StatusProcEntry = create_proc_read_entry("status", 0, DAC960_ProcDirectoryEntry, DAC960_ProcReadStatus, NULL); @@ -3483,36 +3483,20 @@ static void DAC960_CreateProcEntries(void) ControllerNumber++) { DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; - PROC_DirectoryEntry_T *ControllerProcEntry, *InitialStatusProcEntry; - PROC_DirectoryEntry_T *CurrentStatusProcEntry, *UserCommandProcEntry; + PROC_DirectoryEntry_T *ControllerProcEntry; + PROC_DirectoryEntry_T *UserCommandProcEntry; if (Controller == NULL) continue; - ControllerProcEntry = &Controller->ControllerProcEntry; - ControllerProcEntry->name = Controller->ControllerName; - ControllerProcEntry->namelen = strlen(ControllerProcEntry->name); - ControllerProcEntry->mode = S_IFDIR | S_IRUGO | S_IXUGO; - proc_register(DAC960_ProcDirectoryEntry, ControllerProcEntry); - InitialStatusProcEntry = &Controller->InitialStatusProcEntry; - InitialStatusProcEntry->name = "initial_status"; - InitialStatusProcEntry->namelen = strlen(InitialStatusProcEntry->name); - InitialStatusProcEntry->mode = S_IFREG | S_IRUGO; - InitialStatusProcEntry->data = Controller; - InitialStatusProcEntry->read_proc = DAC960_ProcReadInitialStatus; - proc_register(ControllerProcEntry, InitialStatusProcEntry); - CurrentStatusProcEntry = &Controller->CurrentStatusProcEntry; - CurrentStatusProcEntry->name = "current_status"; - CurrentStatusProcEntry->namelen = strlen(CurrentStatusProcEntry->name); - CurrentStatusProcEntry->mode = S_IFREG | S_IRUGO; - CurrentStatusProcEntry->data = Controller; - CurrentStatusProcEntry->read_proc = DAC960_ProcReadCurrentStatus; - proc_register(ControllerProcEntry, CurrentStatusProcEntry); - UserCommandProcEntry = &Controller->UserCommandProcEntry; - UserCommandProcEntry->name = "user_command"; - UserCommandProcEntry->namelen = strlen(UserCommandProcEntry->name); - UserCommandProcEntry->mode = S_IFREG | S_IWUSR | S_IRUSR; - UserCommandProcEntry->data = Controller; - UserCommandProcEntry->read_proc = DAC960_ProcReadUserCommand; + ControllerProcEntry = proc_mkdir(Controller->ControllerName, + DAC960_ProcDirectoryEntry); + create_proc_read_entry("initial_status",0,ControllerProcEntry, + DAC960_ProcReadInitialStatus, Controller); + create_proc_read_entry("current_status",0,ControllerProcEntry, + DAC960_ProcReadCurrentStatus, Controller); + UserCommandProcEntry = + create_proc_read_entry("user_command", S_IWUSR|S_IRUSR, + ControllerProcEntry, + DAC960_ProcReadUserCommand, Controller); UserCommandProcEntry->write_proc = DAC960_ProcWriteUserCommand; - proc_register(ControllerProcEntry, UserCommandProcEntry); } } @@ -3524,6 +3508,7 @@ static void DAC960_CreateProcEntries(void) static void DAC960_DestroyProcEntries(void) { + /* FIXME */ remove_proc_entry("driver/rd", NULL); } diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index 2ff757786..e93448fab 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -1258,10 +1258,6 @@ typedef struct DAC960_Controller DAC960_StatusMailbox_T *FirstStatusMailbox; DAC960_StatusMailbox_T *LastStatusMailbox; DAC960_StatusMailbox_T *NextStatusMailbox; - PROC_DirectoryEntry_T ControllerProcEntry; - PROC_DirectoryEntry_T InitialStatusProcEntry; - PROC_DirectoryEntry_T CurrentStatusProcEntry; - PROC_DirectoryEntry_T UserCommandProcEntry; WaitQueue_T CommandWaitQueue; DAC960_DCDB_T MonitoringDCDB; DAC960_Enquiry_T Enquiry[2]; @@ -2212,14 +2208,14 @@ DAC960_V3_ReadStatusRegister(void *ControllerBaseAddress) static void DAC960_FinalizeController(DAC960_Controller_T *); static int DAC960_Finalize(NotifierBlock_T *, unsigned long, void *); -static void DAC960_RequestFunction0(void); -static void DAC960_RequestFunction1(void); -static void DAC960_RequestFunction2(void); -static void DAC960_RequestFunction3(void); -static void DAC960_RequestFunction4(void); -static void DAC960_RequestFunction5(void); -static void DAC960_RequestFunction6(void); -static void DAC960_RequestFunction7(void); +static void DAC960_RequestFunction0(request_queue_t *); +static void DAC960_RequestFunction1(request_queue_t *); +static void DAC960_RequestFunction2(request_queue_t *); +static void DAC960_RequestFunction3(request_queue_t *); +static void DAC960_RequestFunction4(request_queue_t *); +static void DAC960_RequestFunction5(request_queue_t *); +static void DAC960_RequestFunction6(request_queue_t *); +static void DAC960_RequestFunction7(request_queue_t *); static void DAC960_InterruptHandler(int, void *, Registers_T *); static void DAC960_QueueMonitoringCommand(DAC960_Command_T *); static void DAC960_MonitoringTimerFunction(unsigned long); diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 1de4fa581..7225b7120 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -243,11 +243,11 @@ endif ###Collect ifeq ($(CONFIG_BLK_DEV_IDE),y) - LX_OBJS += ide.o + LX_OBJS += ide.o ide-features.o L_OBJS += ide-probe.o $(IDE_OBJS) else ifeq ($(CONFIG_BLK_DEV_IDE),m) - MIX_OBJS += ide.o $(IDE_OBJS) + MIX_OBJS += ide.o ide-features.o $(IDE_OBJS) M_OBJS += ide-mod.o ide-probe-mod.o endif endif @@ -374,8 +374,8 @@ endif include $(TOPDIR)/Rules.make -ide-mod.o: ide.o $(IDE_OBJS) - $(LD) $(LD_RFLAG) -r -o $@ ide.o $(IDE_OBJS) +ide-mod.o: ide.o ide-features.o $(IDE_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ ide.o ide-features.o $(IDE_OBJS) ide-probe-mod.o: ide-probe.o ide-geometry.o $(LD) $(LD_RFLAG) -r -o $@ ide-probe.o ide-geometry.o diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index 80aa52472..d1631c973 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -360,7 +360,7 @@ static void acsi_times_out( unsigned long dummy ); static void copy_to_acsibuffer( void ); static void copy_from_acsibuffer( void ); static void do_end_requests( void ); -static void do_acsi_request( void ); +static void do_acsi_request( request_queue_t * ); static void redo_acsi_request( void ); static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ); @@ -938,7 +938,7 @@ static void do_end_requests( void ) * ***********************************************************************/ -static void do_acsi_request( void ) +static void do_acsi_request( request_queue_t * q ) { stdma_lock( acsi_interrupt, NULL ); @@ -1808,7 +1808,7 @@ int acsi_init( void ) phys_acsi_buffer = virt_to_phys( acsi_buffer ); STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ acsi_gendisk.next = gendisk_head; gendisk_head = &acsi_gendisk; @@ -1838,7 +1838,7 @@ void cleanup_module(void) struct gendisk ** gdp; del_timer( &acsi_timer ); - blk_dev[MAJOR_NR].request_fn = 0; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); atari_stram_free( acsi_buffer ); if (unregister_blkdev( MAJOR_NR, "ad" ) != 0) diff --git a/drivers/block/aec6210.c b/drivers/block/aec6210.c index 75bb8657f..c3e51052f 100644 --- a/drivers/block/aec6210.c +++ b/drivers/block/aec6210.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/aec6210.c Version 0.02 Sept. 3, 1999 + * linux/drivers/block/aec6210.c Version 0.03 Nov. 12, 1999 * * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License @@ -34,6 +34,7 @@ * 50: ff ff ff ff 00 06 00 00 00 00 00 00 00 00 00 00 */ +#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> @@ -51,10 +52,225 @@ #include <asm/io.h> #include <asm/irq.h> +#include "ide_modes.h" + +#define ACARD_DEBUG_DRIVE_INFO 1 + +#ifdef CONFIG_BLK_DEV_AEC6210_TUNING + +struct chipset_bus_clock_list_entry { + byte xfer_speed; + unsigned short chipset_settings; + byte ultra_settings; +}; + +struct chipset_bus_clock_list_entry aec6210_base [] = { + { XFER_UDMA_2, 0x0401, 0x02 }, + { XFER_UDMA_1, 0x0401, 0x01 }, + { XFER_UDMA_0, 0x0401, 0x01 }, + + { XFER_MW_DMA_2, 0x0401, 0x00 }, + { XFER_MW_DMA_1, 0x0402, 0x00 }, + { XFER_MW_DMA_0, 0x070a, 0x00 }, + + { XFER_PIO_4, 0x0401, 0x00 }, + { XFER_PIO_3, 0x0403, 0x00 }, + { XFER_PIO_2, 0x0708, 0x00 }, + { XFER_PIO_1, 0x070a, 0x00 }, + { XFER_PIO_0, 0x0700, 0x00 }, + { 0, 0x0000, 0x00 } +}; + +extern char *ide_xfer_verbose (byte xfer_rate); + /* * TO DO: active tuning and correction of cards without a bios. */ +static unsigned short pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table) +{ + for ( ; chipset_table->xfer_speed ; chipset_table++) + if (chipset_table->xfer_speed == speed) { + return chipset_table->chipset_settings; + } + return 0x0000; +} + +static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table) +{ + for ( ; chipset_table->xfer_speed ; chipset_table++) + if (chipset_table->xfer_speed == speed) { + return chipset_table->ultra_settings; + } + return 0x00; +} + +static int aec6210_tune_chipset (ide_drive_t *drive, byte speed) +{ + ide_hwif_t *hwif = HWIF(drive); + + int err; + byte drive_pci; + unsigned short drive_conf = 0x0000; + byte ultra = 0x00, ultra_conf = 0x00; + byte tmp1 = 0x00, tmp2 = 0x00; + + int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + + switch(drive_number) { + case 0: drive_pci = 0x40; break; + case 1: drive_pci = 0x42; break; + case 2: drive_pci = 0x44; break; + case 3: drive_pci = 0x46; break; + default: return -1; + } + + pci_read_config_word(HWIF(drive)->pci_dev, drive_pci, &drive_conf); + drive_conf = pci_bus_clock_list(speed, aec6210_base); + pci_write_config_word(HWIF(drive)->pci_dev, drive_pci, drive_conf); + + pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, &ultra); + tmp1 = ((0x00 << (2*drive_number)) | (ultra & ~(3 << (2*drive_number)))); + ultra_conf = pci_bus_clock_list_ultra(speed, aec6210_base); + tmp2 = ((ultra_conf << (2*drive_number)) | (tmp1 & ~(3 << (2*drive_number)))); + pci_write_config_byte(HWIF(drive)->pci_dev, 0x54, tmp2); + + err = ide_config_drive_speed(drive, speed); + +#if ACARD_DEBUG_DRIVE_INFO + printk("%s: %s drive%d 0x04%x 0x02%x 0x02%x 0x02%x 0x02%x\n", + drive->name, ide_xfer_verbose(speed), drive_number, + drive_conf, ultra, tmp1, ultra_conf, tmp2); +#endif /* ACARD_DEBUG_DRIVE_INFO */ + + return(err); +} + +static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) +{ + struct hd_driveid *id = drive->id; + byte speed = -1; + + if (drive->media != ide_disk) + return ((int) ide_dma_off_quietly); + + if (((id->dma_ultra & 0x0010) || + (id->dma_ultra & 0x0008) || + (id->dma_ultra & 0x0004)) && (ultra)) { + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && (ultra)) { + speed = XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0001) && (ultra)) { + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + speed = XFER_SW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); + } + (void) aec6210_tune_chipset(drive, speed); + + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_off : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + +static void aec6210_tune_drive (ide_drive_t *drive, byte pio) +{ + byte speed; + + switch(pio) { + case 5: + speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + case 4: + speed = XFER_PIO_4; break; + case 3: + speed = XFER_PIO_3; break; + case 2: + speed = XFER_PIO_2; break; + case 1: + speed = XFER_PIO_1; break; + default: + speed = XFER_PIO_0; break; + } + (void) aec6210_tune_chipset(drive, speed); +} + +static int config_drive_xfer_rate (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_dma_action_t dma_func = ide_dma_on; + + if (id && (id->capability & 1) && HWIF(drive)->autodma) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + dma_func = ide_dma_off; + goto fast_ata_pio; + } + dma_func = ide_dma_off_quietly; + if (id->field_valid & 4) { + if (id->dma_ultra & 0x001F) { + /* Force if Capable UltraDMA */ + dma_func = config_chipset_for_dma(drive, 1); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0007) || + (id->dma_1word & 0x0007)) { + /* Force if Capable regular DMA modes */ + dma_func = config_chipset_for_dma(drive, 0); + if (dma_func != ide_dma_on) + goto no_dma_set; + } + } else if (ide_dmaproc(ide_dma_good_drive, drive)) { + if (id->eide_dma_time > 150) { + goto no_dma_set; + } + /* Consult the list of known "good" drives */ + dma_func = config_chipset_for_dma(drive, 0); + if (dma_func != ide_dma_on) + goto no_dma_set; + } else { + goto fast_ata_pio; + } + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: + dma_func = ide_dma_off_quietly; +no_dma_set: + aec6210_tune_drive(drive, 5); + } + return HWIF(drive)->dmaproc(dma_func, drive); +} + +/* + * aec6210_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. + */ +int aec6210_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + return config_drive_xfer_rate(drive); + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} +#endif /* CONFIG_BLK_DEV_AEC6210_TUNING */ + unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name) { if (dev->resource[PCI_ROM_RESOURCE].start) { @@ -63,3 +279,44 @@ unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name) } return dev->irq; } + +void __init ide_init_aec6210 (ide_hwif_t *hwif) +{ +#ifdef CONFIG_BLK_DEV_AEC6210_TUNING + hwif->tuneproc = &aec6210_tune_drive; + + if (hwif->dma_base) { + hwif->dmaproc = &aec6210_dmaproc; + hwif->drives[0].autotune = 0; + hwif->drives[1].autotune = 0; + } else { + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + } +#endif /* CONFIG_BLK_DEV_AEC6210_TUNING */ +} + +void __init ide_dmacapable_aec6210 (ide_hwif_t *hwif, unsigned long dmabase) +{ + byte dma_new = 0; + byte dma_old = inb(dmabase+2); + byte reg54h = 0; + byte masterdma = hwif->channel ? 0x30 : 0x03; + byte slavedma = hwif->channel ? 0xc0 : 0x0c; + unsigned long flags; + + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ + + dma_new = dma_old; + + pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); + + if (reg54h & masterdma) dma_new |= 0x20; + if (reg54h & slavedma) dma_new |= 0x40; + if (dma_new != dma_old) outb(dma_new, dmabase+2); + + __restore_flags(flags); /* local CPU only */ + + ide_setup_dma(hwif, dmabase, 8); +} diff --git a/drivers/block/ali14xx.c b/drivers/block/ali14xx.c index 46a275305..e86fe61db 100644 --- a/drivers/block/ali14xx.c +++ b/drivers/block/ali14xx.c @@ -204,11 +204,11 @@ void init_ali14xx (void) { /* auto-detect IDE controller port */ if (!findPort()) { - printk("ali14xx: not found\n"); + printk("\nali14xx: not found"); return; } - printk("ali14xx: base= 0x%03x, regOn = 0x%02x\n", basePort, regOn); + printk("\nali14xx: base= 0x%03x, regOn = 0x%02x", basePort, regOn); ide_hwifs[0].chipset = ide_ali14xx; ide_hwifs[1].chipset = ide_ali14xx; ide_hwifs[0].tuneproc = &ali14xx_tune_drive; @@ -219,7 +219,7 @@ void init_ali14xx (void) /* initialize controller registers */ if (!initRegisters()) { - printk("ali14xx: Chip initialization failed\n"); + printk("\nali14xx: Chip initialization failed"); return; } } diff --git a/drivers/block/alim15x3.c b/drivers/block/alim15x3.c index 545361052..ee398e156 100644 --- a/drivers/block/alim15x3.c +++ b/drivers/block/alim15x3.c @@ -35,8 +35,8 @@ #include <linux/stat.h> #include <linux/proc_fs.h> -static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy); -extern int (*ali_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */ +static int ali_get_info(char *buffer, char **addr, off_t offset, int count); +extern int (*ali_display_info)(char *, char **, off_t, int); /* ide-proc.c */ struct pci_dev *bmide_dev; char *fifo[4] = { @@ -67,7 +67,7 @@ char *channel_status[8] = { "error DRQ busy" }; -static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy) +static int ali_get_info(char *buffer, char **addr, off_t offset, int count) { byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1; unsigned int bibma; @@ -693,6 +693,31 @@ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name) chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0; } + if (m5229_revision == 0x20) { + /* + * check M1533 revision (offset 0x08) + */ + pci_read_config_byte(isa_dev, 0x08, &tmpbyte); + if (tmpbyte == 0x0A) { + unsigned long flags; + pci_read_config_byte(dev, 0x4e, &tmpbyte); + save_flags(flags); + cli(); + /* + * set bit 6 + */ + pci_write_config_byte(dev, 0x4e, tmpbyte | 0x40); + restore_flags(flags); + + /* + * this special version is similar to revision 0xC2 + * but does not support UDMA66 + * (cable_80_pin[0] = 0; cable_80_pin[1] = 0;) + */ + m5229_revision = 0xC2; + } + } + return 0; } @@ -742,7 +767,7 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif) } hwif->tuneproc = &ali15x3_tune_drive; - if ((hwif->dma_base) && (m5229_revision >= 0xC1)) { + if ((hwif->dma_base) && (m5229_revision >= 0x20)) { /* * M1543C or newer for DMAing */ diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index a3ee727bd..1c36e09f2 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1484,7 +1484,7 @@ static void redo_fd_request(void) goto repeat; } -static void do_fd_request(void) +static void do_fd_request(request_queue_t * q) { redo_fd_request(); } @@ -1869,7 +1869,7 @@ int __init amiga_floppy_init(void) post_write_timer.data = 0; post_write_timer.function = post_write; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[MAJOR_NR] = floppy_blocksizes; blk_size[MAJOR_NR] = floppy_sizes; @@ -1911,7 +1911,7 @@ void cleanup_module(void) amiga_chip_free(raw_buf); blk_size[MAJOR_NR] = NULL; blksize_size[MAJOR_NR] = NULL; - blk_dev[MAJOR_NR].request_fn = NULL; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); unregister_blkdev(MAJOR_NR, "fd"); } #endif diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index b8df87205..b47904cdb 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -1529,7 +1529,7 @@ repeat: } -void do_fd_request(void) +void do_fd_request(request_queue_t * q) { unsigned long flags; @@ -2051,7 +2051,7 @@ int __init atari_floppy_init (void) blk_size[MAJOR_NR] = floppy_sizes; blksize_size[MAJOR_NR] = floppy_blocksizes; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n", DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E', @@ -2103,7 +2103,7 @@ void cleanup_module (void) { unregister_blkdev(MAJOR_NR, "fd"); - blk_dev[MAJOR_NR].request_fn = 0; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); timer_active &= ~(1 << FLOPPY_TIMER); timer_table[FLOPPY_TIMER].fn = 0; atari_stram_free( DMABuffer ); diff --git a/drivers/block/cmd640.c b/drivers/block/cmd640.c index ee6d7c9cc..3e5f56cec 100644 --- a/drivers/block/cmd640.c +++ b/drivers/block/cmd640.c @@ -686,6 +686,7 @@ static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted) d.cycle_time, d.overridden ? " (overriding vendor mode)" : ""); display_clocks(index); + return; } #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 451463111..5d5799a89 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -22,6 +22,7 @@ * driver, you'll probably need the Compaq Array Controller Interface * Specificiation (Document number ECG086/1198) */ +#include <linux/config.h> #include <linux/module.h> #include <linux/version.h> #include <linux/types.h> @@ -139,14 +140,14 @@ static void do_ida_request(int i); */ #define DO_IDA_REQUEST(x) { do_ida_request(x); } -static void do_ida_request0(void) DO_IDA_REQUEST(0); -static void do_ida_request1(void) DO_IDA_REQUEST(1); -static void do_ida_request2(void) DO_IDA_REQUEST(2); -static void do_ida_request3(void) DO_IDA_REQUEST(3); -static void do_ida_request4(void) DO_IDA_REQUEST(4); -static void do_ida_request5(void) DO_IDA_REQUEST(5); -static void do_ida_request6(void) DO_IDA_REQUEST(6); -static void do_ida_request7(void) DO_IDA_REQUEST(7); +static void do_ida_request0(request_queue_t * q) DO_IDA_REQUEST(0); +static void do_ida_request1(request_queue_t * q) DO_IDA_REQUEST(1); +static void do_ida_request2(request_queue_t * q) DO_IDA_REQUEST(2); +static void do_ida_request3(request_queue_t * q) DO_IDA_REQUEST(3); +static void do_ida_request4(request_queue_t * q) DO_IDA_REQUEST(4); +static void do_ida_request5(request_queue_t * q) DO_IDA_REQUEST(5); +static void do_ida_request6(request_queue_t * q) DO_IDA_REQUEST(6); +static void do_ida_request7(request_queue_t * q) DO_IDA_REQUEST(7); static void start_io(ctlr_info_t *h); @@ -222,7 +223,7 @@ struct file_operations ida_fops = { static void __init ida_procinit(int i) { if (proc_array == NULL) { - proc_array = create_proc_entry("driver/array", S_IFDIR, NULL); + proc_array = proc_mkdir("driver/array", NULL); if (!proc_array) return; } @@ -378,7 +379,7 @@ void cleanup_module(void) */ void __init cpqarray_init(void) { - void (*request_fns[MAX_CTLR])(void) = { + void (*request_fns[MAX_CTLR])(request_queue_t *) = { do_ida_request0, do_ida_request1, do_ida_request2, do_ida_request3, do_ida_request4, do_ida_request5, @@ -479,7 +480,9 @@ void __init cpqarray_init(void) ida_gendisk[i].sizes = ida_sizes + (i*256); /* ida_gendisk[i].nr_real is handled by getgeometry */ - blk_dev[MAJOR_NR+i].request_fn = request_fns[i]; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i), request_fns[i]); + blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR + i), 0); + blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256); hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256); read_ahead[MAJOR_NR+i] = READ_AHEAD; @@ -893,10 +896,13 @@ static void do_ida_request(int ctlr) cmdlist_t *c; int seg, sect; char *lastdataend; + request_queue_t * q; struct buffer_head *bh; struct request *creq; - creq = blk_dev[MAJOR_NR+ctlr].current_request; + q = &blk_dev[MAJOR_NR+ctlr].request_queue; + + creq = q->current_request; if (creq == NULL || creq->rq_status == RQ_INACTIVE) goto doreq_done; @@ -973,7 +979,7 @@ DBGPX( printk("More to do on same request %p\n", creq); ); } else { DBGPX( printk("Done with %p, queueing %p\n", creq, creq->next); ); creq->rq_status = RQ_INACTIVE; - blk_dev[MAJOR_NR+ctlr].current_request = creq->next; + q->current_request = creq->next; wake_up(&wait_for_request); } diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index d74fdc369..9a204c0a8 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -1169,7 +1169,7 @@ static int output_byte(char byte) /* gets the response from the fdc */ static int result(void) { - int i, status; + int i, status=0; for(i=0; i < MAX_REPLIES; i++) { if ((status = wait_til_ready()) < 0) @@ -2932,7 +2932,7 @@ static void process_fd_request(void) schedule_bh( (void *)(void *) redo_fd_request); } -static void do_fd_request(void) +static void do_fd_request(request_queue_t * q) { if(usage_count == 0) { printk("warning: usage count=0, CURRENT=%p exiting\n", CURRENT); @@ -4132,7 +4132,7 @@ int __init floppy_init(void) blk_size[MAJOR_NR] = floppy_sizes; blksize_size[MAJOR_NR] = floppy_blocksizes; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT); config_types(); @@ -4161,7 +4161,7 @@ int __init floppy_init(void) fdc = 0; /* reset fdc in case of unexpected interrupt */ if (floppy_grab_irq_and_dma()){ del_timer(&fd_timeout); - blk_dev[MAJOR_NR].request_fn = NULL; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); unregister_blkdev(MAJOR_NR,"fd"); del_timer(&fd_timeout); return -EBUSY; @@ -4227,7 +4227,7 @@ int __init floppy_init(void) schedule(); if (usage_count) floppy_release_irq_and_dma(); - blk_dev[MAJOR_NR].request_fn = NULL; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); unregister_blkdev(MAJOR_NR,"fd"); } return have_no_fdc; @@ -4450,7 +4450,7 @@ void cleanup_module(void) unregister_blkdev(MAJOR_NR, "fd"); - blk_dev[MAJOR_NR].request_fn = 0; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); /* eject disk, if any */ dummy = fd_eject(0); } diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 49527026a..8cf37c3de 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -585,7 +585,7 @@ repeat: panic("unknown hd-command"); } -static void do_hd_request (void) +static void do_hd_request (request_queue_t * q) { disable_irq(HD_IRQ); hd_request(); @@ -813,7 +813,7 @@ int __init hd_init(void) printk("hd: unable to get major %d for hard disk\n",MAJOR_NR); return -1; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ hd_gendisk.next = gendisk_head; gendisk_head = &hd_gendisk; diff --git a/drivers/block/hpt366.c b/drivers/block/hpt366.c index d45b5f719..30bc3218c 100644 --- a/drivers/block/hpt366.c +++ b/drivers/block/hpt366.c @@ -218,7 +218,8 @@ static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; byte speed = 0x00; - unsigned int reg40 = 0; + byte reg51h = 0; + unsigned int reg40 = 0; int rval; if ((id->dma_ultra & 0x0010) && @@ -258,15 +259,22 @@ static int config_chipset_for_dma (ide_drive_t *drive) return ((int) ide_dma_off_quietly); } - /* Disable the "fast interrupt" prediction. + pci_read_config_byte(HWIF(drive)->pci_dev, 0x51, ®51h); + +#ifdef HPT366_FAST_IRQ_PREDICTION + /* + * Some drives prefer/allow for the method of handling interrupts. + */ + if (!(reg51h & 0x80)) + pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h|0x80); +#else /* ! HPT366_FAST_IRQ_PREDICTION */ + /* + * Disable the "fast interrupt" prediction. * Instead, always wait for the real interrupt from the drive! */ - { - byte reg51h = 0; - pci_read_config_byte(HWIF(drive)->pci_dev, 0x51, ®51h); - if (reg51h & 0x80) - pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80); - } + if (reg51h & 0x80) + pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80); +#endif /* HPT366_FAST_IRQ_PREDICTION */ /* * Preserve existing PIO settings: diff --git a/drivers/block/icside.c b/drivers/block/icside.c index b83781457..d86a990f7 100644 --- a/drivers/block/icside.c +++ b/drivers/block/icside.c @@ -210,24 +210,11 @@ static iftype_t icside_identifyif (struct expansion_card *ec) /* * SG-DMA support. * - * Similar to the BM-DMA, but we use the RiscPCs IOMD - * DMA controllers. There is only one DMA controller - * per card, which means that only one drive can be - * accessed at one time. NOTE! We do not inforce that - * here, but we rely on the main IDE driver spotting - * that both interfaces use the same IRQ, which should - * guarantee this. - * - * We are limited by the drives IOR/IOW pulse time. - * The closest that we can get to the requirements is - * a type C cycle for both mode 1 and mode 2. However, - * this does give a burst of 8MB/s. - * - * This has been tested with a couple of Conner - * Peripherals 1080MB CFS1081A drives, one on each - * interface, which deliver about 2MB/s each. I - * believe that this is limited by the lack of - * on-board drive cache. + * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers. + * There is only one DMA controller per card, which means that only + * one drive can be accessed at one time. NOTE! We do not enforce that + * here, but we rely on the main IDE driver spotting that both + * interfaces use the same IRQ, which should guarantee this. */ #define TABLE_SIZE 2048 @@ -286,27 +273,43 @@ icside_build_dmatable(ide_drive_t *drive, int reading) } static int -icside_config_drive(ide_drive_t *drive, int mode) +icside_config_if(ide_drive_t *drive, int xfer_mode) { - int speed, err; - - if (mode == 2) { - speed = XFER_MW_DMA_2; + int func = ide_dma_off; + + switch (xfer_mode) { + case XFER_MW_DMA_2: + /* + * The cycle time is limited to 250ns by the r/w + * pulse width (90ns), however we should still + * have a maximum burst transfer rate of 8MB/s. + */ drive->drive_data = 250; - } else { - speed = XFER_MW_DMA_1; + break; + + case XFER_MW_DMA_1: drive->drive_data = 250; - } + break; - err = ide_config_drive_speed(drive, (byte) speed); + case XFER_MW_DMA_0: + drive->drive_data = 480; + break; - if (err == 0) { - drive->id->dma_mword &= 0x00ff; - drive->id->dma_mword |= 256 << mode; - } else + default: drive->drive_data = 0; + break; + } + + if (drive->drive_data && + ide_config_drive_speed(drive, (byte) xfer_mode) == 0) + func = ide_dma_on; + else + drive->drive_data = 480; + + printk("%s: %s selected (peak %dMB/s)\n", drive->name, + ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data); - return err; + return func; } static int @@ -315,34 +318,51 @@ icside_dma_check(ide_drive_t *drive) struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); int autodma = hwif->autodma; + int xfer_mode = XFER_PIO_2; + int func = ide_dma_off_quietly; - if (id && (id->capability & 1) && autodma) { - int dma_mode = 0; + if (!id || !(id->capability & 1) || !autodma) + goto out; - /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive)) - return hwif->dmaproc(ide_dma_off, drive); - - /* Enable DMA on any drive that has - * UltraDMA (mode 0/1/2) enabled - */ - if (id->field_valid & 4 && id->dma_ultra & 7) - dma_mode = 2; - - /* Enable DMA on any drive that has mode1 - * or mode2 multiword DMA enabled - */ - if (id->field_valid & 2 && id->dma_mword & 6) - dma_mode = id->dma_mword & 4 ? 2 : 1; + /* + * Consult the list of known "bad" drives + */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + func = ide_dma_off; + goto out; + } - /* Consult the list of known "good" drives */ - if (ide_dmaproc(ide_dma_good_drive, drive)) - dma_mode = 1; + /* + * Enable DMA on any drive that has multiword DMA + */ + if (id->field_valid & 2) { + if (id->dma_mword & 4) { + xfer_mode = XFER_MW_DMA_2; + func = ide_dma_on; + } else if (id->dma_mword & 2) { + xfer_mode = XFER_MW_DMA_1; + func = ide_dma_on; + } else if (id->dma_mword & 1) { + xfer_mode = XFER_MW_DMA_0; + func = ide_dma_on; + } + goto out; + } - if (dma_mode && icside_config_drive(drive, dma_mode) == 0) - return hwif->dmaproc(ide_dma_on, drive); + /* + * Consult the list of known "good" drives + */ + if (ide_dmaproc(ide_dma_good_drive, drive)) { + if (id->eide_dma_time > 150) + goto out; + xfer_mode = XFER_MW_DMA_1; + func = ide_dma_on; } - return hwif->dmaproc(ide_dma_off_quietly, drive); + +out: + func = icside_config_if(drive, xfer_mode); + + return hwif->dmaproc(func, drive); } static int diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index e3cce8eb4..6b71cd7bf 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -130,7 +130,7 @@ * 3.15 July 2, 1996 -- Added support for Sanyo 3 CD changers * from Ben Galliart <bgallia@luc.edu> with * special help from Jeff Lightfoot - * <jeffml@netcom.com> + * <jeffml@pobox.com> * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification * 3.16 Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl. * 3.17 Sep 17, 1996 -- Tweak audio reads for some drives. @@ -276,7 +276,6 @@ #define IDECD_VERSION "4.56" -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> @@ -314,8 +313,7 @@ static void cdrom_saw_media_change (ide_drive_t *drive) static -void cdrom_analyze_sense_data (ide_drive_t *drive, - struct atapi_request_sense *reqbuf, +void cdrom_analyze_sense_data (ide_drive_t *drive, struct request_sense *reqbuf, struct packet_command *failed_command) { if (reqbuf->sense_key == NOT_READY || @@ -432,27 +430,21 @@ void cdrom_analyze_sense_data (ide_drive_t *drive, * In the case of NOT_READY, if SKSV is set the drive can * give us nice ETA readings. */ - if (reqbuf->sense_key == NOT_READY && - (reqbuf->sense_key_specific[0] & 0x80)) { - int progress = (reqbuf->sense_key_specific[1] << 8 | - reqbuf->sense_key_specific[2]) * 100; + if (reqbuf->sense_key == NOT_READY && (reqbuf->sks[0] & 0x80)) { + int progress = (reqbuf->sks[1] << 8 | reqbuf->sks[2]) * 100; printk(" Command is %02d%% complete\n", progress / 0xffff); } if (reqbuf->sense_key == ILLEGAL_REQUEST && - (reqbuf->sense_key_specific[0] & 0x80) != 0) { + (reqbuf->sks[0] & 0x80) != 0) { printk (" Error in %s byte %d", - (reqbuf->sense_key_specific[0] & 0x40) != 0 - ? "command packet" - : "command data", - (reqbuf->sense_key_specific[1] << 8) + - reqbuf->sense_key_specific[2]); - - if ((reqbuf->sense_key_specific[0] & 0x40) != 0) { - printk (" bit %d", - reqbuf->sense_key_specific[0] & 0x07); - } + (reqbuf->sks[0] & 0x40) != 0 ? + "command packet" : "command data", + (reqbuf->sks[1] << 8) + reqbuf->sks[2]); + + if ((reqbuf->sks[0] & 0x40) != 0) + printk (" bit %d", reqbuf->sks[0] & 0x07); printk ("\n"); } @@ -477,39 +469,25 @@ void cdrom_analyze_sense_data (ide_drive_t *drive, static void cdrom_queue_request_sense (ide_drive_t *drive, struct semaphore *sem, - struct atapi_request_sense *reqbuf, struct packet_command *failed_command) { struct cdrom_info *info = drive->driver_data; struct request *rq; struct packet_command *pc; - int len; - - /* If the request didn't explicitly specify where - to put the sense data, use the statically allocated structure. */ - if (reqbuf == NULL) - reqbuf = &info->sense_data; /* Make up a new request to retrieve sense information. */ - pc = &info->request_sense_pc; - memset (pc, 0, sizeof (*pc)); - - /* The request_sense structure has an odd number of (16-bit) words, - which won't work well with 32-bit transfers. However, we don't care - about the last two bytes, so just truncate the structure down - to an even length. */ - len = sizeof (*reqbuf) / 4; - len *= 4; + memset(pc, 0, sizeof (*pc)); pc->c[0] = GPCMD_REQUEST_SENSE; - pc->c[4] = (unsigned char) len; - pc->buffer = (char *)reqbuf; - pc->buflen = len; - pc->sense_data = (struct atapi_request_sense *)failed_command; - /* stuff the sense request in front of our current request */ + /* just get the first 18 bytes of the sense info, there might not + * be more available */ + pc->c[4] = pc->buflen = 18; + pc->buffer = (char *)&info->sense_data; + pc->sense_data = (struct request_sense *)failed_command; + /* stuff the sense request in front of our current request */ rq = &info->request_sense_request; ide_init_drive_cmd (rq); rq->cmd = REQUEST_SENSE_COMMAND; @@ -527,7 +505,7 @@ static void cdrom_end_request (int uptodate, ide_drive_t *drive) struct packet_command *pc = (struct packet_command *) rq->buffer; cdrom_analyze_sense_data (drive, - (struct atapi_request_sense *) (pc->buffer - pc->c[4]), + (struct request_sense *) (pc->buffer - pc->c[4]), (struct packet_command *) pc->sense_data); } if (rq->cmd == READ && !rq->current_nr_sectors) @@ -539,7 +517,7 @@ static void cdrom_end_request (int uptodate, ide_drive_t *drive) /* Returns 0 if the request should be continued. Returns 1 if the request was ended. */ -static int cdrom_decode_status (ide_drive_t *drive, int good_stat, +static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive, int good_stat, int *stat_ret) { struct request *rq = HWGROUP(drive)->rq; @@ -570,7 +548,7 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, pc->stat = 1; cdrom_end_request (1, drive); - ide_error (drive, "request sense failure", stat); + *startstop = ide_error (drive, "request sense failure", stat); return 1; } else if (cmd == PACKET_COMMAND) { @@ -610,8 +588,7 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, cdrom_end_request (1, drive); if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense (drive, sem, - pc->sense_data, pc); + cdrom_queue_request_sense(drive, sem, pc); } else { /* Handle errors from READ requests. */ @@ -640,7 +617,7 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, } else if ((err & ~ABRT_ERR) != 0) { /* Go to the default handler for other errors. */ - ide_error (drive, "cdrom_decode_status", stat); + *startstop = ide_error (drive, "cdrom_decode_status", stat); return 1; } else if ((++rq->errors > ERROR_MAX)) { /* We've racked up too many retries. Abort. */ @@ -650,12 +627,12 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, /* If we got a CHECK_CONDITION status, queue a request sense command. */ if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense (drive, - NULL, NULL, NULL); + cdrom_queue_request_sense(drive, NULL, NULL); } } /* Retry, or handle the next request. */ + *startstop = ide_stopped; return 1; } @@ -665,7 +642,6 @@ static int cdrom_timer_expiry(ide_drive_t *drive) struct packet_command *pc = (struct packet_command *) rq->buffer; unsigned long wait = 0; - printk("in expiry\n"); /* blank and format can take an extremly long time to * complete, if the IMMED bit was not set. */ @@ -682,13 +658,15 @@ static int cdrom_timer_expiry(ide_drive_t *drive) called when the interrupt from the drive arrives. Otherwise, HANDLER will be called immediately after the drive is prepared for the transfer. */ -static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen, +static ide_startstop_t cdrom_start_packet_command (ide_drive_t *drive, int xferlen, ide_handler_t *handler) { + ide_startstop_t startstop; struct cdrom_info *info = drive->driver_data; /* Wait for the controller to be idle. */ - if (ide_wait_stat(drive, 0, BUSY_STAT, WAIT_READY)) return 1; + if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY)) + return startstop; if (info->dma) info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive); @@ -709,12 +687,11 @@ static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen, if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ + return ide_started; } else { OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ - (*handler) (drive); + return (*handler) (drive); } - - return 0; } /* Send a packet command to DRIVE described by CMD_BUF and CMD_LEN. @@ -722,7 +699,7 @@ static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen, by cdrom_start_packet_command. HANDLER is the interrupt handler to call when the command completes or there's data ready. */ -static int cdrom_transfer_packet_command (ide_drive_t *drive, +static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, unsigned char *cmd_buf, int cmd_len, ide_handler_t *handler) { @@ -730,14 +707,16 @@ static int cdrom_transfer_packet_command (ide_drive_t *drive, /* Here we should have been called after receiving an interrupt from the device. DRQ should how be set. */ int stat_dum; + ide_startstop_t startstop; /* Check for errors. */ - if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum)) - return 1; + if (cdrom_decode_status (&startstop, drive, DRQ_STAT, &stat_dum)) + return startstop; } else { + ide_startstop_t startstop; /* Otherwise, we must wait for DRQ to get set. */ - if (ide_wait_stat (drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) - return 1; + if (ide_wait_stat (&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) + return startstop; } /* Arm the interrupt handler. */ @@ -746,7 +725,7 @@ static int cdrom_transfer_packet_command (ide_drive_t *drive, /* Send the command to the device. */ atapi_output_bytes (drive, cmd_buf, cmd_len); - return 0; + return ide_started; } @@ -843,12 +822,13 @@ int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason) /* * Interrupt routine. Called when a read request has completed. */ -static void cdrom_read_intr (ide_drive_t *drive) +static ide_startstop_t cdrom_read_intr (ide_drive_t *drive) { int stat; int ireason, len, sectors_to_transfer, nskip; struct cdrom_info *info = drive->driver_data; int i, dma = info->dma, dma_error = 0; + ide_startstop_t startstop; struct request *rq = HWGROUP(drive)->rq; @@ -859,19 +839,18 @@ static void cdrom_read_intr (ide_drive_t *drive) HWIF(drive)->dmaproc(ide_dma_off, drive); } - if (cdrom_decode_status (drive, 0, &stat)) - return; + if (cdrom_decode_status (&startstop, drive, 0, &stat)) + return startstop; if (dma) { - if (dma_error) { - ide_error (drive, "dma error", stat); - return; - } - for (i = rq->nr_sectors; i > 0;) { - i -= rq->current_nr_sectors; - ide_end_request(1, HWGROUP(drive)); - } - return; + if (!dma_error) { + for (i = rq->nr_sectors; i > 0;) { + i -= rq->current_nr_sectors; + ide_end_request(1, HWGROUP(drive)); + } + return ide_stopped; + } else + return ide_error (drive, "dma error", stat); } /* Read the interrupt reason and the transfer length. */ @@ -888,11 +867,12 @@ static void cdrom_read_intr (ide_drive_t *drive) cdrom_end_request (0, drive); } else cdrom_end_request (1, drive); - return; + return ide_stopped; } /* Check that the drive is expecting to do the same thing we are. */ - if (cdrom_read_check_ireason (drive, len, ireason)) return; + if (cdrom_read_check_ireason (drive, len, ireason)) + return ide_stopped; /* Assume that the drive will always provide data in multiples of at least SECTOR_SIZE, as it gets hairy to keep track @@ -907,7 +887,7 @@ static void cdrom_read_intr (ide_drive_t *drive) CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1; } cdrom_end_request (0, drive); - return; + return ide_stopped; } /* The number of sectors we need to read from the drive. */ @@ -967,6 +947,7 @@ static void cdrom_read_intr (ide_drive_t *drive) /* Done moving data! Wait for another interrupt. */ ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL); + return ide_started; } /* @@ -1031,7 +1012,7 @@ static int cdrom_read_from_buffer (ide_drive_t *drive) * However, for drq_interrupt devices, it is called from an interrupt * when the drive is ready to accept the command. */ -static void cdrom_start_read_continuation (ide_drive_t *drive) +static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive) { struct packet_command pc; struct request *rq = HWGROUP(drive)->rq; @@ -1058,7 +1039,7 @@ static void cdrom_start_read_continuation (ide_drive_t *drive) printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n", drive->name, rq->current_nr_sectors); cdrom_end_request (0, drive); - return; + return ide_stopped; } sector -= nskip; nsect += nskip; @@ -1083,7 +1064,7 @@ static void cdrom_start_read_continuation (ide_drive_t *drive) put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]); /* Send the command to the drive and return. */ - (void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), + return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_read_intr); } @@ -1092,14 +1073,15 @@ static void cdrom_start_read_continuation (ide_drive_t *drive) #define IDECD_SEEK_TIMER (5 * WAIT_MIN_SLEEP) /* 100 ms */ #define IDECD_SEEK_TIMEOUT WAIT_CMD /* 10 sec */ -static void cdrom_seek_intr (ide_drive_t *drive) +static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive) { struct cdrom_info *info = drive->driver_data; int stat; static int retry = 10; + ide_startstop_t startstop; - if (cdrom_decode_status (drive, 0, &stat)) - return; + if (cdrom_decode_status (&startstop, drive, 0, &stat)) + return startstop; CDROM_CONFIG_FLAGS(drive)->seeking = 1; if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) { @@ -1108,9 +1090,10 @@ static void cdrom_seek_intr (ide_drive_t *drive) drive->dsc_overlap = 0; } } + return ide_stopped; } -static void cdrom_start_seek_continuation (ide_drive_t *drive) +static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive) { struct packet_command pc; struct request *rq = HWGROUP(drive)->rq; @@ -1125,16 +1108,16 @@ static void cdrom_start_seek_continuation (ide_drive_t *drive) memset (&pc.c, 0, sizeof (pc.c)); pc.c[0] = GPCMD_SEEK; put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]); - (void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr); + return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr); } -static void cdrom_start_seek (ide_drive_t *drive, unsigned int block) +static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block) { struct cdrom_info *info = drive->driver_data; info->dma = 0; info->start_seek = jiffies; - cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation); + return cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation); } /* Fix up a possibly partially-processed request so that we can @@ -1153,7 +1136,7 @@ static void restore_request (struct request *rq) /* * Start a read request from the CD-ROM. */ -static void cdrom_start_read (ide_drive_t *drive, unsigned int block) +static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block) { struct cdrom_info *info = drive->driver_data; struct request *rq = HWGROUP(drive)->rq; @@ -1173,8 +1156,9 @@ static void cdrom_start_read (ide_drive_t *drive, unsigned int block) /* Satisfy whatever we can of this request from our cached sector. */ if (cdrom_read_from_buffer(drive)) - return; + return ide_stopped; + /* Clear the local sector buffer. */ info->nsectors_buffered = 0; /* use dma, if possible. */ @@ -1185,7 +1169,7 @@ static void cdrom_start_read (ide_drive_t *drive, unsigned int block) info->dma = 0; /* Start sending the read request to the drive. */ - cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation); + return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation); } /**************************************************************************** @@ -1193,20 +1177,22 @@ static void cdrom_start_read (ide_drive_t *drive, unsigned int block) */ /* Forward declarations. */ -static int -cdrom_lockdoor (ide_drive_t *drive, int lockflag, - struct atapi_request_sense *reqbuf); +static int cdrom_lockdoor(ide_drive_t *drive, int lockflag); /* Interrupt routine for packet command completion. */ -static void cdrom_pc_intr (ide_drive_t *drive) +static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive) { int ireason, len, stat, thislen; struct request *rq = HWGROUP(drive)->rq; struct packet_command *pc = (struct packet_command *)rq->buffer; + struct cdrom_info *info = drive->driver_data; + ide_startstop_t startstop; + + pc->sense_data = &info->sense_data; /* Check for errors. */ - if (cdrom_decode_status (drive, 0, &stat)) - return; + if (cdrom_decode_status (&startstop, drive, 0, &stat)) + return startstop; /* Read the interrupt reason and the transfer length. */ ireason = IN_BYTE (IDE_NSECTOR_REG); @@ -1239,7 +1225,7 @@ static void cdrom_pc_intr (ide_drive_t *drive) pc->stat = 1; cdrom_end_request (1, drive); } - return; + return ide_stopped; } /* Figure out how much data to transfer. */ @@ -1290,21 +1276,22 @@ static void cdrom_pc_intr (ide_drive_t *drive) /* Now we wait for another interrupt. */ ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry); + return ide_started; } -static void cdrom_do_pc_continuation (ide_drive_t *drive) +static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive) { struct request *rq = HWGROUP(drive)->rq; struct packet_command *pc = (struct packet_command *)rq->buffer; /* Send the command to the drive and return. */ - cdrom_transfer_packet_command (drive, pc->c, + return cdrom_transfer_packet_command (drive, pc->c, sizeof (pc->c), &cdrom_pc_intr); } -static void cdrom_do_packet_command (ide_drive_t *drive) +static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive) { int len; struct request *rq = HWGROUP(drive)->rq; @@ -1316,7 +1303,7 @@ static void cdrom_do_packet_command (ide_drive_t *drive) len = pc->buflen; /* Start sending the command to the drive. */ - cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation); + return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation); } @@ -1330,18 +1317,11 @@ void cdrom_sleep (int time) } static -int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc) +int cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc) { - struct atapi_request_sense my_reqbuf; int retries = 10; struct request req; - /* If our caller has not provided a place to stick any sense data, - use our own area. */ - if (pc->sense_data == NULL) - pc->sense_data = &my_reqbuf; - pc->sense_data->sense_key = 0; - /* Start of retry loop. */ do { ide_init_drive_cmd (&req); @@ -1356,7 +1336,7 @@ int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc) /* The request failed. Retry if it was due to a unit attention status (usually means media was changed). */ - struct atapi_request_sense *reqbuf = pc->sense_data; + struct request_sense *reqbuf = pc->sense_data; if (reqbuf->sense_key == UNIT_ATTENTION) cdrom_saw_media_change (drive); @@ -1377,75 +1357,73 @@ int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc) } while (pc->stat != 0 && retries >= 0); /* Return an error if the command failed. */ - if (pc->stat != 0) + if (pc->stat) return -EIO; - else { - /* The command succeeded. If it was anything other than - a request sense, eject, or door lock command, - and we think that the door is presently unlocked, lock it - again. (The door was probably unlocked via an explicit - CDROMEJECT ioctl.) */ - if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && - (pc->c[0] != GPCMD_TEST_UNIT_READY && - pc->c[0] != GPCMD_REQUEST_SENSE && - pc->c[0] != GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL && - pc->c[0] != GPCMD_START_STOP_UNIT && - pc->c[0] != GPCMD_MODE_SENSE_10 && - pc->c[0] != GPCMD_MODE_SELECT_10)) { - (void) cdrom_lockdoor (drive, 1, NULL); - } - return 0; + + /* The command succeeded. If it was anything other than + a request sense, eject, or door lock command, + and we think that the door is presently unlocked, lock it + again. (The door was probably unlocked via an explicit + CDROMEJECT ioctl.) */ + if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && + (pc->c[0] != GPCMD_TEST_UNIT_READY && + pc->c[0] != GPCMD_REQUEST_SENSE && + pc->c[0] != GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL && + pc->c[0] != GPCMD_START_STOP_UNIT && + pc->c[0] != GPCMD_MODE_SENSE_10 && + pc->c[0] != GPCMD_MODE_SELECT_10)) { + (void) cdrom_lockdoor (drive, 1); } + return 0; } /**************************************************************************** * cdrom driver request routine. */ -static -void ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block) +static ide_startstop_t +ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block) { + ide_startstop_t action; struct cdrom_info *info = drive->driver_data; switch (rq->cmd) { - case READ: { - if (CDROM_CONFIG_FLAGS(drive)->seeking) { - unsigned long elpased = jiffies - info->start_seek; - int stat = GET_STAT(); - - if ((stat & SEEK_STAT) != SEEK_STAT) { - if (elpased < IDECD_SEEK_TIMEOUT) { - ide_stall_queue(drive, IDECD_SEEK_TIMER); - return; + case READ: { + if (CDROM_CONFIG_FLAGS(drive)->seeking) { + unsigned long elpased = jiffies - info->start_seek; + int stat = GET_STAT(); + + if ((stat & SEEK_STAT) != SEEK_STAT) { + if (elpased < IDECD_SEEK_TIMEOUT) { + ide_stall_queue(drive, IDECD_SEEK_TIMER); + return ide_stopped; + } + printk ("%s: DSC timeout\n", drive->name); } - printk ("%s: DSC timeout\n", drive->name); + CDROM_CONFIG_FLAGS(drive)->seeking = 0; } - CDROM_CONFIG_FLAGS(drive)->seeking = 0; + if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) + action = cdrom_start_seek (drive, block); + else + action = cdrom_start_read (drive, block); + info->last_block = block; + return action; } - if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) - cdrom_start_seek (drive, block); - else - cdrom_start_read (drive, block); - info->last_block = block; - break; - } - case PACKET_COMMAND: - case REQUEST_SENSE_COMMAND: { - cdrom_do_packet_command(drive); - break; - } + case PACKET_COMMAND: + case REQUEST_SENSE_COMMAND: { + return cdrom_do_packet_command(drive); + } - case RESET_DRIVE_COMMAND: { - cdrom_end_request(1, drive); - ide_do_reset(drive); - break; - } + case RESET_DRIVE_COMMAND: { + cdrom_end_request(1, drive); + return ide_do_reset(drive); + } - default: { - printk("ide-cd: bad cmd %d\n", rq -> cmd); - cdrom_end_request(0, drive); - break; - } + default: { + printk("ide-cd: bad cmd %d\n", rq -> cmd); + cdrom_end_request(0, drive); + return ide_stopped; + } } } @@ -1455,7 +1433,7 @@ void ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long bloc * Ioctl handling. * * Routines which queue packet commands take as a final argument a pointer - * to an atapi_request_sense struct. If execution of the command results + * to a request_sense struct. If execution of the command results * in an error with a CHECK CONDITION status, this structure will be filled * with the results of the subsequent request sense command. The pointer * can also be NULL, in which case no sense information is returned. @@ -1504,18 +1482,14 @@ int msf_to_lba (byte m, byte s, byte f) return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; } - -static int -cdrom_check_status (ide_drive_t *drive, - struct atapi_request_sense *reqbuf) +static int cdrom_check_status (ide_drive_t *drive) { struct packet_command pc; struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; - memset (&pc, 0, sizeof (pc)); + memset(&pc, 0, sizeof(pc)); - pc.sense_data = reqbuf; pc.c[0] = GPCMD_TEST_UNIT_READY; #if ! STANDARD_ATAPI @@ -1525,39 +1499,35 @@ cdrom_check_status (ide_drive_t *drive, pc.c[7] = cdi->sanyo_slot % 3; #endif /* not STANDARD_ATAPI */ - return cdrom_queue_packet_command (drive, &pc); + return cdrom_queue_packet_command(drive, &pc); } /* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */ static int -cdrom_lockdoor (ide_drive_t *drive, int lockflag, - struct atapi_request_sense *reqbuf) +cdrom_lockdoor(ide_drive_t *drive, int lockflag) { - struct atapi_request_sense my_reqbuf; - int stat; + struct request_sense *sense; struct packet_command pc; - - if (reqbuf == NULL) - reqbuf = &my_reqbuf; + int stat; /* If the drive cannot lock the door, just pretend. */ if (CDROM_CONFIG_FLAGS (drive)->no_doorlock) stat = 0; else { - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - + memset(&pc, 0, sizeof(pc)); pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; pc.c[4] = (lockflag != 0); stat = cdrom_queue_packet_command (drive, &pc); } + sense = pc.sense_data; + /* If we got an illegal field error, the drive probably cannot lock the door. */ if (stat != 0 && - reqbuf->sense_key == ILLEGAL_REQUEST && - (reqbuf->asc == 0x24 || reqbuf->asc == 0x20)) { + sense->sense_key == ILLEGAL_REQUEST && + (sense->asc == 0x24 || sense->asc == 0x20)) { printk ("%s: door locking not supported\n", drive->name); CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; @@ -1565,7 +1535,7 @@ cdrom_lockdoor (ide_drive_t *drive, int lockflag, } /* no medium, that's alright. */ - if (stat != 0 && reqbuf->sense_key == NOT_READY && reqbuf->asc == 0x3a) + if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a) stat = 0; if (stat == 0) @@ -1577,30 +1547,25 @@ cdrom_lockdoor (ide_drive_t *drive, int lockflag, /* Eject the disk if EJECTFLAG is 0. If EJECTFLAG is 1, try to reload the disk. */ -static int -cdrom_eject (ide_drive_t *drive, int ejectflag, - struct atapi_request_sense *reqbuf) +static int cdrom_eject(ide_drive_t *drive, int ejectflag) { struct packet_command pc; - if (CDROM_CONFIG_FLAGS (drive)->no_eject && !ejectflag) + if (CDROM_CONFIG_FLAGS(drive)->no_eject && !ejectflag) return -EDRIVE_CANT_DO_THIS; /* reload fails on some drives, if the tray is locked */ - if (CDROM_STATE_FLAGS (drive)->door_locked && ejectflag) + if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag) return 0; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof (pc)); pc.c[0] = GPCMD_START_STOP_UNIT; pc.c[4] = 0x02 + (ejectflag != 0); return cdrom_queue_packet_command (drive, &pc); } -static int -cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity, - struct atapi_request_sense *reqbuf) +static int cdrom_read_capacity(ide_drive_t *drive, unsigned *capacity) { struct { __u32 lba; @@ -1610,30 +1575,25 @@ cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity, int stat; struct packet_command pc; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof (pc)); pc.c[0] = GPCMD_READ_CDVD_CAPACITY; pc.buffer = (char *)&capbuf; - pc.buflen = sizeof (capbuf); + pc.buflen = sizeof(capbuf); - stat = cdrom_queue_packet_command (drive, &pc); + stat = cdrom_queue_packet_command(drive, &pc); if (stat == 0) *capacity = be32_to_cpu(capbuf.lba); return stat; } - -static int -cdrom_read_tocentry (ide_drive_t *drive, int trackno, int msf_flag, - int format, char *buf, int buflen, - struct atapi_request_sense *reqbuf) +static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag, + int format, char *buf, int buflen) { struct packet_command pc; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof(pc)); pc.buffer = buf; pc.buflen = buflen; @@ -1642,14 +1602,16 @@ cdrom_read_tocentry (ide_drive_t *drive, int trackno, int msf_flag, pc.c[7] = (buflen >> 8); pc.c[8] = (buflen & 0xff); pc.c[9] = (format << 6); - if (msf_flag) pc.c[1] = 2; + + if (msf_flag) + pc.c[1] = 2; + return cdrom_queue_packet_command (drive, &pc); } /* Try to read the entire TOC for the disk into our internal buffer. */ -static int -cdrom_read_toc (ide_drive_t *drive, struct atapi_request_sense *reqbuf) +static int cdrom_read_toc (ide_drive_t *drive) { int stat, ntracks, i; struct cdrom_info *info = drive->driver_data; @@ -1674,13 +1636,13 @@ cdrom_read_toc (ide_drive_t *drive, struct atapi_request_sense *reqbuf) /* Check to see if the existing data is still valid. If it is, just return. */ if (CDROM_STATE_FLAGS (drive)->toc_valid) - (void) cdrom_check_status (drive, NULL); + (void) cdrom_check_status(drive); if (CDROM_STATE_FLAGS (drive)->toc_valid) return 0; /* First read just the header, so we know how long the TOC is. */ stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr, - sizeof (struct atapi_toc_header), reqbuf); + sizeof (struct atapi_toc_header)); if (stat) return stat; #if ! STANDARD_ATAPI @@ -1698,7 +1660,7 @@ cdrom_read_toc (ide_drive_t *drive, struct atapi_request_sense *reqbuf) stat = cdrom_read_tocentry (drive, toc->hdr.first_track, 1, 0, (char *)&toc->hdr, sizeof (struct atapi_toc_header) + (ntracks + 1) * - sizeof (struct atapi_toc_entry), reqbuf); + sizeof (struct atapi_toc_entry)); if (stat && toc->hdr.first_track > 1) { /* Cds with CDI tracks only don't have any TOC entries, @@ -1715,8 +1677,7 @@ cdrom_read_toc (ide_drive_t *drive, struct atapi_request_sense *reqbuf) 0, (char *)&toc->hdr, sizeof (struct atapi_toc_header) + (ntracks+1) * - sizeof (struct atapi_toc_entry), - reqbuf); + sizeof (struct atapi_toc_entry)); if (stat) { return stat; } @@ -1761,8 +1722,7 @@ cdrom_read_toc (ide_drive_t *drive, struct atapi_request_sense *reqbuf) if (toc->hdr.first_track != CDROM_LEADOUT) { /* Read the multisession information. */ stat = cdrom_read_tocentry (drive, 0, 1, 1, - (char *)&ms_tmp, sizeof (ms_tmp), - reqbuf); + (char *)&ms_tmp, sizeof (ms_tmp)); if (stat) return stat; } else { ms_tmp.ent.addr.msf.minute = 0; @@ -1788,7 +1748,7 @@ cdrom_read_toc (ide_drive_t *drive, struct atapi_request_sense *reqbuf) (long *)&toc->capacity); if (stat) #endif - stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf); + stat = cdrom_read_capacity (drive, &toc->capacity); if (stat) toc->capacity = 0x1fffff; /* for general /dev/cdrom like mounting, one big disc */ @@ -1821,17 +1781,14 @@ cdrom_read_toc (ide_drive_t *drive, struct atapi_request_sense *reqbuf) } -static int -cdrom_read_subchannel (ide_drive_t *drive, int format, - char *buf, int buflen, - struct atapi_request_sense *reqbuf) +static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf, + int buflen) { struct packet_command pc; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof(pc)); - pc.buffer = buf; + pc.buffer = buf; pc.buflen = buflen; pc.c[0] = GPCMD_READ_SUBCHANNEL; pc.c[1] = 2; /* MSF addressing */ @@ -1839,23 +1796,20 @@ cdrom_read_subchannel (ide_drive_t *drive, int format, pc.c[3] = format; pc.c[7] = (buflen >> 8); pc.c[8] = (buflen & 0xff); - return cdrom_queue_packet_command (drive, &pc); + return cdrom_queue_packet_command(drive, &pc); } /* ATAPI cdrom drives are free to select the speed you request or any slower rate :-( Requesting too fast a speed will _not_ produce an error. */ -static int -cdrom_select_speed (ide_drive_t *drive, int speed, - struct atapi_request_sense *reqbuf) +static int cdrom_select_speed (ide_drive_t *drive, int speed) { struct packet_command pc; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof(pc)); if (speed == 0) - speed = 0xffff; /* set to max */ + speed = 0xffff; /* set to max */ else - speed *= 177; /* Nx to kbytes/s */ + speed *= 177; /* Nx to kbytes/s */ pc.c[0] = GPCMD_SET_SPEED; /* Read Drive speed in kbytes/second MSB */ @@ -1874,10 +1828,8 @@ cdrom_select_speed (ide_drive_t *drive, int speed, } -static -int cdrom_get_toc_entry (ide_drive_t *drive, int track, - struct atapi_toc_entry **ent, - struct atapi_request_sense *reqbuf) +static int cdrom_get_toc_entry(ide_drive_t *drive, int track, + struct atapi_toc_entry **ent) { struct cdrom_info *info = drive->driver_data; struct atapi_toc *toc = info->toc; @@ -1915,7 +1867,13 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi, memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE); pc.buffer = cgc->buffer; pc.buflen = cgc->buflen; - return cgc->stat = cdrom_queue_packet_command(drive, &pc); + cgc->stat = cdrom_queue_packet_command(drive, &pc); + + /* There was an error, assign sense. */ + if (cgc->stat) + cgc->sense = pc.sense_data; + + return cgc->stat; } static @@ -1979,7 +1937,7 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, struct atapi_toc *toc; /* Make sure our saved TOC is valid. */ - stat = cdrom_read_toc (drive, NULL); + stat = cdrom_read_toc(drive); if (stat) return stat; toc = info->toc; @@ -1994,8 +1952,7 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg; struct atapi_toc_entry *toce; - stat = cdrom_get_toc_entry (drive, tocentry->cdte_track, &toce, - NULL); + stat = cdrom_get_toc_entry (drive, tocentry->cdte_track, &toce); if (stat) return stat; tocentry->cdte_ctrl = toce->control; @@ -2032,21 +1989,20 @@ static int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct atapi_request_sense rq; if (position) { - int stat = cdrom_lockdoor (drive, 0, &rq); + int stat = cdrom_lockdoor (drive, 0); if (stat) return stat; } - return cdrom_eject (drive, !position, NULL); + return cdrom_eject(drive, !position); } static int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - return cdrom_lockdoor (drive, lock, NULL); + return cdrom_lockdoor (drive, lock); } static @@ -2054,14 +2010,13 @@ int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) { int stat, attempts = 3; ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct atapi_request_sense reqbuf; struct cdrom_generic_command cgc; struct { char pad[8]; struct atapi_capabilities_page cap; } buf; - stat=cdrom_select_speed (drive, speed, &reqbuf); - if (stat<0) + + if ((stat = cdrom_select_speed (drive, speed)) < 0) return stat; init_cdrom_command(&cgc, &buf, sizeof(buf)); @@ -2092,19 +2047,19 @@ static int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct cdrom_info *info = drive->driver_data; if (slot_nr == CDSL_CURRENT) { - - struct atapi_request_sense sense; - int stat = cdrom_check_status (drive, &sense); - if (stat == 0 || sense.sense_key == UNIT_ATTENTION) + struct request_sense *sense = &info->sense_data; + int stat = cdrom_check_status(drive); + if (stat == 0 || sense->sense_key == UNIT_ATTENTION) return CDS_DISC_OK; - if (sense.sense_key == NOT_READY && sense.asc == 0x04 && - sense.ascq == 0x04) + if (sense->sense_key == NOT_READY && sense->asc == 0x04 && + sense->ascq == 0x04) return CDS_DISC_OK; - if (sense.sense_key == NOT_READY) { + if (sense->sense_key == NOT_READY) { /* ATAPI doesn't have anything that can help us decide whether the drive is really emtpy or the tray is just open. irk. */ @@ -2140,10 +2095,9 @@ int ide_cdrom_get_mcn (struct cdrom_device_info *cdi, char mcnbuf[24]; ide_drive_t *drive = (ide_drive_t*) cdi->handle; - stat = cdrom_read_subchannel (drive, 2, /* get MCN */ - mcnbuf, sizeof (mcnbuf), - NULL); - if (stat) return stat; +/* get MCN */ + if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf)))) + return stat; memcpy (mcn_info->medium_catalog_number, mcnbuf+9, sizeof (mcn_info->medium_catalog_number)-1); @@ -2166,7 +2120,7 @@ int ide_cdrom_check_media_change_real (struct cdrom_device_info *cdi, ide_drive_t *drive = (ide_drive_t*) cdi->handle; if (slot_nr == CDSL_CURRENT) { - (void) cdrom_check_status (drive, NULL); + (void) cdrom_check_status(drive); CDROM_STATE_FLAGS (drive)->media_changed = 0; return CDROM_STATE_FLAGS (drive)->media_changed; } else { @@ -2367,8 +2321,13 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) if (drive->using_dma) { if ((drive->id->field_valid & 4) && - (drive->id->dma_ultra & (drive->id->dma_ultra >> 8) & 7)) { - printk(", UDMA"); /* UDMA BIOS-enabled! */ + (drive->id->word93 & 0x2000) && + (HWIF(drive)->udma_four) && + (drive->id->dma_ultra & (drive->id->dma_ultra >> 11) & 3)) { + printk(", UDMA(66)"); /* UDMA BIOS-enabled! */ + } else if ((drive->id->field_valid & 4) && + (drive->id->dma_ultra & (drive->id->dma_ultra >> 8) & 7)) { + printk(", UDMA(33)"); /* UDMA BIOS-enabled! */ } else if (drive->id->field_valid & 4) { printk(", (U)DMA"); /* Can be BIOS-enabled! */ } else { diff --git a/drivers/block/ide-cd.h b/drivers/block/ide-cd.h index b65baa5fe..8891205ed 100644 --- a/drivers/block/ide-cd.h +++ b/drivers/block/ide-cd.h @@ -7,6 +7,7 @@ * Copyright (C) 1998, 1999 Jens Axboe */ +#include <linux/cdrom.h> #include <asm/byteorder.h> /* Turn this on to have the driver print out the meanings of the @@ -95,47 +96,14 @@ struct ide_cd_state_flags { __u8 reserved : 4; byte current_speed; /* Current speed of the drive */ }; -#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) - -struct atapi_request_sense { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char valid : 1; - unsigned char error_code : 7; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned char error_code : 7; - unsigned char valid : 1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - byte reserved1; -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char reserved3 : 2; - unsigned char ili : 1; - unsigned char reserved2 : 1; - unsigned char sense_key : 4; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned char sense_key : 4; - unsigned char reserved2 : 1; - unsigned char ili : 1; - unsigned char reserved3 : 2; -#else -#error "Please fix <asm/byteorder.h>" -#endif - byte info[4]; - byte sense_len; - byte command_info[4]; - byte asc; - byte ascq; - byte fru; - byte sense_key_specific[3]; -}; +#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) struct packet_command { char *buffer; int buflen; int stat; - struct atapi_request_sense *sense_data; + struct request_sense *sense_data; unsigned char c[12]; }; @@ -502,7 +470,7 @@ struct cdrom_info { /* The result of the last successful request sense command on this device. */ - struct atapi_request_sense sense_data; + struct request_sense sense_data; struct request request_sense_request; struct packet_command request_sense_pc; diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c index 924451f5a..133d9cd85 100644 --- a/drivers/block/ide-disk.c +++ b/drivers/block/ide-disk.c @@ -133,7 +133,7 @@ static int lba_capacity_is_ok (struct hd_driveid *id) /* * read_intr() is the handler for disk read/multread interrupts */ -static void read_intr (ide_drive_t *drive) +static ide_startstop_t read_intr (ide_drive_t *drive) { byte stat; int i; @@ -141,8 +141,7 @@ static void read_intr (ide_drive_t *drive) struct request *rq; if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { - ide_error(drive, "read_intr", stat); - return; + return ide_error(drive, "read_intr", stat); } msect = drive->mult_count; @@ -154,12 +153,6 @@ read_next: msect -= nsect; } else nsect = 1; - /* - * PIO input can take longish times, so we drop the spinlock. - * On SMP, bad things might happen if syscall level code adds - * a new request while we do this PIO, so we just freeze all - * request queue handling while doing the PIO. FIXME - */ idedisk_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); #ifdef DEBUG printk("%s: read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n", @@ -176,21 +169,24 @@ read_next: if (msect) goto read_next; ide_set_handler (drive, &read_intr, WAIT_CMD, NULL); + return ide_started; } + return ide_stopped; } /* * write_intr() is the handler for disk write interrupts */ -static void write_intr (ide_drive_t *drive) +static ide_startstop_t write_intr (ide_drive_t *drive) { byte stat; int i; ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = hwgroup->rq; - int error = 0; - if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { + if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { + printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat); + } else { #ifdef DEBUG printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n", drive->name, rq->sector, (unsigned long) rq->buffer, @@ -207,26 +203,30 @@ static void write_intr (ide_drive_t *drive) if (i > 0) { idedisk_output_data (drive, rq->buffer, SECTOR_WORDS); ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); + return ide_started; } - goto out; + return ide_stopped; } - } else - error = 1; -out: - if (error) - ide_error(drive, "write_intr", stat); + printk("%s: write_intr error2: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat); + } + return ide_error(drive, "write_intr", stat); } /* * ide_multwrite() transfers a block of up to mcount sectors of data * to a drive as part of a disk multiple-sector write operation. + * + * Returns 0 if successful; returns 1 if request had to be aborted due to corrupted buffer list. */ -void ide_multwrite (ide_drive_t *drive, unsigned int mcount) +int ide_multwrite (ide_drive_t *drive, unsigned int mcount) { - struct request *rq = &HWGROUP(drive)->wrq; + ide_hwgroup_t *hwgroup= HWGROUP(drive); + struct request *rq = &hwgroup->wrq; + + do { + unsigned long flags; + unsigned int nsect = rq->current_nr_sectors; - do { - unsigned int nsect = rq->current_nr_sectors; if (nsect > mcount) nsect = mcount; mcount -= nsect; @@ -237,42 +237,50 @@ void ide_multwrite (ide_drive_t *drive, unsigned int mcount) drive->name, rq->sector, (unsigned long) rq->buffer, nsect, rq->nr_sectors - nsect); #endif + spin_lock_irqsave(&io_request_lock, flags); /* Is this really necessary? */ #ifdef CONFIG_BLK_DEV_PDC4030 rq->sector += nsect; #endif if ((rq->nr_sectors -= nsect) <= 0) + { + spin_unlock_irqrestore(&io_request_lock, flags); break; + } if ((rq->current_nr_sectors -= nsect) == 0) { if ((rq->bh = rq->bh->b_reqnext) != NULL) { rq->current_nr_sectors = rq->bh->b_size>>9; rq->buffer = rq->bh->b_data; } else { - panic("%s: buffer list corrupted\n", drive->name); - break; + spin_unlock_irqrestore(&io_request_lock, flags); + printk("%s: buffer list corrupted\n", drive->name); + ide_end_request(0, hwgroup); + return 1; } } else { rq->buffer += nsect << 9; } + spin_unlock_irqrestore(&io_request_lock, flags); } while (mcount); + return 0; } /* * multwrite_intr() is the handler for disk multwrite interrupts */ -static void multwrite_intr (ide_drive_t *drive) +static ide_startstop_t multwrite_intr (ide_drive_t *drive) { byte stat; int i; ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = &hwgroup->wrq; - int error = 0; if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { if (stat & DRQ_STAT) { if (rq->nr_sectors) { - ide_multwrite(drive, drive->mult_count); + if (ide_multwrite(drive, drive->mult_count)) + return ide_stopped; ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL); - goto out; + return ide_started; } } else { if (!rq->nr_sectors) { /* all done? */ @@ -281,20 +289,17 @@ static void multwrite_intr (ide_drive_t *drive) i -= rq->current_nr_sectors; ide_end_request(1, hwgroup); } - goto out; + return ide_stopped; } } - } else - error = 1; -out: - if (error) - ide_error(drive, "multwrite_intr", stat); + } + return ide_error(drive, "multwrite_intr", stat); } /* * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. */ -static void set_multmode_intr (ide_drive_t *drive) +static ide_startstop_t set_multmode_intr (ide_drive_t *drive) { byte stat = GET_STAT(); @@ -309,28 +314,31 @@ static void set_multmode_intr (ide_drive_t *drive) drive->special.b.recalibrate = 1; (void) ide_dump_status(drive, "set_multmode", stat); } + return ide_stopped; } /* * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd. */ -static void set_geometry_intr (ide_drive_t *drive) +static ide_startstop_t set_geometry_intr (ide_drive_t *drive) { byte stat = GET_STAT(); if (!OK_STAT(stat,READY_STAT,BAD_STAT)) - ide_error(drive, "set_geometry_intr", stat); + return ide_error(drive, "set_geometry_intr", stat); + return ide_stopped; } /* * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd. */ -static void recal_intr (ide_drive_t *drive) +static ide_startstop_t recal_intr (ide_drive_t *drive) { byte stat = GET_STAT(); if (!OK_STAT(stat,READY_STAT,BAD_STAT)) - ide_error(drive, "recal_intr", stat); + return ide_error(drive, "recal_intr", stat); + return ide_stopped; } /* @@ -338,7 +346,7 @@ static void recal_intr (ide_drive_t *drive) * using LBA if supported, or CHS otherwise, to address sectors. * It also takes care of issuing special DRIVE_CMDs. */ -static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) +static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) { if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl,IDE_CONTROL_REG); @@ -375,45 +383,61 @@ static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long bl } #ifdef CONFIG_BLK_DEV_PDC4030 if (IS_PDC4030_DRIVE) { - extern void do_pdc4030_io(ide_drive_t *, struct request *); - do_pdc4030_io (drive, rq); - return; + extern ide_startstop_t do_pdc4030_io(ide_drive_t *, struct request *); + return do_pdc4030_io (drive, rq); } #endif /* CONFIG_BLK_DEV_PDC4030 */ if (rq->cmd == READ) { #ifdef CONFIG_BLK_DEV_IDEDMA if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive))) - return; + return ide_started; #endif /* CONFIG_BLK_DEV_IDEDMA */ ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG); - return; + return ide_started; } if (rq->cmd == WRITE) { + ide_startstop_t startstop; #ifdef CONFIG_BLK_DEV_IDEDMA if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive))) - return; + return ide_started; #endif /* CONFIG_BLK_DEV_IDEDMA */ OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG); - if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { + if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE"); - return; + return startstop; } if (!drive->unmask) __cli(); /* local CPU only */ if (drive->mult_count) { - HWGROUP(drive)->wrq = *rq; /* scratchpad */ + ide_hwgroup_t *hwgroup = HWGROUP(drive); + /* + * Ugh.. this part looks ugly because we MUST set up + * the interrupt handler before outputting the first block + * of data to be written. If we hit an error (corrupted buffer list) + * in ide_multwrite(), then we need to remove the handler/timer + * before returning. Fortunately, this NEVER happens (right?). + */ + hwgroup->wrq = *rq; /* scratchpad */ ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL); - ide_multwrite(drive, drive->mult_count); + if (ide_multwrite(drive, drive->mult_count)) { + unsigned long flags; + spin_lock_irqsave(&io_request_lock, flags); + hwgroup->handler = NULL; + del_timer(&hwgroup->timer); + spin_unlock_irqrestore(&io_request_lock, flags); + return ide_stopped; + } } else { ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); idedisk_output_data(drive, rq->buffer, SECTOR_WORDS); } - return; + return ide_started; } printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd); ide_end_request(0, HWGROUP(drive)); + return ide_stopped; } static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive) @@ -472,7 +496,7 @@ static unsigned long idedisk_capacity (ide_drive_t *drive) return (drive->capacity - drive->sect0); } -static void idedisk_special (ide_drive_t *drive) +static ide_startstop_t idedisk_special (ide_drive_t *drive) { special_t *s = &drive->special; @@ -498,7 +522,9 @@ static void idedisk_special (ide_drive_t *drive) int special = s->all; s->all = 0; printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special); + return ide_stopped; } + return IS_PDC4030_DRIVE ? ide_stopped : ide_started; } static void idedisk_pre_reset (ide_drive_t *drive) @@ -620,7 +646,7 @@ static int set_nowerr(ide_drive_t *drive, int arg) return -EBUSY; drive->nowerr = arg; drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); return 0; } diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c index 7712b6cd6..083039e62 100644 --- a/drivers/block/ide-dma.c +++ b/drivers/block/ide-dma.c @@ -186,7 +186,7 @@ const char *bad_dma_drives[] = {"WDC AC11000H", /* * dma_intr() is the handler for disk read/write DMA interrupts */ -void ide_dma_intr (ide_drive_t *drive) +ide_startstop_t ide_dma_intr (ide_drive_t *drive) { int i; byte stat, dma_stat; @@ -201,12 +201,11 @@ void ide_dma_intr (ide_drive_t *drive) i -= rq->current_nr_sectors; ide_end_request(1, HWGROUP(drive)); } - return; + return ide_stopped; } printk("%s: dma_intr: bad DMA status\n", drive->name); } - ide__sti(); /* local CPU only */ - ide_error(drive, "dma_intr", stat); + return ide_error(drive, "dma_intr", stat); } /* diff --git a/drivers/block/ide-features.c b/drivers/block/ide-features.c new file mode 100644 index 000000000..e97cada29 --- /dev/null +++ b/drivers/block/ide-features.c @@ -0,0 +1,275 @@ +/* + * linux/drivers/block/ide-features.c + * + * Copyright (C) 1999 Linus Torvalds & authors (see below) + * + * Andre Hedrick <andre@suse.com> + * + * Extracts if ide.c to address the evolving transfer rate code for + * the SETFEATURES_XFER callouts. Below are original authors of some or + * various parts of any given function below. + * + * Mark Lord <mlord@pobox.com> + * Gadi Oxman <gadio@netvision.net.il> + */ + +#define __NO_VERSION__ +#include <linux/module.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/major.h> +#include <linux/errno.h> +#include <linux/genhd.h> +#include <linux/blkpg.h> +#include <linux/malloc.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/ide.h> + +#include <asm/byteorder.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/bitops.h> + +/* + * + */ +char *ide_xfer_verbose (byte xfer_rate) +{ + switch(xfer_rate) { + case XFER_UDMA_4: return("UDMA 4"); + case XFER_UDMA_3: return("UDMA 3"); + case XFER_UDMA_2: return("UDMA 2"); + case XFER_UDMA_1: return("UDMA 1"); + case XFER_UDMA_0: return("UDMA 0"); + case XFER_MW_DMA_2: return("MW DMA 2"); + case XFER_MW_DMA_1: return("MW DMA 1"); + case XFER_MW_DMA_0: return("MW DMA 0"); + case XFER_SW_DMA_2: return("SW DMA 2"); + case XFER_SW_DMA_1: return("SW DMA 1"); + case XFER_SW_DMA_0: return("SW DMA 0"); + case XFER_PIO_4: return("PIO 4"); + case XFER_PIO_3: return("PIO 3"); + case XFER_PIO_2: return("PIO 2"); + case XFER_PIO_1: return("PIO 1"); + case XFER_PIO_0: return("PIO 0"); + case XFER_PIO_SLOW: return("PIO SLOW"); + default: return("XFER ERROR"); + } +} + +/* + * + */ +char *ide_media_verbose (ide_drive_t *drive) +{ + switch (drive->media) { + case ide_disk: return("disk "); + case ide_cdrom: return("cdrom "); + case ide_tape: return("tape "); + case ide_floppy: return("floppy"); + default: return("??????"); + } +} + +int ide_driveid_update (ide_drive_t *drive) +{ + /* + * Re-read drive->id for possible DMA mode + * change (copied from ide-probe.c) + */ + struct hd_driveid *id; + unsigned long timeout, irqs, flags; + + probe_irq_off(probe_irq_on()); + irqs = probe_irq_on(); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); + ide_delay_50ms(); + OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG); + timeout = jiffies + WAIT_WORSTCASE; + do { + if (0 < (signed long)(jiffies - timeout)) { + if (irqs) + (void) probe_irq_off(irqs); + return 0; /* drive timed-out */ + } + ide_delay_50ms(); /* give drive a breather */ + } while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT); + ide_delay_50ms(); /* wait for IRQ and DRQ_STAT */ + if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) + return 0; + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only; some systems need this */ + id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC); + ide_input_data(drive, id, SECTOR_WORDS); + (void) GET_STAT(); /* clear drive IRQ */ + ide__sti(); /* local CPU only */ + __restore_flags(flags); /* local CPU only */ + ide_fix_driveid(id); + if (id && id->cyls) { + drive->id->dma_ultra = id->dma_ultra; + drive->id->dma_mword = id->dma_mword; + drive->id->dma_1word = id->dma_1word; + /* anything more ? */ +#ifdef DEBUG + printk("%s: dma_ultra=%04X, dma_mword=%04X, dma_1word=%04X\n", + drive->name, id->dma_ultra, id->dma_mword, id->dma_1word); +#endif + kfree(id); + } + return 1; +} + +/* + * Similar to ide_wait_stat(), except it never calls ide_error internally. + * This is a kludge to handle the new ide_config_drive_speed() function, + * and should not otherwise be used anywhere. Eventually, the tuneproc's + * should be updated to return ide_startstop_t, in which case we can get + * rid of this abomination again. :) -ml + */ +int ide_wait_noerr (ide_drive_t *drive, byte good, byte bad, unsigned long timeout) +{ + byte stat; + int i; + unsigned long flags; + + udelay(1); /* spec allows drive 400ns to assert "BUSY" */ + if ((stat = GET_STAT()) & BUSY_STAT) { + __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); /* local CPU only */ + (void)ide_dump_status(drive, "ide_wait_noerr", stat); + return 1; + } + } + __restore_flags(flags); /* local CPU only */ + } + /* + * Allow status to settle, then read it again. + * A few rare drives vastly violate the 400ns spec here, + * so we'll wait up to 10usec for a "good" status + * rather than expensively fail things immediately. + * This fix courtesy of Matthew Faupel & Niccolo Rigacci. + */ + for (i = 0; i < 10; i++) { + udelay(1); + if (OK_STAT((stat = GET_STAT()), good, bad)) + return 0; + } + (void)ide_dump_status(drive, "ide_wait_noerr", stat); + return 1; +} + + +/* + * Verify that we are doing an approved SETFEATURES_XFER with respect + * to the hardware being able to support request. Since some hardware + * can improperly report capabilties, we check to see if the host adapter + * in combination with the device (usually a disk) properly detect + * and acknowledge each end of the ribbon. + */ +int ide_ata66_check (ide_drive_t *drive, int cmd, int nsect, int feature) +{ + if ((cmd == WIN_SETFEATURES) && + (nsect > XFER_UDMA_2) && + (feature == SETFEATURES_XFER)) { + if (!HWIF(drive)->udma_four) { + printk("%s: Speed warnings UDMA 3/4 is not functional.\n", HWIF(drive)->name); + return 1; + } + if ((drive->id->word93 & 0x2000) == 0) { + printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name); + return 1; + } + } + return 0; +} + +/* + * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER. + * 1 : Safe to update drive->id DMA registers. + * 0 : OOPs not allowed. + */ +int set_transfer (ide_drive_t *drive, int cmd, int nsect, int feature) +{ + struct hd_driveid *id = drive->id; + + if ((cmd == WIN_SETFEATURES) && + (nsect >= XFER_SW_DMA_0) && + (feature == SETFEATURES_XFER) && + (id->dma_ultra || id->dma_mword || id->dma_1word)) + return 1; + return 0; +} + +int ide_config_drive_speed (ide_drive_t *drive, byte speed) +{ + unsigned long flags; + int err; + byte stat; + + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ + + /* + * Don't use ide_wait_cmd here - it will + * attempt to set_geometry and recalibrate, + * but for some reason these don't work at + * this point (lost interrupt). + */ + SELECT_DRIVE(HWIF(drive), drive); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); + OUT_BYTE(speed, IDE_NSECTOR_REG); + OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); + OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); + + err = ide_wait_noerr(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD); + +#if 0 + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); +#endif + + __restore_flags(flags); /* local CPU only */ + + stat = GET_STAT(); + if (stat != DRIVE_READY) + (void) ide_dump_status(drive, "set_drive_speed_status", stat); + + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + + switch(speed) { + case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break; + case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break; + case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break; + case XFER_UDMA_1: drive->id->dma_ultra |= 0x0202; break; + case XFER_UDMA_0: drive->id->dma_ultra |= 0x0101; break; + case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break; + case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break; + case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break; + case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break; + case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break; + case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break; + default: break; + } + return(err); +} + +EXPORT_SYMBOL(ide_driveid_update); +EXPORT_SYMBOL(ide_wait_noerr); +EXPORT_SYMBOL(ide_ata66_check); +EXPORT_SYMBOL(set_transfer); +EXPORT_SYMBOL(ide_config_drive_speed); + diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c index 4609e77d9..aade2c6ee 100644 --- a/drivers/block/ide-floppy.c +++ b/drivers/block/ide-floppy.c @@ -830,7 +830,7 @@ static void idefloppy_retry_pc (ide_drive_t *drive) * idefloppy_pc_intr is the usual interrupt handler which will be called * during a packet command. */ -static void idefloppy_pc_intr (ide_drive_t *drive) +static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) { idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_status_reg_t status; @@ -875,24 +875,22 @@ static void idefloppy_pc_intr (ide_drive_t *drive) rq->errors++; if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) { printk (KERN_ERR "ide-floppy: I/O error in request sense command\n"); - ide_do_reset (drive); - return; + return ide_do_reset (drive); } idefloppy_retry_pc (drive); /* Retry operation */ - return; + return ide_stopped; /* queued, but not started */ } pc->error = 0; if (floppy->failed_pc == pc) floppy->failed_pc=NULL; pc->callback(drive); /* Command finished - Call the callback function */ - return; + return ide_stopped; } #ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n"); (void) HWIF(drive)->dmaproc(ide_dma_off, drive); - ide_do_reset (drive); - return; + return ide_do_reset (drive); } #endif /* CONFIG_BLK_DEV_IDEDMA */ bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG); /* Get the number of bytes to transfer */ @@ -901,14 +899,12 @@ static void idefloppy_pc_intr (ide_drive_t *drive) if (ireason.b.cod) { printk (KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n"); - ide_do_reset (drive); - return; + return ide_do_reset (drive); } if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) { /* Hopefully, we will never get here */ printk (KERN_ERR "ide-floppy: We wanted to %s, ", ireason.b.io ? "Write":"Read"); printk (KERN_ERR "but the floppy wants us to %s !\n",ireason.b.io ? "Read":"Write"); - ide_do_reset (drive); - return; + return ide_do_reset (drive); } if (!test_bit (PC_WRITING, &pc->flags)) { /* Reading - Check that we have enough space */ temp = pc->actually_transferred + bcount.all; @@ -917,7 +913,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive) printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n"); idefloppy_discard_data (drive,bcount.all); ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL); - return; + return ide_started; } #if IDEFLOPPY_DEBUG_LOG printk (KERN_NOTICE "ide-floppy: The floppy wants to send us more data than expected - allowing transfer\n"); @@ -939,31 +935,33 @@ static void idefloppy_pc_intr (ide_drive_t *drive) pc->current_position+=bcount.all; ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */ + return ide_started; } -static void idefloppy_transfer_pc (ide_drive_t *drive) +static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive) { + ide_startstop_t startstop; idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_ireason_reg_t ireason; - if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { + if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n"); - return; + return startstop; } ireason.all=IN_BYTE (IDE_IREASON_REG); if (!ireason.b.cod || ireason.b.io) { printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n"); - ide_do_reset (drive); - return; + return ide_do_reset (drive); } ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* Set the interrupt routine */ atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */ + return ide_started; } /* * Issue a packet command */ -static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc) +static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc) { idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_bcount_reg_t bcount; @@ -991,7 +989,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc) } floppy->failed_pc=NULL; pc->callback(drive); - return; + return ide_stopped; } #if IDEFLOPPY_DEBUG_LOG printk (KERN_INFO "Retry number - %d\n",pc->retries); @@ -1027,9 +1025,10 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc) if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) { ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD, NULL); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ + return ide_started; } else { OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); - idefloppy_transfer_pc (drive); + return idefloppy_transfer_pc (drive); } } @@ -1135,7 +1134,7 @@ static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t /* * idefloppy_do_request is our request handling function. */ -static void idefloppy_do_request (ide_drive_t *drive, struct request *rq, unsigned long block) +static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request *rq, unsigned long block) { idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_pc_t *pc; @@ -1152,7 +1151,7 @@ static void idefloppy_do_request (ide_drive_t *drive, struct request *rq, unsign else printk (KERN_ERR "ide-floppy: %s: I/O error\n", drive->name); idefloppy_end_request (0, HWGROUP(drive)); - return; + return ide_stopped; } switch (rq->cmd) { case READ: @@ -1160,7 +1159,7 @@ static void idefloppy_do_request (ide_drive_t *drive, struct request *rq, unsign if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) { printk ("%s: unsupported r/w request size\n", drive->name); idefloppy_end_request (0, HWGROUP(drive)); - return; + return ide_stopped; } pc = idefloppy_next_pc_storage (drive); idefloppy_create_rw_cmd (floppy, pc, rq, block); @@ -1171,10 +1170,10 @@ static void idefloppy_do_request (ide_drive_t *drive, struct request *rq, unsign default: printk (KERN_ERR "ide-floppy: unsupported command %x in request queue\n", rq->cmd); idefloppy_end_request (0,HWGROUP (drive)); - return; + return ide_stopped; } pc->rq = rq; - idefloppy_issue_pc (drive, pc); + return idefloppy_issue_pc (drive, pc); } /* diff --git a/drivers/block/ide-geometry.c b/drivers/block/ide-geometry.c index 8370d35a6..79abaca2b 100644 --- a/drivers/block/ide-geometry.c +++ b/drivers/block/ide-geometry.c @@ -1,6 +1,7 @@ /* * linux/drivers/block/ide-geometry.c */ +#include <linux/config.h> #include <linux/ide.h> #include <asm/io.h> @@ -65,9 +66,6 @@ void probe_cmos_for_drives (ide_hwif_t *hwif) drive->head = drive->bios_head = *(BIOS+2); drive->sect = drive->bios_sect = *(BIOS+14); drive->ctl = *(BIOS+8); -#if 0 - drive->present = 1; -#endif } BIOS += 16; } diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c index 73ffa67ea..06a986641 100644 --- a/drivers/block/ide-pci.c +++ b/drivers/block/ide-pci.c @@ -49,6 +49,7 @@ #define DEVID_HT6565 ((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565}) #define DEVID_AEC6210 ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF}) #define DEVID_W82C105 ((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105}) +#define DEVID_UM8673F ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F}) #define DEVID_UM8886A ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A}) #define DEVID_UM8886BF ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF}) #define DEVID_HPT34X ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343}) @@ -61,66 +62,17 @@ #define IDE_IGNORE ((void *)-1) -#ifdef CONFIG_BLK_DEV_TRM290 -extern void ide_init_trm290(ide_hwif_t *); -#define INIT_TRM290 &ide_init_trm290 -#else -#define INIT_TRM290 IDE_IGNORE -#endif - -#ifdef CONFIG_BLK_DEV_OPTI621 -extern void ide_init_opti621(ide_hwif_t *); -#define INIT_OPTI621 &ide_init_opti621 -#else -#define INIT_OPTI621 NULL -#endif - -#ifdef CONFIG_BLK_DEV_NS87415 -extern void ide_init_ns87415(ide_hwif_t *); -#define INIT_NS87415 &ide_init_ns87415 -#else -#define INIT_NS87415 IDE_IGNORE -#endif - -#ifdef CONFIG_BLK_DEV_CMD646 -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 -extern void ide_init_rz1000(ide_hwif_t *); -#define INIT_RZ1000 &ide_init_rz1000 -#else -#define INIT_RZ1000 IDE_IGNORE -#endif - -#ifdef CONFIG_BLK_DEV_VIA82CXXX -extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *); -extern unsigned int ata66_via82cxxx(ide_hwif_t *); -extern void ide_init_via82cxxx(ide_hwif_t *); -extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long); -#define PCI_VIA82CXXX &pci_init_via82cxxx -#define ATA66_VIA82CXXX &ata66_via82cxxx -#define INIT_VIA82CXXX &ide_init_via82cxxx -#define DMA_VIA82CXXX &ide_dmacapable_via82cxxx +#ifdef CONFIG_BLK_DEV_AEC6210 +extern unsigned int pci_init_aec6210(struct pci_dev *, const char *); +extern void ide_init_aec6210(ide_hwif_t *); +extern void ide_dmacapable_aec6210(ide_hwif_t *, unsigned long); +#define PCI_AEC6210 &pci_init_aec6210 +#define INIT_AEC6210 &ide_init_aec6210 +#define DMA_AEC6210 &ide_dmacapable_aec6210 #else -#define PCI_VIA82CXXX NULL -#define ATA66_VIA82CXXX NULL -#define INIT_VIA82CXXX NULL -#define DMA_VIA82CXXX NULL +#define PCI_AEC6210 NULL +#define INIT_AEC6210 NULL +#define DMA_AEC6210 NULL #endif #ifdef CONFIG_BLK_DEV_ALI15X3 @@ -139,6 +91,17 @@ extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long); #define DMA_ALI15X3 NULL #endif +#ifdef CONFIG_BLK_DEV_CMD646 +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_CY82C693 extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *); extern void ide_init_cy82c693(ide_hwif_t *); @@ -149,32 +112,7 @@ extern void ide_init_cy82c693(ide_hwif_t *); #define INIT_CY82C693 NULL #endif -#ifdef CONFIG_BLK_DEV_PDC202XX -extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *); -extern unsigned int ata66_pdc202xx(ide_hwif_t *); -extern void ide_init_pdc202xx(ide_hwif_t *); -#define PCI_PDC202XX &pci_init_pdc202xx -#define ATA66_PDC202XX &ata66_pdc202xx -#define INIT_PDC202XX &ide_init_pdc202xx -#else -#define PCI_PDC202XX NULL -#define ATA66_PDC202XX NULL -#define INIT_PDC202XX NULL -#endif - -#ifdef CONFIG_BLK_DEV_PIIX -extern void ide_init_piix(ide_hwif_t *); -#define INIT_PIIX &ide_init_piix -#else -#define INIT_PIIX NULL -#endif - -#ifdef CONFIG_BLK_DEV_AEC6210 -extern unsigned int pci_init_aec6210(struct pci_dev *, const char *); -#define PCI_AEC6210 &pci_init_aec6210 -#else -#define PCI_AEC6210 NULL -#endif +#define INIT_CX5530 NULL #ifdef CONFIG_BLK_DEV_HPT34X extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *); @@ -204,6 +142,52 @@ static byte hpt363_shared_irq = 0; #define DMA_HPT366 NULL #endif +#ifdef CONFIG_BLK_DEV_NS87415 +extern void ide_init_ns87415(ide_hwif_t *); +#define INIT_NS87415 &ide_init_ns87415 +#else +#define INIT_NS87415 IDE_IGNORE +#endif + +#ifdef CONFIG_BLK_DEV_OPTI621 +extern void ide_init_opti621(ide_hwif_t *); +#define INIT_OPTI621 &ide_init_opti621 +#else +#define INIT_OPTI621 NULL +#endif + +#ifdef CONFIG_BLK_DEV_PDC202XX +extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *); +extern unsigned int ata66_pdc202xx(ide_hwif_t *); +extern void ide_init_pdc202xx(ide_hwif_t *); +#define PCI_PDC202XX &pci_init_pdc202xx +#define ATA66_PDC202XX &ata66_pdc202xx +#define INIT_PDC202XX &ide_init_pdc202xx +#else +#define PCI_PDC202XX NULL +#define ATA66_PDC202XX NULL +#define INIT_PDC202XX NULL +#endif + +#ifdef CONFIG_BLK_DEV_PIIX +extern unsigned int pci_init_piix(struct pci_dev *, const char *); +extern void ide_init_piix(ide_hwif_t *); +#define PCI_PIIX &pci_init_piix +#define INIT_PIIX &ide_init_piix +#else +#define PCI_PIIX NULL +#define INIT_PIIX NULL +#endif + +#ifdef CONFIG_BLK_DEV_RZ1000 +extern void ide_init_rz1000(ide_hwif_t *); +#define INIT_RZ1000 &ide_init_rz1000 +#else +#define INIT_RZ1000 IDE_IGNORE +#endif + +#define INIT_SAMURAI NULL + #ifdef CONFIG_BLK_DEV_SIS5513 extern unsigned int pci_init_sis5513(struct pci_dev *, const char *); extern unsigned int ata66_sis5513(ide_hwif_t *); @@ -217,8 +201,35 @@ extern void ide_init_sis5513(ide_hwif_t *); #define INIT_SIS5513 NULL #endif -#define INIT_SAMURAI NULL -#define INIT_CX5530 NULL +#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_TRM290 +extern void ide_init_trm290(ide_hwif_t *); +#define INIT_TRM290 &ide_init_trm290 +#else +#define INIT_TRM290 IDE_IGNORE +#endif + +#ifdef CONFIG_BLK_DEV_VIA82CXXX +extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *); +extern unsigned int ata66_via82cxxx(ide_hwif_t *); +extern void ide_init_via82cxxx(ide_hwif_t *); +extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long); +#define PCI_VIA82CXXX &pci_init_via82cxxx +#define ATA66_VIA82CXXX &ata66_via82cxxx +#define INIT_VIA82CXXX &ide_init_via82cxxx +#define DMA_VIA82CXXX &ide_dmacapable_via82cxxx +#else +#define PCI_VIA82CXXX NULL +#define ATA66_VIA82CXXX NULL +#define INIT_VIA82CXXX NULL +#define DMA_VIA82CXXX NULL +#endif typedef struct ide_pci_enablebit_s { byte reg; /* byte pci reg holding the enable-bit */ @@ -241,8 +252,8 @@ typedef struct ide_pci_device_s { static ide_pci_device_t ide_pci_chipsets[] __initdata = { {DEVID_PIIXa, "PIIX", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIXb, "PIIX", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX3, "PIIX3", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX4, "PIIX4", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX3, "PIIX3", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_VP_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, @@ -260,12 +271,13 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = { {DEVID_OPTI621X,"OPTI621X", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, {DEVID_TRM290, "TRM290", NULL, NULL, INIT_TRM290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_NS87415, "NS87415", NULL, NULL, INIT_NS87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_AEC6210, "AEC6210", PCI_AEC6210, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_AEC6210, "AEC6210", PCI_AEC6210, NULL, INIT_AEC6210, DMA_AEC6210, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, {DEVID_W82C105, "W82C105", NULL, NULL, INIT_W82C105, NULL, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 }, + {DEVID_UM8673F, "UM8673F", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_HPT34X, "HPT34X", PCI_HPT34X, NULL, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16 }, - {DEVID_HPT366, "HPT366", PCI_HPT366, ATA66_HPT366, INIT_HPT366, DMA_HPT366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 256 }, + {DEVID_HPT366, "HPT366", PCI_HPT366, ATA66_HPT366, INIT_HPT366, DMA_HPT366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 240 }, {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, ATA66_ALI15X3, INIT_ALI15X3, DMA_ALI15X3, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, @@ -549,7 +561,8 @@ check_if_enabled: } } if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF)) { + IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8673F)) { hwif->irq = hwif->channel ? 15 : 14; goto bypass_umc_dma; } diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index d430c5b1d..c4dc22408 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -56,7 +56,8 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ ide__sti(); /* local CPU only */ ide_fix_driveid(id); - + if (!drive->forced_lun) + drive->last_lun = id->word126 & 0x7; #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA) /* * EATA SCSI controllers do a hardware ATA emulation: @@ -402,7 +403,7 @@ static void probe_hwif (ide_hwif_t *hwif) if (hwif->noprobe) return; if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) { - extern void probe_cmos_for_drives(ide_hwif_t *hwif); + extern void probe_cmos_for_drives(ide_hwif_t *); probe_cmos_for_drives (hwif); } @@ -575,10 +576,6 @@ static int init_irq (ide_hwif_t *hwif) 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; @@ -707,7 +704,8 @@ static void init_gendisk (ide_hwif_t *hwif) static int hwif_init (ide_hwif_t *hwif) { - void (*rfn)(void); + ide_drive_t *drive; + void (*rfn)(request_queue_t *); if (!hwif->present) return 0; @@ -789,11 +787,24 @@ static int hwif_init (ide_hwif_t *hwif) init_gendisk(hwif); blk_dev[hwif->major].data = hwif; - blk_dev[hwif->major].request_fn = rfn; blk_dev[hwif->major].queue = ide_get_queue; read_ahead[hwif->major] = 8; /* (4kB) */ hwif->present = 1; /* success */ + /* + * FIXME(eric) - This needs to be tested. I *think* that this + * is correct. Also, I believe that there is no longer any + * reason to have multiple functions (do_ide[0-7]_request) + * functions - the queuedata field could be used to indicate + * the correct hardware group - either this, or we could add + * a new field to request_queue_t to hold this information. + */ + drive = &hwif->drives[0]; + blk_init_queue(&drive->queue, rfn); + + drive = &hwif->drives[1]; + blk_init_queue(&drive->queue, rfn); + #if (DEBUG_SPINLOCK > 0) { static int done = 0; diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c index b68072428..66e45001c 100644 --- a/drivers/block/ide-proc.c +++ b/drivers/block/ide-proc.c @@ -75,17 +75,22 @@ #ifdef CONFIG_BLK_DEV_ALI15X3 extern byte ali_proc; -int (*ali_display_info)(char *, char **, off_t, int, int) = NULL; +int (*ali_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_ALI15X3 */ +#ifdef CONFIG_BLK_DEV_PIIX +extern byte piix_proc; +int (*piix_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_PIIX */ + #ifdef CONFIG_BLK_DEV_SIS5513 extern byte sis_proc; -int (*sis_display_info)(char *, char **, off_t, int, int) = NULL; +int (*sis_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_SIS5513 */ #ifdef CONFIG_BLK_DEV_VIA82CXXX extern byte via_proc; -int (*via_display_info)(char *, char **, off_t, int, int) = NULL; +int (*via_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_VIA82CXXX */ static int ide_getxdigit(char c) @@ -372,6 +377,8 @@ static int proc_ide_read_imodel case ide_pdc4030: name = "pdc4030"; break; case ide_rz1000: name = "rz1000"; break; case ide_trm290: name = "trm290"; break; + case ide_cmd646: name = "cmd646"; break; + case ide_cy82c693: name = "cy82c693"; break; case ide_4drives: name = "4drives"; break; default: name = "(unknown)"; break; } @@ -661,17 +668,12 @@ void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p) } } -static int proc_ide_readlink(struct proc_dir_entry *de, char *page) -{ - int n = (de->name[2] - 'a') / 2; - return sprintf(page, "ide%d/%s", n, de->name); -} - static void create_proc_ide_drives(ide_hwif_t *hwif) { int d; struct proc_dir_entry *ent; struct proc_dir_entry *parent = hwif->proc; + char name[64]; for (d = 0; d < MAX_DRIVES; d++) { ide_drive_t *drive = &hwif->drives[d]; @@ -682,7 +684,7 @@ static void create_proc_ide_drives(ide_hwif_t *hwif) if (drive->proc) continue; - drive->proc = create_proc_entry(drive->name, S_IFDIR, parent); + drive->proc = proc_mkdir(drive->name, parent); if (drive->proc) { ide_add_proc_entries(drive->proc, generic_drive_entries, drive); if (driver) { @@ -690,11 +692,9 @@ static void create_proc_ide_drives(ide_hwif_t *hwif) ide_add_proc_entries(drive->proc, driver->proc, drive); } } - ent = create_proc_entry(drive->name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, proc_ide_root); + sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name); + ent = proc_symlink(drive->name, proc_ide_root, name); if (!ent) return; - ent->data = drive; - ent->readlink_proc = proc_ide_readlink; - ent->nlink = 1; } } @@ -731,16 +731,15 @@ void create_proc_ide_interfaces(void) for (h = 0; h < MAX_HWIFS; h++) { ide_hwif_t *hwif = &ide_hwifs[h]; - int exist = (hwif->proc != NULL); if (!hwif->present) continue; - if (!exist) - hwif->proc = create_proc_entry(hwif->name, S_IFDIR, proc_ide_root); - if (!hwif->proc) - return; - if (!exist) + if (!hwif->proc) { + hwif->proc = proc_mkdir(hwif->name, proc_ide_root); + if (!hwif->proc) + return; ide_add_proc_entries(hwif->proc, hwif_entries, hwif); + } create_proc_ide_drives(hwif); } } @@ -752,7 +751,6 @@ static void destroy_proc_ide_interfaces(void) for (h = 0; h < MAX_HWIFS; h++) { ide_hwif_t *hwif = &ide_hwifs[h]; int exist = (hwif->proc != NULL); - #if 0 if (!hwif->present) continue; @@ -769,7 +767,7 @@ static void destroy_proc_ide_interfaces(void) void proc_ide_create(void) { - proc_ide_root = create_proc_entry("ide", S_IFDIR, 0); + proc_ide_root = proc_mkdir("ide", 0); if (!proc_ide_root) return; create_proc_ide_interfaces(); @@ -781,6 +779,10 @@ void proc_ide_create(void) if ((ali_display_info) && (ali_proc)) create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info); #endif /* CONFIG_BLK_DEV_ALI15X3 */ +#ifdef CONFIG_BLK_DEV_PIIX + if ((piix_display_info) && (piix_proc)) + create_proc_info_entry("piix", 0, proc_ide_root, piix_display_info); +#endif /* CONFIG_BLK_DEV_PIIX */ #ifdef CONFIG_BLK_DEV_SIS5513 if ((sis_display_info) && (sis_proc)) create_proc_info_entry("sis", 0, proc_ide_root, sis_display_info); @@ -801,6 +803,10 @@ void proc_ide_destroy(void) if ((ali_display_info) && (ali_proc)) remove_proc_entry("ide/ali",0); #endif /* CONFIG_BLK_DEV_ALI15X3 */ +#ifdef CONFIG_BLK_DEV_PIIX + if ((piix_display_info) && (piix_proc)) + remove_proc_entry("ide/piix",0); +#endif /* CONFIG_BLK_DEV_PIIX */ #ifdef CONFIG_BLK_DEV_SIS5513 if ((sis_display_info) && (sis_proc)) remove_proc_entry("ide/sis", 0); @@ -809,6 +815,7 @@ void proc_ide_destroy(void) if ((via_display_info) && (via_proc)) remove_proc_entry("ide/via",0); #endif /* CONFIG_BLK_DEV_VIA82CXXX */ + remove_proc_entry("ide/drivers", 0); destroy_proc_ide_interfaces(); remove_proc_entry("ide", 0); diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index 5ea3230dc..41a3b5045 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -526,7 +526,7 @@ typedef struct idetape_packet_command_s { int b_count; byte *buffer; /* Data buffer */ byte *current_position; /* Pointer into the above buffer */ - void (*callback) (ide_drive_t *); /* Called when this packet command is completed */ + ide_startstop_t (*callback) (ide_drive_t *); /* Called when this packet command is completed */ byte pc_buffer[IDETAPE_PC_BUFFER_SIZE]; /* Temporary buffer */ unsigned int flags; /* Status/Action bit flags */ } idetape_pc_t; @@ -1660,7 +1660,7 @@ static void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_resu } } -static void idetape_request_sense_callback (ide_drive_t *drive) +static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; @@ -1674,6 +1674,7 @@ static void idetape_request_sense_callback (ide_drive_t *drive) printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n"); idetape_end_request (0,HWGROUP (drive)); } + return ide_stopped; } /* @@ -1705,7 +1706,7 @@ static void idetape_create_request_sense_cmd (idetape_pc_t *pc) * last packet command. We queue a request sense packet command in * the head of the request list. */ -static void idetape_retry_pc (ide_drive_t *drive) +static ide_startstop_t idetape_retry_pc (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc; @@ -1718,6 +1719,7 @@ static void idetape_retry_pc (ide_drive_t *drive) idetape_create_request_sense_cmd (pc); set_bit (IDETAPE_IGNORE_DSC, &tape->flags); idetape_queue_pc_head (drive, pc, rq); + return ide_stopped; } /* @@ -1728,7 +1730,7 @@ static void idetape_retry_pc (ide_drive_t *drive) * algorithm described before idetape_issue_packet_command. * */ -static void idetape_pc_intr (ide_drive_t *drive) +static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; idetape_status_reg_t status; @@ -1784,11 +1786,9 @@ static void idetape_pc_intr (ide_drive_t *drive) #endif /* IDETAPE_DEBUG_LOG */ if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { printk (KERN_ERR "ide-tape: I/O error in request sense command\n"); - ide_do_reset (drive); - return; + return ide_do_reset (drive); } - idetape_retry_pc (drive); /* Retry operation */ - return; + return idetape_retry_pc (drive); /* Retry operation */ } pc->error = 0; if (test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) { /* Media access command */ @@ -1796,20 +1796,18 @@ static void idetape_pc_intr (ide_drive_t *drive) tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST; tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT; idetape_postpone_request (drive); /* Allow ide.c to handle other requests */ - return; + return ide_stopped; } if (tape->failed_pc == pc) tape->failed_pc=NULL; - pc->callback(drive); /* Command finished - Call the callback function */ - return; + return pc->callback(drive); /* Command finished - Call the callback function */ } #ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n"); printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n"); (void) HWIF(drive)->dmaproc(ide_dma_off, drive); - ide_do_reset (drive); - return; + return ide_do_reset (drive); } #endif /* CONFIG_BLK_DEV_IDEDMA */ bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG); /* Get the number of bytes to transfer */ @@ -1818,14 +1816,12 @@ static void idetape_pc_intr (ide_drive_t *drive) if (ireason.b.cod) { printk (KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n"); - ide_do_reset (drive); - return; + return ide_do_reset (drive); } if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) { /* Hopefully, we will never get here */ printk (KERN_ERR "ide-tape: We wanted to %s, ", ireason.b.io ? "Write":"Read"); printk (KERN_ERR "but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write"); - ide_do_reset (drive); - return; + return ide_do_reset (drive); } if (!test_bit (PC_WRITING, &pc->flags)) { /* Reading - Check that we have enough space */ temp = pc->actually_transferred + bcount.all; @@ -1834,7 +1830,7 @@ static void idetape_pc_intr (ide_drive_t *drive) printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n"); idetape_discard_data (drive,bcount.all); ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL); - return; + return ide_started; } #if IDETAPE_DEBUG_LOG printk (KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n"); @@ -1856,6 +1852,7 @@ static void idetape_pc_intr (ide_drive_t *drive) pc->current_position+=bcount.all; ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL); /* And set the interrupt handler again */ + return ide_started; } /* @@ -1901,16 +1898,17 @@ static void idetape_pc_intr (ide_drive_t *drive) * */ -static void idetape_transfer_pc(ide_drive_t *drive) +static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc = tape->pc; idetape_ireason_reg_t ireason; int retries = 100; + ide_startstop_t startstop; - if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { + if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); - return; + return startstop; } ireason.all=IN_BYTE (IDE_IREASON_REG); while (retries-- && (!ireason.b.cod || ireason.b.io)) { @@ -1925,14 +1923,14 @@ static void idetape_transfer_pc(ide_drive_t *drive) } if (!ireason.b.cod || ireason.b.io) { printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n"); - ide_do_reset (drive); - return; + return ide_do_reset (drive); } ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* Set the interrupt routine */ atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */ + return ide_started; } -static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) +static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) { idetape_tape_t *tape = drive->driver_data; idetape_bcount_reg_t bcount; @@ -1961,8 +1959,7 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) pc->error = IDETAPE_ERROR_GENERAL; /* Giving up */ } tape->failed_pc=NULL; - pc->callback(drive); - return; + return pc->callback(drive); } #if IDETAPE_DEBUG_LOG printk (KERN_INFO "Retry number - %d\n",pc->retries); @@ -1997,13 +1994,14 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL); OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); + return ide_started; } else { OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); - idetape_transfer_pc(drive); + return idetape_transfer_pc(drive); } } -static void idetape_media_access_finished (ide_drive_t *drive) +static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc = tape->pc; @@ -2013,8 +2011,7 @@ static void idetape_media_access_finished (ide_drive_t *drive) if (status.b.dsc) { if (status.b.check) { /* Error detected */ printk (KERN_ERR "ide-tape: %s: I/O error, ",tape->name); - idetape_retry_pc (drive); /* Retry operation */ - return; + return idetape_retry_pc (drive); /* Retry operation */ } pc->error = 0; if (tape->failed_pc == pc) @@ -2023,13 +2020,13 @@ static void idetape_media_access_finished (ide_drive_t *drive) pc->error = IDETAPE_ERROR_GENERAL; tape->failed_pc = NULL; } - pc->callback (drive); + return pc->callback (drive); } /* * General packet command callback function. */ -static void idetape_pc_callback (ide_drive_t *drive) +static ide_startstop_t idetape_pc_callback (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; @@ -2038,9 +2035,10 @@ static void idetape_pc_callback (ide_drive_t *drive) #endif /* IDETAPE_DEBUG_LOG */ idetape_end_request (tape->pc->error ? 0:1, HWGROUP(drive)); + return ide_stopped; } -static void idetape_rw_callback (ide_drive_t *drive) +static ide_startstop_t idetape_rw_callback (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; struct request *rq = HWGROUP(drive)->rq; @@ -2057,6 +2055,7 @@ static void idetape_rw_callback (ide_drive_t *drive) idetape_end_request (1, HWGROUP (drive)); else idetape_end_request (tape->pc->error, HWGROUP (drive)); + return ide_stopped; } static void idetape_create_locate_cmd (idetape_pc_t *pc, unsigned int block, byte partition) @@ -2175,7 +2174,7 @@ static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, un set_bit (PC_DMA_RECOMMENDED, &pc->flags); } -static void idetape_read_position_callback (ide_drive_t *drive) +static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; idetape_read_position_result_t *result; @@ -2205,6 +2204,7 @@ static void idetape_read_position_callback (ide_drive_t *drive) } } else idetape_end_request (0,HWGROUP (drive)); + return ide_stopped; } static void idetape_create_read_position_cmd (idetape_pc_t *pc) @@ -2218,7 +2218,7 @@ static void idetape_create_read_position_cmd (idetape_pc_t *pc) /* * idetape_do_request is our request handling function. */ -static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block) +static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc; @@ -2234,24 +2234,23 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned /* * We do not support buffer cache originated requests. */ - printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue\n", drive->name); + printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd); ide_end_request (0,HWGROUP (drive)); /* Let the common code handle it */ - return; + return ide_stopped; } /* * Retry a failed packet command */ if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { - idetape_issue_packet_command (drive, tape->failed_pc); - return; + return idetape_issue_packet_command (drive, tape->failed_pc); } #if IDETAPE_DEBUG_BUGS if (postponed_rq != NULL) if (rq != postponed_rq) { printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n"); idetape_end_request (0,HWGROUP (drive)); - return; + return ide_stopped; } #endif /* IDETAPE_DEBUG_BUGS */ @@ -2271,15 +2270,16 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT; } else if ((signed long) (jiffies - tape->dsc_timeout) > 0) { printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name); - if (rq->cmd == IDETAPE_PC_RQ2) + if (rq->cmd == IDETAPE_PC_RQ2) { idetape_media_access_finished (drive); - else - ide_do_reset (drive); - return; + return ide_stopped; + } else { + return ide_do_reset (drive); + } } else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD) tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW; idetape_postpone_request (drive); - return; + return ide_stopped; } switch (rq->cmd) { case IDETAPE_READ_RQ: @@ -2294,20 +2294,20 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned rq->cmd = IDETAPE_WRITE_RQ; rq->errors = IDETAPE_ERROR_EOD; idetape_end_request (1, HWGROUP(drive)); - return; + return ide_stopped; case IDETAPE_PC_RQ1: pc=(idetape_pc_t *) rq->buffer; rq->cmd = IDETAPE_PC_RQ2; break; case IDETAPE_PC_RQ2: idetape_media_access_finished (drive); - return; + return ide_stopped; default: printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n"); idetape_end_request (0,HWGROUP (drive)); - return; + return ide_stopped; } - idetape_issue_packet_command (drive, pc); + return idetape_issue_packet_command (drive, pc); } /* diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 0f3e41fed..0222f8a0c 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 6.20 July 10, 1999 + * linux/drivers/block/ide.c Version 6.21 November 9, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -106,15 +106,18 @@ * ATA-66 compliant, but have yet to determine a method * of verification of the 80c cable presence. * Specifically Promise's PDC20262 chipset. + * Version 6.21 Fixing/Fixed SMP spinlock issue with insight from an old + * hat that clarified original low level driver design. * * Some additional driver compile-time options are in ./include/linux/ide.h * * To do, in likely order of completion: * - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f -*/ + * + */ -#define REVISION "Revision: 6.20" -#define VERSION "Id: ide.c 6.20 1999/07/10" +#define REVISION "Revision: 6.21" +#define VERSION "Id: ide.c 6.21 1999/11/10" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -186,7 +189,7 @@ ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */ * For really screwy hardware (hey, at least it *can* be used with Linux) * we can enforce a minimum delay time between successive operations. */ -static unsigned long read_timer(void) +static unsigned long read_timer (void) { unsigned long t, flags; int i; @@ -472,7 +475,7 @@ static inline int drive_is_ready (ide_drive_t *drive) #if 0 udelay(1); /* need to guarantee 400ns since last command was issued */ #endif - if (GET_STAT() & BUSY_STAT) + if (GET_STAT() & BUSY_STAT) /* Note: this may clear a pending IRQ!! */ return 0; /* drive busy: definitely not interrupting */ return 1; /* drive ready: *might* be interrupting */ } @@ -480,7 +483,7 @@ static inline int drive_is_ready (ide_drive_t *drive) /* * This is our end_request replacement function. */ -void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup) +void ide_end_request (byte uptodate, ide_hwgroup_t *hwgroup) { struct request *rq; unsigned long flags; @@ -490,8 +493,8 @@ void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup) if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) { add_blkdev_randomness(MAJOR(rq->rq_dev)); - hwgroup->drive->queue = rq->next; - blk_dev[MAJOR(rq->rq_dev)].current_request = NULL; + hwgroup->drive->queue.current_request = rq->next; + blk_dev[MAJOR(rq->rq_dev)].request_queue.current_request = NULL; hwgroup->rq = NULL; end_that_request_last(rq); } @@ -511,18 +514,16 @@ void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned long flags; ide_hwgroup_t *hwgroup = HWGROUP(drive); - spin_lock_irqsave(&hwgroup->spinlock, flags); -#ifdef DEBUG + spin_lock_irqsave(&io_request_lock, flags); if (hwgroup->handler != NULL) { printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n", drive->name, hwgroup->handler, handler); } -#endif hwgroup->handler = handler; hwgroup->expiry = expiry; hwgroup->timer.expires = jiffies + timeout; - add_timer(&(hwgroup->timer)); - spin_unlock_irqrestore(&hwgroup->spinlock, flags); + add_timer(&hwgroup->timer); + spin_unlock_irqrestore(&io_request_lock, flags); } /* @@ -557,7 +558,7 @@ void ide_geninit (struct gendisk *gd) } } -static void do_reset1 (ide_drive_t *, int); /* needed below */ +static ide_startstop_t do_reset1 (ide_drive_t *, int); /* needed below */ /* * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms @@ -565,7 +566,7 @@ static void do_reset1 (ide_drive_t *, int); /* needed below */ * and we have not yet hit our maximum waiting time, then the timer is restarted * for another 50ms. */ -static void atapi_reset_pollfunc (ide_drive_t *drive) +static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); byte stat; @@ -578,14 +579,14 @@ static void atapi_reset_pollfunc (ide_drive_t *drive) } else { if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL); - return; /* continue polling */ + return ide_started; /* continue polling */ } hwgroup->poll_timeout = 0; /* end of polling */ printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat); - do_reset1 (drive, 1); /* do it the old fashioned way */ - return; + return do_reset1 (drive, 1); /* do it the old fashioned way */ } hwgroup->poll_timeout = 0; /* done polling */ + return ide_stopped; } /* @@ -594,7 +595,7 @@ static void atapi_reset_pollfunc (ide_drive_t *drive) * and we have not yet hit our maximum waiting time, then the timer is restarted * for another 50ms. */ -static void reset_pollfunc (ide_drive_t *drive) +static ide_startstop_t reset_pollfunc (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); ide_hwif_t *hwif = HWIF(drive); @@ -603,7 +604,7 @@ static void reset_pollfunc (ide_drive_t *drive) if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) { if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL); - return; /* continue polling */ + return ide_started; /* continue polling */ } printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp); } else { @@ -635,6 +636,7 @@ static void reset_pollfunc (ide_drive_t *drive) } } hwgroup->poll_timeout = 0; /* done polling */ + return ide_stopped; } static void pre_reset (ide_drive_t *drive) @@ -664,7 +666,7 @@ static void pre_reset (ide_drive_t *drive) * (up to 30 seconds worstcase). So, instead of busy-waiting here for it, * we set a timer to poll at 50ms intervals. */ -static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) +static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) { unsigned int unit; unsigned long flags; @@ -683,7 +685,7 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL); __restore_flags (flags); /* local CPU only */ - return; + return ide_started; } /* @@ -696,7 +698,7 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) #if OK_TO_RESET_CONTROLLER if (!IDE_CONTROL_REG) { __restore_flags(flags); - return; + return ide_stopped; } /* * Note that we also set nIEN while resetting the device, @@ -724,14 +726,15 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) #endif /* OK_TO_RESET_CONTROLLER */ __restore_flags (flags); /* local CPU only */ + return ide_started; } /* * ide_do_reset() is the entry point to the drive/interface reset code. */ -void ide_do_reset (ide_drive_t *drive) +ide_startstop_t ide_do_reset (ide_drive_t *drive) { - do_reset1 (drive, 0); + return do_reset1 (drive, 0); } /* @@ -752,16 +755,13 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err) } } spin_lock_irqsave(&io_request_lock, flags); - drive->queue = rq->next; - blk_dev[MAJOR(rq->rq_dev)].current_request = NULL; + drive->queue.current_request = rq->next; + blk_dev[MAJOR(rq->rq_dev)].request_queue.current_request = NULL; HWGROUP(drive)->rq = NULL; rq->rq_status = RQ_INACTIVE; spin_unlock_irqrestore(&io_request_lock, flags); - save_flags(flags); /* all CPUs; overkill? */ - cli(); /* all CPUs; overkill? */ if (rq->sem != NULL) up(rq->sem); /* inform originator that rq has been serviced */ - restore_flags(flags); /* all CPUs; overkill? */ } /* @@ -854,19 +854,19 @@ static void try_to_flush_leftover_data (ide_drive_t *drive) /* * ide_error() takes action based on the error returned by the drive. */ -void ide_error (ide_drive_t *drive, const char *msg, byte stat) +ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat) { struct request *rq; byte err; err = ide_dump_status(drive, msg, stat); if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) - return; + return ide_stopped; /* retry only "normal" I/O: */ if (rq->cmd == IDE_DRIVE_CMD) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); - return; + return ide_stopped; } if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */ rq->errors |= ERROR_RESET; @@ -875,7 +875,7 @@ void ide_error (ide_drive_t *drive, const char *msg, byte stat) /* err has different meaning on cdrom and tape */ if (err == ABRT_ERR) { if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY) - return; /* some newer drives don't support WIN_SPECIFY */ + return ide_stopped; /* some newer drives don't support WIN_SPECIFY */ } else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) ; /* UDMA crc error -- just retry the operation */ else if (err & (BBD_ERR | ECC_ERR)) /* retries won't help these */ @@ -897,19 +897,20 @@ void ide_error (ide_drive_t *drive, const char *msg, byte stat) } else { if ((rq->errors & ERROR_RESET) == ERROR_RESET) { ++rq->errors; - ide_do_reset(drive); - return; - } else if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) + return ide_do_reset(drive); + } + if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) drive->special.b.recalibrate = 1; ++rq->errors; } + return ide_stopped; } /* * Issue a simple drive command * The drive must be selected beforehand. */ -void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) +void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) { ide_set_handler (drive, handler, WAIT_CMD, NULL); if (IDE_CONTROL_REG) @@ -921,7 +922,7 @@ void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) /* * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. */ -static void drive_cmd_intr (ide_drive_t *drive) +static ide_startstop_t drive_cmd_intr (ide_drive_t *drive) { struct request *rq = HWGROUP(drive)->rq; byte *args = (byte *) rq->buffer; @@ -938,17 +939,17 @@ static void drive_cmd_intr (ide_drive_t *drive) udelay(100); } - if (OK_STAT(stat, READY_STAT, BAD_STAT)) - ide_end_drive_cmd (drive, stat, GET_ERR()); - else - ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ + if (!OK_STAT(stat, READY_STAT, BAD_STAT)) + return ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ + ide_end_drive_cmd (drive, stat, GET_ERR()); + return ide_stopped; } /* * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT * commands to a drive. It used to do much more, but has been scaled back. */ -static inline void do_special (ide_drive_t *drive) +static ide_startstop_t do_special (ide_drive_t *drive) { special_t *s = &drive->special; @@ -961,11 +962,12 @@ static inline void do_special (ide_drive_t *drive) if (tuneproc != NULL) tuneproc(drive, drive->tune_req); } else if (drive->driver != NULL) { - DRIVER(drive)->special(drive); + return DRIVER(drive)->special(drive); } else if (s->all) { printk("%s: bad special flag: 0x%02x\n", drive->name, s->all); s->all = 0; } + return ide_stopped; } /* @@ -979,12 +981,11 @@ static inline void do_special (ide_drive_t *drive) * setting a timer to wake up at half second intervals thereafter, * until timeout is achieved, before timing out. */ -int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout) -{ +int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) { byte stat; int i; unsigned long flags; - + udelay(1); /* spec allows drive 400ns to assert "BUSY" */ if ((stat = GET_STAT()) & BUSY_STAT) { __save_flags(flags); /* local CPU only */ @@ -993,7 +994,7 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou while ((stat = GET_STAT()) & BUSY_STAT) { if (0 < (signed long)(jiffies - timeout)) { __restore_flags(flags); /* local CPU only */ - ide_error(drive, "status timeout", stat); + *startstop = ide_error(drive, "status timeout", stat); return 1; } } @@ -1011,7 +1012,7 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou if (OK_STAT((stat = GET_STAT()), good, bad)) return 0; } - ide_error(drive, "status error", stat); + *startstop = ide_error(drive, "status error", stat); return 1; } @@ -1019,7 +1020,7 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou * execute_drive_cmd() issues a special drive command, * usually initiated by ioctl() from the external hdparm program. */ -static void execute_drive_cmd (ide_drive_t *drive, struct request *rq) +static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) { byte *args = rq->buffer; if (args) { @@ -1033,11 +1034,11 @@ static void execute_drive_cmd (ide_drive_t *drive, struct request *rq) OUT_BYTE(args[2],IDE_FEATURE_REG); OUT_BYTE(args[1],IDE_SECTOR_REG); ide_cmd(drive, args[0], args[3], &drive_cmd_intr); - return; + return ide_started; } OUT_BYTE(args[2],IDE_FEATURE_REG); ide_cmd(drive, args[0], args[1], &drive_cmd_intr); - return; + return ide_started; } else { /* * NULL is actually a valid way of waiting for @@ -1047,21 +1048,21 @@ static void execute_drive_cmd (ide_drive_t *drive, struct request *rq) printk("%s: DRIVE_CMD (null)\n", drive->name); #endif ide_end_drive_cmd(drive, GET_STAT(), GET_ERR()); - return; + return ide_stopped; } } /* * start_request() initiates handling of a new I/O request */ -static inline void start_request (ide_drive_t *drive) +static ide_startstop_t start_request (ide_drive_t *drive) { + ide_startstop_t startstop; unsigned long block, blockend; - struct request *rq = drive->queue; + struct request *rq = drive->queue.current_request; unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS; ide_hwif_t *hwif = HWIF(drive); - ide__sti(); /* local CPU only */ #ifdef DEBUG printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq); #endif @@ -1094,29 +1095,27 @@ static inline void start_request (ide_drive_t *drive) #endif SELECT_DRIVE(hwif, drive); - if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { + if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { printk("%s: drive not ready for command\n", drive->name); - return; + return startstop; } if (!drive->special.all) { if (rq->cmd == IDE_DRIVE_CMD) { - execute_drive_cmd(drive, rq); - return; + return execute_drive_cmd(drive, rq); } if (drive->driver != NULL) { - DRIVER(drive)->do_request(drive, rq, block); - return; + return (DRIVER(drive)->do_request(drive, rq, block)); } printk("%s: media type %d not supported\n", drive->name, drive->media); goto kill_rq; } - do_special(drive); - return; + return do_special(drive); kill_rq: if (drive->driver != NULL) DRIVER(drive)->end_request(0, HWGROUP(drive)); else ide_end_request(0, HWGROUP(drive)); + return ide_stopped; } /* @@ -1143,13 +1142,13 @@ repeat: best = NULL; drive = hwgroup->drive; do { - if (drive->queue && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) { + if (drive->queue.current_request && (!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) + if( !bdev->request_queue.plugged ) best = drive; } } @@ -1177,280 +1176,272 @@ repeat: } /* - * Caller must have already acquired spinlock using *spinflags + * Issue a new request to a drive from hwgroup + * Caller must have already done spin_lock_irqsave(&io_request_lock, ..); + * + * A hwgroup is a serialized group of IDE interfaces. Usually there is + * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640) + * may have both interfaces in a single hwgroup to "serialize" access. + * Or possibly multiple ISA interfaces can share a common IRQ by being grouped + * together into one hwgroup for serialized access. + * + * Note also that several hwgroups can end up sharing a single IRQ, + * possibly along with many other devices. This is especially common in + * PCI-based systems with off-board IDE controller cards. + * + * The IDE driver uses the single global io_request_lock spinlock to protect + * access to the request queues, and to protect the hwgroup->busy flag. + * + * The first thread into the driver for a particular hwgroup sets the + * hwgroup->busy flag to indicate that this hwgroup is now active, + * and then initiates processing of the top request from the request queue. + * + * Other threads attempting entry notice the busy setting, and will simply + * queue their new requests and exit immediately. Note that hwgroup->busy + * remains set even when the driver is merely awaiting the next interrupt. + * Thus, the meaning is "this hwgroup is busy processing a request". + * + * When processing of a request completes, the completing thread or IRQ-handler + * will start the next request from the queue. If no more work remains, + * the driver will clear the hwgroup->busy flag and exit. + * + * The io_request_lock (spinlock) is used to protect all access to the + * hwgroup->busy flag, but is otherwise not needed for most processing in + * the driver. This makes the driver much more friendlier to shared IRQs + * than previous designs, while remaining 100% (?) SMP safe and capable. */ -static void ide_do_request (ide_hwgroup_t *hwgroup, unsigned long *hwgroup_flags, int masked_irq) +static void ide_do_request (ide_hwgroup_t *hwgroup) { struct blk_dev_struct *bdev; ide_drive_t *drive; ide_hwif_t *hwif; - unsigned long io_flags; + ide_startstop_t startstop; + + ide_get_lock(&ide_lock, ide_intr, hwgroup); /* for atari only: POSSIBLY BROKEN HERE(?) */ - hwgroup->busy = 1; - while (hwgroup->handler == NULL) { - spin_lock_irqsave(&io_request_lock, io_flags); + while (!hwgroup->busy) { + hwgroup->busy = 1; 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( !bdev->request_queue.plugged ) + bdev->request_queue.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); - spin_unlock_irqrestore(&io_request_lock, io_flags); if (sleep) { + /* + * Take a short snooze, and then wake up this hwgroup again. + * This gives other hwgroups on the same a chance to + * play fairly with us, just in case there are big differences + * in relative throughputs.. don't want to hog the cpu too much. + */ if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) sleep = jiffies + WAIT_MIN_SLEEP; #if 1 if (hwgroup->timer.next || hwgroup->timer.prev) printk("ide_set_handler: timer already active\n"); #endif + hwgroup->sleeping = 1; /* so that ide_timer_expiry knows what to do */ mod_timer(&hwgroup->timer, sleep); + /* we purposely leave hwgroup->busy==1 while sleeping */ } 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; } - hwgroup->busy = 0; - return; + return; /* no more work for this hwgroup (for now) */ } hwif = HWIF(drive); - if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && - hwif->io_ports[IDE_CONTROL_OFFSET]) + if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) { /* 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 */ + if( bdev->request_queue.plugged ) /* FIXME: paranoia */ printk("%s: Huh? nuking plugged queue\n", drive->name); - bdev->current_request = hwgroup->rq = drive->queue; - spin_unlock_irqrestore(&io_request_lock, io_flags); - -#if 0 - if (hwif->irq != masked_irq) - disable_irq_nosync(hwif->irq); - spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags); - start_request(drive); - spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags); - if (hwif->irq != masked_irq) - enable_irq(hwif->irq); -#else - - if (masked_irq && hwif->irq != masked_irq) { - printk("%s: (disable_irq) %smasked_irq %d\n", - drive->name, - masked_irq ? "" : "un_", hwif->irq); - -#if 0 - disable_irq(hwif->irq); -#else - disable_irq_nosync(hwif->irq); -#endif - } - spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags); - start_request(drive); - spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags); - if (masked_irq && hwif->irq != masked_irq) { - printk("%s: (enable_irq) %smasked_irq %d\n", - drive->name, - masked_irq ? "" : "un_", hwif->irq); - enable_irq(hwif->irq); - } -#endif + bdev->request_queue.current_request = hwgroup->rq = drive->queue.current_request; + spin_unlock(&io_request_lock); + if (!hwif->serialized) /* play it safe with buggy hardware */ + ide__sti(); + startstop = start_request(drive); + spin_lock_irq(&io_request_lock); + if (startstop == ide_stopped) + hwgroup->busy = 0; } } /* * ide_get_queue() returns the queue which corresponds to a given device. */ -struct request **ide_get_queue (kdev_t dev) +request_queue_t *ide_get_queue (kdev_t dev) { 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 claiming hwgroup->busy. - */ -static void do_hwgroup_request (ide_hwgroup_t *hwgroup) +void do_ide0_request (request_queue_t *q) { - unsigned long flags; - - spin_lock_irqsave(&hwgroup->spinlock, flags); - if (hwgroup->busy) { - spin_unlock_irqrestore(&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); - spin_unlock_irqrestore(&hwgroup->spinlock, flags); -} - -/* - * ll_rw_blk.c invokes our do_idex_request() function - * 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) -{ - spin_unlock(&io_request_lock); - do_hwgroup_request (hwgroup); - spin_lock_irq(&io_request_lock); -} - -void do_ide0_request (void) -{ - unlock_do_hwgroup_request (ide_hwifs[0].hwgroup); + ide_do_request (ide_hwifs[0].hwgroup); } #if MAX_HWIFS > 1 -void do_ide1_request (void) +void do_ide1_request (request_queue_t *q) { - unlock_do_hwgroup_request (ide_hwifs[1].hwgroup); + ide_do_request (ide_hwifs[1].hwgroup); } #endif /* MAX_HWIFS > 1 */ #if MAX_HWIFS > 2 -void do_ide2_request (void) +void do_ide2_request (request_queue_t *q) { - unlock_do_hwgroup_request (ide_hwifs[2].hwgroup); + ide_do_request (ide_hwifs[2].hwgroup); } #endif /* MAX_HWIFS > 2 */ #if MAX_HWIFS > 3 -void do_ide3_request (void) +void do_ide3_request (request_queue_t *q) { - unlock_do_hwgroup_request (ide_hwifs[3].hwgroup); + ide_do_request (ide_hwifs[3].hwgroup); } #endif /* MAX_HWIFS > 3 */ #if MAX_HWIFS > 4 -void do_ide4_request (void) +void do_ide4_request (request_queue_t *q) { - unlock_do_hwgroup_request (ide_hwifs[4].hwgroup); + ide_do_request (ide_hwifs[4].hwgroup); } #endif /* MAX_HWIFS > 4 */ #if MAX_HWIFS > 5 -void do_ide5_request (void) +void do_ide5_request (request_queue_t *q) { - unlock_do_hwgroup_request (ide_hwifs[5].hwgroup); + ide_do_request (ide_hwifs[5].hwgroup); } #endif /* MAX_HWIFS > 5 */ #if MAX_HWIFS > 6 -void do_ide6_request (void) +void do_ide6_request (request_queue_t *q) { - unlock_do_hwgroup_request (ide_hwifs[6].hwgroup); + ide_do_request (ide_hwifs[6].hwgroup); } #endif /* MAX_HWIFS > 6 */ #if MAX_HWIFS > 7 -void do_ide7_request (void) +void do_ide7_request (request_queue_t *q) { - unlock_do_hwgroup_request (ide_hwifs[7].hwgroup); + ide_do_request (ide_hwifs[7].hwgroup); } #endif /* MAX_HWIFS > 7 */ #if MAX_HWIFS > 8 -void do_ide8_request (void) +void do_ide8_request (request_queue_t *q) { - unlock_do_hwgroup_request (ide_hwifs[8].hwgroup); + ide_do_request (ide_hwifs[8].hwgroup); } #endif /* MAX_HWIFS > 8 */ #if MAX_HWIFS > 9 -void do_ide9_request (void) +void do_ide9_request (request_queue_t *q) { - unlock_do_hwgroup_request (ide_hwifs[9].hwgroup); + ide_do_request (ide_hwifs[9].hwgroup); } #endif /* MAX_HWIFS > 9 */ -static void start_next_request (ide_hwgroup_t *hwgroup, int masked_irq) -{ - unsigned long flags; - ide_drive_t *drive; - - spin_lock_irqsave(&hwgroup->spinlock, flags); - if (hwgroup->handler != NULL) { - spin_unlock_irqrestore(&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); - spin_unlock_irqrestore(&hwgroup->spinlock, flags); -} - +/* + * ide_timer_expiry() is our timeout function for all drive operations. + * But note that it can also be invoked as a result of a "sleep" operation + * triggered by the mod_timer() call in ide_do_request. + */ void ide_timer_expiry (unsigned long data) { - ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; - ide_drive_t *drive; - ide_handler_t *handler; - ide_expiry_t *expiry; - unsigned long flags; - unsigned long wait; + ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; + ide_handler_t *handler; + ide_expiry_t *expiry; + unsigned long flags; + unsigned long wait; - spin_lock_irqsave(&hwgroup->spinlock, flags); - drive = hwgroup->drive; - if ((handler = hwgroup->handler) == NULL) { - spin_unlock_irqrestore(&hwgroup->spinlock, flags); - do_hwgroup_request(hwgroup); - return; - } - - hwgroup->busy = 1; /* should already be "1" */ + spin_lock_irqsave(&io_request_lock, flags); + del_timer(&hwgroup->timer); - if ((expiry = hwgroup->expiry) != NULL) { - /* continue */ - if ((wait = expiry(drive)) != 0) { - /* reset timer */ - hwgroup->timer.expires = jiffies + wait; - add_timer(&(hwgroup->timer)); - spin_unlock_irqrestore(&hwgroup->spinlock, flags); - return; + if ((handler = hwgroup->handler) == NULL) { + /* + * Either a marginal timeout occured + * (got the interrupt just as timer expired), + * or we were "sleeping" to give other devices a chance. + * Either way, we don't really want to complain about anything. + */ + if (hwgroup->sleeping) { + hwgroup->sleeping = 0; + hwgroup->busy = 0; } - } - - hwgroup->handler = NULL; - - if (hwgroup->poll_timeout != 0) { - spin_unlock_irqrestore(&hwgroup->spinlock, flags); - handler(drive); - } else if (drive_is_ready(drive)) { - printk("%s: lost interrupt\n", drive->name); - (void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive); - spin_unlock_irqrestore(&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); - /* - * need something here for HPT34X.......AMH - * irq timeout: status=0x58 { DriveReady SeekComplete DataRequest } - */ - (void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive); + ide_drive_t *drive = hwgroup->drive; + hwgroup->handler = NULL; + if (!drive) { + printk("ide_timer_expiry: hwgroup->drive was NULL\n"); + } else { + ide_hwif_t *hwif; + ide_startstop_t startstop; + if (!hwgroup->busy) { + hwgroup->busy = 1; /* paranoia */ + printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name); + } + if ((expiry = hwgroup->expiry) != NULL) { + /* continue */ + if ((wait = expiry(drive)) != 0) { + /* reset timer */ + hwgroup->timer.expires = jiffies + wait; + add_timer(&hwgroup->timer); + spin_unlock_irqrestore(&io_request_lock, flags); + return; + } + } + /* + * We need to simulate a real interrupt when invoking + * the handler() function, which means we need to globally + * mask the specific IRQ: + */ + spin_unlock(&io_request_lock); + hwif = HWIF(drive); + disable_irq(hwif->irq); + __cli(); /* local CPU only, as if we were handling an interrupt */ + if (hwgroup->poll_timeout != 0) { + startstop = handler(drive); + } else if (drive_is_ready(drive)) { + if (drive->waiting_for_dma) + (void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive); + (void)ide_ack_intr(hwif); + printk("%s: lost interrupt\n", drive->name); + startstop = 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); + (void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive); + } + startstop = ide_error(drive, "irq timeout", GET_STAT()); + } + set_recovery_timer(hwif); + drive->service_time = jiffies - drive->service_start; + enable_irq(hwif->irq); + spin_lock_irq(&io_request_lock); + if (startstop == ide_stopped) + hwgroup->busy = 0; } - spin_unlock_irqrestore(&hwgroup->spinlock, flags); - ide_error(drive, "irq timeout", GET_STAT()); } - start_next_request(hwgroup, 0); + ide_do_request(hwgroup); + spin_unlock_irqrestore(&io_request_lock, flags); } /* @@ -1500,6 +1491,7 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) } } while ((hwif = hwif->next) != hwgroup->hwif); } + /* * entry point for all interrupts, caller does __cli() for us */ @@ -1510,13 +1502,13 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) ide_hwif_t *hwif; ide_drive_t *drive; ide_handler_t *handler; + ide_startstop_t startstop; - __cli(); /* local CPU only */ - spin_lock_irqsave(&hwgroup->spinlock, flags); + spin_lock_irqsave(&io_request_lock, flags); hwif = hwgroup->hwif; if (!ide_ack_intr(hwif)) { - spin_unlock_irqrestore(&hwgroup->spinlock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); return; } @@ -1542,29 +1534,72 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) * so we can safely try to do something about it: */ unexpected_intr(irq, hwgroup); +#ifdef CONFIG_BLK_DEV_IDEPCI + } else { + /* + * Whack the status register, just in case we have a leftover pending IRQ. + * + * Unless we are some version of a Promise Ultra66 :: PDC20262. + * We will hang like a rock.... + */ + byte skip_status = ((hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20262) || + (hwif->pci_dev->device == PCI_DEVICE_ID_TTI_HPT366)) ? 1 : 0; + if (!skip_status) + (void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); +#endif /* CONFIG_BLK_DEV_IDEPCI */ } - spin_unlock_irqrestore(&hwgroup->spinlock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); return; } drive = hwgroup->drive; - if (!drive || !drive_is_ready(drive)) { - spin_unlock_irqrestore(&hwgroup->spinlock, flags); + if (!drive) { + /* + * This should NEVER happen, and there isn't much we could do about it here. + */ + spin_unlock_irqrestore(&io_request_lock, flags); return; } + if (!drive_is_ready(drive)) { + /* + * This happens regularly when we share a PCI IRQ with another device. + * Unfortunately, it can also happen with some buggy drives that trigger + * the IRQ before their status register is up to date. Hopefully we have + * enough advance overhead that the latter isn't a problem. + */ + spin_unlock_irqrestore(&io_request_lock, flags); + return; + } + if (!hwgroup->busy) { + hwgroup->busy = 1; /* paranoia */ + printk("%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name); + } hwgroup->handler = NULL; - del_timer(&(hwgroup->timer)); - spin_unlock_irqrestore(&hwgroup->spinlock, flags); + del_timer(&hwgroup->timer); + spin_unlock(&io_request_lock); + if (drive->unmask) ide__sti(); /* local CPU only */ - handler(drive); /* service this interrupt, may set handler for next interrupt */ + startstop = handler(drive); /* service this interrupt, may set handler for next interrupt */ + spin_lock_irq(&io_request_lock); + /* * 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. + * same irq as is currently being serviced here, and Linux + * won't allow another of the same (on any CPU) until we return. */ - start_next_request(hwgroup, hwif->irq); + set_recovery_timer(HWIF(drive)); + drive->service_time = jiffies - drive->service_start; + if (startstop == ide_stopped) { + if (hwgroup->handler == NULL) { /* paranoia */ + hwgroup->busy = 0; + ide_do_request(hwgroup); + } else { + printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name); + } + } + spin_unlock_irqrestore(&io_request_lock, flags); } /* @@ -1649,12 +1684,11 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS); if (action == ide_wait) rq->sem = &sem; - spin_lock_irqsave(&io_request_lock, flags); - cur_rq = drive->queue; + cur_rq = drive->queue.current_request; if (cur_rq == NULL || action == ide_preempt) { rq->next = cur_rq; - drive->queue = rq; + drive->queue.current_request = rq; if (action == ide_preempt) hwgroup->rq = NULL; } else { @@ -1665,13 +1699,14 @@ 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; } + ide_do_request(hwgroup); spin_unlock_irqrestore(&io_request_lock, flags); - do_hwgroup_request(hwgroup); if (action == ide_wait) { - down(&sem); /* wait for it to be serviced */ - rq->sem = NULL; + down(&sem); /* wait for it to be serviced */ + return rq->errors ? -EIO : 0; /* return -EIO if errors */ } - return rq->errors ? -EIO : 0; /* return -EIO if errors */ + return 0; + } /* @@ -1682,7 +1717,7 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio * usage == 1 (we need an open channel to use an ioctl :-), so this * is our limit. */ -int ide_revalidate_disk(kdev_t i_rdev) +int ide_revalidate_disk (kdev_t i_rdev) { ide_drive_t *drive; ide_hwgroup_t *hwgroup; @@ -1694,14 +1729,14 @@ int ide_revalidate_disk(kdev_t i_rdev) major = MAJOR(i_rdev); minor = drive->select.b.unit << PARTN_BITS; hwgroup = HWGROUP(drive); - spin_lock_irqsave(&hwgroup->spinlock, flags); + spin_lock_irqsave(&io_request_lock, flags); if (drive->busy || (drive->usage > 1)) { - spin_unlock_irqrestore(&hwgroup->spinlock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); return -EBUSY; }; drive->busy = 1; MOD_INC_USE_COUNT; - spin_unlock_irqrestore(&hwgroup->spinlock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); for (p = 0; p < (1<<PARTN_BITS); ++p) { if (drive->part[p].nr_sects > 0) { @@ -1767,7 +1802,7 @@ static void ide_init_module (int type) #endif /* CONFIG_KMOD */ } -static int ide_open(struct inode * inode, struct file * filp) +static int ide_open (struct inode * inode, struct file * filp) { ide_drive_t *drive; int rc; @@ -1807,7 +1842,7 @@ static int ide_open(struct inode * inode, struct file * filp) * Releasing a block device means we sync() it, so that it can safely * be forgotten about... */ -static int ide_release(struct inode * inode, struct file * file) +static int ide_release (struct inode * inode, struct file * file) { ide_drive_t *drive; @@ -1821,7 +1856,7 @@ static int ide_release(struct inode * inode, struct file * file) return 0; } -int ide_replace_subdriver(ide_drive_t *drive, const char *driver) +int ide_replace_subdriver (ide_drive_t *drive, const char *driver) { if (!drive->present || drive->busy || drive->usage) goto abort; @@ -1960,7 +1995,7 @@ void ide_unregister (unsigned int index) kfree(blksize_size[hwif->major]); kfree(max_sectors[hwif->major]); kfree(max_readahead[hwif->major]); - blk_dev[hwif->major].request_fn = NULL; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(hwif->major)); blk_dev[hwif->major].data = NULL; blk_dev[hwif->major].queue = NULL; blksize_size[hwif->major] = NULL; @@ -1979,6 +2014,7 @@ void ide_unregister (unsigned int index) init_hwif_data (index); /* restore hwif data to pristine status */ hwif->hwgroup = old_hwif.hwgroup; hwif->tuneproc = old_hwif.tuneproc; + hwif->resetproc = old_hwif.resetproc; hwif->dmaproc = old_hwif.dmaproc; hwif->dma_base = old_hwif.dma_base; hwif->dma_extra = old_hwif.dma_extra; @@ -2089,7 +2125,7 @@ int ide_register (int arg1, int arg2, int irq) return ide_register_hw(&hw, NULL); } -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_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; @@ -2115,7 +2151,7 @@ abort: kfree(setting); } -void ide_remove_setting(ide_drive_t *drive, char *name) +void ide_remove_setting (ide_drive_t *drive, char *name) { ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting; @@ -2128,7 +2164,7 @@ void ide_remove_setting(ide_drive_t *drive, char *name) kfree(setting); } -static ide_settings_t *ide_find_setting_by_ioctl(ide_drive_t *drive, int cmd) +static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd) { ide_settings_t *setting = drive->settings; @@ -2140,7 +2176,7 @@ static ide_settings_t *ide_find_setting_by_ioctl(ide_drive_t *drive, int cmd) return setting; } -ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name) +ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name) { ide_settings_t *setting = drive->settings; @@ -2152,7 +2188,7 @@ ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name) return setting; } -static void auto_remove_settings(ide_drive_t *drive) +static void auto_remove_settings (ide_drive_t *drive) { ide_settings_t *setting; repeat: @@ -2166,13 +2202,13 @@ repeat: } } -int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting) +int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting) { int val = -EINVAL; unsigned long flags; if ((setting->rw & SETTING_READ)) { - spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags); + spin_lock_irqsave(&io_request_lock, flags); switch(setting->data_type) { case TYPE_BYTE: val = *((u8 *) setting->data); @@ -2185,7 +2221,7 @@ int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting) val = *((u32 *) setting->data); break; } - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); } return val; } @@ -2195,20 +2231,29 @@ int ide_spin_wait_hwgroup (ide_drive_t *drive, unsigned long *flags) ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned long timeout = jiffies + (3 * HZ); - spin_lock_irqsave(&hwgroup->spinlock, *flags); + spin_lock_irqsave(&io_request_lock, *flags); while (hwgroup->busy) { - spin_unlock_irqrestore(&hwgroup->spinlock, *flags); - __sti(); /* local CPU only; needed for jiffies */ + unsigned long lflags; + spin_unlock_irqrestore(&io_request_lock, *flags); + __save_flags(lflags); /* local CPU only */ + __sti(); /* local CPU only; needed for jiffies */ if (0 < (signed long)(jiffies - timeout)) { + __restore_flags(lflags); /* local CPU only */ printk("%s: channel busy\n", drive->name); return -EBUSY; } - spin_lock_irqsave(&hwgroup->spinlock, *flags); + __restore_flags(lflags); /* local CPU only */ + spin_lock_irqsave(&io_request_lock, *flags); } return 0; } -int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val) +/* + * FIXME: This should be changed to enqueue a special request + * to the driver to change settings, and then wait on a sema for completion. + * The current scheme of polling is kludgey, though safe enough. + */ +int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val) { unsigned long flags; int i; @@ -2240,7 +2285,7 @@ int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val) *p = val; break; } - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); return 0; } @@ -2254,7 +2299,7 @@ static int set_io_32bit(ide_drive_t *drive, int arg) return 0; } -static int set_using_dma(ide_drive_t *drive, int arg) +static int set_using_dma (ide_drive_t *drive, int arg) { if (!drive->driver || !DRIVER(drive)->supports_dma) return -EPERM; @@ -2265,7 +2310,7 @@ static int set_using_dma(ide_drive_t *drive, int arg) return 0; } -static int set_pio_mode(ide_drive_t *drive, int arg) +static int set_pio_mode (ide_drive_t *drive, int arg) { struct request rq; @@ -2280,7 +2325,7 @@ static int set_pio_mode(ide_drive_t *drive, int arg) return 0; } -void ide_add_generic_settings(ide_drive_t *drive) +void ide_add_generic_settings (ide_drive_t *drive) { /* * drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function @@ -2325,136 +2370,6 @@ void ide_delay_50ms (void) while (0 < (signed long)(timeout - jiffies)); } -int ide_config_drive_speed (ide_drive_t *drive, byte speed) -{ - struct hd_driveid *id = drive->id; - unsigned long flags; - int err; - - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ - - /* - * Don't use ide_wait_cmd here - it will - * attempt to set_geometry and recalibrate, - * but for some reason these don't work at - * this point (lost interrupt). - */ - SELECT_DRIVE(HWIF(drive), drive); - if (IDE_CONTROL_REG) - OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); - OUT_BYTE(speed, IDE_NSECTOR_REG); - OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); - OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); - - err = ide_wait_stat(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD); - -#if 0 - if (IDE_CONTROL_REG) - OUT_BYTE(drive->ctl, IDE_CONTROL_REG); -#endif - - __restore_flags(flags); /* local CPU only */ - - switch(speed) { - case XFER_UDMA_4: - if (!((id->dma_ultra >> 8) & 16)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x1010; - } - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - break; - case XFER_UDMA_3: - if (!((id->dma_ultra >> 8) & 8)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0808; - } - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - break; - case XFER_UDMA_2: - if (!((id->dma_ultra >> 8) & 4)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0404; - } - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - break; - case XFER_UDMA_1: - if (!((id->dma_ultra >> 8) & 2)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0202; - } - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - break; - case XFER_UDMA_0: - if (!((id->dma_ultra >> 8) & 1)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0101; - } - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - break; - case XFER_MW_DMA_2: - drive->id->dma_ultra &= ~0xFF00; - if (!((id->dma_mword >> 8) & 4)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0404; - } - drive->id->dma_1word &= ~0x0F00; - break; - case XFER_MW_DMA_1: - drive->id->dma_ultra &= ~0xFF00; - if (!((id->dma_mword >> 8) & 2)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0202; - } - drive->id->dma_1word &= ~0x0F00; - break; - case XFER_MW_DMA_0: - drive->id->dma_ultra &= ~0xFF00; - if (!((id->dma_mword >> 8) & 1)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0101; - } - drive->id->dma_1word &= ~0x0F00; - break; - case XFER_SW_DMA_2: - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_mword &= ~0x0F00; - if (!((id->dma_1word >> 8) & 4)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0404; - } - break; - case XFER_SW_DMA_1: - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_mword &= ~0x0F00; - if (!((id->dma_1word >> 8) & 2)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0202; - } - break; - case XFER_SW_DMA_0: - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_mword &= ~0x0F00; - if (!((id->dma_1word >> 8) & 1)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0101; - } - break; - default: - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - break; - } - - return(err); -} - static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -2509,8 +2424,7 @@ static int ide_ioctl (struct inode *inode, struct file *file, return -EINVAL; if (drive->id == NULL) return -ENOMSG; - if (copy_to_user((char *)arg, (char *)drive->id, - (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142)) + if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142)) return -EFAULT; return 0; @@ -2537,28 +2451,16 @@ static int ide_ioctl (struct inode *inode, struct file *file, return -ENOMEM; memcpy(argbuf, args, 4); } - if ((((byte *)arg)[0] == WIN_SETFEATURES) && - (((byte *)arg)[1] > 66) && - (((byte *)arg)[2] == 3)) { - if (!HWIF(drive)->udma_four) { - printk("%s: Speed warnings UDMA 3/4 is not functional.\n", HWIF(drive)->name); - goto abort; - } - if ((drive->id->word93 & 0x2000) == 0) { - printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name); - goto abort; - } - } + if (ide_ata66_check(drive, args[0], args[1], args[2])) + goto abort; + err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf); - if (!err && - (((byte *)arg)[0] == WIN_SETFEATURES) && - (((byte *)arg)[1] >= 16) && - (((byte *)arg)[2] == 3) && - (drive->id->dma_ultra || - drive->id->dma_mword || - drive->id->dma_1word)) { - - /* + + if (!err && set_transfer(drive, args[0], args[1], args[2])) { + +#if 1 + ide_driveid_update(drive); +#else /* * Re-read drive->id for possible DMA mode * change (copied from ide-probe.c) */ @@ -2602,6 +2504,7 @@ static int ide_ioctl (struct inode *inode, struct file *file, #endif kfree(id); } +#endif } abort: if (copy_to_user((void *)arg, argbuf, argsize)) @@ -2694,32 +2597,6 @@ void ide_fixstring (byte *s, const int bytecount, const int byteswap) } /* - * - */ -char *ide_xfer_verbose (byte xfer_rate) { - switch(xfer_rate) { - case XFER_UDMA_4: return("UDMA 4"); - case XFER_UDMA_3: return("UDMA 3"); - case XFER_UDMA_2: return("UDMA 2"); - case XFER_UDMA_1: return("UDMA 1"); - case XFER_UDMA_0: return("UDMA 0"); - case XFER_MW_DMA_2: return("MW DMA 2"); - case XFER_MW_DMA_1: return("MW DMA 1"); - case XFER_MW_DMA_0: return("MW DMA 0"); - case XFER_SW_DMA_2: return("SW DMA 2"); - case XFER_SW_DMA_1: return("SW DMA 1"); - case XFER_SW_DMA_0: return("SW DMA 0"); - case XFER_PIO_4: return("PIO 4"); - case XFER_PIO_3: return("PIO 3"); - case XFER_PIO_2: return("PIO 2"); - case XFER_PIO_1: return("PIO 1"); - case XFER_PIO_0: return("PIO 0"); - case XFER_PIO_SLOW: return("PIO SLOW"); - default: return("XFER ERROR"); - } -} - -/* * stridx() returns the offset of c within s, * or -1 if c is '\0' or not found within s. */ @@ -2796,7 +2673,7 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m * "hdx=nowerr" : ignore the WRERR_STAT bit on this drive * "hdx=cdrom" : drive is present, and is a cdrom drive * "hdx=cyl,head,sect" : disk drive is present, with specified geometry - * "hdx=noremap" : do not remap 0->1 even though EZD was detected + * "hdx=noremap" : do not remap 0->1 even though EZD was detected * "hdx=autotune" : driver will attempt to tune interface speed * to the fastest PIO mode supported, * if possible for this drive only. @@ -2809,6 +2686,7 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m * * "hdx=swapdata" : when the drive is a disk, byte swap all data * "hdx=bswap" : same as above.......... + * "hdxlun=xx" : set the drive last logical unit. * "hdx=flash" : allows for more than one ata_flash disk to be * registered. In most cases, only one device * will be present. @@ -2914,6 +2792,19 @@ void __init ide_setup (char *s) strncpy(drive->driver_req, s + 4, 9); goto done; } + /* + * Look for last lun option: "hdxlun=" + */ + if (s[3] == 'l' && s[4] == 'u' && s[5] == 'n') { + if (match_parm(&s[6], NULL, vals, 1) != 1) + goto bad_option; + if (vals[0] >= 0 && vals[0] <= 7) { + drive->last_lun = vals[0]; + drive->forced_lun = 1; + } else + printk(" -- BAD LAST LUN! Expected value from 0 to 7"); + goto done; + } switch (match_parm(&s[3], hd_words, vals, 3)) { case -1: /* "none" */ drive->nobios = 1; /* drop into "noprobe" */ @@ -3198,6 +3089,14 @@ done: } /* + * __setup("ide", ide_setup); + * #ifdef CONFIG_BLK_DEV_VIA82CXXX + * __setup("splitfifo", ide_setup); + * #endif + * __setup("hd", ide_setup); + */ + +/* * probe_for_hwifs() finds/initializes "known" IDE interfaces */ static void __init probe_for_hwifs (void) @@ -3332,9 +3231,10 @@ static int default_cleanup (ide_drive_t *drive) return ide_unregister_subdriver(drive); } -static void default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block) +static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block) { ide_end_request(0, HWGROUP(drive)); + return ide_stopped; } static void default_end_request (byte uptodate, ide_hwgroup_t *hwgroup) @@ -3372,12 +3272,13 @@ static unsigned long default_capacity (ide_drive_t *drive) return 0x7fffffff; /* cdrom or tape */ } -static void default_special (ide_drive_t *drive) +static ide_startstop_t default_special (ide_drive_t *drive) { special_t *s = &drive->special; s->all = 0; drive->mult_req = 0; + return ide_stopped; } static void setup_driver_defaults (ide_drive_t *drive) @@ -3577,7 +3478,6 @@ EXPORT_SYMBOL(ide_revalidate_disk); EXPORT_SYMBOL(ide_cmd); EXPORT_SYMBOL(ide_wait_cmd); EXPORT_SYMBOL(ide_delay_50ms); -EXPORT_SYMBOL(ide_config_drive_speed); EXPORT_SYMBOL(ide_stall_queue); #ifdef CONFIG_PROC_FS EXPORT_SYMBOL(ide_add_proc_entries); diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 5363e04e2..a54f40e00 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -142,14 +142,49 @@ static inline int get_max_segments(kdev_t dev) * NOTE: the device-specific queue() functions * have to be atomic! */ -static inline struct request **get_queue(kdev_t dev) +static inline request_queue_t *get_queue(kdev_t dev) { int major = MAJOR(dev); struct blk_dev_struct *bdev = blk_dev + major; if (bdev->queue) return bdev->queue(dev); - return &blk_dev[major].current_request; + return &blk_dev[major].request_queue; +} + +void blk_cleanup_queue(request_queue_t * q) +{ + memset(q, 0, sizeof(*q)); +} + +void blk_queue_headactive(request_queue_t * q, int active) +{ + q->head_active = active; +} + +void blk_queue_pluggable(request_queue_t * q, int use_plug) +{ + q->use_plug = use_plug; +} + +void blk_init_queue(request_queue_t * q, request_fn_proc * rfn) +{ + q->request_fn = rfn; + q->current_request = NULL; + q->merge_fn = NULL; + q->merge_requests_fn = NULL; + q->plug_tq.sync = 0; + q->plug_tq.routine = &unplug_device; + q->plug_tq.data = q; + q->plugged = 0; + /* + * These booleans describe the queue properties. We set the + * default (and most common) values here. Other drivers can + * use the appropriate functions to alter the queue properties. + * as appropriate. + */ + q->use_plug = 1; + q->head_active = 1; } /* @@ -157,22 +192,18 @@ static inline struct request **get_queue(kdev_t dev) */ void unplug_device(void * data) { - struct blk_dev_struct * dev = (struct blk_dev_struct *) data; - int queue_new_request=0; + request_queue_t * q = (request_queue_t *) data; unsigned long flags; spin_lock_irqsave(&io_request_lock,flags); - if (dev->current_request == &dev->plug) { - struct request * next = dev->plug.next; - dev->current_request = next; - if (next || dev->queue) { - dev->plug.next = NULL; - queue_new_request = 1; + if( q->plugged ) + { + q->plugged = 0; + if( q->current_request != NULL ) + { + (q->request_fn)(q); } } - if (queue_new_request) - (dev->request_fn)(); - spin_unlock_irqrestore(&io_request_lock,flags); } @@ -184,12 +215,13 @@ void unplug_device(void * data) * This is called with interrupts off and no requests on the queue. * (and with the request spinlock aquired) */ -static inline void plug_device(struct blk_dev_struct * dev) +static inline void plug_device(request_queue_t * q) { - if (dev->current_request) + if (q->current_request) return; - dev->current_request = &dev->plug; - queue_task(&dev->plug_tq, &tq_disk); + + q->plugged = 1; + queue_task(&q->plug_tq, &tq_disk); } /* @@ -221,6 +253,7 @@ static inline struct request * get_request(int n, kdev_t dev) prev_found = req; req->rq_status = RQ_ACTIVE; req->rq_dev = dev; + req->special = NULL; return req; } @@ -335,12 +368,11 @@ static inline void drive_stat_acct(struct request *req, * which is important for drive_stat_acct() above. */ -void add_request(struct blk_dev_struct * dev, struct request * req) +static void add_request(request_queue_t * q, struct request * req) { int major = MAJOR(req->rq_dev); - struct request * tmp, **current_request; + struct request * tmp; unsigned long flags; - int queue_new_request = 0; drive_stat_acct(req, req->nr_sectors, 1); req->next = NULL; @@ -349,12 +381,9 @@ void add_request(struct blk_dev_struct * dev, struct request * req) * We use the goto to reduce locking complexity */ spin_lock_irqsave(&io_request_lock,flags); - current_request = get_queue(req->rq_dev); - if (!(tmp = *current_request)) { - *current_request = req; - if (dev->current_request != &dev->plug) - queue_new_request = 1; + if (!(tmp = q->current_request)) { + q->current_request = req; goto out; } for ( ; tmp->next ; tmp = tmp->next) { @@ -372,26 +401,34 @@ void add_request(struct blk_dev_struct * dev, struct request * req) req->next = tmp->next; tmp->next = req; -/* for SCSI devices, call request_fn unconditionally */ - if (scsi_blk_major(major)) - queue_new_request = 1; - if (major >= COMPAQ_SMART2_MAJOR+0 && - major <= COMPAQ_SMART2_MAJOR+7) - queue_new_request = 1; + /* + * FIXME(eric) I don't understand why there is a need for this + * special case code. It clearly doesn't fit any more with + * the new queueing architecture, and it got added in 2.3.10. + * I am leaving this in here until I hear back from the COMPAQ + * people. + */ + if (major >= COMPAQ_SMART2_MAJOR+0 && major <= COMPAQ_SMART2_MAJOR+7) + { + (q->request_fn)(q); + } + if (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) - queue_new_request = 1; + { + (q->request_fn)(q); + } + out: - if (queue_new_request) - (dev->request_fn)(); spin_unlock_irqrestore(&io_request_lock,flags); } /* * Has to be called with the request spinlock aquired */ -static inline void attempt_merge (struct request *req, - int max_sectors, - int max_segments) +static inline void attempt_merge (request_queue_t * q, + struct request *req, + int max_sectors, + int max_segments) { struct request *next = req->next; int total_segments; @@ -407,16 +444,37 @@ static inline void attempt_merge (struct request *req, total_segments--; if (total_segments > max_segments) return; + + if( q->merge_requests_fn != NULL ) + { + /* + * If we are not allowed to merge these requests, then + * return. If we are allowed to merge, then the count + * will have been updated to the appropriate number, + * and we shouldn't do it here too. + */ + if( !(q->merge_requests_fn)(q, req, next) ) + { + return; + } + } + else + { + req->nr_segments = total_segments; + } + req->bhtail->b_reqnext = next->bh; req->bhtail = next->bhtail; req->nr_sectors += next->nr_sectors; - req->nr_segments = total_segments; next->rq_status = RQ_INACTIVE; req->next = next->next; wake_up (&wait_for_request); } -void make_request(int major,int rw, struct buffer_head * bh) +static void __make_request(request_queue_t * q, + int major, + int rw, + struct buffer_head * bh) { unsigned int sector, count; struct request * req; @@ -519,13 +577,20 @@ void make_request(int major,int rw, struct buffer_head * bh) * not to schedule or do something nonatomic */ spin_lock_irqsave(&io_request_lock,flags); - req = *get_queue(bh->b_rdev); + req = q->current_request; if (!req) { /* MD and loop can't handle plugging without deadlocking */ if (major != MD_MAJOR && major != LOOP_MAJOR && - major != DDV_MAJOR && major != NBD_MAJOR) - plug_device(blk_dev + major); /* is atomic */ + major != DDV_MAJOR && major != NBD_MAJOR + && q->use_plug) + plug_device(q); /* is atomic */ } else switch (major) { + /* + * FIXME(eric) - this entire switch statement is going away + * soon, and we will instead key off of q->head_active to decide + * whether the top request in the queue is active on the device + * or not. + */ case IDE0_MAJOR: /* same as HD_MAJOR */ case IDE1_MAJOR: case FLOPPY_MAJOR: @@ -548,7 +613,7 @@ void make_request(int major,int rw, struct buffer_head * bh) * All other drivers need to jump over the first entry, as that * entry may be busy being processed and we thus can't change it. */ - if (req == blk_dev[major].current_request) + if (req == q->current_request) req = req->next; if (!req) break; @@ -592,25 +657,71 @@ void make_request(int major,int rw, struct buffer_head * bh) continue; /* Can we add it to the end of this request? */ if (req->sector + req->nr_sectors == sector) { - if (req->bhtail->b_data + req->bhtail->b_size - != bh->b_data) { - if (req->nr_segments < max_segments) - req->nr_segments++; - else continue; + /* + * The merge_fn is a more advanced way + * of accomplishing the same task. Instead + * of applying a fixed limit of some sort + * we instead define a function which can + * determine whether or not it is safe to + * merge the request or not. + */ + if( q->merge_fn == NULL ) + { + if (req->bhtail->b_data + req->bhtail->b_size + != bh->b_data) { + if (req->nr_segments < max_segments) + req->nr_segments++; + else continue; + } + } + else + { + /* + * See if this queue has rules that + * may suggest that we shouldn't merge + * this + */ + if( !(q->merge_fn)(q, req, bh) ) + { + continue; + } } req->bhtail->b_reqnext = bh; req->bhtail = bh; req->nr_sectors += count; drive_stat_acct(req, count, 0); /* Can we now merge this req with the next? */ - attempt_merge(req, max_sectors, max_segments); + attempt_merge(q, req, max_sectors, max_segments); /* or to the beginning? */ } else if (req->sector - count == sector) { - if (bh->b_data + bh->b_size - != req->bh->b_data) { - if (req->nr_segments < max_segments) - req->nr_segments++; - else continue; + /* + * The merge_fn is a more advanced way + * of accomplishing the same task. Instead + * of applying a fixed limit of some sort + * we instead define a function which can + * determine whether or not it is safe to + * merge the request or not. + */ + if( q->merge_fn == NULL ) + { + if (bh->b_data + bh->b_size + != req->bh->b_data) { + if (req->nr_segments < max_segments) + req->nr_segments++; + else continue; + } + } + else + { + /* + * See if this queue has rules that + * may suggest that we shouldn't merge + * this + */ + if( !(q->merge_fn)(q, req, bh) ) + { + continue; + } } bh->b_reqnext = req->bh; req->bh = bh; @@ -645,20 +756,37 @@ void make_request(int major,int rw, struct buffer_head * bh) req->errors = 0; req->sector = sector; req->nr_sectors = count; - req->nr_segments = 1; req->current_nr_sectors = count; + req->nr_segments = 1; /* Always 1 for a new request. */ req->buffer = bh->b_data; req->sem = NULL; req->bh = bh; req->bhtail = bh; req->next = NULL; - add_request(major+blk_dev,req); + add_request(q, req); return; end_io: bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); } +void make_request(int major,int rw, struct buffer_head * bh) +{ + request_queue_t * q; + unsigned long flags; + + q = get_queue(bh->b_dev); + + __make_request(q, major, rw, bh); + + spin_lock_irqsave(&io_request_lock,flags); + if( !q->plugged ) + (q->request_fn)(q); + spin_unlock_irqrestore(&io_request_lock,flags); +} + + + /* This function can be used to request a number of buffers from a block device. Currently the only restriction is that all buffers must belong to the same device */ @@ -667,13 +795,13 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) { unsigned int major; int correct_size; - struct blk_dev_struct * dev; + request_queue_t * q; + unsigned long flags; int i; - dev = NULL; - if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV) - dev = blk_dev + major; - if (!dev || !dev->request_fn) { + + major = MAJOR(bh[0]->b_dev); + if (!(q = get_queue(bh[0]->b_dev))) { printk(KERN_ERR "ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n", kdevname(bh[0]->b_dev), bh[0]->b_blocknr); @@ -726,8 +854,15 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) continue; } #endif - make_request(MAJOR(bh[i]->b_rdev), rw, bh[i]); + __make_request(q, MAJOR(bh[i]->b_rdev), rw, bh[i]); + } + + spin_lock_irqsave(&io_request_lock,flags); + if( !q->plugged ) + { + (q->request_fn)(q); } + spin_unlock_irqrestore(&io_request_lock,flags); return; sorry: @@ -801,15 +936,8 @@ int __init blk_dev_init(void) struct blk_dev_struct *dev; for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;) { - dev->request_fn = NULL; dev->queue = NULL; - dev->current_request = NULL; - dev->plug.rq_status = RQ_INACTIVE; - dev->plug.cmd = -1; - dev->plug.next = NULL; - dev->plug_tq.sync = 0; - dev->plug_tq.routine = &unplug_device; - dev->plug_tq.data = dev; + blk_init_queue(&dev->request_queue, NULL); } req = all_requests + NR_REQUEST; @@ -926,3 +1054,6 @@ int __init blk_dev_init(void) EXPORT_SYMBOL(io_request_lock); EXPORT_SYMBOL(end_that_request_first); EXPORT_SYMBOL(end_that_request_last); +EXPORT_SYMBOL(blk_init_queue); +EXPORT_SYMBOL(blk_cleanup_queue); +EXPORT_SYMBOL(blk_queue_headactive); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index cace2226c..a950172ff 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -164,7 +164,7 @@ static void figure_loop_size(struct loop_device *lo) loop_sizes[lo->lo_number] = size; } -static void do_lo_request(void) +static void do_lo_request(request_queue_t * q) { int real_block, block, offset, len, blksize, size; char *dest_addr; @@ -425,7 +425,7 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg) lo->lo_flags |= LO_FLAGS_READ_ONLY; set_device_ro(dev, 1); } else { - invalidate_inode_pages (inode); + vmtruncate (inode, 0); set_device_ro(dev, 0); } @@ -754,7 +754,7 @@ int __init loop_init(void) return -ENOMEM; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); for (i=0; i < max_loop; i++) { memset(&loop_dev[i], 0, sizeof(struct loop_device)); loop_dev[i].lo_number = i; diff --git a/drivers/block/md.c b/drivers/block/md.c index 4dedb8671..b525ef2e9 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -761,7 +761,7 @@ int md_make_request (int minor, int rw, struct buffer_head * bh) } } -static void do_md_request (void) +static void do_md_request (request_queue_t * q) { printk ("Got md request, not good..."); return; @@ -1176,98 +1176,85 @@ void mdsyncd (void *data) #ifdef CONFIG_MD_BOOT struct { - int set; - int ints[100]; - char str[100]; + unsigned long set; + int pers[MAX_MD_DEV]; + kdev_t devices[MAX_MD_DEV][MAX_REAL]; } md_setup_args __initdata = { - 0,{0},{0} + 0,{0},{{0}} }; -/* called from init/main.c */ -void __init md_setup(char *str,int *ints) -{ - int i; - for(i=0;i<=ints[0];i++) { - md_setup_args.ints[i] = ints[i]; - strcpy(md_setup_args.str, str); -/* printk ("md: ints[%d]=%d.\n", i, ints[i]);*/ - } - md_setup_args.set=1; - return; -} - -void __init do_md_setup(char *str,int *ints) +/* + * Parse the command-line parameters given our kernel, but do not + * actually try to invoke the MD device now; that is handled by + * md_setup_drive after the low-level disk drivers have initialised. + * + * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which + * assigns the task of parsing integer arguments to the + * invoked program now). Added ability to initialise all + * the MD devices (by specifying multiple "md=" lines) + * instead of just one. -- KTK + */ +int __init md_setup(char *str) { - int minor, pers, factor, fault; - kdev_t dev; - int i=1; - - if(ints[0] < 4) { - printk ("md: Too few Arguments (%d).\n", ints[0]); - return; - } - - minor=ints[i++]; - - if (minor >= MAX_MD_DEV) { + int minor, level, factor, fault, i; + kdev_t device; + char *devnames, *pername; + + if(get_option(&str, &minor) != 2 || /* MD Number */ + get_option(&str, &level) != 2 || /* RAID Personality */ + get_option(&str, &factor) != 2 || /* Chunk Size */ + get_option(&str, &fault) != 2) { + printk("md: Too few arguments supplied to md=.\n"); + return 0; + } else if (minor >= MAX_MD_DEV) { printk ("md: Minor device number too high.\n"); - return; + return 0; + } else if (md_setup_args.set & (1 << minor)) { + printk ("md: Warning - md=%d,... has been specified twice;\n" + " will discard the first definition.\n", minor); } - - pers = 0; - - switch(ints[i++]) { /* Raidlevel */ - case -1: + switch(level) { #ifdef CONFIG_MD_LINEAR - pers = LINEAR; - printk ("md: Setting up md%d as linear device.\n",minor); -#else - printk ("md: Linear mode not configured." - "Recompile the kernel with linear mode enabled!\n"); -#endif + case -1: + level = LINEAR; + pername = "linear"; break; - case 0: - pers = STRIPED; -#ifdef CONFIG_MD_STRIPED - printk ("md: Setting up md%d as a striped device.\n",minor); -#else - printk ("md: Striped mode not configured." - "Recompile the kernel with striped mode enabled!\n"); #endif +#ifdef CONFIG_MD_STRIPED + case 0: + level = STRIPED; + pername = "striped"; break; -/* not supported yet - case 1: - pers = RAID1; - printk ("md: Setting up md%d as a raid1 device.\n",minor); - break; - case 5: - pers = RAID5; - printk ("md: Setting up md%d as a raid5 device.\n",minor); - break; -*/ - default: - printk ("md: Unknown or not supported raid level %d.\n", ints[--i]); - return; +#endif + default: + printk ("md: The kernel has not been configured for raid%d" + " support!\n", level); + return 0; } - - if(pers) { - - factor=ints[i++]; /* Chunksize */ - fault =ints[i++]; /* Faultlevel */ - - pers=pers | factor | (fault << FAULT_SHIFT); - - while( str && (dev = name_to_kdev_t(str))) { - do_md_add (minor, dev); - if((str = strchr (str, ',')) != NULL) - str++; - } - - do_md_run (minor, pers); - printk ("md: Loading md%d.\n",minor); + devnames = str; + for (i = 0; str; i++) { + if ((device = name_to_kdev_t(str))) { + md_setup_args.devices[minor][i] = device; + } else { + printk ("md: Unknown device name, %s.\n", str); + return 0; + } + if ((str = strchr(str, ',')) != NULL) + str++; } - + if (!i) { + printk ("md: No devices specified for md%d?\n", minor); + return 0; + } + + printk ("md: Will configure md%d (%s) from %s, below.\n", + minor, pername, devnames); + md_setup_args.devices[minor][i] = (kdev_t) 0; + md_setup_args.pers[minor] = level | factor | (fault << FAULT_SHIFT); + md_setup_args.set |= (1 << minor); + return 0; } + #endif void linear_init (void); @@ -1287,8 +1274,7 @@ int __init md_init (void) return (-1); } - blk_dev[MD_MAJOR].request_fn=DEVICE_REQUEST; - blk_dev[MD_MAJOR].current_request=NULL; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MD_MAJOR]=INT_MAX; memset(md_dev, 0, MAX_MD_DEV * sizeof (struct md_dev)); md_gendisk.next=gendisk_head; @@ -1318,7 +1304,18 @@ int __init md_init (void) #ifdef CONFIG_MD_BOOT void __init md_setup_drive(void) { - if(md_setup_args.set) - do_md_setup(md_setup_args.str, md_setup_args.ints); + int minor, i; + kdev_t dev; + + for (minor = 0; minor < MAX_MD_DEV; minor++) { + if ((md_setup_args.set & (1 << minor)) == 0) + continue; + printk("md: Loading md%d.\n", minor); + for (i = 0; (dev = md_setup_args.devices[minor][i]); i++) + do_md_add (minor, dev); + do_md_run (minor, md_setup_args.pers[minor]); + } } + +__setup("md=", md_setup); #endif diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 7c24449ac..cda45cc01 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -290,7 +290,7 @@ void nbd_clear_que(struct nbd_device *lo) #undef FAIL #define FAIL( s ) { printk( KERN_ERR "NBD, minor %d: " s "\n", dev ); goto error_out; } -static void do_nbd_request(void) +static void do_nbd_request(request_queue_t * q) { struct request *req; int dev; @@ -488,7 +488,7 @@ int nbd_init(void) #endif blksize_size[MAJOR_NR] = nbd_blksizes; blk_size[MAJOR_NR] = nbd_sizes; - blk_dev[MAJOR_NR].request_fn = do_nbd_request; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_nbd_request); for (i = 0; i < MAX_NBD; i++) { nbd_dev[i].refcnt = 0; nbd_dev[i].file = NULL; diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 96e0e421e..7db6626f4 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -220,7 +220,7 @@ static int pcd_packet(struct cdrom_device_info *cdi, static int pcd_detect(void); static void pcd_probe_capabilities(void); static void do_pcd_read_drq(void); -static void do_pcd_request(void); +static void do_pcd_request(request_queue_t * q); static void do_pcd_read(void); static int pcd_blocksizes[PCD_UNITS]; @@ -343,7 +343,7 @@ int pcd_init (void) /* preliminary initialisation */ for (unit=0;unit<PCD_UNITS;unit++) if (PCD.present) register_cdrom(&PCD.info); - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */ for (i=0;i<PCD_UNITS;i++) pcd_blocksizes[i] = 1024; @@ -750,7 +750,7 @@ static int pcd_detect( void ) /* I/O request processing */ -static void do_pcd_request (void) +static void do_pcd_request (request_queue_t * q) { int unit; @@ -814,7 +814,7 @@ static void pcd_start( void ) spin_lock_irqsave(&io_request_lock,saved_flags); pcd_busy = 0; end_request(0); - do_pcd_request(); + do_pcd_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -838,7 +838,7 @@ static void do_pcd_read( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(1); pcd_busy = 0; - do_pcd_request(); + do_pcd_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -862,14 +862,14 @@ static void do_pcd_read_drq( void ) pcd_busy = 0; pcd_bufblk = -1; end_request(0); - do_pcd_request(); + do_pcd_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } do_pcd_read(); spin_lock_irqsave(&io_request_lock,saved_flags); - do_pcd_request(); + do_pcd_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); } diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index bd2839053..cf8f1fc2f 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -265,7 +265,7 @@ void cleanup_module( void ); #endif static void pd_geninit(struct gendisk *ignored); static int pd_open(struct inode *inode, struct file *file); -static void do_pd_request(void); +static void do_pd_request(request_queue_t * q); static int pd_ioctl(struct inode *inode,struct file *file, unsigned int cmd, unsigned long arg); static int pd_release (struct inode *inode, struct file *file); @@ -404,7 +404,7 @@ int pd_init (void) name,major); return -1; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */ pd_gendisk.major = major; @@ -894,7 +894,7 @@ static int pd_ready( void ) return (!(RR(1,6) & STAT_BUSY)) ; } -static void do_pd_request (void) +static void do_pd_request (request_queue_t * q) { struct buffer_head * bh; struct request * req; @@ -992,7 +992,7 @@ static void do_pd_read_start( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pd_busy = 0; - do_pd_request(); + do_pd_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -1016,7 +1016,7 @@ static void do_pd_read_drq( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pd_busy = 0; - do_pd_request(); + do_pd_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -1031,7 +1031,7 @@ static void do_pd_read_drq( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(1); pd_busy = 0; - do_pd_request(); + do_pd_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); } @@ -1058,7 +1058,7 @@ static void do_pd_write_start( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pd_busy = 0; - do_pd_request(); + do_pd_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -1074,7 +1074,7 @@ static void do_pd_write_start( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pd_busy = 0; - do_pd_request(); + do_pd_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -1103,7 +1103,7 @@ static void do_pd_write_done( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pd_busy = 0; - do_pd_request(); + do_pd_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -1111,7 +1111,7 @@ static void do_pd_write_done( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(1); pd_busy = 0; - do_pd_request(); + do_pd_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); } diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 4dba8c8b5..1b935dc50 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -246,7 +246,7 @@ int pf_init(void); void cleanup_module( void ); #endif static int pf_open(struct inode *inode, struct file *file); -static void do_pf_request(void); +static void do_pf_request(request_queue_t * q); static int pf_ioctl(struct inode *inode,struct file *file, unsigned int cmd, unsigned long arg); @@ -365,7 +365,7 @@ int pf_init (void) /* preliminary initialisation */ major); return -1; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */ for (i=0;i<PF_UNITS;i++) pf_blocksizes[i] = 1024; @@ -863,7 +863,7 @@ static int pf_ready( void ) return (((RR(1,6)&(STAT_BUSY|pf_mask)) == pf_mask)); } -static void do_pf_request (void) +static void do_pf_request (request_queue_t * q) { struct buffer_head * bh; struct request * req; @@ -958,7 +958,7 @@ static void do_pf_read_start( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -984,7 +984,7 @@ static void do_pf_read_drq( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -999,7 +999,7 @@ static void do_pf_read_drq( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(1); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); } @@ -1025,7 +1025,7 @@ static void do_pf_write_start( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -1042,7 +1042,7 @@ static void do_pf_write_start( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -1072,7 +1072,7 @@ static void do_pf_write_done( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -1080,7 +1080,7 @@ static void do_pf_write_done( void ) spin_lock_irqsave(&io_request_lock,saved_flags); end_request(1); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); } diff --git a/drivers/block/pdc202xx.c b/drivers/block/pdc202xx.c index 2155aa8af..f65fb46be 100644 --- a/drivers/block/pdc202xx.c +++ b/drivers/block/pdc202xx.c @@ -78,6 +78,7 @@ * Released under terms of General Public License */ +#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> @@ -220,7 +221,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) int err; unsigned int drive_conf; - byte drive_pci; + byte drive_pci, speed_ok = 0; byte test1, test2, speed = -1; byte AP, BP, CP, DP, TB, TC; unsigned short EP; @@ -278,16 +279,20 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) switch(drive_number) { case 0: drive_pci = 0x60; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) { + speed_ok = 1; goto chipset_is_set; + } pci_read_config_byte(dev, (drive_pci), &test1); if (!(test1 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); break; case 1: drive_pci = 0x64; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) { + speed_ok = 1; goto chipset_is_set; + } pci_read_config_byte(dev, 0x60, &test1); pci_read_config_byte(dev, (drive_pci), &test2); if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) @@ -295,16 +300,20 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) break; case 2: drive_pci = 0x68; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) { + speed_ok = 1; goto chipset_is_set; + } pci_read_config_byte(dev, (drive_pci), &test1); if (!(test1 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); break; case 3: drive_pci = 0x6c; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) { + speed_ok = 1; goto chipset_is_set; + } pci_read_config_byte(dev, 0x68, &test1); pci_read_config_byte(dev, (drive_pci), &test2); if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) @@ -402,7 +411,8 @@ chipset_is_set: decode_registers(REG_D, DP); #endif /* PDC202XX_DECODE_REGISTER_INFO */ - err = ide_config_drive_speed(drive, speed); + if (!speed_ok) + err = ide_config_drive_speed(drive, speed); #if PDC202XX_DEBUG_DRIVE_INFO printk("%s: %s drive%d 0x%08x ", diff --git a/drivers/block/pdc4030.c b/drivers/block/pdc4030.c index bf5465695..0b682645c 100644 --- a/drivers/block/pdc4030.c +++ b/drivers/block/pdc4030.c @@ -158,6 +158,7 @@ int __init setup_pdc4030 (ide_hwif_t *hwif) ide_hwif_t *hwif2; struct dc_ident ident; int i; + ide_startstop_t startstop; if (!hwif) return 0; @@ -174,7 +175,7 @@ int __init setup_pdc4030 (ide_hwif_t *hwif) if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) { return 0; } - if (ide_wait_stat(drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) { + if (ide_wait_stat(&startstop, drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) { printk(KERN_INFO "%s: Failed Promise read config!\n",hwif->name); return 0; @@ -301,7 +302,7 @@ void __init ide_probe_for_pdc4030(void) /* * promise_read_intr() is the handler for disk read/multread interrupts */ -static void promise_read_intr (ide_drive_t *drive) +static ide_startstop_t promise_read_intr (ide_drive_t *drive) { byte stat; int total_remaining; @@ -309,8 +310,7 @@ static void promise_read_intr (ide_drive_t *drive) struct request *rq; if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { - ide_error(drive, "promise_read_intr", stat); - return; + return ide_error(drive, "promise_read_intr", stat); } read_again: @@ -367,12 +367,13 @@ read_next: printk(KERN_DEBUG "%s: promise_read: waiting for" "interrupt\n", drive->name); #endif - return; + return ide_started; } printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left " "!DRQ !BUSY\n", drive->name); - ide_error(drive, "promise read intr", stat); + return ide_error(drive, "promise read intr", stat); } + return ide_stopped; } /* @@ -383,7 +384,7 @@ read_next: * * Once not busy, the end request is called. */ -static void promise_complete_pollfunc(ide_drive_t *drive) +static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = hwgroup->rq; @@ -392,13 +393,12 @@ static void promise_complete_pollfunc(ide_drive_t *drive) if (GET_STAT() & BUSY_STAT) { if (time_before(jiffies, hwgroup->poll_timeout)) { ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL); - return; /* continue polling... */ + return ide_started; /* continue polling... */ } hwgroup->poll_timeout = 0; printk(KERN_ERR "%s: completion timeout - still busy!\n", drive->name); - ide_error(drive, "busy timeout", GET_STAT()); - return; + return ide_error(drive, "busy timeout", GET_STAT()); } hwgroup->poll_timeout = 0; @@ -409,24 +409,24 @@ static void promise_complete_pollfunc(ide_drive_t *drive) i -= rq->current_nr_sectors; ide_end_request(1, hwgroup); } + return ide_stopped; } /* * promise_write_pollfunc() is the handler for disk write completion polling. */ -static void promise_write_pollfunc (ide_drive_t *drive) +static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); if (IN_BYTE(IDE_NSECTOR_REG) != 0) { if (time_before(jiffies, hwgroup->poll_timeout)) { ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL); - return; /* continue polling... */ + return ide_started; /* continue polling... */ } hwgroup->poll_timeout = 0; printk(KERN_ERR "%s: write timed-out!\n",drive->name); - ide_error (drive, "write timeout", GET_STAT()); - return; + return ide_error (drive, "write timeout", GET_STAT()); } /* @@ -439,7 +439,7 @@ static void promise_write_pollfunc (ide_drive_t *drive) printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n", drive->name, GET_STAT()); #endif - return; + return ide_started; } /* @@ -449,7 +449,7 @@ static void promise_write_pollfunc (ide_drive_t *drive) * before the final 4 sectors are transfered. There is no interrupt generated * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY. */ -static void promise_write (ide_drive_t *drive) +static ide_startstop_t promise_write (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = &hwgroup->wrq; @@ -465,21 +465,25 @@ static void promise_write (ide_drive_t *drive) * the polling strategy as defined above. */ if (rq->nr_sectors > 4) { - ide_multwrite(drive, rq->nr_sectors - 4); + if (ide_multwrite(drive, rq->nr_sectors - 4)) + return ide_stopped; hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL); + return ide_started; } else { /* * There are 4 or fewer sectors to transfer, do them all in one go * and wait for NOT BUSY. */ - ide_multwrite(drive, rq->nr_sectors); + if (ide_multwrite(drive, rq->nr_sectors)) + return ide_stopped; hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL); #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, " "status = %02x\n", drive->name, GET_STAT()); #endif + return ide_started; } } @@ -488,7 +492,7 @@ static void promise_write (ide_drive_t *drive) * already set up. It issues a READ or WRITE command to the Promise * controller, assuming LBA has been used to set up the block number. */ -void do_pdc4030_io (ide_drive_t *drive, struct request *rq) +ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq) { unsigned long timeout; byte stat; @@ -510,8 +514,7 @@ void do_pdc4030_io (ide_drive_t *drive, struct request *rq) stat=GET_STAT(); if (stat & DRQ_STAT) { udelay(1); - promise_read_intr(drive); - return; + return promise_read_intr(drive); } if (IN_BYTE(IDE_SELECT_REG) & 0x01) { #ifdef DEBUG_READ @@ -519,29 +522,31 @@ void do_pdc4030_io (ide_drive_t *drive, struct request *rq) "interrupt\n", drive->name); #endif ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL); - return; + return ide_started; } udelay(1); } while (time_before(jiffies, timeout)); printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n", drive->name); - + return ide_stopped; } else if (rq->cmd == WRITE) { + ide_startstop_t startstop; OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG); - if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { + if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { printk(KERN_ERR "%s: no DRQ after issuing " "PROMISE_WRITE\n", drive->name); - return; + return startstop; } if (!drive->unmask) __cli(); /* local CPU only */ HWGROUP(drive)->wrq = *rq; /* scratchpad */ - promise_write(drive); + return promise_write(drive); } else { printk("KERN_WARNING %s: bad command: %d\n", drive->name, rq->cmd); ide_end_request(0, HWGROUP(drive)); + return ide_stopped; } } diff --git a/drivers/block/piix.c b/drivers/block/piix.c index a9bcb347c..f3db84963 100644 --- a/drivers/block/piix.c +++ b/drivers/block/piix.c @@ -68,6 +68,42 @@ #define PIIX_DEBUG_DRIVE_INFO 0 +#define DISPLAY_PIIX_TIMINGS + +#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) +#include <linux/stat.h> +#include <linux/proc_fs.h> + +static int piix_get_info(char *, char **, off_t, int); +extern int (*piix_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int piix_get_info (char *buffer, char **addr, off_t offset, int count) +{ + /* int rc; */ + int piix_who = (bmide_dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? 4 : 3; + char *p = buffer; + p += sprintf(p, "\n Intel PIIX%d Chipset.\n", piix_who); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n\n"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "\n"); + p += sprintf(p, "\n"); + +/* + * FIXME.... Add configuration junk data....blah blah...... + */ + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */ + +/* + * Used to set Fifo configuration via kernel command line: + */ + +byte piix_proc = 0; + extern char *ide_xfer_verbose (byte xfer_rate); #ifdef CONFIG_BLK_DEV_PIIX_TUNING @@ -248,6 +284,18 @@ static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive) } #endif /* CONFIG_BLK_DEV_PIIX_TUNING */ +unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name) +{ +#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) + if (!piix_proc) { + piix_proc = 1; + bmide_dev = dev; + piix_display_info = &piix_get_info; + } +#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */ + return 0; +} + void __init ide_init_piix (ide_hwif_t *hwif) { hwif->tuneproc = &piix_tune_drive; @@ -262,5 +310,4 @@ void __init ide_init_piix (ide_hwif_t *hwif) hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } - } diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index 221a3297a..a90f3bbd6 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -70,7 +70,7 @@ int ps2esdi_init(void); static void ps2esdi_geninit(struct gendisk *ignored); -static void do_ps2esdi_request(void); +static void do_ps2esdi_request(request_queue_t * q); static void ps2esdi_readwrite(int cmd, u_char drive, u_int block, u_int count); @@ -188,7 +188,7 @@ int __init ps2esdi_init(void) return -1; } /* set up some global information - indicating device specific info */ - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */ /* some minor housekeeping - setup the global gendisk structure */ @@ -464,7 +464,7 @@ static void __init ps2esdi_get_device_cfg(void) } /* strategy routine that handles most of the IO requests */ -static void do_ps2esdi_request(void) +static void do_ps2esdi_request(request_queue_t * q) { u_int block, count; /* since, this routine is called with interrupts cleared - they @@ -487,7 +487,7 @@ static void do_ps2esdi_request(void) printk("%s: DMA above 16MB not supported\n", DEVICE_NAME); end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(q); return; } /* check for above 16Mb dmas */ if ((CURRENT_DEV < ps2esdi_drives) && @@ -521,7 +521,7 @@ static void do_ps2esdi_request(void) printk("%s: Unknown command\n", DEVICE_NAME); end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(q); break; } /* handle different commands */ } @@ -531,7 +531,7 @@ static void do_ps2esdi_request(void) CURRENT->sector, ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects); end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(q); } } /* main strategy routine */ @@ -598,11 +598,11 @@ static void ps2esdi_readwrite(int cmd, u_char drive, u_int block, u_int count) if (ps2esdi_out_cmd_blk(cmd_blk)) { printk("%s: Controller failed\n", DEVICE_NAME); if ((++CURRENT->errors) < MAX_RETRIES) - return do_ps2esdi_request(); + return do_ps2esdi_request(NULL); else { end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); } } /* check for failure to put out the command block */ @@ -901,11 +901,11 @@ static void ps2esdi_normal_interrupt_handler(u_int int_ret_code) outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); if ((++CURRENT->errors) < MAX_RETRIES) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); else { end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); } break; } @@ -947,11 +947,11 @@ static void ps2esdi_normal_interrupt_handler(u_int int_ret_code) outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); if ((++CURRENT->errors) < MAX_RETRIES) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); else { end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); } break; @@ -961,7 +961,7 @@ static void ps2esdi_normal_interrupt_handler(u_int int_ret_code) outb(CTRL_ENABLE_INTR, ESDI_CONTROL); end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); break; case INT_CMD_FORMAT: @@ -993,11 +993,11 @@ static void ps2esdi_continue_request(void) if (CURRENT->nr_sectors -= CURRENT->current_nr_sectors) { CURRENT->buffer += CURRENT->current_nr_sectors * SECT_SIZE; CURRENT->sector += CURRENT->current_nr_sectors; - do_ps2esdi_request(); + do_ps2esdi_request(NULL); } else { end_request(SUCCES); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); } } diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 9fec26361..f83a76162 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -181,7 +181,7 @@ __setup("ramdisk_size=", ramdisk_size2); * allocated size, we must get rid of it... * */ -static void rd_request(void) +static void rd_request(request_queue_t * q) { unsigned int minor; unsigned long offset, len; @@ -276,9 +276,11 @@ static ssize_t initrd_read(struct file *file, char *buf, static int initrd_release(struct inode *inode,struct file *file) { + extern void free_initrd_mem(unsigned long, unsigned long); + + if (--initrd_users) return 0; + free_initrd_mem(initrd_start, initrd_end); initrd_start = 0; - /* No need to actually release the pages, because that is - done later by free_all_bootmem. */ return 0; } @@ -339,8 +341,20 @@ static struct file_operations fd_fops = { block_fsync /* fsync */ }; +/* Before freeing the module, invalidate all of the protected buffers! */ +static void __exit rd_cleanup (void) +{ + int i; + + for (i = 0 ; i < NUM_RAMDISKS; i++) + invalidate_buffers(MKDEV(MAJOR_NR, i)); + + unregister_blkdev( MAJOR_NR, "ramdisk" ); + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); +} + /* This is the registration and initialization section of the RAM disk driver */ -int __init rd_init(void) +int __init rd_init (void) { int i; @@ -357,7 +371,7 @@ int __init rd_init(void) return -EIO; } - blk_dev[MAJOR_NR].request_fn = &rd_request; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &rd_request); for (i = 0; i < NUM_RAMDISKS; i++) { /* rd_size is given in kB */ @@ -378,37 +392,17 @@ int __init rd_init(void) return 0; } -/* loadable module support */ - #ifdef MODULE +module_init(rd_init); +#endif +module_exit(rd_cleanup); +/* loadable module support */ MODULE_PARM (rd_size, "1i"); MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes."); MODULE_PARM (rd_blocksize, "i"); MODULE_PARM_DESC(rd_blocksize, "Blocksize of each RAM disk in bytes."); -int init_module(void) -{ - int error = rd_init(); - if (!error) - printk(KERN_INFO "RAMDISK: Loaded as module.\n"); - return error; -} - -/* Before freeing the module, invalidate all of the protected buffers! */ -void cleanup_module(void) -{ - int i; - - for (i = 0 ; i < NUM_RAMDISKS; i++) - invalidate_buffers(MKDEV(MAJOR_NR, i)); - - unregister_blkdev( MAJOR_NR, "ramdisk" ); - blk_dev[MAJOR_NR].request_fn = 0; -} - -#endif /* MODULE */ - /* End of non-loading portions of the RAM disk driver */ #ifdef RD_LOADER diff --git a/drivers/block/sis5513.c b/drivers/block/sis5513.c index 8a3abd025..bdd30a20d 100644 --- a/drivers/block/sis5513.c +++ b/drivers/block/sis5513.c @@ -8,6 +8,7 @@ * Tested and designed on the SiS620/5513 chipset. */ +#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> @@ -27,13 +28,35 @@ #include "ide_modes.h" -#define SIS5513_DEBUG_DRIVE_INFO 0 - #define DISPLAY_SIS_TIMINGS +#define SIS5513_DEBUG_DRIVE_INFO 0 -static struct pci_dev *host_dev; +static struct pci_dev *host_dev = NULL; + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +#define SIS5513_FLAG_ATA_00 0x00000000 +#define SIS5513_FLAG_ATA_16 0x00000001 +#define SIS5513_FLAG_ATA_33 0x00000002 +#define SIS5513_FLAG_ATA_66 0x00000004 +#define SIS5513_FLAG_LATENCY 0x00000010 + +static const struct { + const char *name; + unsigned short host_id; + unsigned int flags; +} SiSHostChipInfo[] = { + { "SiS530", PCI_DEVICE_ID_SI_530, SIS5513_FLAG_ATA_66, }, + { "SiS540", PCI_DEVICE_ID_SI_540, SIS5513_FLAG_ATA_66, }, + { "SiS620", PCI_DEVICE_ID_SI_620, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, + { "SiS630", PCI_DEVICE_ID_SI_630, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, + { "SiS5597", PCI_DEVICE_ID_SI_5597, SIS5513_FLAG_ATA_33, }, + { "SiS5600", PCI_DEVICE_ID_SI_5600, SIS5513_FLAG_ATA_33, }, + { "SiS5511", PCI_DEVICE_ID_SI_5511, SIS5513_FLAG_ATA_16, }, +}; #if 0 + static struct _pio_mode_mapping { byte data_active; byte recovery; @@ -83,8 +106,8 @@ static __inline__ char * find_udma_mode (byte cycle_time) #include <linux/stat.h> #include <linux/proc_fs.h> -static int sis_get_info(char *, char **, off_t, int, int); -extern int (*sis_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */ +static int sis_get_info(char *, char **, off_t, int); +extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */ struct pci_dev *bmide_dev; static char *cable_type[] = { @@ -117,14 +140,11 @@ static char *active_time [] = { "6 PCICLK", "12 PCICLK" }; -static int sis_get_info (char *buffer, char **addr, off_t offset, int count, int dummy) +static int sis_get_info (char *buffer, char **addr, off_t offset, int count) { int rc; char *p = buffer; byte reg,reg1; -#if 0 - byte cyc, rec, act; -#endif u16 reg2, reg3; p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); @@ -213,16 +233,16 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) byte drive_pci, test1, test2, mask; int err; - byte speed = 0x00; - byte unmask = 0xE0; - byte four_two = 0x00; + byte speed = 0x00, unmask = 0xE0, four_two = 0x00; int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); byte udma_66 = ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0; if (host_dev) { switch(host_dev->device) { case PCI_DEVICE_ID_SI_530: + case PCI_DEVICE_ID_SI_540: case PCI_DEVICE_ID_SI_620: + case PCI_DEVICE_ID_SI_630: unmask = 0xF0; four_two = 0x01; default: @@ -246,13 +266,15 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) pci_read_config_byte(dev, drive_pci|0x01, &test2); } - if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two)) { + if ((id->dma_ultra & 0x0010) && (ultra) && + (udma_66) && (four_two)) { if (!(test2 & 0x90)) { pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); pci_write_config_byte(dev, drive_pci|0x01, test2|0x90); } speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two)) { + } else if ((id->dma_ultra & 0x0008) && (ultra) && + (udma_66) && (four_two)) { if (!(test2 & 0xA0)) { pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); pci_write_config_byte(dev, drive_pci|0x01, test2|0xA0); @@ -438,29 +460,23 @@ int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive) unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name) { struct pci_dev *host; + int i = 0; byte latency = 0; pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency); - for (host = pci_devices; host; host=host->next) { - if (host->vendor == PCI_VENDOR_ID_SI && - host->device == PCI_DEVICE_ID_SI_620) { + for (i = 0; i < arraysize (SiSHostChipInfo) && !host_dev; i++) { + host = pci_find_device (PCI_VENDOR_ID_SI, + SiSHostChipInfo[i].host_id, + NULL); + if (!host) + continue; + + host_dev = host; + printk(SiSHostChipInfo[i].name); + if (SiSHostChipInfo[i].flags & SIS5513_FLAG_LATENCY) { if (latency != 0x10) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10); - host_dev = host; - break; - } else if (host->vendor == PCI_VENDOR_ID_SI && - host->device == PCI_DEVICE_ID_SI_530) { - host_dev = host; - break; - } else if (host->vendor == PCI_VENDOR_ID_SI && - host->device == PCI_DEVICE_ID_SI_5600) { - host_dev = host; - break; - } else if (host->vendor == PCI_VENDOR_ID_SI && - host->device == PCI_DEVICE_ID_SI_5597) { - host_dev = host; - break; } } @@ -468,9 +484,10 @@ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name) byte reg52h = 0; pci_read_config_byte(dev, 0x52, ®52h); - if (!(reg52h & 0x04)) + if (!(reg52h & 0x04)) { /* set IDE controller to operate in Compabitility mode obly */ pci_write_config_byte(dev, 0x52, reg52h|0x04); + } #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) sis_proc = 1; bmide_dev = dev; @@ -489,7 +506,9 @@ unsigned int __init ata66_sis5513 (ide_hwif_t *hwif) if (host_dev) { switch(host_dev->device) { case PCI_DEVICE_ID_SI_530: + case PCI_DEVICE_ID_SI_540: case PCI_DEVICE_ID_SI_620: + case PCI_DEVICE_ID_SI_630: ata66 = (reg48h & mask) ? 0 : 1; default: break; @@ -509,7 +528,9 @@ void __init ide_init_sis5513 (ide_hwif_t *hwif) if (host_dev) { switch(host_dev->device) { case PCI_DEVICE_ID_SI_530: + case PCI_DEVICE_ID_SI_540: case PCI_DEVICE_ID_SI_620: + case PCI_DEVICE_ID_SI_630: case PCI_DEVICE_ID_SI_5600: case PCI_DEVICE_ID_SI_5597: hwif->autodma = 1; diff --git a/drivers/block/sl82c105.c b/drivers/block/sl82c105.c index fa47adbb7..e029fcce6 100644 --- a/drivers/block/sl82c105.c +++ b/drivers/block/sl82c105.c @@ -61,6 +61,7 @@ static unsigned int get_timing_sl82c105(ide_pio_data_t *p) static int ide_set_drive_pio_mode(ide_drive_t *drive, byte pio) { ide_hwif_t *hwif = HWIF(drive); + ide_startstop_t startstop; if (pio > 2) { /* FIXME: I don't believe that this SELECT_DRIVE is required, @@ -74,7 +75,7 @@ static int ide_set_drive_pio_mode(ide_drive_t *drive, byte pio) OUT_BYTE(0x03, IDE_FEATURE_REG); OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); - if (ide_wait_stat(drive, DRIVE_READY, + if (ide_wait_stat(&startstop, drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD)) { printk("%s: drive not ready for command\n", drive->name); diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index cee5493da..06cd279af 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -219,7 +219,7 @@ static unsigned short write_postamble[] = { static void swim3_select(struct floppy_state *fs, int sel); static void swim3_action(struct floppy_state *fs, int action); static int swim3_readbit(struct floppy_state *fs, int bit); -static void do_fd_request(void); +static void do_fd_request(request_queue_t * q); static void start_request(struct floppy_state *fs); static void set_timeout(struct floppy_state *fs, int nticks, void (*proc)(unsigned long)); @@ -290,7 +290,7 @@ static int swim3_readbit(struct floppy_state *fs, int bit) return (stat & DATA) == 0; } -static void do_fd_request(void) +static void do_fd_request(request_queue_t * q) { int i; for(i=0;i<floppy_count;i++) @@ -1089,7 +1089,7 @@ int swim3_init(void) MAJOR_NR); return -EBUSY; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[MAJOR_NR] = floppy_blocksizes; blk_size[MAJOR_NR] = floppy_sizes; } diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c index 462ef7f26..f15f590a4 100644 --- a/drivers/block/swim_iop.c +++ b/drivers/block/swim_iop.c @@ -121,7 +121,7 @@ static void release_drive(struct floppy_state *fs); static void set_timeout(struct floppy_state *fs, int nticks, void (*proc)(unsigned long)); static void fd_request_timeout(unsigned long); -static void do_fd_request(void); +static void do_fd_request(request_queue_t * q); static void start_request(struct floppy_state *fs); static struct file_operations floppy_fops = { @@ -163,7 +163,7 @@ int swimiop_init(void) MAJOR_NR); return -EBUSY; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[MAJOR_NR] = floppy_blocksizes; blk_size[MAJOR_NR] = floppy_sizes; @@ -566,7 +566,7 @@ static void set_timeout(struct floppy_state *fs, int nticks, restore_flags(flags); } -static void do_fd_request(void) +static void do_fd_request(request_queue_t * q) { int i; diff --git a/drivers/block/via82cxxx.c b/drivers/block/via82cxxx.c index e6f61c03f..9d7836e98 100644 --- a/drivers/block/via82cxxx.c +++ b/drivers/block/via82cxxx.c @@ -119,8 +119,8 @@ static char *control3_str[] = { "192" }; -static int via_get_info(char *, char **, off_t, int, int); -extern int (*via_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */ +static int via_get_info(char *, char **, off_t, int); +extern int (*via_display_info)(char *, char **, off_t, int); /* ide-proc.c */ static struct pci_dev *bmide_dev; static char * print_apollo_drive_config (char *buf, struct pci_dev *dev) @@ -304,7 +304,7 @@ static char * print_apollo_chipset_control3 (char *buf, struct pci_dev *dev, return (char *)p; } -static int via_get_info (char *buffer, char **addr, off_t offset, int count, int dummy) +static int via_get_info (char *buffer, char **addr, off_t offset, int count) { /* * print what /proc/via displays, diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 44e8317f0..6d2bde45a 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -185,7 +185,7 @@ int __init xd_init (void) printk("xd: Unable to get major number %d\n",MAJOR_NR); return -1; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */ xd_gendisk.next = gendisk_head; gendisk_head = &xd_gendisk; @@ -207,7 +207,7 @@ static u_char __init xd_detect (u_char *controller, unsigned int *address) for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])) && !found; i++) for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])) && !found; j++) - if (check_signature(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) { + if (isa_check_signature(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) { *controller = j; xd_type = j; *address = xd_bases[i]; @@ -284,7 +284,7 @@ static int xd_open (struct inode *inode,struct file *file) } /* do_xd_request: handle an incoming request */ -static void do_xd_request (void) +static void do_xd_request (request_queue_t * q) { u_int block,count,retry; int code; @@ -1143,7 +1143,7 @@ static void xd_done (void) struct gendisk ** gdp; blksize_size[MAJOR_NR] = NULL; - blk_dev[MAJOR_NR].request_fn = NULL; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); blk_size[MAJOR_NR] = NULL; hardsect_size[MAJOR_NR] = NULL; read_ahead[MAJOR_NR] = 0; diff --git a/drivers/block/xd.h b/drivers/block/xd.h index b45fae4e7..c121e8e9f 100644 --- a/drivers/block/xd.h +++ b/drivers/block/xd.h @@ -112,7 +112,7 @@ static u_char xd_initdrives (void (*init_drive)(u_char drive)); static void xd_geninit (struct gendisk *); static int xd_open (struct inode *inode,struct file *file); -static void do_xd_request (void); +static void do_xd_request (request_queue_t * q); static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg); static int xd_release (struct inode *inode,struct file *file); static int xd_reread_partitions (kdev_t dev); diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index f75150e4a..cceb82dd5 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -68,7 +68,7 @@ static int list_count = 0; static int current_device = -1; static void -do_z2_request( void ) +do_z2_request( request_queue_t * q ) { u_long start, len, addr, size; @@ -373,7 +373,7 @@ z2_init( void ) } } - blk_dev[ MAJOR_NR ].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[ MAJOR_NR ] = z2_blocksizes; blk_size[ MAJOR_NR ] = z2_sizes; |